From de9a06c969e9c59d3f8413e70d5f55813ca5e8f8 Mon Sep 17 00:00:00 2001 From: jimenezz22 Date: Sun, 17 Aug 2025 16:10:59 -0600 Subject: [PATCH 01/10] feat: initialize project structure with essential configuration files and documentation --- client-new/.gitignore | 58 ++++++++++++++++++++++++++++++++++++++ client-new/package.json | 15 ++++++++++ client-new/pages/index.mdx | 14 +++++++++ client-new/tsconfig.json | 30 ++++++++++++++++++++ client-new/vocs.config.ts | 12 ++++++++ 5 files changed, 129 insertions(+) create mode 100644 client-new/.gitignore create mode 100644 client-new/package.json create mode 100644 client-new/pages/index.mdx create mode 100644 client-new/tsconfig.json create mode 100644 client-new/vocs.config.ts diff --git a/client-new/.gitignore b/client-new/.gitignore new file mode 100644 index 0000000..c207408 --- /dev/null +++ b/client-new/.gitignore @@ -0,0 +1,58 @@ +# Dependencies +node_modules/ +.pnp +.pnp.js + +# Build outputs +dist/ +.vocs/ +build/ +out/ + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# Logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# OS files +.DS_Store +Thumbs.db + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# TypeScript +*.tsbuildinfo + +# Testing +coverage/ +.nyc_output + +# Misc +*.log +.cache +.parcel-cache +.vercel +.turbo + +# Temporary files +*.tmp +*.temp +.tmp/ +.temp/ \ No newline at end of file diff --git a/client-new/package.json b/client-new/package.json new file mode 100644 index 0000000..4dfee0b --- /dev/null +++ b/client-new/package.json @@ -0,0 +1,15 @@ +{ + "name": "dojo-by-example", + "version": "2.0.0", + "description": "Learn Dojo Engine through practical examples", + "type": "module", + "scripts": { + "dev": "vocs dev", + "build": "vocs build", + "preview": "vocs preview", + "type-check": "tsc --noEmit" + }, + "keywords": ["dojo", "starknet", "blockchain", "gaming", "documentation"], + "author": "Dojo by Example Team", + "license": "MIT" +} diff --git a/client-new/pages/index.mdx b/client-new/pages/index.mdx new file mode 100644 index 0000000..febc3c5 --- /dev/null +++ b/client-new/pages/index.mdx @@ -0,0 +1,14 @@ +# Welcome to Dojo by Example + +This is the new Vocs-powered documentation site for learning Dojo Engine. + +## Getting Started + +The site is being migrated to a modern stack with: +- Latest Vocs version +- React 19 +- Tailwind CSS +- Improved theme switching +- Better performance + +Stay tuned for more content! \ No newline at end of file diff --git a/client-new/tsconfig.json b/client-new/tsconfig.json new file mode 100644 index 0000000..31f062c --- /dev/null +++ b/client-new/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "jsx": "react-jsx", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowSyntheticDefaultImports": true, + "noEmit": true, + "types": ["vite/client"], + "paths": { + "@/*": ["./src/*"], + "@components/*": ["./components/*"], + "@pages/*": ["./pages/*"], + "@public/*": ["./public/*"] + } + }, + "include": [ + "**/*.ts", + "**/*.tsx", + "**/*.mdx", + "vocs.config.ts" + ], + "exclude": ["node_modules", "dist"] +} \ No newline at end of file diff --git a/client-new/vocs.config.ts b/client-new/vocs.config.ts new file mode 100644 index 0000000..0ff4493 --- /dev/null +++ b/client-new/vocs.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vocs' + +export default defineConfig({ + title: 'Dojo by Example', + description: 'Learn Dojo Engine through practical examples', + sidebar: [ + { + text: 'Introduction', + link: '/', + }, + ], +}) \ No newline at end of file From 96fc9f4ff937349c4cedac782aebcd19fafa86c5 Mon Sep 17 00:00:00 2001 From: jimenezz22 Date: Sun, 17 Aug 2025 16:17:50 -0600 Subject: [PATCH 02/10] Add design system, global styles, and partner logos - Introduced a comprehensive design system including design tokens, theme configuration, and global styles for Dojo by Example. - Added a new SVG logo for Torii in the partners directory. - Established a color palette with brand and semantic colors. - Implemented typography and spacing scales for consistent styling. - Enabled automatic dark/light mode switching in the design system. - Created utility classes for common styles and animations. - Configured theme settings in TypeScript for easy access to design tokens. - Documented the design system structure and usage in README files. --- client-new/public/logos/Horizontal_Dark.svg | 16 ++ client-new/public/logos/Horizontal_Light.svg | 16 ++ client-new/public/logos/Icon_Dark.svg | 3 + client-new/public/logos/Icon_Light.svg | 3 + client-new/public/logos/Vertical_Dark.svg | 16 ++ client-new/public/logos/Vertical_Light.svg | 16 ++ client-new/public/partners/Cartridge.svg | 13 ++ client-new/public/partners/DojoLogo.svg | 8 + client-new/public/partners/KatanaLogo.svg | 9 + client-new/public/partners/Onlydust.svg | 24 +++ client-new/public/partners/OrigamiLogo.svg | 13 ++ client-new/public/partners/SayaLogo.svg | 8 + client-new/public/partners/SozoLogo.svg | 7 + client-new/public/partners/Starknet.svg | 1 + client-new/public/partners/ToriiLogo.svg | 10 + client-new/styles/README.md | 65 +++++++ client-new/styles/design-tokens.css | 135 +++++++++++++ client-new/styles/globals.css | 192 +++++++++++++++++++ client-new/styles/theme.ts | 105 ++++++++++ 19 files changed, 660 insertions(+) create mode 100644 client-new/public/logos/Horizontal_Dark.svg create mode 100644 client-new/public/logos/Horizontal_Light.svg create mode 100644 client-new/public/logos/Icon_Dark.svg create mode 100644 client-new/public/logos/Icon_Light.svg create mode 100644 client-new/public/logos/Vertical_Dark.svg create mode 100644 client-new/public/logos/Vertical_Light.svg create mode 100644 client-new/public/partners/Cartridge.svg create mode 100644 client-new/public/partners/DojoLogo.svg create mode 100644 client-new/public/partners/KatanaLogo.svg create mode 100644 client-new/public/partners/Onlydust.svg create mode 100644 client-new/public/partners/OrigamiLogo.svg create mode 100644 client-new/public/partners/SayaLogo.svg create mode 100644 client-new/public/partners/SozoLogo.svg create mode 100644 client-new/public/partners/Starknet.svg create mode 100644 client-new/public/partners/ToriiLogo.svg create mode 100644 client-new/styles/README.md create mode 100644 client-new/styles/design-tokens.css create mode 100644 client-new/styles/globals.css create mode 100644 client-new/styles/theme.ts diff --git a/client-new/public/logos/Horizontal_Dark.svg b/client-new/public/logos/Horizontal_Dark.svg new file mode 100644 index 0000000..839c33b --- /dev/null +++ b/client-new/public/logos/Horizontal_Dark.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/client-new/public/logos/Horizontal_Light.svg b/client-new/public/logos/Horizontal_Light.svg new file mode 100644 index 0000000..fe07b72 --- /dev/null +++ b/client-new/public/logos/Horizontal_Light.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/client-new/public/logos/Icon_Dark.svg b/client-new/public/logos/Icon_Dark.svg new file mode 100644 index 0000000..47449ec --- /dev/null +++ b/client-new/public/logos/Icon_Dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/client-new/public/logos/Icon_Light.svg b/client-new/public/logos/Icon_Light.svg new file mode 100644 index 0000000..47449ec --- /dev/null +++ b/client-new/public/logos/Icon_Light.svg @@ -0,0 +1,3 @@ + + + diff --git a/client-new/public/logos/Vertical_Dark.svg b/client-new/public/logos/Vertical_Dark.svg new file mode 100644 index 0000000..56e9c26 --- /dev/null +++ b/client-new/public/logos/Vertical_Dark.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/client-new/public/logos/Vertical_Light.svg b/client-new/public/logos/Vertical_Light.svg new file mode 100644 index 0000000..18b08a7 --- /dev/null +++ b/client-new/public/logos/Vertical_Light.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/client-new/public/partners/Cartridge.svg b/client-new/public/partners/Cartridge.svg new file mode 100644 index 0000000..f3d8556 --- /dev/null +++ b/client-new/public/partners/Cartridge.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/client-new/public/partners/DojoLogo.svg b/client-new/public/partners/DojoLogo.svg new file mode 100644 index 0000000..3d0eec9 --- /dev/null +++ b/client-new/public/partners/DojoLogo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/client-new/public/partners/KatanaLogo.svg b/client-new/public/partners/KatanaLogo.svg new file mode 100644 index 0000000..dee073d --- /dev/null +++ b/client-new/public/partners/KatanaLogo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/client-new/public/partners/Onlydust.svg b/client-new/public/partners/Onlydust.svg new file mode 100644 index 0000000..f200f45 --- /dev/null +++ b/client-new/public/partners/Onlydust.svg @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/client-new/public/partners/OrigamiLogo.svg b/client-new/public/partners/OrigamiLogo.svg new file mode 100644 index 0000000..e727754 --- /dev/null +++ b/client-new/public/partners/OrigamiLogo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/client-new/public/partners/SayaLogo.svg b/client-new/public/partners/SayaLogo.svg new file mode 100644 index 0000000..7bae812 --- /dev/null +++ b/client-new/public/partners/SayaLogo.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/client-new/public/partners/SozoLogo.svg b/client-new/public/partners/SozoLogo.svg new file mode 100644 index 0000000..210d5b9 --- /dev/null +++ b/client-new/public/partners/SozoLogo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/client-new/public/partners/Starknet.svg b/client-new/public/partners/Starknet.svg new file mode 100644 index 0000000..aa25044 --- /dev/null +++ b/client-new/public/partners/Starknet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client-new/public/partners/ToriiLogo.svg b/client-new/public/partners/ToriiLogo.svg new file mode 100644 index 0000000..b1ee8ce --- /dev/null +++ b/client-new/public/partners/ToriiLogo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/client-new/styles/README.md b/client-new/styles/README.md new file mode 100644 index 0000000..efc4e10 --- /dev/null +++ b/client-new/styles/README.md @@ -0,0 +1,65 @@ +# Design System + +## Overview +This directory contains the design system for Dojo by Example, including design tokens, theme configuration, and global styles. + +## Files + +- `design-tokens.css` - CSS custom properties for colors, spacing, typography, etc. +- `theme.ts` - TypeScript theme configuration for Vocs and components +- `globals.css` - Global styles and Tailwind CSS imports + +## Color Palette + +### Brand Colors +- Primary: `#ff3000` (Dojo Red) +- Primary Hover: `#e62900` +- Primary Light: `#ff6b4a` +- Primary Dark: `#cc2600` + +### Semantic Colors +- Success: `#10b981` +- Warning: `#f59e0b` +- Error: `#ef4444` +- Info: `#3b82f6` + +## Typography +- Font Family: DM Sans (primary), JetBrains Mono (code) +- Scale: xs (0.75rem) to 5xl (3rem) + +## Spacing +Uses a consistent scale from xs (0.25rem) to 3xl (4rem) + +## Theme Switching +The design system supports automatic dark/light mode switching: +- Light mode: Default white backgrounds with dark text +- Dark mode: Dark backgrounds (#0a0a0a base) with light text + +## Usage + +### In CSS/Tailwind +```css +/* Use CSS variables */ +.my-element { + color: var(--dojo-primary); + padding: var(--space-md); +} +``` + +### In React Components +```tsx +import { theme } from '@/styles/theme' + +// Use theme values +
+ Dojo by Example +
+``` + +## Assets Structure +``` +public/ +├── logos/ # Dojo logos (light/dark variants) +├── partners/ # Partner/sponsor logos +└── og-images/ # Open Graph images for social sharing +``` \ No newline at end of file diff --git a/client-new/styles/design-tokens.css b/client-new/styles/design-tokens.css new file mode 100644 index 0000000..ad68d3e --- /dev/null +++ b/client-new/styles/design-tokens.css @@ -0,0 +1,135 @@ +/* Design Tokens for Dojo by Example */ + +:root { + /* Color Palette */ + --dojo-primary: #ff3000; + --dojo-primary-hover: #e62900; + --dojo-primary-light: #ff6b4a; + --dojo-primary-dark: #cc2600; + + /* Neutral Colors - Light Mode */ + --color-background: #ffffff; + --color-background-secondary: #f9fafb; + --color-background-tertiary: #f3f4f6; + --color-surface: #ffffff; + --color-surface-hover: #f9fafb; + --color-border: #e5e7eb; + --color-border-hover: #d1d5db; + + /* Text Colors - Light Mode */ + --color-text-primary: #111827; + --color-text-secondary: #4b5563; + --color-text-tertiary: #6b7280; + --color-text-muted: #9ca3af; + --color-text-on-primary: #ffffff; + + /* Semantic Colors */ + --color-success: #10b981; + --color-warning: #f59e0b; + --color-error: #ef4444; + --color-info: #3b82f6; + + /* Spacing Scale */ + --space-xs: 0.25rem; + --space-sm: 0.5rem; + --space-md: 1rem; + --space-lg: 1.5rem; + --space-xl: 2rem; + --space-2xl: 3rem; + --space-3xl: 4rem; + + /* Typography Scale */ + --font-size-xs: 0.75rem; + --font-size-sm: 0.875rem; + --font-size-base: 1rem; + --font-size-lg: 1.125rem; + --font-size-xl: 1.25rem; + --font-size-2xl: 1.5rem; + --font-size-3xl: 1.875rem; + --font-size-4xl: 2.25rem; + --font-size-5xl: 3rem; + + /* Font Weights */ + --font-weight-normal: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; + --font-weight-bold: 700; + + /* Line Heights */ + --line-height-tight: 1.25; + --line-height-normal: 1.5; + --line-height-relaxed: 1.75; + + /* Border Radius */ + --radius-sm: 0.25rem; + --radius-md: 0.375rem; + --radius-lg: 0.5rem; + --radius-xl: 0.75rem; + --radius-2xl: 1rem; + --radius-full: 9999px; + + /* Shadows */ + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1); + --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1); + + /* Transitions */ + --transition-fast: 150ms ease; + --transition-base: 250ms ease; + --transition-slow: 350ms ease; + + /* Z-index Scale */ + --z-base: 0; + --z-dropdown: 1000; + --z-sticky: 1100; + --z-overlay: 1200; + --z-modal: 1300; + --z-popover: 1400; + --z-tooltip: 1500; +} + +/* Dark Mode */ +[data-theme="dark"] { + /* Neutral Colors - Dark Mode */ + --color-background: #0a0a0a; + --color-background-secondary: #141414; + --color-background-tertiary: #1f1f1f; + --color-surface: #1a1a1a; + --color-surface-hover: #242424; + --color-border: #2e2e2e; + --color-border-hover: #3e3e3e; + + /* Text Colors - Dark Mode */ + --color-text-primary: #f9fafb; + --color-text-secondary: #d1d5db; + --color-text-tertiary: #9ca3af; + --color-text-muted: #6b7280; + + /* Shadows - Dark Mode */ + --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.25); + --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.3); + --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.35); + --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.4); +} + +/* Utility Classes */ +.text-primary { + color: var(--color-text-primary); +} + +.text-secondary { + color: var(--color-text-secondary); +} + +.text-dojo { + color: var(--dojo-primary); +} + +.bg-surface { + background-color: var(--color-surface); +} + +.border-default { + border-color: var(--color-border); +} \ No newline at end of file diff --git a/client-new/styles/globals.css b/client-new/styles/globals.css new file mode 100644 index 0000000..473400e --- /dev/null +++ b/client-new/styles/globals.css @@ -0,0 +1,192 @@ +/* Global Styles for Dojo by Example */ + +/* Import design tokens */ +@import './design-tokens.css'; + +/* Tailwind base styles */ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* Base styles */ +@layer base { + /* Smooth scrolling */ + html { + scroll-behavior: smooth; + } + + /* Default body styles */ + body { + @apply bg-background text-text-primary; + font-family: 'DM Sans', system-ui, -apple-system, sans-serif; + transition: background-color var(--transition-base); + } + + /* Heading styles */ + h1, h2, h3, h4, h5, h6 { + @apply font-semibold text-text-primary; + } + + h1 { @apply text-4xl md:text-5xl; } + h2 { @apply text-3xl md:text-4xl; } + h3 { @apply text-2xl md:text-3xl; } + h4 { @apply text-xl md:text-2xl; } + h5 { @apply text-lg md:text-xl; } + h6 { @apply text-base md:text-lg; } + + /* Link styles */ + a { + @apply text-dojo-primary hover:text-dojo-hover; + transition: color var(--transition-fast); + } + + /* Code block styles */ + code { + @apply px-1 py-0.5 rounded-md bg-surface-secondary text-sm; + font-family: 'JetBrains Mono', Consolas, monospace; + } + + pre { + @apply p-4 rounded-lg overflow-x-auto; + background-color: var(--color-background-tertiary); + } + + pre code { + @apply p-0 bg-transparent; + } + + /* Selection styles */ + ::selection { + background-color: var(--dojo-primary); + color: white; + opacity: 0.2; + } +} + +/* Component styles */ +@layer components { + /* Button styles */ + .btn { + @apply px-4 py-2 rounded-lg font-medium transition-all duration-200; + @apply focus:outline-none focus:ring-2 focus:ring-dojo-primary focus:ring-offset-2; + } + + .btn-primary { + @apply bg-dojo-primary text-white hover:bg-dojo-hover; + } + + .btn-secondary { + @apply bg-surface border border-border hover:bg-surface-hover; + } + + /* Card styles */ + .card { + @apply bg-surface rounded-xl border border-border p-6; + @apply hover:shadow-lg transition-shadow duration-300; + } + + /* Badge styles */ + .badge { + @apply inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium; + } + + .badge-dojo { + @apply bg-dojo-primary/10 text-dojo-primary; + } + + /* Feature card for homepage */ + .feature-card { + @apply card hover:border-dojo-primary/50; + @apply hover:shadow-dojo-primary/10; + } +} + +/* Utility styles */ +@layer utilities { + /* Hide scrollbar but keep functionality */ + .scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; + } + + .scrollbar-hide::-webkit-scrollbar { + display: none; + } + + /* Gradient text */ + .gradient-text { + @apply bg-gradient-to-r from-dojo-primary to-dojo-light; + @apply bg-clip-text text-transparent; + } + + /* Glow effect */ + .glow-dojo { + box-shadow: 0 0 20px rgba(255, 48, 0, 0.3); + } + + /* Backdrop blur for overlays */ + .backdrop-blur-subtle { + backdrop-filter: blur(8px); + } +} + +/* Animation keyframes */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideIn { + from { + transform: translateX(-100%); + } + to { + transform: translateX(0); + } +} + +.animate-fadeIn { + animation: fadeIn 0.5s ease-out; +} + +.animate-slideIn { + animation: slideIn 0.3s ease-out; +} + +/* Custom scrollbar styles */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--color-background-secondary); +} + +::-webkit-scrollbar-thumb { + background: var(--color-border); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--color-border-hover); +} + +/* Responsive utilities */ +@media (max-width: 768px) { + .hide-mobile { + display: none; + } +} + +@media (min-width: 769px) { + .hide-desktop { + display: none; + } +} \ No newline at end of file diff --git a/client-new/styles/theme.ts b/client-new/styles/theme.ts new file mode 100644 index 0000000..813ca98 --- /dev/null +++ b/client-new/styles/theme.ts @@ -0,0 +1,105 @@ +// Theme configuration for Dojo by Example + +export const theme = { + colors: { + // Brand colors + dojo: { + DEFAULT: '#ff3000', + hover: '#e62900', + light: '#ff6b4a', + dark: '#cc2600', + }, + + // Semantic colors + success: '#10b981', + warning: '#f59e0b', + error: '#ef4444', + info: '#3b82f6', + }, + + fonts: { + sans: ['DM Sans', 'system-ui', '-apple-system', 'sans-serif'], + mono: ['JetBrains Mono', 'Consolas', 'monospace'], + }, + + transitions: { + fast: '150ms ease', + base: '250ms ease', + slow: '350ms ease', + }, +} + +// Export color palette for Vocs config +export const vocsTheme = { + accentColor: { + light: theme.colors.dojo.DEFAULT, + dark: theme.colors.dojo.light, + }, + + // Logo configurations with theme switching + logos: { + light: { + icon: '/logos/Icon_Light.svg', + horizontal: '/logos/Horizontal_Light.svg', + vertical: '/logos/Vertical_Light.svg', + }, + dark: { + icon: '/logos/Icon_Dark.svg', + horizontal: '/logos/Horizontal_Dark.svg', + vertical: '/logos/Vertical_Dark.svg', + }, + }, +} + +// Partner logos configuration +export const partners = { + powered: [ + { + name: 'Cartridge', + logo: '/partners/Cartridge.svg', + url: 'https://docs.cartridge.gg/', + }, + { + name: 'Starknet', + logo: '/partners/Starknet.svg', + url: 'https://www.starknet.io', + }, + { + name: 'OnlyDust', + logo: '/partners/Onlydust.svg', + url: 'https://app.onlydust.com/p/starknet-by-example', + }, + ], + ecosystem: [ + { + name: 'Dojo', + logo: '/partners/DojoLogo.svg', + url: 'https://book.dojoengine.org/', + }, + { + name: 'Katana', + logo: '/partners/KatanaLogo.svg', + url: 'https://book.dojoengine.org/toolchain/katana', + }, + { + name: 'Sozo', + logo: '/partners/SozoLogo.svg', + url: 'https://book.dojoengine.org/toolchain/sozo', + }, + { + name: 'Torii', + logo: '/partners/ToriiLogo.svg', + url: 'https://book.dojoengine.org/toolchain/torii', + }, + { + name: 'Origami', + logo: '/partners/OrigamiLogo.svg', + url: 'https://book.dojoengine.org/libraries/origami', + }, + { + name: 'Saya', + logo: '/partners/SayaLogo.svg', + url: 'https://book.dojoengine.org/toolchain/saya', + }, + ], +} \ No newline at end of file From 71d43332515e3c18b34ca57674e5b572edacd9ad Mon Sep 17 00:00:00 2001 From: jimenezz22 Date: Sun, 17 Aug 2025 17:59:48 -0600 Subject: [PATCH 03/10] Refactor code structure for improved readability and maintainability --- client-new/package.json | 27 +- client-new/pnpm-lock.yaml | 7246 +++++++++++++++++++++++++++++++++++++ 2 files changed, 7269 insertions(+), 4 deletions(-) create mode 100644 client-new/pnpm-lock.yaml diff --git a/client-new/package.json b/client-new/package.json index 4dfee0b..aff7a9b 100644 --- a/client-new/package.json +++ b/client-new/package.json @@ -4,12 +4,31 @@ "description": "Learn Dojo Engine through practical examples", "type": "module", "scripts": { - "dev": "vocs dev", + "dev": "vocs dev --port 4000", "build": "vocs build", - "preview": "vocs preview", + "preview": "vocs preview --port 4000", "type-check": "tsc --noEmit" }, - "keywords": ["dojo", "starknet", "blockchain", "gaming", "documentation"], + "keywords": [ + "dojo", + "starknet", + "blockchain", + "gaming", + "documentation" + ], "author": "Dojo by Example Team", - "license": "MIT" + "license": "MIT", + "dependencies": { + "react": "^19.1.1", + "react-dom": "^19.1.1", + "vocs": "^1.0.13" + }, + "devDependencies": { + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "autoprefixer": "^10.4.21", + "postcss": "^8.5.6", + "tailwindcss": "^4.1.12", + "typescript": "^5.9.2" + } } diff --git a/client-new/pnpm-lock.yaml b/client-new/pnpm-lock.yaml new file mode 100644 index 0000000..4d8fb03 --- /dev/null +++ b/client-new/pnpm-lock.yaml @@ -0,0 +1,7246 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + react: + specifier: ^19.1.1 + version: 19.1.1 + react-dom: + specifier: ^19.1.1 + version: 19.1.1(react@19.1.1) + vocs: + specifier: ^1.0.13 + version: 1.0.13(@types/node@24.3.0)(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(acorn@8.15.0)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.46.2)(typescript@5.9.2)(yaml@2.8.1) + devDependencies: + '@types/react': + specifier: ^19.1.10 + version: 19.1.10 + '@types/react-dom': + specifier: ^19.1.7 + version: 19.1.7(@types/react@19.1.10) + autoprefixer: + specifier: ^10.4.21 + version: 10.4.21(postcss@8.5.6) + postcss: + specifier: ^8.5.6 + version: 8.5.6 + tailwindcss: + specifier: ^4.1.12 + version: 4.1.12 + typescript: + specifier: ^5.9.2 + version: 5.9.2 + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@antfu/utils@8.1.1': + resolution: {integrity: sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ==} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.0': + resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.3': + resolution: {integrity: sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.3': + resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.3': + resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.3': + resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-typescript@7.27.1': + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.3': + resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.3': + resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} + + '@braintree/sanitize-url@7.1.1': + resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} + + '@chevrotain/cst-dts-gen@11.0.3': + resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} + + '@chevrotain/gast@11.0.3': + resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} + + '@chevrotain/regexp-to-ast@11.0.3': + resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} + + '@chevrotain/types@11.0.3': + resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} + + '@chevrotain/utils@11.0.3': + resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + + '@clack/core@0.3.5': + resolution: {integrity: sha512-5cfhQNH+1VQ2xLQlmzXMqUoiaH0lRBq9/CLW9lTyMbuKLC3+xEK01tHVvyut++mLOn5urSHmkm6I0Lg9MaJSTQ==} + + '@clack/prompts@0.7.0': + resolution: {integrity: sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA==} + bundledDependencies: + - is-unicode-supported + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.9': + resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.9': + resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.9': + resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.9': + resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.9': + resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.9': + resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.9': + resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.9': + resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.3': + resolution: {integrity: sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==} + + '@floating-ui/react-dom@2.1.5': + resolution: {integrity: sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.27.15': + resolution: {integrity: sha512-0LGxhBi3BB1DwuSNQAmuaSuertFzNAerlMdPbotjTVnvPtdOs7CkrHLaev5NIXemhzDXNC0tFzuseut7cWA5mw==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@fortawesome/fontawesome-free@6.7.2': + resolution: {integrity: sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==} + engines: {node: '>=6'} + + '@hono/node-server@1.18.2': + resolution: {integrity: sha512-icgNvC0vRYivzyuSSaUv9ttcwtN8fDyd1k3AOIBDJgYd84tXRZSS6na8X54CY/oYoFTNhEmZraW/Rb9XYwX4KA==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@2.3.0': + resolution: {integrity: sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA==} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.30': + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + + '@mdx-js/mdx@3.1.0': + resolution: {integrity: sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==} + + '@mdx-js/react@3.1.0': + resolution: {integrity: sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==} + peerDependencies: + '@types/react': '>=16' + react: '>=16' + + '@mdx-js/rollup@3.1.0': + resolution: {integrity: sha512-q4xOtUXpCzeouE8GaJ8StT4rDxm/U5j6lkMHL2srb2Q3Y7cobE0aXyPzXVVlbeIMBi+5R5MpbiaVE5/vJUdnHg==} + peerDependencies: + rollup: '>=2' + + '@mermaid-js/parser@0.6.2': + resolution: {integrity: sha512-+PO02uGF6L6Cs0Bw8RpGhikVvMWEysfAyl27qTlroUB8jSWr1lL0Sf6zi78ZxlSnmgSY2AMMKVgghnN9jTtwkQ==} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@radix-ui/colors@3.0.0': + resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} + + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-accessible-icon@1.1.7': + resolution: {integrity: sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-accordion@1.2.12': + resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-alert-dialog@1.1.15': + resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-aspect-ratio@1.1.7': + resolution: {integrity: sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-avatar@1.1.10': + resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-checkbox@1.3.3': + resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collapsible@1.1.12': + resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context-menu@2.2.16': + resolution: {integrity: sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.16': + resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-form@0.1.8': + resolution: {integrity: sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-hover-card@1.1.15': + resolution: {integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-icons@1.3.2': + resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} + peerDependencies: + react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.7': + resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.16': + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menubar@1.1.16': + resolution: {integrity: sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-navigation-menu@1.2.14': + resolution: {integrity: sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-one-time-password-field@0.1.8': + resolution: {integrity: sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-password-toggle-field@0.1.3': + resolution: {integrity: sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popover@1.1.15': + resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-progress@1.1.7': + resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-radio-group@1.3.8': + resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.10': + resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.6': + resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-separator@1.1.7': + resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slider@1.3.6': + resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.2.6': + resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toast@1.2.15': + resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle-group@1.1.11': + resolution: {integrity: sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toggle@1.1.10': + resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-toolbar@1.1.11': + resolution: {integrity: sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.2.8': + resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-is-hydrated@0.1.0': + resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rollup/pluginutils@5.2.0': + resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.46.2': + resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.46.2': + resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.46.2': + resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.46.2': + resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.46.2': + resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.46.2': + resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.46.2': + resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.46.2': + resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.46.2': + resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.46.2': + resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.46.2': + resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.46.2': + resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.46.2': + resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.46.2': + resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.46.2': + resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.46.2': + resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.46.2': + resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.46.2': + resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} + cpu: [x64] + os: [win32] + + '@shikijs/core@1.29.2': + resolution: {integrity: sha512-vju0lY9r27jJfOY4Z7+Rt/nIOjzJpZ3y+nYpqtUZInVoXQ/TJZcfGnNOGnKjFdVZb8qexiCuSlZRKcGfhhTTZQ==} + + '@shikijs/engine-javascript@1.29.2': + resolution: {integrity: sha512-iNEZv4IrLYPv64Q6k7EPpOCE/nuvGiKl7zxdq0WFuRPF5PAE9PRo2JGq/d8crLusM59BRemJ4eOqrFrC4wiQ+A==} + + '@shikijs/engine-oniguruma@1.29.2': + resolution: {integrity: sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA==} + + '@shikijs/langs@1.29.2': + resolution: {integrity: sha512-FIBA7N3LZ+223U7cJDUYd5shmciFQlYkFXlkKVaHsCPgfVLiO+e12FmQE6Tf9vuyEsFe3dIl8qGWKXgEHL9wmQ==} + + '@shikijs/rehype@1.29.2': + resolution: {integrity: sha512-sxi53HZe5XDz0s2UqF+BVN/kgHPMS9l6dcacM4Ra3ZDzCJa5rDGJ+Ukpk4LxdD1+MITBM6hoLbPfGv9StV8a5Q==} + + '@shikijs/themes@1.29.2': + resolution: {integrity: sha512-i9TNZlsq4uoyqSbluIcZkmPL9Bfi3djVxRnofUHwvx/h6SRW3cwgBC5SML7vsDcWyukY0eCzVN980rqP6qNl9g==} + + '@shikijs/transformers@1.29.2': + resolution: {integrity: sha512-NHQuA+gM7zGuxGWP9/Ub4vpbwrYCrho9nQCLcCPfOe3Yc7LOYwmSuhElI688oiqIXk9dlZwDiyAG9vPBTuPJMA==} + + '@shikijs/twoslash@1.29.2': + resolution: {integrity: sha512-2S04ppAEa477tiaLfGEn1QJWbZUmbk8UoPbAEw4PifsrxkBXtAtOflIZJNtuCwz8ptc/TPxy7CO7gW4Uoi6o/g==} + + '@shikijs/types@1.29.2': + resolution: {integrity: sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + + '@tailwindcss/node@4.0.7': + resolution: {integrity: sha512-dkFXufkbRB2mu3FPsW5xLAUWJyexpJA+/VtQj18k3SUiJVLdpgzBd1v1gRRcIpEJj7K5KpxBKfOXlZxT3ZZRuA==} + + '@tailwindcss/oxide-android-arm64@4.0.7': + resolution: {integrity: sha512-5iQXXcAeOHBZy8ASfHFm1k0O/9wR2E3tKh6+P+ilZZbQiMgu+qrnfpBWYPc3FPuQdWiWb73069WT5D+CAfx/tg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.0.7': + resolution: {integrity: sha512-7yGZtEc5IgVYylqK/2B0yVqoofk4UAbkn1ygNpIJZyrOhbymsfr8uUFCueTu2fUxmAYIfMZ8waWo2dLg/NgLgg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.0.7': + resolution: {integrity: sha512-tPQDV20fBjb26yWbPqT1ZSoDChomMCiXTKn4jupMSoMCFyU7+OJvIY1ryjqBuY622dEBJ8LnCDDWsnj1lX9nNQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.0.7': + resolution: {integrity: sha512-sZqJpTyTZiknU9LLHuByg5GKTW+u3FqM7q7myequAXxKOpAFiOfXpY710FuMY+gjzSapyRbDXJlsTQtCyiTo5w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.7': + resolution: {integrity: sha512-PBgvULgeSswjd8cbZ91gdIcIDMdc3TUHV5XemEpxlqt9M8KoydJzkuB/Dt910jYdofOIaTWRL6adG9nJICvU4A==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.0.7': + resolution: {integrity: sha512-By/a2yeh+e9b+C67F88ndSwVJl2A3tcUDb29FbedDi+DZ4Mr07Oqw9Y1DrDrtHIDhIZ3bmmiL1dkH2YxrtV+zw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.0.7': + resolution: {integrity: sha512-WHYs3cpPEJb/ccyT20NOzopYQkl7JKncNBUbb77YFlwlXMVJLLV3nrXQKhr7DmZxz2ZXqjyUwsj2rdzd9stYdw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.0.7': + resolution: {integrity: sha512-7bP1UyuX9kFxbOwkeIJhBZNevKYPXB6xZI37v09fqi6rqRJR8elybwjMUHm54GVP+UTtJ14ueB1K54Dy1tIO6w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.0.7': + resolution: {integrity: sha512-gBQIV8nL/LuhARNGeroqzXymMzzW5wQzqlteVqOVoqwEfpHOP3GMird5pGFbnpY+NP0fOlsZGrxxOPQ4W/84bQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-win32-arm64-msvc@4.0.7': + resolution: {integrity: sha512-aH530NFfx0kpQpvYMfWoeG03zGnRCMVlQG8do/5XeahYydz+6SIBxA1tl/cyITSJyWZHyVt6GVNkXeAD30v0Xg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.0.7': + resolution: {integrity: sha512-8Cva6bbJN7ZJx320k7vxGGdU0ewmpfS5A4PudyzUuofdi8MgeINuiiWiPQ0VZCda/GX88K6qp+6UpDZNVr8HMQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.0.7': + resolution: {integrity: sha512-yr6w5YMgjy+B+zkJiJtIYGXW+HNYOPfRPtSs+aqLnKwdEzNrGv4ZuJh9hYJ3mcA+HMq/K1rtFV+KsEr65S558g==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.0.7': + resolution: {integrity: sha512-GYx5sxArfIMtdZCsxfya3S/efMmf4RvfqdiLUozkhmSFBNUFnYVodatpoO/en4/BsOIGvq/RB6HwcTLn9prFnQ==} + peerDependencies: + vite: ^5.2.0 || ^6 + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdx@2.0.13': + resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@24.3.0': + resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} + + '@types/react-dom@19.1.7': + resolution: {integrity: sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==} + peerDependencies: + '@types/react': ^19.0.0 + + '@types/react@19.1.10': + resolution: {integrity: sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@typescript/vfs@1.6.1': + resolution: {integrity: sha512-JwoxboBh7Oz1v38tPbkrZ62ZXNHAk9bJ7c9x0eI5zBfBnBYGhURdbnh7Z4smN/MV48Y5OCcZb58n972UtbazsA==} + peerDependencies: + typescript: '*' + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@vanilla-extract/babel-plugin-debug-ids@1.2.2': + resolution: {integrity: sha512-MeDWGICAF9zA/OZLOKwhoRlsUW+fiMwnfuOAqFVohL31Agj7Q/RBWAYweqjHLgFBCsdnr6XIfwjJnmb2znEWxw==} + + '@vanilla-extract/compiler@0.3.1': + resolution: {integrity: sha512-KZ67DZQu58dMo7Jv4PNMPG5TbMOXB68xxVYV2cRJvUdPeiOmX0FOaPgEsYBAZUgd/oLEx4IyV0AvlvsxJ1akfQ==} + + '@vanilla-extract/css@1.17.4': + resolution: {integrity: sha512-m3g9nQDWPtL+sTFdtCGRMI1Vrp86Ay4PBYq1Bo7Bnchj5ElNtAJpOqD+zg+apthVA4fB7oVpMWNjwpa6ElDWFQ==} + + '@vanilla-extract/dynamic@2.1.5': + resolution: {integrity: sha512-QGIFGb1qyXQkbzx6X6i3+3LMc/iv/ZMBttMBL+Wm/DetQd36KsKsFg5CtH3qy+1hCA/5w93mEIIAiL4fkM8ycw==} + + '@vanilla-extract/integration@8.0.4': + resolution: {integrity: sha512-cmOb7tR+g3ulKvFtSbmdw3YUyIS1d7MQqN+FcbwNhdieyno5xzUyfDCMjeWJhmCSMvZ6WlinkrOkgs6SHB+FRg==} + + '@vanilla-extract/private@1.0.9': + resolution: {integrity: sha512-gT2jbfZuaaCLrAxwXbRgIhGhcXbRZCG3v4TTUnjw0EJ7ArdBRxkq4msNJkbuRkCgfIK5ATmprB5t9ljvLeFDEA==} + + '@vanilla-extract/vite-plugin@5.1.1': + resolution: {integrity: sha512-Nd1worqkHrd8XED4ZAA7Wmkd3pCqCwpmzCBVF8v6T1BSLHGXQE5HYflVgygw0CsIAbFRMS6zQBIk4F4/r/YKIw==} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ansi-regex@6.2.0: + resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} + engines: {node: '>=12'} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + + autoprefixer@10.4.21: + resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bcp-47-match@2.0.3: + resolution: {integrity: sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==} + + bl@5.1.0: + resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.25.2: + resolution: {integrity: sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + caniuse-lite@1.0.30001735: + resolution: {integrity: sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@5.6.0: + resolution: {integrity: sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chevrotain-allstar@0.3.1: + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + + chevrotain@11.0.3: + resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==} + + chroma-js@3.1.2: + resolution: {integrity: sha512-IJnETTalXbsLx1eKEgx19d5L6SRM7cH4vINw/99p/M11HCuXGRWL+6YmCm7FWFGIo6dtWuQoQi1dc5yQ7ESIHg==} + + cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + collapse-white-space@2.1.0: + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + + compression@1.8.1: + resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} + engines: {node: '>= 0.8.0'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + + create-vocs@1.0.0: + resolution: {integrity: sha512-Lv1Bd3WZEgwG4nrogkM54m8viW+TWPlGivLyEi7aNb3cuKPsEfMDZ/kTbo87fzOGtsZ2yh7scO54ZmVhhgBgTw==} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-selector-parser@3.1.3: + resolution: {integrity: sha512-gJMigczVZqYAk0hPVzx/M4Hm1D9QOtqkdQk9005TNzDIUGzo5cnHEDiKUT7jGPximL/oYb+LIitcHFQ4aKupxg==} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.1: + resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.11: + resolution: {integrity: sha512-tvlJLyQf834SylNKax8Wkzco/1ias1OPw8DcUMDE7oUIoSEW25riQVuiu/0OWEFqT0cxHT3Pa9/D82Jr47IONw==} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + + dedent@1.6.0: + resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-object-diff@1.1.9: + resolution: {integrity: sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + detect-package-manager@3.0.2: + resolution: {integrity: sha512-8JFjJHutStYrfWwzfretQoyNGoZVW1Fsrp4JO9spa7h/fBfwgTMEIy4/LBzRDGsxwVPHU0q+T9YvwLDJoOApLQ==} + engines: {node: '>=12'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + direction@2.0.1: + resolution: {integrity: sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==} + hasBin: true + + dompurify@3.2.6: + resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.203: + resolution: {integrity: sha512-uz4i0vLhfm6dLZWbz/iH88KNDV+ivj5+2SA+utpgjKaj9Q0iDLuwk6Idhe9BTxciHudyx6IvTvijhkPvFGUQ0g==} + + emoji-regex-xs@1.0.0: + resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} + + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + esast-util-from-estree@2.0.0: + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} + + esast-util-from-js@2.0.1: + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} + + esbuild@0.25.9: + resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + estree-util-attach-comments@3.0.0: + resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} + + estree-util-build-jsx@3.0.1: + resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-scope@1.0.0: + resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==} + + estree-util-to-js@2.0.0: + resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} + + estree-util-value-to-estree@3.4.0: + resolution: {integrity: sha512-Zlp+gxis+gCfK12d3Srl2PdX2ybsEA8ZYy6vQGVQTNNYLEGRQQ56XB64bjemN8kxIKXP1nC9ip4Z+ILy9LGzvQ==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eval@0.1.8: + resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==} + engines: {node: '>= 0.8'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exsolve@1.0.7: + resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fault@2.0.1: + resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + format@0.2.2: + resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} + engines: {node: '>=0.4.x'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + fs-extra@11.3.1: + resolution: {integrity: sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==} + engines: {node: '>=14.14'} + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} + engines: {node: '>=18'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + + hast-util-classnames@3.0.0: + resolution: {integrity: sha512-tI3JjoGDEBVorMAWK4jNRsfLMYmih1BUOG3VV36pH36njs1IEl7xkNrVTD2mD2yYHmQCa5R/fj61a8IAF4bRaQ==} + + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} + + hast-util-from-html-isomorphic@2.0.0: + resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-has-property@3.0.0: + resolution: {integrity: sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==} + + hast-util-heading-rank@3.0.0: + resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} + + hast-util-is-element@3.0.0: + resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} + + hast-util-parse-selector@4.0.0: + resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} + + hast-util-select@6.0.4: + resolution: {integrity: sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==} + + hast-util-to-estree@3.1.3: + resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@8.0.0: + resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + hono@4.9.2: + resolution: {integrity: sha512-UG2jXGS/gkLH42l/1uROnwXpkjvvxkl3kpopL3LBo27NuaDPI6xHNfuUSilIHcrBkPfl4y0z6y2ByI455TjNRw==} + engines: {node: '>=16.9.0'} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + inline-style-parser@0.2.4: + resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} + + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + javascript-stringify@2.1.0: + resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} + + jiti@2.5.1: + resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + katex@0.16.22: + resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + langium@3.3.1: + resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==} + engines: {node: '>=16.0.0'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} + engines: {node: '>=14'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash-es@4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + + log-symbols@5.1.0: + resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} + engines: {node: '>=12'} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + mark.js@8.11.1: + resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + + markdown-extensions@2.0.0: + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} + engines: {node: '>=16'} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + marked@16.1.2: + resolution: {integrity: sha512-rNQt5EvRinalby7zJZu/mB+BvaAY2oz3wCuCjt1RDrWNpS1Pdf9xqMOeC9Hm5adBdcV/3XZPJpG58eT+WBc0XQ==} + engines: {node: '>= 20'} + hasBin: true + + mdast-util-directive@3.1.0: + resolution: {integrity: sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-frontmatter@2.0.1: + resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdx@3.0.0: + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + media-query-parser@2.0.2: + resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + mermaid-isomorphic@3.0.4: + resolution: {integrity: sha512-XQTy7H1XwHK3DPEHf+ZNWiqUEd9BwX3Xws38R9Fj2gx718srmgjlZoUzHr+Tca+O+dqJOJsAJaKzCoP65QDfDg==} + peerDependencies: + playwright: '1' + peerDependenciesMeta: + playwright: + optional: true + + mermaid@11.9.0: + resolution: {integrity: sha512-YdPXn9slEwO0omQfQIsW6vS84weVQftIyyTGAZCwM//MGhPzL1+l6vO6bkf0wnP4tHigH1alZ5Ooy3HXI2gOag==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-directive@3.0.2: + resolution: {integrity: sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==} + + micromark-extension-frontmatter@2.0.0: + resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-mdx-expression@3.0.1: + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} + + micromark-extension-mdx-jsx@3.0.2: + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} + + micromark-extension-mdx-md@2.0.0: + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} + + micromark-extension-mdxjs-esm@3.0.0: + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} + + micromark-extension-mdxjs@3.0.0: + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mini-svg-data-uri@1.4.4: + resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} + hasBin: true + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minisearch@6.3.0: + resolution: {integrity: sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==} + + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + + modern-ahocorasick@1.1.0: + resolution: {integrity: sha512-sEKPVl2rM+MNVkGQt3ChdmD8YsigmXdn5NifZn6jiwn9LRJpWm8F3guhaqrJT/JOat6pwpbXEk6kv+b9DMIjsQ==} + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + on-headers@1.1.0: + resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} + engines: {node: '>= 0.8'} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + oniguruma-to-es@2.3.0: + resolution: {integrity: sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g==} + + ora@7.0.1: + resolution: {integrity: sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==} + engines: {node: '>=16'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + package-manager-detector@1.3.0: + resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.2.0: + resolution: {integrity: sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==} + + playwright-core@1.54.2: + resolution: {integrity: sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.54.2: + resolution: {integrity: sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==} + engines: {node: '>=18'} + hasBin: true + + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + property-information@6.5.0: + resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + radix-ui@1.4.3: + resolution: {integrity: sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + react-dom@19.1.1: + resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} + peerDependencies: + react: ^19.1.1 + + react-intersection-observer@9.16.0: + resolution: {integrity: sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==} + peerDependencies: + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + react-dom: + optional: true + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-router@7.8.1: + resolution: {integrity: sha512-5cy/M8DHcG51/KUIka1nfZ2QeylS4PJRs6TT8I4PF5axVsI5JUxp0hC0NZ/AEEj8Vw7xsEoD7L/6FY+zoYaOGA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@19.1.1: + resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + recma-build-jsx@1.0.0: + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} + + recma-jsx@1.0.1: + resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + recma-parse@1.0.0: + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} + + recma-stringify@1.0.0: + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} + + regex-recursion@5.1.1: + resolution: {integrity: sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@5.1.1: + resolution: {integrity: sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw==} + + rehype-autolink-headings@7.1.0: + resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} + + rehype-class-names@2.0.0: + resolution: {integrity: sha512-jldCIiAEvXKdq8hqr5f5PzNdIDkvHC6zfKhwta9oRoMu7bn0W7qLES/JrrjBvr9rKz3nJ8x4vY1EWI+dhjHVZQ==} + + rehype-mermaid@3.0.0: + resolution: {integrity: sha512-fxrD5E4Fa1WXUjmjNDvLOMT4XB1WaxcfycFIWiYU0yEMQhcTDElc9aDFnbDFRLxG1Cfo1I3mfD5kg4sjlWaB+Q==} + peerDependencies: + playwright: '1' + peerDependenciesMeta: + playwright: + optional: true + + rehype-recma@1.0.0: + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + + rehype-slug@6.0.0: + resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} + + remark-directive@3.0.1: + resolution: {integrity: sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==} + + remark-frontmatter@5.0.0: + resolution: {integrity: sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-mdx-frontmatter@5.2.0: + resolution: {integrity: sha512-U/hjUYTkQqNjjMRYyilJgLXSPF65qbLPdoESOkXyrwz2tVyhAnm4GUKhfXqOOS9W34M3545xEMq+aMpHgVjEeQ==} + + remark-mdx@3.1.0: + resolution: {integrity: sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + require-like@0.1.2: + resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} + + restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + + rollup@4.46.2: + resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shiki@1.29.2: + resolution: {integrity: sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + stdin-discarder@0.1.0: + resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + string-width@6.1.0: + resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} + engines: {node: '>=16'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + style-to-js@1.1.17: + resolution: {integrity: sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==} + + style-to-object@1.0.9: + resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==} + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + + tailwindcss@4.0.7: + resolution: {integrity: sha512-yH5bPPyapavo7L+547h3c4jcBXcrKwybQRjwdEIVAd9iXRvy/3T1CC6XSQEgZtRySjKfqvo3Cc0ZF1DTheuIdA==} + + tailwindcss@4.1.12: + resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==} + + tapable@2.2.2: + resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} + engines: {node: '>=6'} + + tinyexec@1.0.1: + resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} + + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + twoslash-protocol@0.2.12: + resolution: {integrity: sha512-5qZLXVYfZ9ABdjqbvPc4RWMr7PrpPaaDSeaYY55vl/w1j6H6kzsWK/urAEIXlzYlyrFmyz1UbwIt+AA0ck+wbg==} + + twoslash@0.2.12: + resolution: {integrity: sha512-tEHPASMqi7kqwfJbkk7hc/4EhlrKCSLcur+TcvYki3vhIfaRMXnXjaYFgXpoZRbT6GdprD4tGuVBEmTpUgLBsw==} + peerDependencies: + typescript: '*' + + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + engines: {node: '>=14.17'} + hasBin: true + + ua-parser-js@1.0.40: + resolution: {integrity: sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==} + hasBin: true + + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + undici-types@7.10.0: + resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + + unist-util-mdx-define@1.1.2: + resolution: {integrity: sha512-9ncH7i7TN5Xn7/tzX5bE3rXgz1X/u877gYVAUB3mLeTKYJmQHmqKTDBi6BTGXV7AeolBCI9ErcVsOt2qryoD0g==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@6.3.5: + resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vocs@1.0.13: + resolution: {integrity: sha512-V/ogXG5xw7jMFXI2Wv0d0ZdCeeT5jzaX0PKdRKcqhnd21UtLZrqa5pKZkStNIZyVpvfsLW0WB7wjB4iBOpueiw==} + hasBin: true + peerDependencies: + react: ^19 + react-dom: ^19 + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-uri@3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + engines: {node: '>= 14.6'} + hasBin: true + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.2.1: + resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} + engines: {node: '>=12.20'} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.3.0 + tinyexec: 1.0.1 + + '@antfu/utils@8.1.1': {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.0': {} + + '@babel/core@7.28.3': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) + '@babel/helpers': 7.28.3 + '@babel/parser': 7.28.3 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.3': + dependencies: + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)': + dependencies: + '@babel/core': 7.28.3 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.3 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.3': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + + '@babel/parser@7.28.3': + dependencies: + '@babel/types': 7.28.2 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.3)': + dependencies: + '@babel/core': 7.28.3 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.3)': + dependencies: + '@babel/core': 7.28.3 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.3)': + dependencies: + '@babel/core': 7.28.3 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/runtime@7.28.3': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + + '@babel/traverse@7.28.3': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.3 + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.2': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@braintree/sanitize-url@7.1.1': {} + + '@chevrotain/cst-dts-gen@11.0.3': + dependencies: + '@chevrotain/gast': 11.0.3 + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/gast@11.0.3': + dependencies: + '@chevrotain/types': 11.0.3 + lodash-es: 4.17.21 + + '@chevrotain/regexp-to-ast@11.0.3': {} + + '@chevrotain/types@11.0.3': {} + + '@chevrotain/utils@11.0.3': {} + + '@clack/core@0.3.5': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@clack/prompts@0.7.0': + dependencies: + '@clack/core': 0.3.5 + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@emotion/hash@0.9.2': {} + + '@esbuild/aix-ppc64@0.25.9': + optional: true + + '@esbuild/android-arm64@0.25.9': + optional: true + + '@esbuild/android-arm@0.25.9': + optional: true + + '@esbuild/android-x64@0.25.9': + optional: true + + '@esbuild/darwin-arm64@0.25.9': + optional: true + + '@esbuild/darwin-x64@0.25.9': + optional: true + + '@esbuild/freebsd-arm64@0.25.9': + optional: true + + '@esbuild/freebsd-x64@0.25.9': + optional: true + + '@esbuild/linux-arm64@0.25.9': + optional: true + + '@esbuild/linux-arm@0.25.9': + optional: true + + '@esbuild/linux-ia32@0.25.9': + optional: true + + '@esbuild/linux-loong64@0.25.9': + optional: true + + '@esbuild/linux-mips64el@0.25.9': + optional: true + + '@esbuild/linux-ppc64@0.25.9': + optional: true + + '@esbuild/linux-riscv64@0.25.9': + optional: true + + '@esbuild/linux-s390x@0.25.9': + optional: true + + '@esbuild/linux-x64@0.25.9': + optional: true + + '@esbuild/netbsd-arm64@0.25.9': + optional: true + + '@esbuild/netbsd-x64@0.25.9': + optional: true + + '@esbuild/openbsd-arm64@0.25.9': + optional: true + + '@esbuild/openbsd-x64@0.25.9': + optional: true + + '@esbuild/openharmony-arm64@0.25.9': + optional: true + + '@esbuild/sunos-x64@0.25.9': + optional: true + + '@esbuild/win32-arm64@0.25.9': + optional: true + + '@esbuild/win32-ia32@0.25.9': + optional: true + + '@esbuild/win32-x64@0.25.9': + optional: true + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.3': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@floating-ui/dom': 1.7.3 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@floating-ui/react@0.27.15(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@floating-ui/react-dom': 2.1.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@floating-ui/utils': 0.2.10 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + tabbable: 6.2.0 + + '@floating-ui/utils@0.2.10': {} + + '@fortawesome/fontawesome-free@6.7.2': {} + + '@hono/node-server@1.18.2(hono@4.9.2)': + dependencies: + hono: 4.9.2 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@2.3.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@antfu/utils': 8.1.1 + '@iconify/types': 2.0.0 + debug: 4.4.1 + globals: 15.15.0 + kolorist: 1.8.0 + local-pkg: 1.1.1 + mlly: 1.7.4 + transitivePeerDependencies: + - supports-color + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.30': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@mdx-js/mdx@3.1.0(acorn@8.15.0)': + dependencies: + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdx': 2.0.13 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.0 + estree-walker: 3.0.3 + hast-util-to-jsx-runtime: 2.3.6 + markdown-extensions: 2.0.0 + recma-build-jsx: 1.0.0 + recma-jsx: 1.0.1(acorn@8.15.0) + recma-stringify: 1.0.0 + rehype-recma: 1.0.0 + remark-mdx: 3.1.0 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + source-map: 0.7.6 + unified: 11.0.5 + unist-util-position-from-estree: 2.0.0 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + transitivePeerDependencies: + - acorn + - supports-color + + '@mdx-js/react@3.1.0(@types/react@19.1.10)(react@19.1.1)': + dependencies: + '@types/mdx': 2.0.13 + '@types/react': 19.1.10 + react: 19.1.1 + + '@mdx-js/rollup@3.1.0(acorn@8.15.0)(rollup@4.46.2)': + dependencies: + '@mdx-js/mdx': 3.1.0(acorn@8.15.0) + '@rollup/pluginutils': 5.2.0(rollup@4.46.2) + rollup: 4.46.2 + source-map: 0.7.6 + vfile: 6.0.3 + transitivePeerDependencies: + - acorn + - supports-color + + '@mermaid-js/parser@0.6.2': + dependencies: + langium: 3.3.1 + + '@noble/hashes@1.8.0': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@radix-ui/colors@3.0.0': {} + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.10)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-context@1.1.2(@types/react@19.1.10)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + aria-hidden: 1.2.6 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-remove-scroll: 2.7.1(@types/react@19.1.10)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-direction@1.1.1(@types/react@19.1.10)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.1.10)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-form@0.1.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-icons@1.3.2(react@19.1.1)': + dependencies: + react: 19.1.1 + + '@radix-ui/react-id@1.1.1(@types/react@19.1.10)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + aria-hidden: 1.2.6 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-remove-scroll: 2.7.1(@types/react@19.1.10)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + aria-hidden: 1.2.6 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-remove-scroll: 2.7.1(@types/react@19.1.10)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@floating-ui/react-dom': 2.1.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/rect': 1.1.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-progress@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-select@2.2.6(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + aria-hidden: 1.2.6 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-remove-scroll: 2.7.1(@types/react@19.1.10)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-slider@1.3.6(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-slot@1.2.3(@types/react@19.1.10)(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-toast@1.2.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-toolbar@1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.10)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.10)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.10)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.10)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.1.10)(react@19.1.1)': + dependencies: + react: 19.1.1 + use-sync-external-store: 1.5.0(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.10)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-use-previous@1.1.1(@types/react@19.1.10)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.10)(react@19.1.1)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.1.10)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.10 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + '@radix-ui/rect@1.1.1': {} + + '@rolldown/pluginutils@1.0.0-beta.27': {} + + '@rollup/pluginutils@5.2.0(rollup@4.46.2)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.46.2 + + '@rollup/rollup-android-arm-eabi@4.46.2': + optional: true + + '@rollup/rollup-android-arm64@4.46.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.46.2': + optional: true + + '@rollup/rollup-darwin-x64@4.46.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.46.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.46.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.46.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.46.2': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.46.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.46.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.46.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.46.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.46.2': + optional: true + + '@shikijs/core@1.29.2': + dependencies: + '@shikijs/engine-javascript': 1.29.2 + '@shikijs/engine-oniguruma': 1.29.2 + '@shikijs/types': 1.29.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@1.29.2': + dependencies: + '@shikijs/types': 1.29.2 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 2.3.0 + + '@shikijs/engine-oniguruma@1.29.2': + dependencies: + '@shikijs/types': 1.29.2 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@1.29.2': + dependencies: + '@shikijs/types': 1.29.2 + + '@shikijs/rehype@1.29.2': + dependencies: + '@shikijs/types': 1.29.2 + '@types/hast': 3.0.4 + hast-util-to-string: 3.0.1 + shiki: 1.29.2 + unified: 11.0.5 + unist-util-visit: 5.0.0 + + '@shikijs/themes@1.29.2': + dependencies: + '@shikijs/types': 1.29.2 + + '@shikijs/transformers@1.29.2': + dependencies: + '@shikijs/core': 1.29.2 + '@shikijs/types': 1.29.2 + + '@shikijs/twoslash@1.29.2(typescript@5.9.2)': + dependencies: + '@shikijs/core': 1.29.2 + '@shikijs/types': 1.29.2 + twoslash: 0.2.12(typescript@5.9.2) + transitivePeerDependencies: + - supports-color + - typescript + + '@shikijs/types@1.29.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@sindresorhus/merge-streams@2.3.0': {} + + '@tailwindcss/node@4.0.7': + dependencies: + enhanced-resolve: 5.18.3 + jiti: 2.5.1 + tailwindcss: 4.0.7 + + '@tailwindcss/oxide-android-arm64@4.0.7': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.0.7': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.0.7': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.0.7': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.0.7': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.0.7': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.0.7': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.0.7': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.0.7': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.0.7': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.0.7': + optional: true + + '@tailwindcss/oxide@4.0.7': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.0.7 + '@tailwindcss/oxide-darwin-arm64': 4.0.7 + '@tailwindcss/oxide-darwin-x64': 4.0.7 + '@tailwindcss/oxide-freebsd-x64': 4.0.7 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.0.7 + '@tailwindcss/oxide-linux-arm64-gnu': 4.0.7 + '@tailwindcss/oxide-linux-arm64-musl': 4.0.7 + '@tailwindcss/oxide-linux-x64-gnu': 4.0.7 + '@tailwindcss/oxide-linux-x64-musl': 4.0.7 + '@tailwindcss/oxide-win32-arm64-msvc': 4.0.7 + '@tailwindcss/oxide-win32-x64-msvc': 4.0.7 + + '@tailwindcss/vite@4.0.7(vite@6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1))': + dependencies: + '@tailwindcss/node': 4.0.7 + '@tailwindcss/oxide': 4.0.7 + lightningcss: 1.30.1 + tailwindcss: 4.0.7 + vite: 6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.2 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.2 + + '@types/d3-array@3.2.1': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@1.0.8': {} + + '@types/geojson@7946.0.16': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdx@2.0.13': {} + + '@types/ms@2.1.0': {} + + '@types/node@24.3.0': + dependencies: + undici-types: 7.10.0 + + '@types/react-dom@19.1.7(@types/react@19.1.10)': + dependencies: + '@types/react': 19.1.10 + + '@types/react@19.1.10': + dependencies: + csstype: 3.1.3 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@typescript/vfs@1.6.1(typescript@5.9.2)': + dependencies: + debug: 4.4.1 + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@ungap/structured-clone@1.3.0': {} + + '@vanilla-extract/babel-plugin-debug-ids@1.2.2': + dependencies: + '@babel/core': 7.28.3 + transitivePeerDependencies: + - supports-color + + '@vanilla-extract/compiler@0.3.1(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1)': + dependencies: + '@vanilla-extract/css': 1.17.4 + '@vanilla-extract/integration': 8.0.4 + vite: 6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + '@vanilla-extract/css@1.17.4': + dependencies: + '@emotion/hash': 0.9.2 + '@vanilla-extract/private': 1.0.9 + css-what: 6.2.2 + cssesc: 3.0.0 + csstype: 3.1.3 + dedent: 1.6.0 + deep-object-diff: 1.1.9 + deepmerge: 4.3.1 + lru-cache: 10.4.3 + media-query-parser: 2.0.2 + modern-ahocorasick: 1.1.0 + picocolors: 1.1.1 + transitivePeerDependencies: + - babel-plugin-macros + + '@vanilla-extract/dynamic@2.1.5': + dependencies: + '@vanilla-extract/private': 1.0.9 + + '@vanilla-extract/integration@8.0.4': + dependencies: + '@babel/core': 7.28.3 + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.3) + '@vanilla-extract/babel-plugin-debug-ids': 1.2.2 + '@vanilla-extract/css': 1.17.4 + dedent: 1.6.0 + esbuild: 0.25.9 + eval: 0.1.8 + find-up: 5.0.0 + javascript-stringify: 2.1.0 + mlly: 1.7.4 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + '@vanilla-extract/private@1.0.9': {} + + '@vanilla-extract/vite-plugin@5.1.1(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(vite@6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1))(yaml@2.8.1)': + dependencies: + '@vanilla-extract/compiler': 0.3.1(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + '@vanilla-extract/integration': 8.0.4 + vite: 6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + '@vitejs/plugin-react@4.7.0(vite@6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1))': + dependencies: + '@babel/core': 7.28.3 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.3) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.3) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ansi-regex@6.2.0: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + astring@1.9.0: {} + + autoprefixer@10.4.21(postcss@8.5.6): + dependencies: + browserslist: 4.25.2 + caniuse-lite: 1.0.30001735 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + bcp-47-match@2.0.3: {} + + bl@5.1.0: + dependencies: + buffer: 6.0.3 + inherits: 2.0.4 + readable-stream: 3.6.2 + + boolbase@1.0.0: {} + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.25.2: + dependencies: + caniuse-lite: 1.0.30001735 + electron-to-chromium: 1.5.203 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.2) + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bytes@3.1.2: {} + + cac@6.7.14: {} + + caniuse-lite@1.0.30001735: {} + + ccount@2.0.1: {} + + chalk@5.6.0: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chevrotain-allstar@0.3.1(chevrotain@11.0.3): + dependencies: + chevrotain: 11.0.3 + lodash-es: 4.17.21 + + chevrotain@11.0.3: + dependencies: + '@chevrotain/cst-dts-gen': 11.0.3 + '@chevrotain/gast': 11.0.3 + '@chevrotain/regexp-to-ast': 11.0.3 + '@chevrotain/types': 11.0.3 + '@chevrotain/utils': 11.0.3 + lodash-es: 4.17.21 + + chroma-js@3.1.2: {} + + cli-cursor@4.0.0: + dependencies: + restore-cursor: 4.0.0 + + cli-spinners@2.9.2: {} + + clsx@2.1.1: {} + + collapse-white-space@2.1.0: {} + + comma-separated-tokens@2.0.3: {} + + commander@7.2.0: {} + + commander@8.3.0: {} + + compressible@2.0.18: + dependencies: + mime-db: 1.54.0 + + compression@1.8.1: + dependencies: + bytes: 3.1.2 + compressible: 2.0.18 + debug: 2.6.9 + negotiator: 0.6.4 + on-headers: 1.1.0 + safe-buffer: 5.2.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + confbox@0.1.8: {} + + confbox@0.2.2: {} + + convert-source-map@2.0.0: {} + + cookie@1.0.2: {} + + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + + create-vocs@1.0.0: + dependencies: + '@clack/prompts': 0.7.0 + cac: 6.7.14 + detect-package-manager: 3.0.2 + fs-extra: 11.3.1 + picocolors: 1.1.1 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-selector-parser@3.1.3: {} + + css-what@6.2.2: {} + + cssesc@3.0.0: {} + + csstype@3.1.3: {} + + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.1 + + cytoscape-fcose@2.2.0(cytoscape@3.33.1): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.1 + + cytoscape@3.33.1: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.11: + dependencies: + d3: 7.9.0 + lodash-es: 4.17.21 + + dayjs@1.11.13: {} + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + + dedent@1.6.0: {} + + deep-object-diff@1.1.9: {} + + deepmerge@4.3.1: {} + + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + + depd@2.0.0: {} + + dequal@2.0.3: {} + + destroy@1.2.0: {} + + detect-libc@2.0.4: {} + + detect-node-es@1.1.0: {} + + detect-package-manager@3.0.2: + dependencies: + execa: 5.1.1 + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + direction@2.0.1: {} + + dompurify@3.2.6: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.203: {} + + emoji-regex-xs@1.0.0: {} + + emoji-regex@10.4.0: {} + + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.2 + + entities@6.0.1: {} + + es-module-lexer@1.7.0: {} + + esast-util-from-estree@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + unist-util-position-from-estree: 2.0.0 + + esast-util-from-js@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + acorn: 8.15.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.3 + + esbuild@0.25.9: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.9 + '@esbuild/android-arm': 0.25.9 + '@esbuild/android-arm64': 0.25.9 + '@esbuild/android-x64': 0.25.9 + '@esbuild/darwin-arm64': 0.25.9 + '@esbuild/darwin-x64': 0.25.9 + '@esbuild/freebsd-arm64': 0.25.9 + '@esbuild/freebsd-x64': 0.25.9 + '@esbuild/linux-arm': 0.25.9 + '@esbuild/linux-arm64': 0.25.9 + '@esbuild/linux-ia32': 0.25.9 + '@esbuild/linux-loong64': 0.25.9 + '@esbuild/linux-mips64el': 0.25.9 + '@esbuild/linux-ppc64': 0.25.9 + '@esbuild/linux-riscv64': 0.25.9 + '@esbuild/linux-s390x': 0.25.9 + '@esbuild/linux-x64': 0.25.9 + '@esbuild/netbsd-arm64': 0.25.9 + '@esbuild/netbsd-x64': 0.25.9 + '@esbuild/openbsd-arm64': 0.25.9 + '@esbuild/openbsd-x64': 0.25.9 + '@esbuild/openharmony-arm64': 0.25.9 + '@esbuild/sunos-x64': 0.25.9 + '@esbuild/win32-arm64': 0.25.9 + '@esbuild/win32-ia32': 0.25.9 + '@esbuild/win32-x64': 0.25.9 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@5.0.0: {} + + estree-util-attach-comments@3.0.0: + dependencies: + '@types/estree': 1.0.8 + + estree-util-build-jsx@3.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-walker: 3.0.3 + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-scope@1.0.0: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + + estree-util-to-js@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + astring: 1.9.0 + source-map: 0.7.6 + + estree-util-value-to-estree@3.4.0: + dependencies: + '@types/estree': 1.0.8 + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + etag@1.8.1: {} + + eval@0.1.8: + dependencies: + '@types/node': 24.3.0 + require-like: 0.1.2 + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exsolve@1.0.7: {} + + extend@3.0.2: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fault@2.0.1: + dependencies: + format: 0.2.2 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + format@0.2.2: {} + + fraction.js@4.3.7: {} + + fresh@0.5.2: {} + + fs-extra@11.3.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fsevents@2.3.2: + optional: true + + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + get-nonce@1.0.1: {} + + get-stream@6.0.1: {} + + github-slugger@2.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + globals@15.15.0: {} + + globby@14.1.0: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + path-type: 6.0.0 + slash: 5.1.0 + unicorn-magic: 0.3.0 + + graceful-fs@4.2.11: {} + + hachure-fill@0.5.2: {} + + hast-util-classnames@3.0.0: + dependencies: + '@types/hast': 3.0.4 + space-separated-tokens: 2.0.2 + + hast-util-from-dom@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hastscript: 9.0.1 + web-namespaces: 2.0.1 + + hast-util-from-html-isomorphic@2.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-dom: 5.0.1 + hast-util-from-html: 2.0.3 + unist-util-remove-position: 5.0.0 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-has-property@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-heading-rank@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-select@6.0.4: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + bcp-47-match: 2.0.3 + comma-separated-tokens: 2.0.3 + css-selector-parser: 3.1.3 + devlop: 1.1.0 + direction: 2.0.1 + hast-util-has-property: 3.0.0 + hast-util-to-string: 3.0.1 + hast-util-whitespace: 3.0.0 + nth-check: 2.1.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + hast-util-to-estree@3.1.3: + dependencies: + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-attach-comments: 3.0.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.17 + unist-util-position: 5.0.0 + zwitch: 2.0.4 + transitivePeerDependencies: + - supports-color + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.17 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@8.0.0: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + hono@4.9.2: {} + + html-void-elements@3.0.0: {} + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + human-signals@2.1.0: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore@7.0.5: {} + + inherits@2.0.4: {} + + inline-style-parser@0.2.4: {} + + internmap@1.0.1: {} + + internmap@2.0.3: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-interactive@2.0.0: {} + + is-number@7.0.0: {} + + is-plain-obj@4.1.0: {} + + is-stream@2.0.1: {} + + is-unicode-supported@1.3.0: {} + + isexe@2.0.0: {} + + javascript-stringify@2.1.0: {} + + jiti@2.5.1: {} + + js-tokens@4.0.0: {} + + jsesc@3.1.0: {} + + json5@2.2.3: {} + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + katex@0.16.22: + dependencies: + commander: 8.3.0 + + khroma@2.1.0: {} + + kolorist@1.8.0: {} + + langium@3.3.1: + dependencies: + chevrotain: 11.0.3 + chevrotain-allstar: 0.3.1(chevrotain@11.0.3) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.0.8 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-darwin-arm64: 1.30.1 + lightningcss-darwin-x64: 1.30.1 + lightningcss-freebsd-x64: 1.30.1 + lightningcss-linux-arm-gnueabihf: 1.30.1 + lightningcss-linux-arm64-gnu: 1.30.1 + lightningcss-linux-arm64-musl: 1.30.1 + lightningcss-linux-x64-gnu: 1.30.1 + lightningcss-linux-x64-musl: 1.30.1 + lightningcss-win32-arm64-msvc: 1.30.1 + lightningcss-win32-x64-msvc: 1.30.1 + + local-pkg@1.1.1: + dependencies: + mlly: 1.7.4 + pkg-types: 2.2.0 + quansync: 0.2.11 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash-es@4.17.21: {} + + log-symbols@5.1.0: + dependencies: + chalk: 5.6.0 + is-unicode-supported: 1.3.0 + + longest-streak@3.1.0: {} + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + mark.js@8.11.1: {} + + markdown-extensions@2.0.0: {} + + markdown-table@3.0.4: {} + + marked@16.1.2: {} + + mdast-util-directive@3.1.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-visit-parents: 6.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-frontmatter@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + escape-string-regexp: 5.0.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-extension-frontmatter: 2.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx@3.0.0: + dependencies: + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.0 + + mdast-util-to-hast@13.2.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + media-query-parser@2.0.2: + dependencies: + '@babel/runtime': 7.28.3 + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + mermaid-isomorphic@3.0.4(playwright@1.54.2): + dependencies: + '@fortawesome/fontawesome-free': 6.7.2 + mermaid: 11.9.0 + optionalDependencies: + playwright: 1.54.2 + transitivePeerDependencies: + - supports-color + + mermaid@11.9.0: + dependencies: + '@braintree/sanitize-url': 7.1.1 + '@iconify/utils': 2.3.0 + '@mermaid-js/parser': 0.6.2 + '@types/d3': 7.4.3 + cytoscape: 3.33.1 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.1) + cytoscape-fcose: 2.2.0(cytoscape@3.33.1) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.11 + dayjs: 1.11.13 + dompurify: 3.2.6 + katex: 0.16.22 + khroma: 2.1.0 + lodash-es: 4.17.21 + marked: 16.1.2 + roughjs: 4.6.6 + stylis: 4.3.6 + ts-dedent: 2.2.0 + uuid: 11.1.0 + transitivePeerDependencies: + - supports-color + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-directive@3.0.2: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + parse-entities: 4.0.2 + + micromark-extension-frontmatter@2.0.0: + dependencies: + fault: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-expression@3.0.1: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.2: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-extension-mdx-md@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-mdxjs-esm@3.0.0: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-extension-mdxjs@3.0.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + micromark-extension-mdx-expression: 3.0.1 + micromark-extension-mdx-jsx: 3.0.2 + micromark-extension-mdx-md: 2.0.0 + micromark-extension-mdxjs-esm: 3.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.1 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.54.0: {} + + mime@1.6.0: {} + + mimic-fn@2.1.0: {} + + mini-svg-data-uri@1.4.4: {} + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minisearch@6.3.0: {} + + mlly@1.7.4: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + + modern-ahocorasick@1.1.0: {} + + ms@2.0.0: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + negotiator@0.6.4: {} + + node-releases@2.0.19: {} + + normalize-range@0.1.2: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + on-headers@1.1.0: {} + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + oniguruma-to-es@2.3.0: + dependencies: + emoji-regex-xs: 1.0.0 + regex: 5.1.1 + regex-recursion: 5.1.1 + + ora@7.0.1: + dependencies: + chalk: 5.6.0 + cli-cursor: 4.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 1.3.0 + log-symbols: 5.1.0 + stdin-discarder: 0.1.0 + string-width: 6.1.0 + strip-ansi: 7.1.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@5.0.0: + dependencies: + yocto-queue: 1.2.1 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + package-manager-detector@1.3.0: {} + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + parseurl@1.3.3: {} + + path-data-parser@0.1.0: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-type@6.0.0: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + + pkg-types@2.2.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.7 + pathe: 2.0.3 + + playwright-core@1.54.2: {} + + playwright@1.54.2: + dependencies: + playwright-core: 1.54.2 + optionalDependencies: + fsevents: 2.3.2 + + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + property-information@6.5.0: {} + + property-information@7.1.0: {} + + quansync@0.2.11: {} + + queue-microtask@1.2.3: {} + + radix-ui@1.4.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-direction': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-form': 0.1.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-menubar': 1.1.16(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-password-toggle-field': 0.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-select': 2.2.6(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-toolbar': 1.1.11(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.10)(react@19.1.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + '@types/react-dom': 19.1.7(@types/react@19.1.10) + + range-parser@1.2.1: {} + + react-dom@19.1.1(react@19.1.1): + dependencies: + react: 19.1.1 + scheduler: 0.26.0 + + react-intersection-observer@9.16.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + optionalDependencies: + react-dom: 19.1.1(react@19.1.1) + + react-refresh@0.17.0: {} + + react-remove-scroll-bar@2.3.8(@types/react@19.1.10)(react@19.1.1): + dependencies: + react: 19.1.1 + react-style-singleton: 2.2.3(@types/react@19.1.10)(react@19.1.1) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.10 + + react-remove-scroll@2.7.1(@types/react@19.1.10)(react@19.1.1): + dependencies: + react: 19.1.1 + react-remove-scroll-bar: 2.3.8(@types/react@19.1.10)(react@19.1.1) + react-style-singleton: 2.2.3(@types/react@19.1.10)(react@19.1.1) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.1.10)(react@19.1.1) + use-sidecar: 1.1.3(@types/react@19.1.10)(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.10 + + react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + cookie: 1.0.2 + react: 19.1.1 + set-cookie-parser: 2.7.1 + optionalDependencies: + react-dom: 19.1.1(react@19.1.1) + + react-style-singleton@2.2.3(@types/react@19.1.10)(react@19.1.1): + dependencies: + get-nonce: 1.0.1 + react: 19.1.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.10 + + react@19.1.1: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + recma-build-jsx@1.0.0: + dependencies: + '@types/estree': 1.0.8 + estree-util-build-jsx: 3.0.1 + vfile: 6.0.3 + + recma-jsx@1.0.1(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + estree-util-to-js: 2.0.0 + recma-parse: 1.0.0 + recma-stringify: 1.0.0 + unified: 11.0.5 + + recma-parse@1.0.0: + dependencies: + '@types/estree': 1.0.8 + esast-util-from-js: 2.0.1 + unified: 11.0.5 + vfile: 6.0.3 + + recma-stringify@1.0.0: + dependencies: + '@types/estree': 1.0.8 + estree-util-to-js: 2.0.0 + unified: 11.0.5 + vfile: 6.0.3 + + regex-recursion@5.1.1: + dependencies: + regex: 5.1.1 + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@5.1.1: + dependencies: + regex-utilities: 2.3.0 + + rehype-autolink-headings@7.1.0: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.3.0 + hast-util-heading-rank: 3.0.0 + hast-util-is-element: 3.0.0 + unified: 11.0.5 + unist-util-visit: 5.0.0 + + rehype-class-names@2.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-classnames: 3.0.0 + hast-util-select: 6.0.4 + unified: 11.0.5 + + rehype-mermaid@3.0.0(playwright@1.54.2): + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html-isomorphic: 2.0.0 + hast-util-to-text: 4.0.2 + mermaid-isomorphic: 3.0.4(playwright@1.54.2) + mini-svg-data-uri: 1.4.4 + space-separated-tokens: 2.0.2 + unified: 11.0.5 + unist-util-visit-parents: 6.0.1 + vfile: 6.0.3 + optionalDependencies: + playwright: 1.54.2 + transitivePeerDependencies: + - supports-color + + rehype-recma@1.0.0: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + hast-util-to-estree: 3.1.3 + transitivePeerDependencies: + - supports-color + + rehype-slug@6.0.0: + dependencies: + '@types/hast': 3.0.4 + github-slugger: 2.0.0 + hast-util-heading-rank: 3.0.0 + hast-util-to-string: 3.0.1 + unist-util-visit: 5.0.0 + + remark-directive@3.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-directive: 3.1.0 + micromark-extension-directive: 3.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-frontmatter@5.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-frontmatter: 2.0.1 + micromark-extension-frontmatter: 2.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-mdx-frontmatter@5.2.0: + dependencies: + '@types/mdast': 4.0.4 + estree-util-value-to-estree: 3.4.0 + toml: 3.0.0 + unified: 11.0.5 + unist-util-mdx-define: 1.1.2 + yaml: 2.8.1 + + remark-mdx@3.1.0: + dependencies: + mdast-util-mdx: 3.0.0 + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.2 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.0 + unified: 11.0.5 + vfile: 6.0.3 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + require-like@0.1.2: {} + + restore-cursor@4.0.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + reusify@1.1.0: {} + + robust-predicates@3.0.2: {} + + rollup@4.46.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.46.2 + '@rollup/rollup-android-arm64': 4.46.2 + '@rollup/rollup-darwin-arm64': 4.46.2 + '@rollup/rollup-darwin-x64': 4.46.2 + '@rollup/rollup-freebsd-arm64': 4.46.2 + '@rollup/rollup-freebsd-x64': 4.46.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.46.2 + '@rollup/rollup-linux-arm-musleabihf': 4.46.2 + '@rollup/rollup-linux-arm64-gnu': 4.46.2 + '@rollup/rollup-linux-arm64-musl': 4.46.2 + '@rollup/rollup-linux-loongarch64-gnu': 4.46.2 + '@rollup/rollup-linux-ppc64-gnu': 4.46.2 + '@rollup/rollup-linux-riscv64-gnu': 4.46.2 + '@rollup/rollup-linux-riscv64-musl': 4.46.2 + '@rollup/rollup-linux-s390x-gnu': 4.46.2 + '@rollup/rollup-linux-x64-gnu': 4.46.2 + '@rollup/rollup-linux-x64-musl': 4.46.2 + '@rollup/rollup-win32-arm64-msvc': 4.46.2 + '@rollup/rollup-win32-ia32-msvc': 4.46.2 + '@rollup/rollup-win32-x64-msvc': 4.46.2 + fsevents: 2.3.3 + + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rw@1.3.3: {} + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + scheduler@0.26.0: {} + + semver@6.3.1: {} + + send@0.19.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + + set-cookie-parser@2.7.1: {} + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shiki@1.29.2: + dependencies: + '@shikijs/core': 1.29.2 + '@shikijs/engine-javascript': 1.29.2 + '@shikijs/engine-oniguruma': 1.29.2 + '@shikijs/langs': 1.29.2 + '@shikijs/themes': 1.29.2 + '@shikijs/types': 1.29.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + signal-exit@3.0.7: {} + + sisteransi@1.0.5: {} + + slash@5.1.0: {} + + source-map-js@1.2.1: {} + + source-map@0.7.6: {} + + space-separated-tokens@2.0.2: {} + + statuses@2.0.1: {} + + stdin-discarder@0.1.0: + dependencies: + bl: 5.1.0 + + string-width@6.1.0: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 10.4.0 + strip-ansi: 7.1.0 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.2.0 + + strip-final-newline@2.0.0: {} + + style-to-js@1.1.17: + dependencies: + style-to-object: 1.0.9 + + style-to-object@1.0.9: + dependencies: + inline-style-parser: 0.2.4 + + stylis@4.3.6: {} + + tabbable@6.2.0: {} + + tailwindcss@4.0.7: {} + + tailwindcss@4.1.12: {} + + tapable@2.2.2: {} + + tinyexec@1.0.1: {} + + tinyglobby@0.2.14: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + toml@3.0.0: {} + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + ts-dedent@2.2.0: {} + + tslib@2.8.1: {} + + twoslash-protocol@0.2.12: {} + + twoslash@0.2.12(typescript@5.9.2): + dependencies: + '@typescript/vfs': 1.6.1(typescript@5.9.2) + twoslash-protocol: 0.2.12 + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + typescript@5.9.2: {} + + ua-parser-js@1.0.40: {} + + ufo@1.6.1: {} + + undici-types@7.10.0: {} + + unicorn-magic@0.3.0: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + + unist-util-is@6.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-mdx-define@1.1.2: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.0 + estree-walker: 3.0.3 + vfile: 6.0.3 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.0.0 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.1: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + + universalify@2.0.1: {} + + update-browserslist-db@1.1.3(browserslist@4.25.2): + dependencies: + browserslist: 4.25.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + use-callback-ref@1.3.3(@types/react@19.1.10)(react@19.1.1): + dependencies: + react: 19.1.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.10 + + use-sidecar@1.1.3(@types/react@19.1.10)(react@19.1.1): + dependencies: + detect-node-es: 1.1.0 + react: 19.1.1 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.1.10 + + use-sync-external-store@1.5.0(react@19.1.1): + dependencies: + react: 19.1.1 + + util-deprecate@1.0.2: {} + + uuid@11.1.0: {} + + vary@1.1.2: {} + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite-node@3.2.4(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1): + dependencies: + cac: 6.7.14 + debug: 4.4.1 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1): + dependencies: + esbuild: 0.25.9 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.46.2 + tinyglobby: 0.2.14 + optionalDependencies: + '@types/node': 24.3.0 + fsevents: 2.3.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + yaml: 2.8.1 + + vocs@1.0.13(@types/node@24.3.0)(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(acorn@8.15.0)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.46.2)(typescript@5.9.2)(yaml@2.8.1): + dependencies: + '@floating-ui/react': 0.27.15(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@hono/node-server': 1.18.2(hono@4.9.2) + '@mdx-js/react': 3.1.0(@types/react@19.1.10)(react@19.1.1) + '@mdx-js/rollup': 3.1.0(acorn@8.15.0)(rollup@4.46.2) + '@noble/hashes': 1.8.0 + '@radix-ui/colors': 3.0.0 + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-icons': 1.3.2(react@19.1.1) + '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@shikijs/rehype': 1.29.2 + '@shikijs/transformers': 1.29.2 + '@shikijs/twoslash': 1.29.2(typescript@5.9.2) + '@tailwindcss/vite': 4.0.7(vite@6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1)) + '@vanilla-extract/css': 1.17.4 + '@vanilla-extract/dynamic': 2.1.5 + '@vanilla-extract/vite-plugin': 5.1.1(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(vite@6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1))(yaml@2.8.1) + '@vitejs/plugin-react': 4.7.0(vite@6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1)) + autoprefixer: 10.4.21(postcss@8.5.6) + cac: 6.7.14 + chroma-js: 3.1.2 + clsx: 2.1.1 + compression: 1.8.1 + create-vocs: 1.0.0 + cross-spawn: 7.0.6 + fs-extra: 11.3.1 + globby: 14.1.0 + hastscript: 8.0.0 + hono: 4.9.2 + mark.js: 8.11.1 + mdast-util-directive: 3.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-frontmatter: 2.0.1 + mdast-util-gfm: 3.1.0 + mdast-util-mdx: 3.0.0 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-to-hast: 13.2.0 + mdast-util-to-markdown: 2.1.2 + minimatch: 9.0.5 + minisearch: 6.3.0 + ora: 7.0.1 + p-limit: 5.0.0 + playwright: 1.54.2 + postcss: 8.5.6 + radix-ui: 1.4.3(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-intersection-observer: 9.16.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react-router: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + rehype-autolink-headings: 7.1.0 + rehype-class-names: 2.0.0 + rehype-mermaid: 3.0.0(playwright@1.54.2) + rehype-slug: 6.0.0 + remark-directive: 3.0.1 + remark-frontmatter: 5.0.0 + remark-gfm: 4.0.1 + remark-mdx: 3.1.0 + remark-mdx-frontmatter: 5.2.0 + remark-parse: 11.0.0 + serve-static: 1.16.2 + shiki: 1.29.2 + toml: 3.0.0 + twoslash: 0.2.12(typescript@5.9.2) + ua-parser-js: 1.0.40 + unified: 11.0.5 + unist-util-visit: 5.0.0 + vite: 6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + transitivePeerDependencies: + - '@types/node' + - '@types/react' + - '@types/react-dom' + - acorn + - babel-plugin-macros + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - yaml + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-uri@3.0.8: {} + + web-namespaces@2.0.1: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + yallist@3.1.1: {} + + yaml@2.8.1: {} + + yocto-queue@0.1.0: {} + + yocto-queue@1.2.1: {} + + zwitch@2.0.4: {} From 7a4c7f22f39baf9dd3362538729dc341b0d48ed0 Mon Sep 17 00:00:00 2001 From: jimenezz22 Date: Sun, 17 Aug 2025 19:45:14 -0600 Subject: [PATCH 04/10] feat: enhance project setup with Tailwind CSS, Vocs configuration, and improved documentation structure --- client-new/package.json | 1 + client-new/pages/index.mdx | 45 ++++++++--- client-new/pnpm-lock.yaml | 40 ++++++++++ client-new/postcss.config.js | 6 ++ client-new/public/favicon.ico | 1 + client-new/src/app.tsx | 7 ++ client-new/styles/globals.css | 6 +- client-new/tailwind.config.js | 143 ++++++++++++++++++++++++++++++++++ client-new/tsconfig.json | 1 - client-new/vocs.config.ts | 142 ++++++++++++++++++++++++++++++++- 10 files changed, 378 insertions(+), 14 deletions(-) create mode 100644 client-new/postcss.config.js create mode 100644 client-new/public/favicon.ico create mode 100644 client-new/src/app.tsx create mode 100644 client-new/tailwind.config.js diff --git a/client-new/package.json b/client-new/package.json index aff7a9b..ec375c4 100644 --- a/client-new/package.json +++ b/client-new/package.json @@ -24,6 +24,7 @@ "vocs": "^1.0.13" }, "devDependencies": { + "@tailwindcss/typography": "^0.5.16", "@types/react": "^19.1.10", "@types/react-dom": "^19.1.7", "autoprefixer": "^10.4.21", diff --git a/client-new/pages/index.mdx b/client-new/pages/index.mdx index febc3c5..0166191 100644 --- a/client-new/pages/index.mdx +++ b/client-new/pages/index.mdx @@ -1,14 +1,41 @@ # Welcome to Dojo by Example -This is the new Vocs-powered documentation site for learning Dojo Engine. +Learn **Dojo Engine** through practical examples and comprehensive guides. -## Getting Started +
+
+

🚀 Getting Started

+

Set up your environment and learn the basics of Dojo Engine development.

+
+ +
+

🎮 Game Examples

+

Explore fully on-chain games built with Dojo and learn from real implementations.

+
+ +
+

🔧 Integration Guides

+

Connect Dojo with React, Unity, and other frameworks for complete applications.

+
+
-The site is being migrated to a modern stack with: -- Latest Vocs version -- React 19 -- Tailwind CSS -- Improved theme switching -- Better performance +## What You'll Learn -Stay tuned for more content! \ No newline at end of file +The site is powered by a modern stack with: +- ✅ **Latest Vocs** - Modern documentation framework +- ✅ **React 19** - Latest React features +- ✅ **Tailwind CSS** - Utility-first styling +- ✅ **Dark/Light Theme** - Automatic theme switching +- ✅ **TypeScript** - Type-safe development + +
+

🎯 Ready to Build?

+

+ Start your journey with Dojo Engine and build the next generation of on-chain games. +

+ Get Started → +
+ +--- + +*Built with ❤️ by the Dojo community* \ No newline at end of file diff --git a/client-new/pnpm-lock.yaml b/client-new/pnpm-lock.yaml index 4d8fb03..6101c47 100644 --- a/client-new/pnpm-lock.yaml +++ b/client-new/pnpm-lock.yaml @@ -18,6 +18,9 @@ importers: specifier: ^1.0.13 version: 1.0.13(@types/node@24.3.0)(@types/react-dom@19.1.7(@types/react@19.1.10))(@types/react@19.1.10)(acorn@8.15.0)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rollup@4.46.2)(typescript@5.9.2)(yaml@2.8.1) devDependencies: + '@tailwindcss/typography': + specifier: ^0.5.16 + version: 0.5.16(tailwindcss@4.1.12) '@types/react': specifier: ^19.1.10 version: 19.1.10 @@ -1327,6 +1330,11 @@ packages: resolution: {integrity: sha512-yr6w5YMgjy+B+zkJiJtIYGXW+HNYOPfRPtSs+aqLnKwdEzNrGv4ZuJh9hYJ3mcA+HMq/K1rtFV+KsEr65S558g==} engines: {node: '>= 10'} + '@tailwindcss/typography@0.5.16': + resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + '@tailwindcss/vite@4.0.7': resolution: {integrity: sha512-GYx5sxArfIMtdZCsxfya3S/efMmf4RvfqdiLUozkhmSFBNUFnYVodatpoO/en4/BsOIGvq/RB6HwcTLn9prFnQ==} peerDependencies: @@ -2367,6 +2375,15 @@ packages: lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + log-symbols@5.1.0: resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} engines: {node: '>=12'} @@ -2739,6 +2756,10 @@ packages: points-on-path@0.2.1: resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -4589,6 +4610,14 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.0.7 '@tailwindcss/oxide-win32-x64-msvc': 4.0.7 + '@tailwindcss/typography@0.5.16(tailwindcss@4.1.12)': + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 4.1.12 + '@tailwindcss/vite@4.0.7(vite@6.3.5(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1))': dependencies: '@tailwindcss/node': 4.0.7 @@ -5799,6 +5828,12 @@ snapshots: lodash-es@4.17.21: {} + lodash.castarray@4.4.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.merge@4.6.2: {} + log-symbols@5.1.0: dependencies: chalk: 5.6.0 @@ -6480,6 +6515,11 @@ snapshots: path-data-parser: 0.1.0 points-on-curve: 0.2.0 + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-value-parser@4.2.0: {} postcss@8.5.6: diff --git a/client-new/postcss.config.js b/client-new/postcss.config.js new file mode 100644 index 0000000..e99ebc2 --- /dev/null +++ b/client-new/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} \ No newline at end of file diff --git a/client-new/public/favicon.ico b/client-new/public/favicon.ico new file mode 100644 index 0000000..b418a20 --- /dev/null +++ b/client-new/public/favicon.ico @@ -0,0 +1 @@ +# Placeholder for favicon - use the icon SVG as fallback \ No newline at end of file diff --git a/client-new/src/app.tsx b/client-new/src/app.tsx new file mode 100644 index 0000000..0911d34 --- /dev/null +++ b/client-new/src/app.tsx @@ -0,0 +1,7 @@ +import { ReactNode } from 'react' +import '../styles/globals.css' + +// Custom App component for Vocs +export default function App({ children }: { children: ReactNode }) { + return <>{children} +} \ No newline at end of file diff --git a/client-new/styles/globals.css b/client-new/styles/globals.css index 473400e..4c60321 100644 --- a/client-new/styles/globals.css +++ b/client-new/styles/globals.css @@ -1,13 +1,13 @@ /* Global Styles for Dojo by Example */ -/* Import design tokens */ -@import './design-tokens.css'; - /* Tailwind base styles */ @tailwind base; @tailwind components; @tailwind utilities; +/* Import design tokens */ +@import './design-tokens.css'; + /* Base styles */ @layer base { /* Smooth scrolling */ diff --git a/client-new/tailwind.config.js b/client-new/tailwind.config.js new file mode 100644 index 0000000..31c9605 --- /dev/null +++ b/client-new/tailwind.config.js @@ -0,0 +1,143 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + './pages/**/*.{js,ts,jsx,tsx,mdx}', + './components/**/*.{js,ts,jsx,tsx}', + './layout/**/*.{js,ts,jsx,tsx}', + './src/**/*.{js,ts,jsx,tsx}', + './vocs.config.ts', + ], + darkMode: ['class', '[data-theme="dark"]'], + theme: { + extend: { + colors: { + // Dojo brand colors + 'dojo-primary': '#ff3000', + 'dojo-hover': '#e62900', + 'dojo-light': '#ff6b4a', + 'dojo-dark': '#cc2600', + + // Dynamic colors that change with theme + 'background': 'var(--color-background)', + 'background-secondary': 'var(--color-background-secondary)', + 'background-tertiary': 'var(--color-background-tertiary)', + 'surface': 'var(--color-surface)', + 'surface-hover': 'var(--color-surface-hover)', + 'border': 'var(--color-border)', + 'border-hover': 'var(--color-border-hover)', + + // Text colors + 'text-primary': 'var(--color-text-primary)', + 'text-secondary': 'var(--color-text-secondary)', + 'text-tertiary': 'var(--color-text-tertiary)', + 'text-muted': 'var(--color-text-muted)', + + // Semantic colors + 'success': '#10b981', + 'warning': '#f59e0b', + 'error': '#ef4444', + 'info': '#3b82f6', + }, + fontFamily: { + 'sans': ['DM Sans', 'system-ui', '-apple-system', 'sans-serif'], + 'mono': ['JetBrains Mono', 'Consolas', 'Monaco', 'monospace'], + }, + spacing: { + 'xs': 'var(--space-xs)', + 'sm': 'var(--space-sm)', + 'md': 'var(--space-md)', + 'lg': 'var(--space-lg)', + 'xl': 'var(--space-xl)', + '2xl': 'var(--space-2xl)', + '3xl': 'var(--space-3xl)', + }, + fontSize: { + 'xs': 'var(--font-size-xs)', + 'sm': 'var(--font-size-sm)', + 'base': 'var(--font-size-base)', + 'lg': 'var(--font-size-lg)', + 'xl': 'var(--font-size-xl)', + '2xl': 'var(--font-size-2xl)', + '3xl': 'var(--font-size-3xl)', + '4xl': 'var(--font-size-4xl)', + '5xl': 'var(--font-size-5xl)', + }, + borderRadius: { + 'sm': 'var(--radius-sm)', + 'md': 'var(--radius-md)', + 'lg': 'var(--radius-lg)', + 'xl': 'var(--radius-xl)', + '2xl': 'var(--radius-2xl)', + }, + boxShadow: { + 'sm': 'var(--shadow-sm)', + 'md': 'var(--shadow-md)', + 'lg': 'var(--shadow-lg)', + 'xl': 'var(--shadow-xl)', + 'dojo': '0 0 20px rgba(255, 48, 0, 0.3)', + }, + animation: { + 'fadeIn': 'fadeIn 0.5s ease-out', + 'slideIn': 'slideIn 0.3s ease-out', + 'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite', + }, + keyframes: { + fadeIn: { + '0%': { opacity: '0', transform: 'translateY(10px)' }, + '100%': { opacity: '1', transform: 'translateY(0)' }, + }, + slideIn: { + '0%': { transform: 'translateX(-100%)' }, + '100%': { transform: 'translateX(0)' }, + }, + }, + typography: (theme) => ({ + DEFAULT: { + css: { + color: 'var(--color-text-primary)', + a: { + color: '#ff3000', + '&:hover': { + color: '#e62900', + }, + }, + h1: { + color: 'var(--color-text-primary)', + }, + h2: { + color: 'var(--color-text-primary)', + }, + h3: { + color: 'var(--color-text-primary)', + }, + h4: { + color: 'var(--color-text-primary)', + }, + code: { + color: 'var(--color-text-primary)', + backgroundColor: 'var(--color-background-tertiary)', + borderRadius: '0.375rem', + padding: '0.125rem 0.25rem', + }, + 'code::before': { + content: '""', + }, + 'code::after': { + content: '""', + }, + pre: { + backgroundColor: 'var(--color-background-tertiary)', + }, + blockquote: { + borderLeftColor: '#ff3000', + color: 'var(--color-text-secondary)', + }, + }, + }, + }), + }, + }, + plugins: [ + require('@tailwindcss/typography'), + ], +} \ No newline at end of file diff --git a/client-new/tsconfig.json b/client-new/tsconfig.json index 31f062c..cb0b9cb 100644 --- a/client-new/tsconfig.json +++ b/client-new/tsconfig.json @@ -12,7 +12,6 @@ "forceConsistentCasingInFileNames": true, "allowSyntheticDefaultImports": true, "noEmit": true, - "types": ["vite/client"], "paths": { "@/*": ["./src/*"], "@components/*": ["./components/*"], diff --git a/client-new/vocs.config.ts b/client-new/vocs.config.ts index 0ff4493..e7f0bec 100644 --- a/client-new/vocs.config.ts +++ b/client-new/vocs.config.ts @@ -1,12 +1,152 @@ import { defineConfig } from 'vocs' export default defineConfig({ + // Basic configuration title: 'Dojo by Example', - description: 'Learn Dojo Engine through practical examples', + titleTemplate: '%s · Dojo by Example', + description: 'Learn Dojo Engine through practical examples and comprehensive guides', + + // Logo configuration with theme switching + iconUrl: { + light: '/logos/Icon_Light.svg', + dark: '/logos/Icon_Dark.svg', + }, + logoUrl: { + light: '/logos/Horizontal_Light.svg', + dark: '/logos/Horizontal_Dark.svg', + }, + + // Theme configuration + theme: { + accentColor: { + light: '#ff3000', + dark: '#ff6b4a', + }, + colorScheme: 'system', // Auto dark/light mode + }, + + // Font configuration + font: { + google: 'DM Sans', + }, + + // Social links + socials: [ + { + icon: 'github', + link: 'https://github.com/AkatsukiLabs/DojoByExample', + }, + { + icon: 'telegram', + link: 'https://t.me/+8T2gw4hgblowZTBh', + }, + { + icon: 'x', + link: 'https://twitter.com/dojoengine', + }, + ], + + // Edit link configuration + editLink: { + pattern: 'https://github.com/AkatsukiLabs/DojoByExample/edit/main/client-new/pages/:path', + text: 'Edit this page on GitHub', + }, + + // Sponsors configuration + sponsors: [ + { + name: 'Powered by', + height: 60, + items: [ + [ + { + name: 'Cartridge', + link: 'https://docs.cartridge.gg/', + image: '/partners/Cartridge.svg', + }, + ], + [ + { + name: 'Starknet', + link: 'https://www.starknet.io', + image: '/partners/Starknet.svg', + }, + { + name: 'OnlyDust', + link: 'https://app.onlydust.com/p/starknet-by-example', + image: '/partners/Onlydust.svg', + }, + ], + ], + }, + { + name: 'Ecosystem Tooling', + items: [ + [ + { + name: 'Dojo', + link: 'https://book.dojoengine.org/', + image: '/partners/DojoLogo.svg', + }, + ], + [ + { + name: 'Katana', + link: 'https://book.dojoengine.org/toolchain/katana', + image: '/partners/KatanaLogo.svg', + }, + { + name: 'Sozo', + link: 'https://book.dojoengine.org/toolchain/sozo', + image: '/partners/SozoLogo.svg', + }, + { + name: 'Torii', + link: 'https://book.dojoengine.org/toolchain/torii', + image: '/partners/ToriiLogo.svg', + }, + ], + [ + { + name: 'Origami', + link: 'https://book.dojoengine.org/libraries/origami', + image: '/partners/OrigamiLogo.svg', + }, + { + name: 'Saya', + link: 'https://book.dojoengine.org/toolchain/saya', + image: '/partners/SayaLogo.svg', + }, + ], + ], + }, + ], + + // Sidebar configuration (basic for now) sidebar: [ { text: 'Introduction', link: '/', }, ], + + + // Markdown configuration + markdown: { + code: { + themes: { + light: 'github-light', + dark: 'github-dark-dimmed', + }, + }, + }, + + // Custom App component for styles + app: './src/app.tsx', + + // Root directory + rootDir: '.', + + // Base URL (useful for deployment) + baseUrl: process.env.NODE_ENV === 'production' ? 'https://dojobyexample.com' : 'http://localhost:4000', }) \ No newline at end of file From 0d3df2fd5c64fe16dfc0ebafa12ad8e5c4662bb3 Mon Sep 17 00:00:00 2001 From: jimenezz22 Date: Sun, 17 Aug 2025 20:37:29 -0600 Subject: [PATCH 05/10] feat: implement dynamic sidebar configuration and add navigation components for improved user experience --- client-new/components/Navigation.tsx | 137 +++++++++ client-new/pages/getting-started.mdx | 85 ++++++ .../pages/getting-started/basics/models.mdx | 67 +++++ .../pages/getting-started/quickstart.mdx | 38 +++ client-new/pages/getting-started/setup.mdx | 38 +++ client-new/pages/guides/react/overview.mdx | 50 ++++ client-new/src/routes.ts | 260 ++++++++++++++++++ client-new/vocs.config.ts | 10 +- 8 files changed, 678 insertions(+), 7 deletions(-) create mode 100644 client-new/components/Navigation.tsx create mode 100644 client-new/pages/getting-started.mdx create mode 100644 client-new/pages/getting-started/basics/models.mdx create mode 100644 client-new/pages/getting-started/quickstart.mdx create mode 100644 client-new/pages/getting-started/setup.mdx create mode 100644 client-new/pages/guides/react/overview.mdx create mode 100644 client-new/src/routes.ts diff --git a/client-new/components/Navigation.tsx b/client-new/components/Navigation.tsx new file mode 100644 index 0000000..6dea73a --- /dev/null +++ b/client-new/components/Navigation.tsx @@ -0,0 +1,137 @@ +import { ReactNode } from 'react' + +interface NavigationCardProps { + title: string + description: string + href: string + icon?: string + children?: ReactNode +} + +export function NavigationCard({ title, description, href, icon, children }: NavigationCardProps) { + return ( + +
+ {icon && ( +
+ {icon} +
+ )} +
+

+ {title} +

+

+ {description} +

+ {children && ( +
+ {children} +
+ )} +
+
+ → +
+
+
+ ) +} + +interface NavigationGridProps { + children: ReactNode + columns?: 1 | 2 | 3 +} + +export function NavigationGrid({ children, columns = 2 }: NavigationGridProps) { + const gridCols = { + 1: 'grid-cols-1', + 2: 'grid-cols-1 md:grid-cols-2', + 3: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3', + } + + return ( +
+ {children} +
+ ) +} + +interface BreadcrumbProps { + items: Array<{ + label: string + href?: string + }> +} + +export function Breadcrumb({ items }: BreadcrumbProps) { + return ( + + ) +} + +interface NextPrevProps { + prev?: { + label: string + href: string + } + next?: { + label: string + href: string + } +} + +export function NextPrev({ prev, next }: NextPrevProps) { + return ( +
+ + + +
+ ) +} \ No newline at end of file diff --git a/client-new/pages/getting-started.mdx b/client-new/pages/getting-started.mdx new file mode 100644 index 0000000..c26d4a3 --- /dev/null +++ b/client-new/pages/getting-started.mdx @@ -0,0 +1,85 @@ +import { NavigationGrid, NavigationCard } from '../components/Navigation' + +# Getting Started + +Welcome to Dojo Engine! This section will guide you through setting up your development environment and learning the fundamentals. + +## Quick Navigation + + + + + + + +## Core Concepts + + + + + + + + + + + + + + + +## Learning Path + +We recommend following this learning path: + +1. **[Environment Setup](/getting-started/setup)** - Get your tools ready +2. **[Quick Start](/getting-started/quickstart)** - Build your first app +3. **[Models](/getting-started/basics/models)** - Define your data +4. **[Systems](/getting-started/basics/systems)** - Add game logic +5. **[Testing](/getting-started/basics/testing/unit)** - Ensure quality + +## Need Help? + +- 📖 [Read the official Dojo book](https://book.dojoengine.org/) +- 💬 [Join our Telegram](https://t.me/+8T2gw4hgblowZTBh) +- 🐛 [Report issues on GitHub](https://github.com/AkatsukiLabs/DojoByExample) \ No newline at end of file diff --git a/client-new/pages/getting-started/basics/models.mdx b/client-new/pages/getting-started/basics/models.mdx new file mode 100644 index 0000000..97452de --- /dev/null +++ b/client-new/pages/getting-started/basics/models.mdx @@ -0,0 +1,67 @@ +# Models + +Models in Dojo define the structure of your game state and data. + +## What are Models? + +Models are Cairo structures that represent entities in your game world. They define: + +- **State structure** - How data is organized +- **Permissions** - Who can read/write the data +- **Relationships** - How entities connect + +## Basic Model Example + +```cairo +#[derive(Model, Copy, Drop, Serde)] +struct Player { + #[key] + id: u32, + name: felt252, + health: u32, + position: Position, +} + +#[derive(Copy, Drop, Serde, Introspect)] +struct Position { + x: u32, + y: u32, +} +``` + +## Key Features + +### Primary Keys + +Use `#[key]` to mark fields as primary keys: + +```cairo +#[derive(Model, Copy, Drop, Serde)] +struct GameSession { + #[key] + session_id: u32, + #[key] + player_id: u32, + score: u32, +} +``` + +### Derived Traits + +Models must implement these traits: +- `Model` - Core Dojo functionality +- `Copy` - For copying values +- `Drop` - For cleanup +- `Serde` - For serialization + +## Best Practices + +1. **Keep models simple** - One responsibility per model +2. **Use appropriate types** - Choose efficient Cairo types +3. **Design for queries** - Consider how you'll access data +4. **Plan relationships** - Think about entity connections + +## Next Steps + +- [Learn about Systems](/getting-started/basics/systems) +- [Understand the World](/getting-started/basics/world) \ No newline at end of file diff --git a/client-new/pages/getting-started/quickstart.mdx b/client-new/pages/getting-started/quickstart.mdx new file mode 100644 index 0000000..af96f69 --- /dev/null +++ b/client-new/pages/getting-started/quickstart.mdx @@ -0,0 +1,38 @@ +# Quick Start + +Get up and running with Dojo in minutes. + +## Create a New Project + +```bash +dojo new my-first-game +cd my-first-game +``` + +## Project Structure + +Your new Dojo project contains: + +- `src/` - Cairo smart contracts +- `models/` - Game state models +- `systems/` - Game logic systems +- `scripts/` - Deployment scripts + +## Build and Run + +```bash +# Build the project +dojo build + +# Start local development node +katana --dev + +# Deploy to local network +dojo deploy +``` + +## What's Next? + +- [Learn about Models](/getting-started/basics/models) +- [Understand Systems](/getting-started/basics/systems) +- [Explore Examples](/examples/starters/react) \ No newline at end of file diff --git a/client-new/pages/getting-started/setup.mdx b/client-new/pages/getting-started/setup.mdx new file mode 100644 index 0000000..b06f18d --- /dev/null +++ b/client-new/pages/getting-started/setup.mdx @@ -0,0 +1,38 @@ +# Environment Setup + +Setting up your development environment for Dojo Engine. + +## Prerequisites + +Before you begin, make sure you have the following installed: + +- **Rust** - Required for building Cairo smart contracts +- **Node.js** - For frontend development +- **Git** - For version control + +## Installation Steps + +### 1. Install Dojo + +```bash +curl -L https://install.dojoengine.org | bash +dojoup +``` + +### 2. Verify Installation + +```bash +dojo --version +``` + +### 3. Create Your First Project + +```bash +dojo new my-dojo-game +cd my-dojo-game +``` + +## Next Steps + +- [Quick Start Guide](/getting-started/quickstart) +- [Learn about Models](/getting-started/basics/models) \ No newline at end of file diff --git a/client-new/pages/guides/react/overview.mdx b/client-new/pages/guides/react/overview.mdx new file mode 100644 index 0000000..81e12ca --- /dev/null +++ b/client-new/pages/guides/react/overview.mdx @@ -0,0 +1,50 @@ +# React Integration Overview + +Learn how to integrate Dojo Engine with React applications. + +## Why React + Dojo? + +React provides an excellent frontend framework for building user interfaces that interact with Dojo's on-chain game logic: + +- **Reactive UI** - Updates automatically when game state changes +- **Component Architecture** - Modular, reusable game components +- **Rich Ecosystem** - Leverage existing React libraries +- **Developer Experience** - Great tooling and debugging + +## Architecture + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ React App │ │ Dojo.js │ │ Dojo Core │ +│ │ │ │ │ │ +│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │ +│ │ Components │◄┼────┼►│ Hooks │◄┼────┼►│ Models │ │ +│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │ +│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │ +│ │ State │◄┼────┼►│ Providers │◄┼────┼►│ Systems │ │ +│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ +``` + +## Key Concepts + +### State Management +- **Global State** - Game world state from Dojo +- **Local State** - UI-specific state in React +- **Sync Strategy** - Keep frontend in sync with on-chain state + +### Real-time Updates +- **Event Listening** - Subscribe to on-chain events +- **Optimistic Updates** - Update UI before confirmation +- **Error Handling** - Handle failed transactions gracefully + +## Getting Started + +1. [Setup your environment](/guides/react/setup) +2. [Learn about hooks](/guides/react/hooks) +3. [Build components](/guides/react/components) + +## Example Projects + +- [React Starter Template](/examples/starters/react) +- [Production Game Example](/examples/games/simple) \ No newline at end of file diff --git a/client-new/src/routes.ts b/client-new/src/routes.ts new file mode 100644 index 0000000..1660e44 --- /dev/null +++ b/client-new/src/routes.ts @@ -0,0 +1,260 @@ +import type { Sidebar, SidebarItem } from 'vocs' + +// Main sidebar configuration +const sidebarConfig: SidebarItem[] = [ + { + text: 'Introduction', + link: '/', + }, + { + text: 'Getting Started', + items: [ + { + text: 'Environment Setup', + link: '/getting-started/setup', + }, + { + text: 'Quick Start', + link: '/getting-started/quickstart', + }, + { + text: 'Basics', + collapsed: true, + items: [ + { + text: 'Models', + link: '/getting-started/basics/models', + }, + { + text: 'Systems', + link: '/getting-started/basics/systems', + }, + { + text: 'World', + link: '/getting-started/basics/world', + }, + { + text: 'Store', + link: '/getting-started/basics/store', + }, + { + text: 'Events', + link: '/getting-started/basics/events', + }, + { + text: 'Testing', + items: [ + { + text: 'Unit Testing', + link: '/getting-started/basics/testing/unit', + }, + { + text: 'Integration Testing', + link: '/getting-started/basics/testing/integration', + }, + ], + }, + ], + }, + ], + }, + { + text: 'Guides', + collapsed: true, + items: [ + { + text: 'React Integration', + collapsed: true, + items: [ + { + text: 'Overview', + link: '/guides/react/overview', + }, + { + text: 'Setup', + link: '/guides/react/setup', + }, + { + text: 'Hooks & State', + link: '/guides/react/hooks', + }, + { + text: 'Components', + link: '/guides/react/components', + }, + ], + }, + { + text: 'Unity Integration', + link: '/guides/unity', + }, + { + text: 'AI Agents', + items: [ + { + text: 'Daydreams', + link: '/guides/ai/daydreams', + }, + { + text: 'Eliza', + link: '/guides/ai/eliza', + }, + ], + }, + ], + }, + { + text: 'Deployment', + collapsed: true, + items: [ + { + text: 'Local Development', + link: '/deployment/local', + }, + { + text: 'Testnet (Sepolia)', + link: '/deployment/sepolia', + }, + { + text: 'Mainnet', + link: '/deployment/mainnet', + }, + { + text: 'Slot', + link: '/deployment/slot', + }, + ], + }, + { + text: 'Examples', + collapsed: true, + items: [ + { + text: 'Starter Templates', + items: [ + { + text: 'React Starter', + link: '/examples/starters/react', + }, + { + text: 'Bevy Starter', + link: '/examples/starters/bevy', + }, + ], + }, + { + text: 'Production Games', + items: [ + { + text: 'Simple Game', + link: '/examples/games/simple', + }, + { + text: 'Advanced Game', + link: '/examples/games/advanced', + }, + ], + }, + ], + }, + { + text: 'Advanced', + collapsed: true, + items: [ + { + text: 'Gas Optimization', + link: '/advanced/gas-optimization', + }, + { + text: 'Smart Contracts vs Dojo', + link: '/advanced/contracts-comparison', + }, + { + text: 'Best Practices', + link: '/advanced/best-practices', + }, + { + text: 'Performance', + link: '/advanced/performance', + }, + ], + }, + { + text: 'Reference', + collapsed: true, + items: [ + { + text: 'API Reference', + link: '/reference/api', + }, + { + text: 'CLI Commands', + link: '/reference/cli', + }, + { + text: 'Configuration', + link: '/reference/config', + }, + { + text: 'Troubleshooting', + link: '/reference/troubleshooting', + }, + ], + }, +] + +/** + * Gets all top-level routes from the sidebar config + */ +const getTopLevelRoutes = (sidebar: SidebarItem[]): Array<[string, string]> => + sidebar + .filter((item) => item.text !== 'Introduction') // Skip Introduction + .map((item) => { + // Convert the text to a URL-friendly format and get the first link if available + const path = item.link || `/${item.text.toLowerCase().replace(/\s+/g, '-')}` + return [path.split('/')[1], item.text] as [string, string] + }) + +/** + * Recursively modifies the sidebar structure to control which sections are collapsed + */ +const sidebarFocusOn = ( + sidebar: SidebarItem[], + target: string, + closeOther: boolean = false, +): SidebarItem[] => + sidebar.map((item) => + item.items && item.items.length > 0 + ? { + ...item, + collapsed: item.text === target ? false : closeOther ? true : item.collapsed, + items: sidebarFocusOn(item.items, target, closeOther), + } + : { + ...item, + collapsed: item.text === target ? false : closeOther ? true : item.collapsed, + }, + ) + +/** + * Generates a complete sidebar configuration with automatic route-based collapsing + */ +const generateSidebarConfig = (sidebar: SidebarItem[]): Sidebar => { + // Initialize with the default route + const config: Sidebar = { + '/': sidebar, + } + + // Configure for all top-level routes + getTopLevelRoutes(sidebar).forEach(([route, sectionName]) => { + config[`/${route}`] = sidebarFocusOn(sidebar, sectionName, false) + }) + + return config +} + +// Export the generated sidebar configuration +export const sidebar = generateSidebarConfig(sidebarConfig) + +// Export individual pieces for potential customization +export { sidebarConfig, getTopLevelRoutes, sidebarFocusOn, generateSidebarConfig } \ No newline at end of file diff --git a/client-new/vocs.config.ts b/client-new/vocs.config.ts index e7f0bec..001c4ca 100644 --- a/client-new/vocs.config.ts +++ b/client-new/vocs.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from 'vocs' +import { sidebar } from './src/routes' export default defineConfig({ // Basic configuration @@ -122,13 +123,8 @@ export default defineConfig({ }, ], - // Sidebar configuration (basic for now) - sidebar: [ - { - text: 'Introduction', - link: '/', - }, - ], + // Sidebar configuration with dynamic sections + sidebar: sidebar, // Markdown configuration From 60b45e59f0e4c5af5a2b6d9e833b8fe912ed27c8 Mon Sep 17 00:00:00 2001 From: jimenezz22 Date: Sun, 17 Aug 2025 21:23:52 -0600 Subject: [PATCH 06/10] feat: add CTA, Features, Hero, and Stats components with responsive design and improved structure --- client-new/components/CTA.tsx | 83 +++++++++++ client-new/components/Features.tsx | 133 ++++++++++++++++++ client-new/components/Hero.tsx | 103 ++++++++++++++ client-new/components/Stats.tsx | 108 +++++++++++++++ client-new/pages/index.mdx | 215 +++++++++++++++++++++++++---- client-new/vocs.config.ts | 3 - 6 files changed, 612 insertions(+), 33 deletions(-) create mode 100644 client-new/components/CTA.tsx create mode 100644 client-new/components/Features.tsx create mode 100644 client-new/components/Hero.tsx create mode 100644 client-new/components/Stats.tsx diff --git a/client-new/components/CTA.tsx b/client-new/components/CTA.tsx new file mode 100644 index 0000000..cd6bdd8 --- /dev/null +++ b/client-new/components/CTA.tsx @@ -0,0 +1,83 @@ +import { ReactNode } from 'react' + +interface CTAProps { + title: string + description?: string + children?: ReactNode + variant?: 'default' | 'gradient' +} + +export function CTA({ title, description, children, variant = 'default' }: CTAProps) { + const bgClass = variant === 'gradient' + ? 'bg-gradient-to-r from-dojo-primary to-dojo-light' + : 'bg-surface border border-dojo-primary/20' + + const textClass = variant === 'gradient' + ? 'text-white' + : 'text-text-primary' + + const descClass = variant === 'gradient' + ? 'text-white/90' + : 'text-text-secondary' + + return ( +
+
+
+

+ {title} +

+ {description && ( +

+ {description} +

+ )} + {children && ( +
+ {children} +
+ )} +
+
+
+ ) +} + +interface CTAButtonProps { + href: string + children: ReactNode + variant?: 'primary' | 'white' + external?: boolean +} + +export function CTAButton({ href, children, variant = 'primary', external = false }: CTAButtonProps) { + const className = variant === 'white' + ? 'inline-flex items-center px-6 py-3 rounded-lg bg-white text-dojo-primary font-semibold hover:bg-gray-100 transition-colors shadow-lg' + : 'inline-flex items-center px-6 py-3 rounded-lg bg-dojo-primary text-white font-semibold hover:bg-dojo-hover transition-colors shadow-lg' + + const content = ( + <> + {children} + + + ) + + if (external) { + return ( + + {content} + + ) + } + + return ( + + {content} + + ) +} \ No newline at end of file diff --git a/client-new/components/Features.tsx b/client-new/components/Features.tsx new file mode 100644 index 0000000..2bad845 --- /dev/null +++ b/client-new/components/Features.tsx @@ -0,0 +1,133 @@ +import { ReactNode } from 'react' + +interface Feature { + icon: string | ReactNode + title: string + description: string + href?: string +} + +interface FeaturesProps { + title?: string + subtitle?: string + features: Feature[] + columns?: 2 | 3 | 4 +} + +export function Features({ title, subtitle, features, columns = 3 }: FeaturesProps) { + const gridCols = { + 2: 'grid-cols-1 md:grid-cols-2', + 3: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3', + 4: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4', + } + + return ( +
+
+ {(title || subtitle) && ( +
+ {subtitle && ( +

+ {subtitle} +

+ )} + {title && ( +

+ {title} +

+ )} +
+ )} + +
+ {features.map((feature, index) => ( + + ))} +
+
+
+ ) +} + +interface FeatureCardProps extends Feature {} + +export function FeatureCard({ icon, title, description, href }: FeatureCardProps) { + const content = ( + <> +
+ {icon} +
+

+ {title} +

+

+ {description} +

+ {href && ( +
+ Learn more → +
+ )} + + ) + + if (href) { + return ( + + {content} + + ) + } + + return ( +
+ {content} +
+ ) +} + +interface FeatureHighlightProps { + icon: string | ReactNode + title: string + description: string + image?: string + reverse?: boolean + children?: ReactNode +} + +export function FeatureHighlight({ icon, title, description, image, reverse = false, children }: FeatureHighlightProps) { + return ( +
+
+
+
+
+ {icon} +
+

+ {title} +

+

+ {description} +

+ {children} +
+ +
+ {image ? ( + {title} + ) : ( +
+
{icon}
+
+ )} +
+
+
+
+ ) +} \ No newline at end of file diff --git a/client-new/components/Hero.tsx b/client-new/components/Hero.tsx new file mode 100644 index 0000000..b9369a4 --- /dev/null +++ b/client-new/components/Hero.tsx @@ -0,0 +1,103 @@ +import { ReactNode } from 'react' + +interface HeroProps { + title: string | ReactNode + subtitle?: string + description?: string + children?: ReactNode +} + +export function Hero({ title, subtitle, description, children }: HeroProps) { + return ( +
+
+
+ {subtitle && ( +

+ {subtitle} +

+ )} + +

+ {title} +

+ + {description && ( +

+ {description} +

+ )} + + {children && ( +
+ {children} +
+ )} +
+
+ + {/* Gradient background effect */} +
+
+
+
+ ) +} + +interface HeroButtonProps { + href: string + children: ReactNode + variant?: 'primary' | 'secondary' + external?: boolean +} + +export function HeroButton({ href, children, variant = 'primary', external = false }: HeroButtonProps) { + const className = variant === 'primary' + ? 'inline-flex items-center px-6 py-3 rounded-lg bg-dojo-primary text-white font-semibold hover:bg-dojo-hover transition-colors shadow-lg hover:shadow-xl' + : 'inline-flex items-center px-6 py-3 rounded-lg bg-surface border border-border text-text-primary font-semibold hover:bg-surface-hover transition-colors' + + const content = ( + <> + {children} + + + ) + + if (external) { + return ( + + {content} + + ) + } + + return ( + + {content} + + ) +} + +interface HeroBadgeProps { + text: string + href?: string +} + +export function HeroBadge({ text, href }: HeroBadgeProps) { + const className = "inline-flex items-center px-3 py-1 rounded-full bg-dojo-primary/10 text-dojo-primary text-sm font-medium" + + if (href) { + return ( + + {text} + + ) + } + + return {text} +} \ No newline at end of file diff --git a/client-new/components/Stats.tsx b/client-new/components/Stats.tsx new file mode 100644 index 0000000..dd5c706 --- /dev/null +++ b/client-new/components/Stats.tsx @@ -0,0 +1,108 @@ +interface Stat { + label: string + value: string | number + suffix?: string +} + +interface StatsProps { + title?: string + subtitle?: string + stats: Stat[] +} + +export function Stats({ title, subtitle, stats }: StatsProps) { + return ( +
+
+ {(title || subtitle) && ( +
+ {subtitle && ( +

+ {subtitle} +

+ )} + {title && ( +

+ {title} +

+ )} +
+ )} + +
+ {stats.map((stat, index) => ( +
+
+ {stat.value}{stat.suffix} +
+
+ {stat.label} +
+
+ ))} +
+
+
+ ) +} + +interface TimelineItem { + date: string + title: string + description: string + icon?: string +} + +interface TimelineProps { + title?: string + subtitle?: string + items: TimelineItem[] +} + +export function Timeline({ title, subtitle, items }: TimelineProps) { + return ( +
+
+ {(title || subtitle) && ( +
+ {subtitle && ( +

+ {subtitle} +

+ )} + {title && ( +

+ {title} +

+ )} +
+ )} + +
+ {/* Vertical line */} +
+ + {items.map((item, index) => ( +
+ {/* Dot */} +
+ {item.icon && ( +
+ {item.icon} +
+ )} +
+ + {/* Content */} +
+
{item.date}
+

{item.title}

+

{item.description}

+
+
+ ))} +
+
+
+ ) +} \ No newline at end of file diff --git a/client-new/pages/index.mdx b/client-new/pages/index.mdx index 0166191..dcb708f 100644 --- a/client-new/pages/index.mdx +++ b/client-new/pages/index.mdx @@ -1,41 +1,196 @@ -# Welcome to Dojo by Example +import { Hero, HeroButton, HeroBadge } from '../components/Hero' +import { Features, FeatureHighlight } from '../components/Features' +import { Stats, Timeline } from '../components/Stats' +import { NavigationGrid, NavigationCard } from '../components/Navigation' -Learn **Dojo Engine** through practical examples and comprehensive guides. +Build On-Chain Games with Dojo Engine} + description="The comprehensive guide to building fully on-chain games and autonomous worlds on Starknet. From basics to production-ready applications." +> + + Get Started + + + Read the Docs + + -
-
-

🚀 Getting Started

-

Set up your environment and learn the basics of Dojo Engine development.

-
- -
-

🎮 Game Examples

-

Explore fully on-chain games built with Dojo and learn from real implementations.

-
- -
-

🔧 Integration Guides

-

Connect Dojo with React, Unity, and other frameworks for complete applications.

+ + +## Quick Start Guides + + + + + + + + + -
+ -## What You'll Learn + -The site is powered by a modern stack with: -- ✅ **Latest Vocs** - Modern documentation framework -- ✅ **React 19** - Latest React features -- ✅ **Tailwind CSS** - Utility-first styling -- ✅ **Dark/Light Theme** - Automatic theme switching -- ✅ **TypeScript** - Type-safe development +## Learning Path -
-

🎯 Ready to Build?

-

- Start your journey with Dojo Engine and build the next generation of on-chain games. + + +## Popular Examples + + + + + + + + +## Ready to Build? + +

+

+ Start Your Journey Today +

+

+ Join thousands of developers building the future of gaming on Starknet.

- Get Started → +
+ + Start Learning + + + View on GitHub + +
--- -*Built with ❤️ by the Dojo community* \ No newline at end of file +
+ Built with ❤️ by the Dojo Community +
\ No newline at end of file diff --git a/client-new/vocs.config.ts b/client-new/vocs.config.ts index 001c4ca..125bf3f 100644 --- a/client-new/vocs.config.ts +++ b/client-new/vocs.config.ts @@ -137,9 +137,6 @@ export default defineConfig({ }, }, - // Custom App component for styles - app: './src/app.tsx', - // Root directory rootDir: '.', From e92c1c40d3a768924a9d5052dd03327285e9400c Mon Sep 17 00:00:00 2001 From: jimenezz22 Date: Sun, 17 Aug 2025 23:44:12 -0600 Subject: [PATCH 07/10] Add comprehensive guides for React integration with Dojo - Introduced `main.md` detailing the initialization process of Dojo React applications, including SDK setup, provider hierarchy, and error handling. - Created `manifest.md` to explain the deployment-specific contract information management across different networks. - Developed `overview.md` summarizing the key concepts and benefits of integrating Dojo with React for onchain game development. - Added `starknet-provider.md` outlining the configuration of the Starknet provider for seamless blockchain interactions in React applications. - Initiated `unity.mdx` for future Unity integration documentation. - Established `api.mdx` as a reference for Dojo Engine APIs and interfaces. - Compiled `cli.mdx` for a complete reference of Dojo CLI commands. - Documented `config.mdx` for project and network configuration guidelines. - Created `troubleshooting.mdx` to address common issues and solutions when working with Dojo Engine. --- .../pages/advanced/contracts-comparison.md | 3 + client-new/pages/advanced/gas-optimization.md | 3 + client-new/pages/deployment/local.md | 3 + client-new/pages/deployment/mainnet.md | 3 + client-new/pages/deployment/sepolia.md | 3 + client-new/pages/deployment/slot.md | 3 + client-new/pages/examples/games/advanced.mdx | 373 +++++++++++ client-new/pages/examples/games/simple.mdx | 191 ++++++ client-new/pages/examples/starters/bevy.md | 100 +++ client-new/pages/examples/starters/react.md | 62 ++ .../pages/getting-started/basics/constants.md | 192 ++++++ .../pages/getting-started/basics/enums.md | 460 +++++++++++++ .../pages/getting-started/basics/events.md | 3 + .../pages/getting-started/basics/helpers.md | 303 +++++++++ .../pages/getting-started/basics/models.md | 399 +++++++++++ .../basics/models/ModelsBestPractices.md | 169 +++++ .../basics/models/ModelsTesting.md | 583 +++++++++++++++++ .../basics/models/models-patterns.md | 619 ++++++++++++++++++ .../pages/getting-started/basics/store.md | 3 + .../pages/getting-started/basics/systems.md | 3 + .../basics/testing/integration.md | 3 + .../getting-started/basics/testing/unit.md | 130 ++++ .../pages/getting-started/basics/world.md | 3 + client-new/pages/getting-started/env_setup.md | 107 +++ client-new/pages/guides/ai/daydreams.md | 3 + client-new/pages/guides/ai/eliza.md | 3 + .../react/bindings/contracts-bindings.md | 369 +++++++++++ .../guides/react/bindings/models-bindings.md | 334 ++++++++++ .../guides/react/controller-connector.md | 375 +++++++++++ client-new/pages/guides/react/dojo-config.md | 122 ++++ client-new/pages/guides/react/main.md | 248 +++++++ client-new/pages/guides/react/manifest.md | 237 +++++++ client-new/pages/guides/react/overview.md | 58 ++ .../pages/guides/react/starknet-provider.md | 300 +++++++++ client-new/pages/guides/unity.mdx | 3 + client-new/pages/reference/api.mdx | 71 ++ client-new/pages/reference/cli.mdx | 101 +++ client-new/pages/reference/config.mdx | 123 ++++ .../pages/reference/troubleshooting.mdx | 197 ++++++ 39 files changed, 6265 insertions(+) create mode 100644 client-new/pages/advanced/contracts-comparison.md create mode 100644 client-new/pages/advanced/gas-optimization.md create mode 100644 client-new/pages/deployment/local.md create mode 100644 client-new/pages/deployment/mainnet.md create mode 100644 client-new/pages/deployment/sepolia.md create mode 100644 client-new/pages/deployment/slot.md create mode 100644 client-new/pages/examples/games/advanced.mdx create mode 100644 client-new/pages/examples/games/simple.mdx create mode 100644 client-new/pages/examples/starters/bevy.md create mode 100644 client-new/pages/examples/starters/react.md create mode 100644 client-new/pages/getting-started/basics/constants.md create mode 100644 client-new/pages/getting-started/basics/enums.md create mode 100644 client-new/pages/getting-started/basics/events.md create mode 100644 client-new/pages/getting-started/basics/helpers.md create mode 100644 client-new/pages/getting-started/basics/models.md create mode 100644 client-new/pages/getting-started/basics/models/ModelsBestPractices.md create mode 100644 client-new/pages/getting-started/basics/models/ModelsTesting.md create mode 100644 client-new/pages/getting-started/basics/models/models-patterns.md create mode 100644 client-new/pages/getting-started/basics/store.md create mode 100644 client-new/pages/getting-started/basics/systems.md create mode 100644 client-new/pages/getting-started/basics/testing/integration.md create mode 100644 client-new/pages/getting-started/basics/testing/unit.md create mode 100644 client-new/pages/getting-started/basics/world.md create mode 100644 client-new/pages/getting-started/env_setup.md create mode 100644 client-new/pages/guides/ai/daydreams.md create mode 100644 client-new/pages/guides/ai/eliza.md create mode 100644 client-new/pages/guides/react/bindings/contracts-bindings.md create mode 100644 client-new/pages/guides/react/bindings/models-bindings.md create mode 100644 client-new/pages/guides/react/controller-connector.md create mode 100644 client-new/pages/guides/react/dojo-config.md create mode 100644 client-new/pages/guides/react/main.md create mode 100644 client-new/pages/guides/react/manifest.md create mode 100644 client-new/pages/guides/react/overview.md create mode 100644 client-new/pages/guides/react/starknet-provider.md create mode 100644 client-new/pages/guides/unity.mdx create mode 100644 client-new/pages/reference/api.mdx create mode 100644 client-new/pages/reference/cli.mdx create mode 100644 client-new/pages/reference/config.mdx create mode 100644 client-new/pages/reference/troubleshooting.mdx diff --git a/client-new/pages/advanced/contracts-comparison.md b/client-new/pages/advanced/contracts-comparison.md new file mode 100644 index 0000000..9b26376 --- /dev/null +++ b/client-new/pages/advanced/contracts-comparison.md @@ -0,0 +1,3 @@ +# Traditional Smart Contracts vs Dojo Contracts + +Under development... diff --git a/client-new/pages/advanced/gas-optimization.md b/client-new/pages/advanced/gas-optimization.md new file mode 100644 index 0000000..9b0d8a7 --- /dev/null +++ b/client-new/pages/advanced/gas-optimization.md @@ -0,0 +1,3 @@ +# Gas fee Optimization + +Under development... diff --git a/client-new/pages/deployment/local.md b/client-new/pages/deployment/local.md new file mode 100644 index 0000000..6783340 --- /dev/null +++ b/client-new/pages/deployment/local.md @@ -0,0 +1,3 @@ +# Katana Deployment + +Under development... diff --git a/client-new/pages/deployment/mainnet.md b/client-new/pages/deployment/mainnet.md new file mode 100644 index 0000000..b65a11f --- /dev/null +++ b/client-new/pages/deployment/mainnet.md @@ -0,0 +1,3 @@ +# Mainnet Deployment + +Under development... diff --git a/client-new/pages/deployment/sepolia.md b/client-new/pages/deployment/sepolia.md new file mode 100644 index 0000000..29ab0c3 --- /dev/null +++ b/client-new/pages/deployment/sepolia.md @@ -0,0 +1,3 @@ +# Sepoli Deployment + +Under development... diff --git a/client-new/pages/deployment/slot.md b/client-new/pages/deployment/slot.md new file mode 100644 index 0000000..973da09 --- /dev/null +++ b/client-new/pages/deployment/slot.md @@ -0,0 +1,3 @@ +# Slot Deployment + +Under development... diff --git a/client-new/pages/examples/games/advanced.mdx b/client-new/pages/examples/games/advanced.mdx new file mode 100644 index 0000000..7b6da02 --- /dev/null +++ b/client-new/pages/examples/games/advanced.mdx @@ -0,0 +1,373 @@ +# Advanced Strategy Game + +A complex strategy game showcasing advanced Dojo patterns. + +## Overview + +This example demonstrates: +- Complex entity relationships +- Multiple interacting systems +- Resource management +- Advanced state management +- Event-driven architecture + +## Game Mechanics + +- Players build and manage cities +- Resource collection and trade +- Unit production and combat +- Territory control +- Technology research + +## Advanced Models + +### City Model + +```cairo +#[derive(Model, Copy, Drop, Serde)] +struct City { + #[key] + id: u32, + #[key] + owner: ContractAddress, + position: Position, + population: u32, + resources: Resources, + buildings: Array, + units: Array, +} +``` + +### Resources Model + +```cairo +#[derive(Copy, Drop, Serde)] +struct Resources { + food: u32, + wood: u32, + stone: u32, + gold: u32, +} +``` + +### Technology Model + +```cairo +#[derive(Model, Copy, Drop, Serde)] +struct Technology { + #[key] + player: ContractAddress, + #[key] + tech_type: TechType, + research_progress: u32, + is_completed: bool, +} +``` + +## Complex Systems + +### Production System + +```cairo +#[system] +impl ProductionImpl of ProductionTrait { + fn execute(world: IWorldDispatcher, city_id: u32) { + let mut city = get!(world, (city_id, get_caller_address()), City); + + // Calculate production based on buildings + let mut production = Resources { food: 0, wood: 0, stone: 0, gold: 0 }; + + let mut i = 0; + loop { + if i >= city.buildings.len() { + break; + } + + match city.buildings.at(i) { + BuildingType::Farm => production.food += 10, + BuildingType::Mine => production.gold += 5, + BuildingType::Quarry => production.stone += 8, + BuildingType::Sawmill => production.wood += 6, + }; + + i += 1; + }; + + // Apply population bonus + production.food += city.population / 10; + + // Update city resources + city.resources.food += production.food; + city.resources.wood += production.wood; + city.resources.stone += production.stone; + city.resources.gold += production.gold; + + set!(world, city); + + emit!(world, ProductionEvent { + city_id, + owner: get_caller_address(), + production, + }); + } +} +``` + +### Combat System + +```cairo +#[system] +impl CombatImpl of CombatTrait { + fn execute( + world: IWorldDispatcher, + attacker_city: u32, + defender_city: u32, + units: Array + ) { + let attacker = get_caller_address(); + let mut attacker_city_data = get!(world, (attacker_city, attacker), City); + let mut defender_city_data = get!(world, defender_city, City); + + // Validate attack + assert(attacker != defender_city_data.owner, 'Cannot attack own city'); + assert(calculate_distance(attacker_city_data.position, defender_city_data.position) <= MAX_ATTACK_RANGE, 'City too far'); + + // Calculate battle outcome + let attacker_strength = calculate_army_strength(units); + let defender_strength = calculate_army_strength(defender_city_data.units); + + let (winner, casualties) = resolve_battle(attacker_strength, defender_strength); + + // Apply casualties + apply_casualties(world, attacker_city, defender_city, casualties); + + // Handle victory + if winner == BattleOutcome::Attacker { + // Transfer city ownership + defender_city_data.owner = attacker; + // Take resources + let loot = calculate_loot(defender_city_data.resources); + attacker_city_data.resources = add_resources(attacker_city_data.resources, loot); + } + + set!(world, (attacker_city_data, defender_city_data)); + + emit!(world, BattleEvent { + attacker_city, + defender_city, + winner, + casualties, + }); + } +} +``` + +### Trade System + +```cairo +#[system] +impl TradeImpl of TradeTrait { + fn execute( + world: IWorldDispatcher, + offer: TradeOffer, + target_player: ContractAddress + ) { + let trader = get_caller_address(); + + // Validate trade offer + validate_trade_offer(world, trader, offer); + + // Create trade proposal + let trade_id = world.uuid(); + set!(world, Trade { + id: trade_id, + proposer: trader, + target: target_player, + offer, + status: TradeStatus::Pending, + expires_at: get_block_timestamp() + TRADE_EXPIRY_TIME, + }); + + emit!(world, TradeProposedEvent { + trade_id, + proposer: trader, + target: target_player, + offer, + }); + } +} +``` + +## Advanced Patterns + +### Event Aggregation + +```cairo +#[derive(Copy, Drop, Serde)] +struct GameTurnEvent { + turn_number: u32, + active_players: u32, + total_cities: u32, + major_events: Array, +} +``` + +### Resource Management + +```cairo +fn calculate_upkeep(world: IWorldDispatcher, player: ContractAddress) -> Resources { + let cities = query_player_cities(world, player); + let mut total_upkeep = Resources::default(); + + let mut i = 0; + loop { + if i >= cities.len() { + break; + } + + let city = cities.at(i); + total_upkeep = add_resources(total_upkeep, calculate_city_upkeep(city)); + i += 1; + }; + + total_upkeep +} +``` + +### State Validation + +```cairo +fn validate_game_state(world: IWorldDispatcher) -> bool { + // Validate all player resources are non-negative + // Validate all units are in valid positions + // Validate no resource duplication + // etc. + true +} +``` + +## Frontend Architecture + +### State Management + +```typescript +interface GameState { + players: Map; + cities: Map; + trades: Map; + technologies: Map; + currentTurn: number; + gamePhase: GamePhase; +} + +export function useGameState(): GameState { + const players = useEntityQuery([Has(Player)]); + const cities = useEntityQuery([Has(City)]); + // ... other queries + + return useMemo(() => ({ + players: new Map(players.map(p => [p.id, p])), + cities: new Map(cities.map(c => [c.id, c])), + // ... other state + }), [players, cities]); +} +``` + +### Complex UI Components + +```typescript +function CityManagement({ cityId }: { cityId: string }) { + const city = useComponentValue(City, cityId); + const { execute: produceUnit } = useDojoCall("produce_unit"); + const { execute: constructBuilding } = useDojoCall("construct_building"); + + return ( +
+ + + + + +
+ ); +} +``` + +## Performance Optimizations + +### Batch Operations + +```cairo +#[system] +impl BatchUpdateImpl of BatchUpdateTrait { + fn execute(world: IWorldDispatcher, updates: Array) { + let mut i = 0; + loop { + if i >= updates.len() { + break; + } + + let update = updates.at(i); + apply_city_update(world, update); + i += 1; + }; + + emit!(world, BatchUpdateEvent { count: updates.len() }); + } +} +``` + +### Efficient Queries + +```typescript +// Use specific queries instead of fetching all entities +const playerCities = useEntityQuery([ + Has(City), + HasValue(City, { owner: playerAddress }) +]); + +// Cache expensive calculations +const cityStats = useMemo(() => + calculateCityStats(cities), [cities] +); +``` + +## Running the Example + +1. **Setup:** + ```bash + git clone https://github.com/dojoengine/advanced-strategy + cd advanced-strategy + ``` + +2. **Deploy:** + ```bash + dojo build + dojo migrate + ``` + +3. **Start the game:** + ```bash + cd client + npm run dev + ``` + +## Key Learnings + +- **Complex State:** Managing interconnected game entities +- **System Design:** Breaking complex logic into manageable systems +- **Performance:** Optimizing for gas and query efficiency +- **Events:** Using events for real-time updates +- **Testing:** Comprehensive testing of game mechanics + +## Next Steps + +- [Production Deployment](/deployment/mainnet) +- [Gas Optimization](/advanced/gas-optimization) +- [Testing Strategies](/getting-started/basics/testing/integration) \ No newline at end of file diff --git a/client-new/pages/examples/games/simple.mdx b/client-new/pages/examples/games/simple.mdx new file mode 100644 index 0000000..bd745c4 --- /dev/null +++ b/client-new/pages/examples/games/simple.mdx @@ -0,0 +1,191 @@ +# Simple Battle Game + +A turn-based battle game to learn Dojo fundamentals. + +## Overview + +This example demonstrates: +- Basic model definitions +- Simple game logic in systems +- Player interactions +- Turn-based mechanics + +## Game Mechanics + +- Players create characters with health and attack power +- Players can attack other players +- Last player standing wins +- Simple turn-based combat + +## Models + +### Player Model + +```cairo +#[derive(Model, Copy, Drop, Serde)] +struct Player { + #[key] + id: ContractAddress, + name: felt252, + health: u32, + attack: u32, + is_alive: bool, +} +``` + +### Game Model + +```cairo +#[derive(Model, Copy, Drop, Serde)] +struct Game { + #[key] + id: u32, + players: Array, + current_turn: ContractAddress, + winner: Option, + is_active: bool, +} +``` + +## Systems + +### Spawn System + +```cairo +#[system] +impl SpawnImpl of SpawnTrait { + fn execute(world: IWorldDispatcher, name: felt252) { + let player = get_caller_address(); + + set!( + world, + Player { + id: player, + name, + health: 100, + attack: 20, + is_alive: true, + } + ); + } +} +``` + +### Attack System + +```cairo +#[system] +impl AttackImpl of AttackTrait { + fn execute(world: IWorldDispatcher, target: ContractAddress) { + let attacker = get_caller_address(); + + let mut attacker_data = get!(world, attacker, Player); + let mut target_data = get!(world, target, Player); + + assert(attacker_data.is_alive, 'Attacker is dead'); + assert(target_data.is_alive, 'Target is dead'); + + // Apply damage + if target_data.health <= attacker_data.attack { + target_data.health = 0; + target_data.is_alive = false; + } else { + target_data.health -= attacker_data.attack; + } + + set!(world, target_data); + + // Emit attack event + emit!(world, AttackEvent { + attacker, + target, + damage: attacker_data.attack, + }); + } +} +``` + +## Events + +```cairo +#[derive(Copy, Drop, Serde)] +struct AttackEvent { + attacker: ContractAddress, + target: ContractAddress, + damage: u32, +} +``` + +## Frontend Integration + +### React Component + +```typescript +import { useComponentValue } from "@dojoengine/react"; + +function PlayerStatus({ playerId }: { playerId: string }) { + const player = useComponentValue(Player, playerId); + + if (!player) return
Player not found
; + + return ( +
+

{player.name}

+
Health: {player.health}
+
Attack: {player.attack}
+
Status: {player.is_alive ? "Alive" : "Dead"}
+
+ ); +} +``` + +### Attack Action + +```typescript +import { useDojoCall } from "@dojoengine/react"; + +function AttackButton({ targetId }: { targetId: string }) { + const { execute } = useDojoCall({ + contract: "attack", + entrypoint: "execute", + }); + + const handleAttack = () => { + execute([targetId]); + }; + + return ( + + ); +} +``` + +## Running the Example + +1. **Clone the repository:** + ```bash + git clone https://github.com/dojoengine/dojo-examples + cd simple-battle + ``` + +2. **Build and deploy:** + ```bash + dojo build + katana --dev + dojo migrate + ``` + +3. **Run the frontend:** + ```bash + cd client + npm install + npm run dev + ``` + +## Next Steps + +- [Advanced Game Example](/examples/games/advanced) +- [React Integration Guide](/guides/react/overview) +- [Testing Your Game](/getting-started/basics/testing/unit) \ No newline at end of file diff --git a/client-new/pages/examples/starters/bevy.md b/client-new/pages/examples/starters/bevy.md new file mode 100644 index 0000000..1c7c14b --- /dev/null +++ b/client-new/pages/examples/starters/bevy.md @@ -0,0 +1,100 @@ +# Bevy Dojo Starter Template + +[bevy_dojo_starter](https://github.com/okhaimie-dev/bevy_dojo_starter.git) provides a comprehensive template for building 2D onchain games using Bevy game engine integrated with Dojo framework on Starknet. The template showcases a fully functional 2D game that leverages blockchain state management while maintaining smooth gameplay through Bevy's ECS architecture. + +## What's Included +### Core Components + +- [dojo.bevy](https://github.com/dojoengine/dojo.bevy) Plugin Integration: Pre-configured plugin by the Cartridge.gg team +- Automatic Indexer Connection: Direct integration with [Torii](https://github.com/dojoengine/torii) indexer for real-time blockchain state +- Katana Testnet Integration: Ready-to-use connection to [Katana](https://github.com/dojoengine/katana) sequencer for testing +- 2D Game Example: Complete working game demonstrating onchain mechanics + +### Features Demonstrated + +- Blockchain state synchronization with game state +- Real-time updates from the Torii indexer +- Transaction handling within game loops +- Seamless onchain/offchain game logic separation + +``` +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ Bevy Engine │◄──►│ dojo.bevy Plugin │◄──►│ Starknet │ +└─────────────────┘ └──────────────────┘ └─────────────────┘ + │ │ │ + ▼ ▼ ▼ +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ +│ Game Systems │ │ State Sync │ │ Torii Indexer │ +│ & Components │ │ & Game Systems │ │ Katana Sequencer│ +└─────────────────┘ └──────────────────┘ └─────────────────┘ +``` + +## Getting Started +### Prerequisites + +- Rust ([latest stable version](https://rustup.rs/)) +- Dojo development environment +- Basic understanding of Bevy ECS patterns +- Familiarity with Cairo smart contracts + +### Installation + +- Clone the starter kit repository +- Install dependencies +- Configure your Dojo environment +- Run the example game + +1. Clone the starter kit repository +``` +git clone https://github.com/okhaimie-dev/bevy_dojo_starter.git +``` +2. Install dependencies +``` +cd bevy_dojo_starter +cargo build +``` +3. Configure your Dojo environment +``` +cd contracts +``` +``` +katana --config ./katana.toml +``` +``` +torii --config ./torii_dev.toml +``` +``` +sozo build +``` +``` +sozo migrate +``` +``` +sozo inspect +``` +``` +cd .. +``` + +Open the `src/constants/dojo.rs` file. +And modify the `WORLD_ADDRESS` and `ACTION_ADDRESS` constants. To the value you get for this respective constants from the `sozo inspect` command. + +4. Run the example game +``` +cargo run +``` + +## Next Steps + +- Explore the example game code +- Modify game mechanics to suit your needs +- Deploy to testnet for testing +- Scale to mainnet for production + +## Resources + +[Bevy Documentation](https://bevy.org/learn/quick-start/introduction/) +[Dojoengine Documentation](https://dojoengine.org/overview) + +## Contributing +Contributions are welcome! Please see our contributing guidelines for more diff --git a/client-new/pages/examples/starters/react.md b/client-new/pages/examples/starters/react.md new file mode 100644 index 0000000..b0a04a4 --- /dev/null +++ b/client-new/pages/examples/starters/react.md @@ -0,0 +1,62 @@ +# Dojo Game Starter Template 🚀 + +Building onchain games requires integrating many complex pieces: Cairo contracts, React frontends, wallet connections, state management, and deployment pipelines. Instead of spending weeks setting this up from scratch, you can start with a production-ready foundation. + +## What is Dojo Game Starter? 🎮 + +**Dojo Game Starter** is a complete template that provides everything you need to build onchain games on Starknet. It's the same foundation used by successful hackathon teams and game studios to ship games quickly. + +**In the box:** +- ✅ Complete React + Dojo integration with TypeScript +- ✅ Cartridge Controller wallet integration +- ✅ Cairo contracts with player progression system +- ✅ Achievement system implementation +- ✅ Production deployment configurations +- ✅ Comprehensive documentation for extending the game + +## Why Use a Template? 🤔 + +**Time to first playable game:** +- From scratch: 2-4 weeks of setup +- With template: 5 minutes to running game + +**What you avoid building:** +- Frontend-blockchain integration patterns +- Wallet connection and session management +- State management for onchain operations +- Achievement and progression systems +- Deployment pipeline configurations + +## Sample Game Mechanics 🎯 + +The template includes a simple RPG system to demonstrate core patterns: + +- **🏋️ Train:** Gain experience (pure advancement) +- **⛏️ Mine:** Earn coins, lose health (risk/reward) +- **💤 Rest:** Restore health (resource management) + +These mechanics teach you how to build any onchain game system. + +## Perfect For 🎪 + +- **Hackathon teams** who need to ship in 48 hours +- **Developers** learning Dojo through hands-on practice +- **Studios** prototyping new game concepts quickly +- **Anyone** who wants to focus on game design, not infrastructure + +## Get Started 🚀 + +```bash +git clone https://github.com/AkatsukiLabs/Dojo-Game-Starter.git +cd dojo-game-starter +``` + +**Next steps:** +1. Follow the [Frontend Guide](https://github.com/AkatsukiLabs/Dojo-Game-Starter/tree/main/client) for React development +2. Check the [Backend Guide](https://github.com/AkatsukiLabs/Dojo-Game-Starter/tree/main/contract) for Cairo contracts + +--- + +**🔗 [Get the Template](https://github.com/AkatsukiLabs/Dojo-Game-Starter)** | **🎮 [Live Demo](https://dojo-game-starter.vercel.app/)** + +Ready to build your onchain game? Start with a solid foundation and focus on what makes your game unique! 🎮 \ No newline at end of file diff --git a/client-new/pages/getting-started/basics/constants.md b/client-new/pages/getting-started/basics/constants.md new file mode 100644 index 0000000..ebbde11 --- /dev/null +++ b/client-new/pages/getting-started/basics/constants.md @@ -0,0 +1,192 @@ +# Constants Usage in Dojo Engine 🎮 + +Constants are like the **configuration file** of your game - they define the fixed values that control how your game behaves. Think of them as the "rules" that determine damage amounts, health points, cooldown times, and other gameplay mechanics in your Dojo game. + +## Why Constants Matter in Game Development 🤔 + +Imagine you're balancing a fighting game. Without constants, you'd have random numbers scattered throughout your code like: + +```cairo +// ❌ Bad: Magic numbers everywhere +let damage = attack_power * 150; // What does 150 mean? +let health = base_health + level * 20; // Why 20? +``` + +With constants, your code becomes self-documenting and easier to balance: + +```cairo +// ✅ Good: Clear, meaningful constants +let damage = attack_power * SUPER_EFFECTIVE; +let health = base_health + level * HEALTH_BONUS_PER_LEVEL; +``` + +**Key Benefits:** +- **Easy Game Balancing**: Change one number to affect the entire game +- **Clear Code**: Anyone can understand what `MAX_ENERGY` means +- **Consistent Values**: No more accidentally using 100 in one place and 99 in another +- **Team Collaboration**: Designers can suggest balance changes without touching code logic + +## Real-World Example: Building a Combat System 💻 + +Here's how you might structure constants for a turn-based RPG in Dojo: + +```cairo +// constants.cairo +// Combat Balance - The heart of your game's feel + +// Type Effectiveness System (Rock-Paper-Scissors mechanics) +pub const SUPER_EFFECTIVE: u8 = 150; // 1.5x damage - strong advantage +pub const NORMAL_EFFECTIVENESS: u8 = 100; // 1.0x damage - neutral matchup +pub const NOT_VERY_EFFECTIVE: u8 = 50; // 0.5x damage - poor matchup + +// Character Progression +pub const BASE_LEVEL_BONUS: u8 = 10; // Stats gained per level +pub const MAX_HEALTH_BONUS_PER_LEVEL: u8 = 20; // HP increase per level + +// Energy Management (Prevents spam, adds strategy) +pub const MAX_ENERGY: u8 = 100; // Energy cap +pub const ENERGY_REGEN_RATE: u8 = 5; // Energy gained per turn +pub const ENERGY_COST_PER_ACTION: u8 = 10; // Energy spent per basic attack + +// Time-Based Mechanics +pub const SECONDS_PER_DAY: u64 = 86400; // For daily rewards/events +pub const GAME_TICK_RATE: u64 = 60; // How often game updates + +// Special Attack Modifiers +pub const FAVORED_ATTACK_MULTIPLIER: u8 = 120; // 1.2x for specialized attacks +pub const NORMAL_ATTACK_MULTIPLIER: u8 = 100; // 1.0x for basic attacks + +// Utility Constants +pub fn ZERO_ADDRESS() -> ContractAddress { + contract_address_const::<0x0>() // Null address for empty/invalid states +} +``` + +## How to Organize Your Constants 📊 + +**Group by Game System:** +```cairo +// ⚡ Energy System +pub const MAX_ENERGY: u8 = 100; +pub const ENERGY_REGEN_RATE: u8 = 5; + +// ❤️ Health System +pub const BASE_HEALTH: u8 = 100; +pub const HEALTH_REGEN_RATE: u8 = 2; + +// ⚔️ Combat System +pub const SUPER_EFFECTIVE: u8 = 150; +pub const NORMAL_EFFECTIVENESS: u8 = 100; +``` + +**Naming Convention:** Use `SCREAMING_SNAKE_CASE` for constants - it's the Cairo standard and makes them easy to spot in your code. + +## Putting Constants to Work 👨‍💻 + +Once you've defined your constants, here's how to use them effectively in your game logic: + +### Import Your Constants +```cairo +// At the top of your Cairo files +use dojo_examples::constants::*; +``` + +### Example 1: Combat Effectiveness Calculator +```cairo +// Calculate how effective an attack is based on elemental types +fn calculate_damage_multiplier(attacker_type: ElementType, defender_type: ElementType) -> u8 { + match (attacker_type, defender_type) { + // Fire beats Ice, Water beats Fire, Ice beats Water + (ElementType::Fire, ElementType::Ice) | + (ElementType::Water, ElementType::Fire) | + (ElementType::Ice, ElementType::Water) => SUPER_EFFECTIVE, + + // Reverse matchups are weak + (ElementType::Ice, ElementType::Fire) | + (ElementType::Fire, ElementType::Water) | + (ElementType::Water, ElementType::Ice) => NOT_VERY_EFFECTIVE, + + // Same types are neutral + _ => NORMAL_EFFECTIVENESS, + } +} +``` + +### Example 2: Level-Up Rewards +```cairo +// Calculate how much health a player gains when leveling up +fn calculate_level_up_bonus(current_level: u8) -> u8 { + current_level * BASE_LEVEL_BONUS + MAX_HEALTH_BONUS_PER_LEVEL +} +``` + +### Example 3: Energy Management +```cairo +// Check if player has enough energy for an action +fn can_perform_action(current_energy: u8, action_cost: u8) -> bool { + current_energy >= action_cost +} + +// Regenerate energy each turn (with cap) +fn regenerate_energy(current_energy: u8) -> u8 { + let new_energy = current_energy + ENERGY_REGEN_RATE; + if new_energy > MAX_ENERGY { + MAX_ENERGY + } else { + new_energy + } +} +``` + +## Game Designer's Perspective 🎯 + +Constants make your game **designer-friendly**. Want to make combat faster? Increase `ENERGY_REGEN_RATE`. Want to reduce grinding? Boost `BASE_LEVEL_BONUS`. + +**Before Constants:** +"The game feels too slow, but I'd need to find every energy-related calculation in the code..." + +**With Constants:** +"Change `ENERGY_REGEN_RATE` from 5 to 8 and test it!" + +## Best Practices for Dojo Games ⭐ + +1. **Document Your Intent**: Add comments explaining why you chose specific values +2. **Group Related Constants**: Keep all combat constants together, all time constants together +3. **Use Meaningful Names**: `CRITICAL_HIT_CHANCE` is better than `CRIT_CHANCE` +4. **Start Conservative**: It's easier to buff than nerf in live games +5. **Version Your Balance**: Keep track of constant changes for rollback purposes + +## Testing Your Constants 🧪 + +```cairo +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_type_effectiveness() { + // Fire should be super effective against Ice + let multiplier = calculate_damage_multiplier(ElementType::Fire, ElementType::Ice); + assert(multiplier == SUPER_EFFECTIVE, 'Fire should beat Ice'); + } + + #[test] + fn test_energy_cap() { + // Energy should never exceed maximum + let capped_energy = regenerate_energy(MAX_ENERGY); + assert(capped_energy == MAX_ENERGY, 'Energy should be capped'); + } +} +``` + +## Summary 📚 + +Constants are the foundation of maintainable game development in Dojo. They transform scattered magic numbers into a centralized, editable configuration system that makes balancing your game a breeze. + +**Remember:** +- Constants = Game Balance Control Center +- Good naming = Self-documenting code +- Organized constants = Happy team +- Testable constants = Reliable game mechanics + +Start simple, stay organized, and let constants handle the heavy lifting of game balance while you focus on creating amazing gameplay experiences! 🚀 \ No newline at end of file diff --git a/client-new/pages/getting-started/basics/enums.md b/client-new/pages/getting-started/basics/enums.md new file mode 100644 index 0000000..0679e3a --- /dev/null +++ b/client-new/pages/getting-started/basics/enums.md @@ -0,0 +1,460 @@ +# Enums in Dojo Engine + +## Introduction to Enums + +Enums (enumerations) are custom data types consisting of a fixed set of named values, called variants. They are fundamental in on-chain game development with Dojo, allowing developers to elegantly represent: + +- Game states (waiting, active, finished) +- Entity types (fire, water, earth) +- Player actions (attack, defend, move) +- Skills or characteristics (slash, freeze, burn) + +## What is an Enum? + +An enum in Cairo is a way to define a type that can have one of several distinct values. Each possible value is called a "variant." Unlike integers or flags, enums are explicit and named, which improves code readability and safety. + +Let's look at a basic example: + +```cairo +#[derive(Copy, Drop, Serde, Introspect, Debug, PartialEq)] +enum PlayerCharacter { + Godzilla, + Dragon, + Fox, + Rhyno +} +``` + +This `PlayerCharacter` enum has four possible variants. Each instance of this type will contain exactly one of these variants. + +## Enums in the Dojo Ecosystem + +In Dojo, enums are extremely useful for modeling game state and entity types. They are an integral part of the Entity Component System (ECS) pattern used by Dojo. + +### Basic Structure of a Dojo Enum + +A typical enum in Dojo has this structure: + +```cairo +#[derive(Copy, Drop, Serde, Introspect, Debug, PartialEq)] +pub enum EnumName { + Variant1, + Variant2, + // More variants... +} +``` + +The most common `derive` attributes for enums are: +- `Copy`: Allows the enum to be copied rather than moved +- `Drop`: Allows the enum to be discarded when no longer needed +- `Serde`: Enables serialization/deserialization +- `Introspect`: Allows Dojo to "introspect" the type (important for models) +- `Debug`: Facilitates debugging with text representations +- `PartialEq`: Allows comparing enums with the `==` operator + +## Practical Examples of Enums + +### 1. Battle States + +Let's look at a real example of an enum representing possible battle states: + +```cairo +#[derive(Copy, Drop, Serde, Debug, PartialEq)] +pub enum BattleStatus { + Waiting, + Active, + Finished, + None, +} +``` + +This enum allows tracking which phase a battle is in, facilitating the logic for transitioning between states. + +### 2. Creature Types + +Another common example is representing different types of creatures in a game: + +```cairo +#[derive(Copy, Drop, Serde, Debug, PartialEq)] +pub enum BeastType { + Fire, + Water, + Earth, + Electric, + Dragon, + Ice, + Magic, + Rock, + Undefined, +} +``` + +### 3. Skill Types + +Enums are also useful for categorizing skills or actions: + +```cairo +#[derive(Copy, Drop, Serde, Introspect, Debug, PartialEq)] +pub enum SkillType { + Slash, + Beam, + Wave, + Punch, + Kick, + Blast, + Crush, + Pierce, + Smash, + Burn, + Freeze, + Shock, + Default, +} +``` + +## Implementing Traits for Enums + +One of the most powerful features of enums in Cairo is the ability to implement traits for them, which allows adding specific functionality. + +### Display Trait for Text Representation + +The `Display` trait allows converting an enum to a textual representation: + +```cairo +pub impl SkillTypeDisplay of core::fmt::Display { + fn fmt(self: @SkillType, ref f: core::fmt::Formatter) -> Result<(), core::fmt::Error> { + let s = match self { + SkillType::Beam => "Beam", + SkillType::Slash => "Slash", + SkillType::Wave => "Wave", + SkillType::Punch => "Punch", + // Other variants... + }; + f.buffer.append(@s); + Result::Ok(()) + } +} +``` + +This pattern is very useful for debugging and UI representation. + +### Into Trait for Type Conversion + +The `Into` traits allow converting enums to other types, such as `felt252` or `u8`: + +```cairo +pub impl IntoBattleStatusFelt252 of Into { + #[inline(always)] + fn into(self: BattleStatus) -> felt252 { + match self { + BattleStatus::Waiting => 0, + BattleStatus::Active => 1, + BattleStatus::Finished => 2, + BattleStatus::None => 3, + } + } +} + +pub impl IntoBattleStatusU8 of Into { + #[inline(always)] + fn into(self: BattleStatus) -> u8 { + match self { + BattleStatus::Waiting => 0, + BattleStatus::Active => 1, + BattleStatus::Finished => 2, + BattleStatus::None => 3, + } + } +} +``` + +The reverse conversion can also be implemented: + +```cairo +pub impl Intou8BattleStatus of Into { + #[inline(always)] + fn into(self: u8) -> BattleStatus { + let battle_type: u8 = self.into(); + match battle_type { + 0 => BattleStatus::Waiting, + 1 => BattleStatus::Active, + 2 => BattleStatus::Finished, + 3 => BattleStatus::None, + _ => BattleStatus::None, // Default value for unhandled cases + } + } +} +``` + +## Pattern Matching with Enums + +Pattern matching is one of the most powerful features when using enums: + +```cairo +fn handle_battle_status(status: BattleStatus) { + match status { + BattleStatus::Waiting => { + // Logic for waiting state + }, + BattleStatus::Active => { + // Logic for active state + }, + BattleStatus::Finished => { + // Logic for finished battle + }, + BattleStatus::None => { + // Default case handling + }, + } +} +``` + +The Cairo compiler will verify that all possible cases are handled, which helps prevent errors. + +## Enums with Associated Data + +Enums can contain additional data in each variant: + +```cairo +#[derive(Serde, Drop, Introspect)] +enum PlayerCharacter { + Godzilla: u128, // Godzilla creature ID + Dragon: u32, // Dragon level + Fox: (u8, u8), // Fox coordinates (x,y) + Rhyno: ByteArray // Custom rhino name +} +``` + +This allows creating more complex and expressive data structures. + +## Using Enums in Dojo Models + +Enums integrate perfectly with Dojo models: + +```cairo +#[derive(Drop, Serde)] +#[dojo::model] +struct Battle { + #[key] + id: u64, + status: BattleStatus, + battle_type: BeastType, + winning_skill: SkillType, +} +``` + +When using enums in models, it's important to ensure the enum has implemented the `Introspect` or `IntrospectPacked` trait. + +## Integration with Game Logic + +Enums allow implementing complex game rules clearly: + +```cairo +fn calculate_effectiveness(attacker_type: BeastType, defender_type: BeastType) -> u8 { + match (attacker_type, defender_type) { + (BeastType::Light, BeastType::Shadow) | + (BeastType::Magic, BeastType::Light) | + (BeastType::Shadow, BeastType::Magic) => SUPER_EFFECTIVE, + + (BeastType::Light, BeastType::Magic) | + (BeastType::Magic, BeastType::Shadow) | + (BeastType::Shadow, BeastType::Light) => NOT_VERY_EFFECTIVE, + + _ => NORMAL_EFFECTIVENESS, + } +} +``` + +This pattern allows modeling type systems and advantages like in Pokémon-style games. + +## Testing Enums + +Testing enums is critical to ensure correct behavior: + +```cairo +#[test] +fn test_into_battle_status_waiting() { + let battle_status = BattleStatus::Waiting; + let battle_status_felt252: felt252 = battle_status.into(); + assert_eq!(battle_status_felt252, 0); +} + +#[test] +fn test_into_battle_status_from_u8_invalid() { + let battle_status_u8: u8 = 4; + let battle_status: BattleStatus = battle_status_u8.into(); + assert_eq!(battle_status, BattleStatus::None); +} +``` + +Tests for enums should cover: +- Conversions between types +- Behavior with invalid values +- Edge cases +- Integration with other system components + +## Best Practices for Enums in Dojo + +### 1. Always Include a Default Value + +```cairo +pub enum BeastType { + // Common variants... + Undefined, // ← Default value +} +``` + +Having a default value makes error handling and unexpected cases easier to manage. + +### 2. Implement Conversion Traits + +Implementing `Into` and `Into` facilitates serialization and storage. + +### 3. Document the Purpose of Each Variant + +A good comment explains the purpose and context of use: + +```cairo +pub enum BattleStatus { + Waiting, // Players joining the battle, but it hasn't started + Active, // Battle in progress, players can make moves + Finished, // Battle completed with a defined result + None, // Invalid or uninitialized state +} +``` + +### 4. Definition Location + +Define enums at the appropriate level of organization: +- If specific to a component, define the enum in the same file as the component +- If used across multiple components, place it in a shared module (e.g., `types/battle_status.cairo`) + +### 5. Prioritize Readability + +Use descriptive names for variants and organize them logically: + +```cairo +// Prefer this: +enum MatchResult { + Victory, + Defeat, + Draw, + Cancelled, +} + +// Instead of this: +enum MatchResult { + R1, // Victory + R2, // Defeat + R3, // Draw + R4, // Cancelled +} +``` + +## Comparison with Alternative Systems + +### Enums vs. Integers with Constants + +**Using constants:** +```cairo +const BATTLE_WAITING: u8 = 0; +const BATTLE_ACTIVE: u8 = 1; +const BATTLE_FINISHED: u8 = 2; +``` + +**Using enums:** +```cairo +enum BattleStatus { + Waiting, + Active, + Finished, +} +``` + +**Advantages of enums:** +- Compile-time checking +- Descriptive names in the code +- Exhaustive pattern matching +- Impossible to use invalid values + +## Enums in Dojo's ECS Pattern + +In Dojo's Entity-Component-System (ECS) pattern, enums play important roles: + +- As properties in components (models) +- For defining system event types +- For representing entity states +- For modeling types and categories + +## Advanced Examples + +### Example 1: Type-Advantage System + +This pattern implements a system where different types have advantages over others: + +```cairo +fn is_favored_attack(self: @Beast, skill_type: SkillType) -> bool { + match skill_type { + SkillType::Beam | SkillType::Slash | SkillType::Pierce | + SkillType::Wave => self.beast_type == @BeastType::Light, + + SkillType::Blast | SkillType::Freeze | SkillType::Burn | + SkillType::Punch => self.beast_type == @BeastType::Magic, + + SkillType::Smash | SkillType::Crush | SkillType::Shock | + SkillType::Kick => self.beast_type == @BeastType::Shadow, + + _ => false, + } +} +``` + +### Example 2: State Machine with Enums + +```cairo +fn transition_game_state(current: GameStatus, event: GameEvent) -> GameStatus { + match (current, event) { + (GameStatus::NotStarted, GameEvent::PlayerJoined) => GameStatus::Lobby, + (GameStatus::Lobby, GameEvent::GameStart) => GameStatus::InProgress, + (GameStatus::InProgress, GameEvent::GameEnd) => GameStatus::Finished, + // Invalid transitions maintain the current state + _ => current, + } +} +``` + +## Debugging Tips + +1. **Implement Display for your enums:** + ```cairo + impl BeastTypeDisplay of core::fmt::Display { + fn fmt(self: @BeastType, ref f: core::fmt::Formatter) -> Result<(), core::fmt::Error> { + let s = match self { + BeastType::Fire => "Fire", + // Other variants... + }; + f.buffer.append(@s); + Result::Ok(()) + } + } + ``` + +2. **Use the `Debug` derive to facilitate representation:** + ```cairo + #[derive(Debug)] + pub enum BattleStatus { + // Variants... + } + ``` + +## Conclusion + +Enums in Dojo are an indispensable tool for on-chain game development. They offer a perfect balance between expressiveness, type safety, and computational efficiency. As you build more complex games, you'll discover that enums make your code more robust, easier to understand, and more maintainable in the long run. + +Use the examples in this document as a starting point for integrating enums into your own Dojo development, and don't hesitate to expand these patterns to adapt them to the specific needs of your game. + +## Additional Resources + +- [Official Cairo Documentation on Enums](https://book.cairo-lang.org/ch06-00-enums-and-pattern-matching.html) +- [ECS Design Patterns in Dojo](https://docs.dojoengine.org/overview/ecs) +- [Introspect Trait Implementation](https://docs.dojoengine.org/cairo/models/introspect.html) diff --git a/client-new/pages/getting-started/basics/events.md b/client-new/pages/getting-started/basics/events.md new file mode 100644 index 0000000..aaf92c8 --- /dev/null +++ b/client-new/pages/getting-started/basics/events.md @@ -0,0 +1,3 @@ +# Events + +Under development... diff --git a/client-new/pages/getting-started/basics/helpers.md b/client-new/pages/getting-started/basics/helpers.md new file mode 100644 index 0000000..10157de --- /dev/null +++ b/client-new/pages/getting-started/basics/helpers.md @@ -0,0 +1,303 @@ +# Helper Functions in Dojo Engine 🎮 + +Helper functions are the **utility belt** of your game development toolkit. Think of them as specialized tools that solve common problems across your entire game - from generating random numbers to calculating complex formulas. Instead of writing the same logic over and over, you create one helper function and reuse it everywhere. + +## Why Helper Functions Are Game Changers 🛠️ + +Imagine you're building an RPG where you need random numbers for: +- Loot drops when defeating enemies +- Critical hit chances in combat +- Spawning random encounters +- Determining quest rewards + +**Without helpers:** +```cairo +// ❌ Repeated random logic everywhere +// In combat system +let crit_chance = hash_something_complex(player_id, block_data, salt1); + +// In loot system +let drop_chance = hash_something_else(monster_id, block_data, salt2); + +// In quest system +let reward_amount = another_random_function(quest_id, block_data, salt3); +``` + +**With a helper function:** +```cairo +// ✅ One reusable helper +use helpers::pseudo_random::generate_random_u8; + +// Clean, consistent usage everywhere +let crit_chance = generate_random_u8(player_id, salt, 1, 100); +let drop_chance = generate_random_u8(monster_id, salt, 1, 100); +let reward_amount = generate_random_u8(quest_id, salt, 10, 50); +``` + +**Key Benefits:** +- **DRY Principle**: Don't Repeat Yourself - write once, use everywhere +- **Consistency**: Same logic produces predictable results across your game +- **Maintainability**: Fix a bug once, it's fixed everywhere +- **Testability**: Test complex logic in isolation +- **Readability**: Your game code becomes self-documenting + +## Real-World Example: Pseudo-Random Number Generation 🎲 + +Let's break down a production-ready random number helper that you'll use constantly in game development: + +```cairo +// helpers/pseudo_random.cairo +use starknet::{get_block_timestamp, get_block_number}; +use hash::{HashStateTrait, HashStateExTrait}; +use pedersen::PedersenTrait; + +/// Generates a pseudo-random number between min and max (inclusive) +/// Perfect for game mechanics like damage rolls, loot chances, etc. +pub fn generate_random_u8( + unique_id: u16, // Makes each call unique (player_id, monster_id, etc.) + salt: u16, // Adds extra randomness variation + min: u8, // Minimum value (inclusive) + max: u8 // Maximum value (inclusive) +) -> u8 { + // Step 1: Gather on-chain entropy + let block_timestamp = get_block_timestamp(); + let block_number = get_block_number(); + + // Step 2: Create unique seed for this specific call + let seed = unique_id.into() + salt.into() + block_timestamp + block_number; + + // Step 3: Hash the seed for cryptographic randomness + let hash_state = PedersenTrait::new(0); + let hash_state = hash_state.update(seed); + let hash = hash_state.finalize(); + + // Step 4: Convert to our desired range + let range: u64 = (max - min + 1).into(); + let random_in_range = (hash % range.into()).try_into().unwrap(); + + min + random_in_range +} +``` + +### How Each Step Works 🔍 + +**🌍 Step 1: On-Chain Entropy** +```cairo +let block_timestamp = get_block_timestamp(); +let block_number = get_block_number(); +``` +Uses Starknet block data as a source of randomness. This is deterministic (same block = same values) but unpredictable when the transaction is created. + +**🎯 Step 2: Unique Seed Creation** +```cairo +let seed = unique_id.into() + salt.into() + block_timestamp + block_number; +``` +Combines your inputs with block data to ensure different results for different entities/actions, even in the same block. + +**🔒 Step 3: Cryptographic Hashing** +```cairo +let hash_state = PedersenTrait::new(0); +let hash = hash_state.finalize(); +``` +Pedersen hash transforms our seed into a uniformly distributed random value - this is where the "magic" happens. + +**📏 Step 4: Range Conversion** +```cairo +let range: u64 = (max - min + 1).into(); +let random_in_range = (hash % range.into()).try_into().unwrap(); +``` +Mathematically ensures our result falls exactly within [min, max] bounds. + +## Practical Usage Examples 🎯 + +### Combat System +```cairo +// Calculate if attack is a critical hit (5% chance) +let crit_roll = generate_random_u8(attacker_id, 1, 1, 100); +let is_critical = crit_roll <= 5; + +// Random damage variance (±10%) +let base_damage = 50; +let variance = generate_random_u8(attacker_id, 2, 90, 110); +let final_damage = (base_damage * variance) / 100; +``` + +### Loot System +```cairo +// Determine loot rarity (Common: 70%, Rare: 25%, Epic: 5%) +let loot_roll = generate_random_u8(monster_id, 3, 1, 100); +let rarity = if loot_roll <= 70 { + LootRarity::Common +} else if loot_roll <= 95 { + LootRarity::Rare +} else { + LootRarity::Epic +}; +``` + +### Procedural Generation +```cairo +// Generate random dungeon room size +let room_width = generate_random_u8(room_id, 4, 5, 15); +let room_height = generate_random_u8(room_id, 5, 5, 15); +``` + +## Testing Your Helpers 🧪 + +Helper functions are perfect for unit testing because they're isolated and predictable: + +```cairo +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_random_range_bounds() { + let min = 10; + let max = 20; + let result = generate_random_u8(12345, 6789, min, max); + + // Verify result is always in bounds + assert!(result >= min && result <= max, "Random value out of range"); + } + + #[test] + fn test_random_deterministic() { + // Same inputs should produce same output (deterministic) + let result1 = generate_random_u8(100, 200, 1, 10); + let result2 = generate_random_u8(100, 200, 1, 10); + + assert_eq!(result1, result2, "Random function should be deterministic"); + } + + #[test] + fn test_random_distribution() { + // Test that different inputs produce different outputs + let result1 = generate_random_u8(1, 1, 1, 100); + let result2 = generate_random_u8(2, 1, 1, 100); + + // Very likely to be different (not guaranteed, but statistically sound) + assert_ne!(result1, result2, "Different inputs should likely produce different outputs"); + } +} +``` + +## Types of Helpers You'll Need 🗂️ + +### **🎲 Randomness Helpers** +```cairo +// pseudo_random.cairo +generate_random_u8() +generate_random_bool() +roll_dice(sides: u8) +``` + +### **🧮 Math Helpers** +```cairo +// math_utils.cairo +clamp_value(value: u32, min: u32, max: u32) +calculate_percentage(part: u32, total: u32) +distance_between_points(x1: u32, y1: u32, x2: u32, y2: u32) +``` + +### **⚔️ Combat Helpers** +```cairo +// combat_utils.cairo +calculate_damage(base: u32, multiplier: u8) +apply_elemental_weakness(damage: u32, attacker_type: Element, defender_type: Element) +calculate_experience_gain(base_exp: u32, level_difference: u8) +``` + +### **🎮 Game Logic Helpers** +```cairo +// game_utils.cairo +validate_move(from: Position, to: Position, movement_type: MovementType) +calculate_cooldown_remaining(last_action: u64, cooldown_duration: u64) +check_inventory_space(current_items: u8, max_capacity: u8) +``` + +## Best Practices for Dojo Helpers ⭐ + +### ✅ **Do's** +- **Keep them pure**: No side effects, only input → output transformations +- **Make them stateless**: Don't modify global game state +- **Use descriptive names**: `calculate_critical_hit_chance` not `calc_crit` +- **Add comprehensive tests**: Test edge cases and typical usage +- **Document parameters**: Explain what each input does and expects +- **Group by domain**: Separate files for different helper categories + +### ❌ **Don'ts** +- **Don't embed game logic**: Helpers support systems, they don't replace them +- **Don't access ECS directly**: Keep helpers independent of world state +- **Don't make them too complex**: One helper = one clear purpose +- **Don't hardcode values**: Accept parameters for flexibility + +## Advanced Helper Patterns 🚀 + +### **Chained Helpers** +```cairo +// Combine simple helpers for complex operations +let base_damage = calculate_base_damage(attacker_stats); +let elemental_damage = apply_elemental_modifier(base_damage, element_type); +let final_damage = apply_random_variance(elemental_damage, variance_percent); +``` + +### **Configuration Helpers** +```cairo +// Use constants with helpers for game balance +let crit_chance = calculate_crit_chance( + base_chance: WARRIOR_BASE_CRIT, + weapon_bonus: weapon.crit_modifier, + level_bonus: player.level * CRIT_PER_LEVEL +); +``` + +### **Validation Helpers** +```cairo +// Input validation helpers prevent runtime errors +fn validate_position(x: u32, y: u32, map_width: u32, map_height: u32) -> bool { + x < map_width && y < map_height +} +``` + +## Integration with Dojo ECS 🎪 + +Helper functions work perfectly with Dojo's ECS pattern: + +```cairo +// In your system +#[dojo::interface] +impl CombatActionsImpl { + fn attack(ref world: IWorldDispatcher, target_id: u32) { + // Get ECS data + let attacker = get!(world, (caller), (Player)); + let target = get!(world, (target_id), (Player)); + + // Use helpers for calculations + let hit_chance = calculate_hit_chance(attacker.accuracy, target.evasion); + let hit_roll = generate_random_u8(attacker.id, 1, 1, 100); + + if hit_roll <= hit_chance { + let damage = calculate_damage(attacker.attack, target.defense); + let new_health = target.health.saturating_sub(damage); + + // Update ECS state + set!(world, (Player { id: target_id, health: new_health, ..target })); + } + } +} +``` + +## Conclusion 🎯 + +Helper functions are the unsung heroes of clean, maintainable game code in Dojo Engine. They transform repetitive, error-prone calculations into reliable, reusable tools that make your systems easier to read, test, and debug. + +**Remember:** +- **Helpers = Reusable Logic Tools** +- **Pure Functions = Predictable Results** +- **Good Tests = Confident Code** +- **Clear Names = Self-Documenting Code** + +Start building your helper library early - your future self (and your teammates) will thank you when balancing, debugging, or extending your game becomes a breeze! 🚀 + +> Think of helpers as the silent workhorses behind your game's core systems — small, focused, and incredibly powerful. \ No newline at end of file diff --git a/client-new/pages/getting-started/basics/models.md b/client-new/pages/getting-started/basics/models.md new file mode 100644 index 0000000..4e8e377 --- /dev/null +++ b/client-new/pages/getting-started/basics/models.md @@ -0,0 +1,399 @@ +# Models in Dojo Engine + +Welcome to the **Models** guide for the Dojo By Example documentation! This page introduces models in the Dojo Engine, a powerful framework for building on-chain games using the **Entity Component System (ECS)** pattern on Starknet. Whether you're new to game development or Cairo programming, this guide will help you understand what models are, how they're structured, and how they integrate with Dojo's ECS architecture. + +## Introduction to Models in Dojo and ECS + +In the Dojo Engine, a **model** is a fundamental data structure that defines the schema for storing game state (state of entities within a game world) on-chain. Think of models as blueprints for the attributes of game objects, such as a character's health, a game's status, or an inventory's contents. Models are the "data layer" in Dojo's ECS pattern, enabling efficient storage, querying, and updating of game state in a decentralized environment. + +### Why Models Matter +- **Structured Data**: Models define the properties (fields) of game entities, like a character's strength or a game's turn count. +- **ECS Integration**: Models act as **components** in the ECS pattern, attaching data to **entities** and enabling **systems** (game logic) to manipulate them. +- **On-Chain Efficiency**: Built for Starknet, models are optimized for scalability and verifiability, storing state in the world contract. + +Models are written in **Cairo**, Starknet's native language, and use the `#[dojo::model]` attribute to integrate with Dojo's framework. By defining models, you create the foundation for your game's state, which systems can query and update via Dojo's introspection tools. + +### What is ECS? +**ECS (Entity Component System)** is a design pattern used in game development to organize and manage game state and logic. It consists of: +- **Entities**: Unique identifiers (e.g., a character or game instance) that serve as "containers" for data. In Dojo, entities are typically represented by their key values (ContractAddress, u32, etc.). +- **Components**: Data structures (in Dojo, **models**) that hold specific attributes of an entity, such as health or inventory. +- **Systems**: Logic modules (service layer) that process entities by querying and updating their components. Systems contain the game's rules, like combat or movement logic. + +ECS enables scalable, modular game development by separating data (models/components) from logic (systems), making it ideal for on-chain games. + +## Anatomy of a Model + +A model in Dojo is a Cairo struct with specific attributes and fields. Let's explore the key components using examples from real-world implementations. + +### Key Concepts and Examples + +1. **`#[dojo::model]` Attribute**: + - Marks a struct as a Dojo model, registering it in the world contract for ECS integration. + - **Example**: From `Player` model: + ```cairo + #[derive(Copy, Drop, Serde, Debug, PartialEq)] + #[dojo::model] + pub struct Player { + #[key] + pub address: ContractAddress, + pub current_beast_id: u16, + pub battles_won: u16, + pub battles_lost: u16, + pub last_active_day: u32, + pub creation_day: u32, + } + ``` + - **Commentary**: The `#[dojo::model]` attribute tells Dojo to treat `Player` as a model. This model stores a player's stats and activity metrics, with `address` as the unique identifier. + +2. **`#[key]` Attribute**: + - Specifies which fields are used to index the model. You can have multiple keys to create a composite key. + - **Example**: From the `Beast` model: + ```cairo + #[derive(Copy, Drop, Serde, Debug, PartialEq)] + #[dojo::model] + pub struct Beast { + #[key] + pub player: ContractAddress, + #[key] + pub beast_id: u16, + pub level: u8, + pub experience: u16, + pub beast_type: BeastType, + } + ``` + - **Commentary**: Both `player` and `beast_id` fields are keys, creating a composite key. This means to query this beast, you need both the player's address and the beast's ID. + +3. **Key Order and Requirements**: + - You must define at least one key for each model, as this is how you query the model. + - All keys must come before any non-key members in the struct. + - When using composite keys, all keys must be provided to query the model. + - **Example**: Querying a model with composite keys: + ```cairo + let player = get_caller_address(); + let beast_id = 123; + + // Using both parts of the composite key for the query + let beast = world.read_model((player, beast_id)); + ``` + +4. **Field Types**: + - Models use Cairo's primitive types and custom types to define fields. + - Custom types must implement the `Introspect` trait to be used in models. + - **Example**: From the `Potion` model: + ```cairo + #[derive(Drop, Serde, IntrospectPacked, Debug)] + #[dojo::model] + struct Potion { + #[key] + id: u64, + name: felt252, + effect: u8, + rarity: Rarity, + power: u32, + } + ``` + - **Commentary**: The model uses various types: `u64` for the ID, `felt252` for the name, `u8` for the effect, a custom `Rarity` enum, and `u32` for the power value. + +5. **Metadata (Derives)**: + - Essential derives for models: + - **`Drop`**: Ensures the struct can be safely deallocated when no longer needed, as part of Cairo's ownership system. + - **`Serde`**: Enables serialization/deserialization for data transfer. + - **`Copy`** (optional): Allows the type to be copied rather than moved, useful for simple data types. + - **`Debug`** (optional): Enables formatted debug output. + - **`PartialEq`** (optional): Enables equality comparison. + - **Example**: All models include at least `Drop` and `Serde`: + ```cairo + #[derive(Drop, Serde)] + #[dojo::model] + struct Moves { + #[key] + player: ContractAddress, + remaining: u8, + } + ``` + +6. **Introspect and IntrospectPacked**: + - `Introspect` is automatically implemented for models, enabling the world database to understand their structure. + - `IntrospectPacked` is used when you want to store the model in a packed way to save storage: + ```cairo + #[derive(Drop, Serde, IntrospectPacked, Debug)] + #[dojo::model] + struct Potion { + #[key] + id: u64, + name: felt252, + effect: u8, + rarity: Rarity, + power: u32, + } + ``` + - **Commentary**: The `IntrospectPacked` derive forces the use of a `Fixed` layout, saving storage space but with less flexibility for upgrades. + +## Implementing Custom Types for Models + +When using custom types in models (like enums or complex structs), you need to ensure they implement the `Introspect` trait. + +### Two Approaches to Implementing Introspect + +1. **Automatic Derivation** (for types defined in your project): + ```cairo + #[derive(Drop, Serde, Introspect)] + struct Stats { + atk: u8, + def: u8, + } + ``` + +2. **Manual Implementation** (for types from other projects or complex cases): + ```cairo + impl StatsIntrospect of dojo::database::introspect::Introspect { + #[inline(always)] + fn size() -> Option { + Option::Some(2) + } + + fn layout() -> dojo::database::introspect::Layout { + // Layout implementation + } + + #[inline(always)] + fn ty() -> dojo::database::introspect::Ty { + // Type implementation + } + } + ``` + +### Using IntrospectPacked for Space Efficiency + +`IntrospectPacked` is useful when you know the size of the model and want to save storage space: + +```cairo +#[derive(Drop, Serde, IntrospectPacked)] +struct Stats { + atk: u8, + def: u8, +} +``` + +Note that dynamic types like `ByteArray` and `Array` cannot be used in packed models. + +## Model Traits and Patterns + +Dojo models often include additional traits and implementations to enhance their functionality. + +### The Zero Pattern + +```cairo +pub impl ZeroablePlayerTrait of Zero { + #[inline(always)] + fn zero() -> Player { + Player { + address: constants::ZERO_ADDRESS(), + current_beast_id: 0, + battles_won: 0, + battles_lost: 0, + last_active_day: 0, + creation_day: 1, + } + } + + #[inline(always)] + fn is_zero(self: @Player) -> bool { + *self.address == constants::ZERO_ADDRESS() + } + + #[inline(always)] + fn is_non_zero(self: @Player) -> bool { + !self.is_zero() + } +} +``` + +This pattern provides: +- A standard way to create "empty" model instances +- Methods to check if a model is empty +- Utility for initialization and validation + +### Custom Trait Generation + +The `#[generate_trait]` attribute creates trait implementations for model-specific operations: + +```cairo +#[generate_trait] +pub impl PlayerAssert of AssertTrait { + #[inline(always)] + fn assert_exists(self: Player) { + assert(self.is_non_zero(), 'Player: Does not exist'); + } + + #[inline(always)] + fn assert_not_exists(self: Player) { + assert(self.is_zero(), 'Player: Already exist'); + } +} +``` + +This creates reusable validation logic specific to the model. + +### Implementing Model Methods + +Models often include implementation blocks with methods for common operations: + +```cairo +#[generate_trait] +pub impl PotionImpl of PotionTrait { + fn new_potion(potion_id: u64) -> Potion { + Potion { id: potion_id, name: 'Potion', effect: 0, rarity: Rarity::Basic, power: 0 } + } + + fn use_potion(self: @Potion, target_hp: u32) -> u32 { + target_hp.saturating_add(*self.power) + } + + fn is_rare(self: @Potion) -> bool { + self.rarity.is_rare() + } +} +``` + +## Models, Entities, and Components in ECS + +Understanding how models fit into the broader ECS architecture is essential for effective Dojo development. + +### Entities vs. Models + +In Dojo: +- **Entities** are identified by their key values (e.g., a ContractAddress, u32, or composite key). +- **Models** (components) are attached to entities via these keys. + +### Example: Relationship Between Entities and Models + +Consider a player entity with multiple associated models: + +``` +Entity: Player (identified by ContractAddress) +├── Player model (stats, battles won/lost) +├── Inventory model (items owned) +└── Position model (location in game world) +``` + +Each model stores a specific aspect of the entity's state, and they're all linked by the same key value (the player's address). + +### Comparison Table + +| Concept | Role in ECS | Example | +|-------------|------------------------------------------|------------------------------------| +| **Entity** | A unique identifier for a game object | A player's ContractAddress | +| **Component** | Data (model) attached to an entity | `Player`, `Beast`, or `Potion` model | +| **System** | Logic that operates on components | A battle system updating player stats | + +## Working with Models in Systems + +Systems interact with models through the World contract, which manages all game state. + +### Reading Models + +```cairo +fn get_player_info(world: IWorldDispatcher, player_address: ContractAddress) { + // Read a model using its key(s) + let player = world.read_model(player_address); + + // For composite keys, provide a tuple of all keys + let beast = world.read_model((player_address, beast_id)); +} +``` + +### Writing Models + +```cairo +fn update_player(world: IWorldDispatcher, player_address: ContractAddress) { + // First read the current state + let mut player = world.read_model(player_address); + + // Update fields + player.battles_won += 1; + player.last_active_day = get_current_day(); + + // Write the updated model back to the world + world.write_model(@Player { + address: player_address, + battles_won: player.battles_won, + battles_lost: player.battles_lost, + current_beast_id: player.current_beast_id, + last_active_day: player.last_active_day, + creation_day: player.creation_day + }); +} +``` + +### Practical Example: Battle System + +Here's a simplified battle system using multiple models: + +```cairo +fn process_battle( + world: IWorldDispatcher, + player_address: ContractAddress, + opponent_address: ContractAddress +) { + // Read player models + let player = world.read_model(player_address); + let opponent = world.read_model(opponent_address); + + // Read beast models (using composite keys) + let player_beast = world.read_model((player_address, player.current_beast_id)); + let opponent_beast = world.read_model((opponent_address, opponent.current_beast_id)); + + // Battle logic (simplified) + let (damage, is_favored, is_super_effective) = player_beast.attack( + opponent_beast.beast_type, + SkillType::Beam, + 100 + ); + + // Update stats based on outcome + let mut updated_player = player; + updated_player.battles_won += 1; + + let mut updated_opponent = opponent; + updated_opponent.battles_lost += 1; + + // Write updated models + world.write_model(@updated_player); + world.write_model(@updated_opponent); +} +``` + +## Testing Models + +Cairo provides a built-in testing framework that works well with Dojo models. + +### Test Block Structure + +```cairo +#[cfg(test)] +mod tests { + use super::{Potion, PotionTrait}; + use crate::types::rarity::Rarity; + + #[test] + #[available_gas(300000)] + fn test_basic_initialization() { + let id = 1; + let potion = Potion { + id: 1, + name: 'Murder', + effect: 0, + rarity: Rarity::Basic, + power: 10 + }; + + assert_eq!(potion.id, id, "Potion ID should match"); + assert_eq!(potion.name, 'Murder', "Potion name should be Murder"); + assert_eq!(potion.power, 10, "Power should be 10"); + } + + // More tests... +} +``` + diff --git a/client-new/pages/getting-started/basics/models/ModelsBestPractices.md b/client-new/pages/getting-started/basics/models/ModelsBestPractices.md new file mode 100644 index 0000000..251b416 --- /dev/null +++ b/client-new/pages/getting-started/basics/models/ModelsBestPractices.md @@ -0,0 +1,169 @@ +# Models Best Practices Quick Reference + +A concise checklist and guidelines for optimal Dojo model development. + +## Model Design Principles + +### Design Checklist +- **Single responsibility** - Each model stores one aspect of entity data +- **Appropriate key structure** - Use single keys for entities, composite for relationships +- **Minimal derives** - Always include `Drop, Serde`; add others only when needed +- **Descriptive field names** - Use clear, consistent naming conventions +- **Input validation** - Implement assertion logic for data constraints +- **Upgrade planning** - Consider future schema changes during design + +### Model Structure Best Practices +```cairo +// ✅ Good: Focused, single-responsibility model +#[derive(Copy, Drop, Serde)] +#[dojo::model] +struct Health { + #[key] + id: u32, + health: u8, +} + +// ❌ Bad: Monolithic model with mixed concerns +#[derive(Copy, Drop, Serde)] +#[dojo::model] +struct Character { + #[key] + id: u32, + health: u8, + max_health: u8, + mana: u8, + max_mana: u8, + // ... many more fields +} +``` + +## Type Selection Guide + +| Data Range | Type | Use Cases | Gas Efficiency | +|------------|------|-----------|----------------| +| 0–255 | `u8` | Health, levels, percentages, flags | ⭐⭐⭐ | +| 0–65,535 | `u16` | Player IDs, item counts, beast IDs | ⭐⭐⭐ | +| 0–4.2B | `u32` | Timestamps, large counters, coordinates | ⭐⭐ | +| Large numbers | `u64`, `u128` | Complex calculations, tokens | ⭐ | +| Text/IDs | `felt252` | Names, identifiers, enum values | ⭐⭐ | +| Addresses | `ContractAddress` | Player/contract references | ⭐⭐ | + +### Custom Types Requirements +```cairo +// Custom types must implement Introspect (For space efficiency, use IntrospectPacked) +#[derive(Drop, Serde, Introspect)] +struct Stats { + atk: u8, + def: u8, +} +``` + +## Performance Guidelines + +### Storage Optimization +| Pattern | When to Use | Trade-offs | +|---------|-------------|------------| +| `Introspect` (default) | Most models | Flexible upgrades, more storage | +| `IntrospectPacked` | Known fixed size | Less storage, limited upgrades | +| Single keys | Entity-specific data | Simple queries, efficient | +| Composite keys | Relationships | Complex queries, relationship modeling | + +### Key Design Patterns +```cairo +// Single key for entity data +#[dojo::model] +struct Player { + #[key] + player_id: u64, + username: String, + score: u32, +} + +// Composite key for relationships +#[dojo::model] +pub struct Beast { + #[key] + pub player: ContractAddress, + #[key] + pub beast_id: u16, + pub level: u8, +} + +// Constant key for global settings +const GAME_SETTINGS_ID: u32 = 999999999; +#[dojo::model] +struct GameSettings { + #[key] + game_settings_id: u32, + combat_cool_down: u32, +} +``` + +## Security & Validation + +### Assertion Strategies +```cairo +// Implement validation traits +#[generate_trait] +pub impl PlayerAssert of AssertTrait { + #[inline(always)] + fn assert_exists(self: Player) { + assert(self.is_non_zero(), 'Player: Does not exist'); + } + + #[inline(always)] + fn assert_not_exists(self: Player) { + assert(self.is_zero(), 'Player: Already exist'); + } +} + +// Use Zero pattern for existence checks +pub impl ZeroablePlayerTrait of Zero { + #[inline(always)] + fn zero() -> Player { + Player { + address: constants::ZERO_ADDRESS(), + current_beast_id: 0, + battles_won: 0, + } + } + + #[inline(always)] + fn is_zero(self: @Player) -> bool { + *self.address == constants::ZERO_ADDRESS() + } +} +``` + +### Testing Patterns +```cairo +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_model_creation() { + let player = Player { address: ADDRESS(), score: 100 }; + assert_eq!(player.score, 100); + } + + #[test] + fn test_validation() { + let player = Player::zero(); + assert!(player.is_zero()); + } +} +``` + +## Upgrade Safety + +### Safe Changes +- Adding new fields at the model's end +- Adding new methods to traits +- Changing method implementations + +### Unsafe Changes +- Removing or reordering fields +- Changing field types +- Modifying key structure +- Changing from `Introspect` to `IntrospectPacked` \ No newline at end of file diff --git a/client-new/pages/getting-started/basics/models/ModelsTesting.md b/client-new/pages/getting-started/basics/models/ModelsTesting.md new file mode 100644 index 0000000..60775d0 --- /dev/null +++ b/client-new/pages/getting-started/basics/models/ModelsTesting.md @@ -0,0 +1,583 @@ +# Models Testing Documentation + +Welcome to the **Models Testing** guide for Dojo Engine! This comprehensive guide focuses specifically on testing strategies and patterns for Dojo models in game development. Whether you're new to testing Cairo models or looking to improve your testing practices, this guide provides practical examples and proven patterns for testing game models effectively. + +## Table of Contents +- [Testing Fundamentals](#testing-fundamentals) +- [Basic Model Testing](#basic-model-testing) +- [Advanced Model Testing](#advanced-model-testing) +- [Gaming-Specific Testing Scenarios](#gaming-specific-testing-scenarios) + +## Testing Fundamentals + +### Model Testing Overview and Importance + +Testing models in Dojo is crucial for ensuring the reliability of your game's data integrity and business logic. Models represent the state of your game entities, and proper testing helps catch bugs early, validates data integrity, and ensures your game logic behaves as expected. + +Key reasons for model testing: +- **Data Integrity**: Ensure model fields are initialized and updated correctly +- **Business Logic Validation**: Verify custom traits and methods work as intended +- **Regression Prevention**: Catch breaking changes when models change +- **Documentation**: Tests serve as executable documentation for model behavior + +### Cairo Testing Framework Basics for Models + +Dojo uses the Cairo testing framework with specific enhancements. All model tests should be organized using the standard Cairo testing structure: + +```cairo +#[cfg(test)] +mod tests { + // Import the model and its traits + use super::*; + + #[test] + #[available_gas(300000)] + fn test_model_functionality() { + // Test implementation goes here + } +} +``` + +### Test Block Structure and Organization + +Structure your model tests in a logical hierarchy: + +1. **Unit Tests**: Test individual model functionality in the same file as the model +2. **Integration Tests**: Test model interactions with systems in separate test files +3. **Property Tests**: Test model traits and custom implementations + +### Gas Considerations and Test Attributes + +Start with a reasonable gas limit and adjust based on your test complexity: +- Begin with `#[available_gas(100000)]` for simple tests +- Increase as needed if you get "out of gas" errors +- Use `#[available_gas(300000)]` or higher for complex operations + +### Setting Up Test Environments for Game Models + +For models that interact with the world contract, use the Dojo testing utilities: + +```cairo +use dojo::model::{ModelStorage, ModelValueStorage, ModelStorageTest}; +use dojo::world::{WorldStorage, WorldStorageTrait}; +use dojo_cairo_test::{spawn_test_world, NamespaceDef, TestResource}; +``` + +## Basic Model Testing + +### Testing Model Initialization and Creation + +Test that your models can be properly created with valid initial values: + +```cairo +#[cfg(test)] +mod tests { + use super::{Position, Vec2, Vec2Trait}; + + #[test] + #[available_gas(100000)] + fn test_position_initialization() { + let position = Position { + player: starknet::contract_address_const::<0x123>(), + vec: Vec2 { x: 10, y: 20 } + }; + + assert_eq!(position.vec.x, 10, "X coordinate should be 10"); + assert_eq!(position.vec.y, 20, "Y coordinate should be 20"); + } +} +``` + +### Testing Field Assignments and Validation + +Verify that model fields can be properly assigned and maintain their values: + +```cairo +#[test] +#[available_gas(100000)] +fn test_player_stats_assignment() { + let player = Player { + address: starknet::contract_address_const::<0x456>(), + current_beast_id: 5, + battles_won: 10, + battles_lost: 3, + last_active_day: 100, + creation_day: 1, + }; + + assert_eq!(player.battles_won, 10, "Battles won should be 10"); + assert_eq!(player.battles_lost, 3, "Battles lost should be 3"); + assert_eq!(player.current_beast_id, 5, "Current beast ID should be 5"); +} +``` + +### Testing Model Equality and Comparison + +Test that models can be properly compared for equality: + +```cairo +#[test] +#[available_gas(100000)] +fn test_vec_equality() { + let vec1 = Vec2 { x: 420, y: 0 }; + let vec2 = Vec2 { x: 420, y: 0 }; + let vec3 = Vec2 { x: 421, y: 0 }; + + assert!(vec1.is_equal(vec2), "Identical vectors should be equal"); + assert!(!vec1.is_equal(vec3), "Different vectors should not be equal"); +} +``` + +### Testing Simple Model Operations + +Test basic operations and transformations on model data: + +```cairo +#[test] +#[available_gas(100000)] +fn test_vec_is_zero() { + let zero_vec = Vec2 { x: 0, y: 0 }; + let non_zero_vec = Vec2 { x: 1, y: 2 }; + + assert!(Vec2Trait::is_zero(zero_vec), "Zero vector should return true"); + assert!(!Vec2Trait::is_zero(non_zero_vec), "Non-zero vector should return false"); +} +``` + +## Advanced Model Testing + +### Testing Custom Traits and Implementations + +Test custom trait implementations for your models: + +```cairo +#[derive(Drop, Serde, IntrospectPacked, Debug)] +#[dojo::model] +struct Potion { + #[key] + id: u64, + name: felt252, + effect: u8, + rarity: Rarity, + power: u32, +} + +#[cfg(test)] +mod potion_tests { + use super::{Potion, PotionTrait, Rarity}; + + #[test] + #[available_gas(300000)] + fn test_potion_creation() { + let potion = PotionTrait::new_potion(1); + + assert_eq!(potion.id, 1, "Potion ID should be 1"); + assert_eq!(potion.name, 'Potion', "Potion name should be 'Potion'"); + assert_eq!(potion.rarity, Rarity::Basic, "Default rarity should be Basic"); + } + + #[test] + #[available_gas(300000)] + fn test_potion_rarity_check() { + let mut potion = PotionTrait::new_potion(1); + + // Test rare potion + potion.rarity = Rarity::VeryRare; + assert_eq!(potion.is_rare(), true, "VeryRare should return true"); + + potion.rarity = Rarity::Rare; + assert_eq!(potion.is_rare(), true, "Rare should return true"); + + // Test common potion + potion.rarity = Rarity::Uncommon; + assert_eq!(potion.is_rare(), false, "Uncommon should return false"); + + potion.rarity = Rarity::Basic; + assert_eq!(potion.is_rare(), false, "Basic should return false"); + } + + #[test] + #[available_gas(300000)] + fn test_potion_use_effect() { + let potion = Potion { + id: 1, + name: 'Healing Potion', + effect: 0, + rarity: Rarity::Basic, + power: 50 + }; + + let initial_hp = 70; + let new_hp = potion.use_potion(initial_hp); + + assert_eq!(new_hp, 120, "HP should increase by potion power"); + } +} +``` + +### Testing Model Validation Logic + +Test custom validation methods like `assert_exists` and `assert_not_exists`: + +```cairo +#[test] +#[available_gas(200000)] +fn test_player_existence_validation() { + let existing_player = Player { + address: starknet::contract_address_const::<0x123>(), + current_beast_id: 1, + battles_won: 5, + battles_lost: 2, + last_active_day: 50, + creation_day: 1, + }; + + let empty_player = Player { + address: constants::ZERO_ADDRESS(), + current_beast_id: 0, + battles_won: 0, + battles_lost: 0, + last_active_day: 0, + creation_day: 1, + }; + + // Should not panic for existing player + existing_player.assert_exists(); + + // Should not panic for empty player + empty_player.assert_not_exists(); + + assert!(existing_player.is_non_zero(), "Existing player should be non-zero"); + assert!(empty_player.is_zero(), "Empty player should be zero"); +} +``` + +### Testing Zero Pattern Implementations + +Test the Zero trait implementation for proper initialization and validation: + +```cairo +#[test] +#[available_gas(200000)] +fn test_zero_pattern() { + let zero_player = Player::zero(); + + assert_eq!(zero_player.address, constants::ZERO_ADDRESS(), "Zero player should have zero address"); + assert_eq!(zero_player.current_beast_id, 0, "Zero player should have zero beast ID"); + assert_eq!(zero_player.battles_won, 0, "Zero player should have zero battles won"); + assert_eq!(zero_player.creation_day, 1, "Zero player should have creation day 1"); + + assert!(zero_player.is_zero(), "Zero player should return true for is_zero()"); + assert!(!zero_player.is_non_zero(), "Zero player should return false for is_non_zero()"); +} +``` + +### Testing Custom Model Methods and Behaviors + +Test complex model methods that involve calculations or state changes: + +```cairo +#[test] +#[available_gas(300000)] +fn test_beast_level_calculation() { + let mut beast = Beast { + player: starknet::contract_address_const::<0x123>(), + beast_id: 1, + level: 1, + experience: 0, + beast_type: BeastType::Fire, + }; + + // Test experience gain and level up + beast.gain_experience(150); + assert_eq!(beast.experience, 150, "Experience should be updated"); + + // Assuming level up happens at 100 XP + assert_eq!(beast.level, 2, "Beast should level up to 2"); +} +``` + +## Gaming-Specific Testing Scenarios + +### Testing Player Stat Calculations and Updates + +Test complex player statistics and progression systems: + +```cairo +#[test] +#[available_gas(500000)] +fn test_player_battle_statistics() { + let mut player = Player { + address: starknet::contract_address_const::<0x123>(), + current_beast_id: 1, + battles_won: 10, + battles_lost: 5, + last_active_day: 100, + creation_day: 1, + }; + + // Test win rate calculation + let total_battles = player.battles_won + player.battles_lost; + let win_rate = (player.battles_won * 100) / total_battles; + assert_eq!(win_rate, 66, "Win rate should be 66%"); + + // Test battle outcome updates + player.record_battle_win(); + assert_eq!(player.battles_won, 11, "Battles won should increase"); + + player.record_battle_loss(); + assert_eq!(player.battles_lost, 6, "Battles lost should increase"); +} +``` + +### Testing Game State Transitions + +Test how models change state during game progression: + +```cairo +#[test] +#[available_gas(400000)] +fn test_game_state_progression() { + let mut game_state = GameState { + game_id: 1, + status: GameStatus::WaitingForPlayers, + turn_count: 0, + current_player: starknet::contract_address_const::<0x0>(), + max_players: 4, + current_players: 0, + }; + + // Test joining game + game_state.add_player(starknet::contract_address_const::<0x123>()); + assert_eq!(game_state.current_players, 1, "Player count should increase"); + + // Test game start when enough players + if game_state.current_players >= 2 { + game_state.start_game(); + assert_eq!(game_state.status, GameStatus::InProgress, "Game should start"); + assert!(game_state.turn_count > 0, "Turn count should be initialized"); + } +} +``` + +### Testing Battle Mechanics and Combat Calculations + +Test complex battle calculations and damage systems: + +```cairo +#[test] +#[available_gas(600000)] +fn test_battle_damage_calculation() { + let attacker_beast = Beast { + player: starknet::contract_address_const::<0x123>(), + beast_id: 1, + level: 5, + experience: 500, + beast_type: BeastType::Fire, + }; + + let defender_beast = Beast { + player: starknet::contract_address_const::<0x456>(), + beast_id: 2, + level: 4, + experience: 400, + beast_type: BeastType::Water, + }; + + // Test type effectiveness + let (damage, is_favored, is_super_effective) = attacker_beast.attack( + defender_beast.beast_type, + SkillType::Beam, + 100 + ); + + // Fire vs Water should not be favored + assert!(!is_favored, "Fire should not be favored against Water"); + assert!(!is_super_effective, "Fire should not be super effective against Water"); + + // Test damage calculation based on level difference + let expected_damage = calculate_base_damage(attacker_beast.level, defender_beast.level); + assert!(damage >= expected_damage * 80 / 100, "Damage should be within expected range"); +} +``` + +### Testing Inventory and Item Management + +Test inventory operations and item interactions: + +```cairo +#[test] +#[available_gas(400000)] +fn test_inventory_management() { + let mut inventory = Inventory { + player: starknet::contract_address_const::<0x123>(), + item_count: 0, + max_capacity: 10, + }; + + // Test adding items + let potion = Item { + id: 1, + item_type: ItemType::Potion, + quantity: 5, + }; + + inventory.add_item(potion); + assert_eq!(inventory.item_count, 1, "Item count should increase"); + + // Test inventory capacity limits + let result = inventory.can_add_item(ItemType::Weapon); + assert!(result, "Should be able to add item when under capacity"); + + // Fill inventory to test capacity + inventory.item_count = inventory.max_capacity; + let result = inventory.can_add_item(ItemType::Armor); + assert!(!result, "Should not be able to add item when at capacity"); +} +``` + +### Testing Achievement and Progression Systems + +Test player achievements and milestone tracking: + +```cairo +#[test] +#[available_gas(500000)] +fn test_achievement_system() { + let mut player_progress = PlayerProgress { + player: starknet::contract_address_const::<0x123>(), + total_experience: 0, + achievements_unlocked: 0, + milestones_reached: 0, + }; + + // Test experience tracking + player_progress.add_experience(1000); + assert_eq!(player_progress.total_experience, 1000, "Experience should be tracked"); + + // Test achievement unlocking + if player_progress.total_experience >= 500 { + player_progress.unlock_achievement(AchievementType::FirstHundredXP); + assert_eq!(player_progress.achievements_unlocked, 1, "Achievement should be unlocked"); + } + + // Test milestone progression + let milestone_reached = player_progress.check_milestone(MilestoneType::Level10); + if milestone_reached { + player_progress.milestones_reached += 1; + assert!(player_progress.milestones_reached > 0, "Milestone should be recorded"); + } +} +``` + +### Integration Testing with World Contract + +Test models in the context of the world contract: + +```cairo +#[cfg(test)] +mod integration_tests { + use dojo::model::{ModelStorage, ModelValueStorage, ModelStorageTest}; + use dojo::world::WorldStorageTrait; + use dojo_cairo_test::{spawn_test_world, NamespaceDef, TestResource, ContractDefTrait}; + + fn namespace_def() -> NamespaceDef { + NamespaceDef { + namespace: "game_models", + resources: [ + TestResource::Model(m_Player::TEST_CLASS_HASH), + TestResource::Model(m_Beast::TEST_CLASS_HASH), + TestResource::Model(m_Inventory::TEST_CLASS_HASH), + ].span() + } + } + + #[test] + fn test_world_model_interactions() { + let caller = starknet::contract_address_const::<0x123>(); + let mut world = spawn_test_world(namespace_def().resources); + + // Test writing and reading models + let player = Player { + address: caller, + current_beast_id: 1, + battles_won: 0, + battles_lost: 0, + last_active_day: 1, + creation_day: 1, + }; + + world.write_model(@player); + let retrieved_player: Player = world.read_model(caller); + + assert_eq!(retrieved_player.address, caller, "Player address should match"); + assert_eq!(retrieved_player.current_beast_id, 1, "Beast ID should match"); + } +} +``` + +## Testing Best Practices for Game Models + +### Consistent Naming Conventions + +Use descriptive test names that clearly indicate what is being tested: + +```cairo +#[test] +fn test_player_initialization_with_valid_data() { /* ... */ } + +#[test] +fn test_battle_damage_calculation_with_type_advantage() { /* ... */ } + +#[test] +fn test_inventory_capacity_limit_enforcement() { /* ... */ } +``` + +### Comprehensive Edge Case Testing + +Always test boundary conditions and edge cases: + +```cairo +#[test] +#[available_gas(300000)] +fn test_experience_overflow_protection() { + let mut beast = Beast { /* ... */ }; + + // Test maximum experience value + beast.experience = u16::MAX; + beast.gain_experience(1); + + // Should handle overflow gracefully + assert!(beast.experience <= u16::MAX, "Experience should not overflow"); +} +``` + +### Test Data Consistency + +Ensure your test data represents realistic game scenarios: + +```cairo +#[test] +fn test_realistic_battle_scenario() { + // Use realistic level ranges (1-100) + let attacker = create_test_beast(level: 25, beast_type: BeastType::Fire); + let defender = create_test_beast(level: 23, beast_type: BeastType::Grass); + + // Test with realistic damage values + let damage = calculate_damage(attacker, defender); + assert!(damage > 0 && damage < 1000, "Damage should be within realistic range"); +} +``` + +## Conclusion + +Model testing is essential for building reliable and maintainable game systems in Dojo. By following the patterns and examples in this guide, you can create comprehensive test suites that catch bugs early, validate game logic, and provide confidence in your model implementations. + +Remember to: +- Test both happy paths and edge cases +- Use realistic game data in your tests +- Test model interactions with the world contract +- Maintain your tests as your models evolve +- Use descriptive test names and clear assertions + +Start with basic model testing and gradually expand to more complex scenarios as your game grows in complexity. Well-tested models form the foundation for reliable and enjoyable gaming experiences. \ No newline at end of file diff --git a/client-new/pages/getting-started/basics/models/models-patterns.md b/client-new/pages/getting-started/basics/models/models-patterns.md new file mode 100644 index 0000000..850c243 --- /dev/null +++ b/client-new/pages/getting-started/basics/models/models-patterns.md @@ -0,0 +1,619 @@ +# Models Patterns and Integration + +Welcome to the **Models Patterns and Integration** guide! This document focuses on advanced model patterns and practical integration techniques for building complex game logic in Dojo Engine. If you're new to models, start with the [Models Basics](../models.md) guide first. + +This guide covers essential patterns for production game development, including trait implementations, systems integration, and real-world battle system examples. + +## Model Traits and Common Patterns + +### The Zero Pattern + +The Zero pattern is fundamental for model initialization and validation. It provides a standardized way to create "empty" model instances and check model existence. + +```cairo +use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; + +#[derive(Copy, Drop, Serde, Debug, PartialEq)] +#[dojo::model] +pub struct Player { + #[key] + pub address: ContractAddress, + pub current_beast_id: u16, + pub battles_won: u16, + pub battles_lost: u16, + pub last_active_day: u32, + pub creation_day: u32, +} + +pub impl ZeroablePlayerTrait of Zero { + #[inline(always)] + fn zero() -> Player { + Player { + address: constants::ZERO_ADDRESS(), + current_beast_id: 0, + battles_won: 0, + battles_lost: 0, + last_active_day: 0, + creation_day: 1, + } + } + + #[inline(always)] + fn is_zero(self: @Player) -> bool { + *self.address == constants::ZERO_ADDRESS() + } + + #[inline(always)] + fn is_non_zero(self: @Player) -> bool { + !self.is_zero() + } +} +``` + +**Usage in Game Logic:** +```cairo +fn check_player_exists(world: IWorldDispatcher, player_address: ContractAddress) -> bool { + let player = world.read_model(player_address); + player.is_non_zero() +} + +fn initialize_new_player(world: IWorldDispatcher, player_address: ContractAddress) { + let existing_player = world.read_model(player_address); + assert(existing_player.is_zero(), 'Player already exists'); + + let new_player = Player { + address: player_address, + current_beast_id: 1, + battles_won: 0, + battles_lost: 0, + last_active_day: get_current_day(), + creation_day: get_current_day(), + }; + + world.write_model(@new_player); +} +``` + +### Custom Trait Generation with `#[generate_trait]` + +Use `#[generate_trait]` to create model-specific validation and utility functions: + +```cairo +#[generate_trait] +pub impl PlayerAssert of AssertTrait { + #[inline(always)] + fn assert_exists(self: Player) { + assert(self.is_non_zero(), 'Player: Does not exist'); + } + + #[inline(always)] + fn assert_not_exists(self: Player) { + assert(self.is_zero(), 'Player: Already exist'); + } + + #[inline(always)] + fn assert_active(self: Player) { + let current_day = get_current_day(); + assert(current_day - self.last_active_day <= 7, 'Player: Inactive too long'); + } +} +``` + +### Gaming-Specific Validation Patterns + +Implement game-specific validation logic for common scenarios: + +```cairo +#[derive(Copy, Drop, Serde, Debug, PartialEq)] +#[dojo::model] +pub struct Beast { + #[key] + pub player: ContractAddress, + #[key] + pub beast_id: u16, + pub level: u8, + pub experience: u16, + pub health: u8, + pub max_health: u8, + pub beast_type: BeastType, +} + +#[generate_trait] +pub impl BeastValidation of BeastValidationTrait { + fn assert_alive(self: @Beast) { + assert(*self.health > 0, 'Beast: Is dead'); + } + + fn assert_can_battle(self: @Beast) { + self.assert_alive(); + assert(*self.level >= 5, 'Beast: Level too low for battle'); + } + + fn assert_can_evolve(self: @Beast) { + assert(*self.level >= 10, 'Beast: Not ready to evolve'); + assert(*self.experience >= 1000, 'Beast: Insufficient experience'); + } + + fn is_elite(self: @Beast) -> bool { + *self.level >= 50 && *self.experience >= 10000 + } +} +``` + +## Advanced Model Methods + +### Implementing Custom Model Behaviors + +Create sophisticated model behaviors that encapsulate game logic: + +```cairo +#[derive(Drop, Serde, IntrospectPacked, Debug)] +#[dojo::model] +struct Potion { + #[key] + id: u64, + name: felt252, + effect: u8, + rarity: Rarity, + power: u32, +} + +#[generate_trait] +pub impl PotionImpl of PotionTrait { + fn new_potion(potion_id: u64, rarity: Rarity) -> Potion { + let (power, effect) = match rarity { + Rarity::Basic => (10, 1), + Rarity::Uncommon => (25, 2), + Rarity::Rare => (50, 3), + Rarity::VeryRare => (100, 5), + }; + + Potion { + id: potion_id, + name: 'Health Potion', + effect, + rarity, + power + } + } + + fn use_potion(self: @Potion, target_hp: u32, target_max_hp: u32) -> u32 { + let healing = *self.power; + let new_hp = target_hp + healing; + + if new_hp > target_max_hp { + target_max_hp + } else { + new_hp + } + } + + fn is_rare(self: @Potion) -> bool { + match self.rarity { + Rarity::Rare | Rarity::VeryRare => true, + _ => false, + } + } + + fn get_sell_value(self: @Potion) -> u32 { + let base_value = match self.rarity { + Rarity::Basic => 5, + Rarity::Uncommon => 15, + Rarity::Rare => 50, + Rarity::VeryRare => 200, + }; + base_value * (*self.power / 10) + } +} +``` + +### Performance Considerations + +Optimize model operations for gas efficiency: + +```cairo +#[generate_trait] +pub impl BeastOptimized of BeastOptimizedTrait { + // Batch operations to reduce gas costs + fn level_up_with_rewards( + ref self: Beast, + experience_gained: u16, + health_bonus: u8 + ) -> (bool, u8) { // Returns (leveled_up, new_level) + self.experience += experience_gained; + let old_level = self.level; + + // Calculate new level efficiently + let new_level = min(100, old_level + (experience_gained / 100)); + + if new_level > old_level { + self.level = new_level; + self.max_health += health_bonus * (new_level - old_level); + self.health = self.max_health; // Full heal on level up + (true, new_level) + } else { + (false, old_level) + } + } + + // Inline calculations for critical path operations + #[inline(always)] + fn calculate_damage_multiplier(self: @Beast, target_type: BeastType) -> u8 { + if self.beast_type.is_effective_against(target_type) { + 150 // 1.5x damage + } else if self.beast_type.is_weak_against(target_type) { + 75 // 0.75x damage + } else { + 100 // 1.0x damage + } + } +} +``` + +## Models in ECS Context + +### Entity Identification and Component Composition + +Understanding how entities and models work together: + +```cairo +// Entity: Player (identified by ContractAddress) +// ├── Player model (stats, battles won/lost) +// ├── Inventory model (items owned) +// ├── Position model (location in game world) +// └── Beast model (current beast, composite key with beast_id) + +#[derive(Copy, Drop, Serde)] +#[dojo::model] +struct Inventory { + #[key] + player: ContractAddress, + potions: u8, + gold: u32, + equipped_weapon: u16, +} + +#[derive(Copy, Drop, Serde)] +#[dojo::model] +struct Position { + #[key] + player: ContractAddress, + x: u32, + y: u32, + zone: felt252, +} +``` + +### Component Composition Patterns + +Design entities with multiple focused models: + +```cairo +fn get_complete_player_state( + world: IWorldDispatcher, + player_address: ContractAddress +) -> (Player, Inventory, Position, Option) { + let player = world.read_model(player_address); + let inventory = world.read_model(player_address); + let position = world.read_model(player_address); + + // Beast uses composite key + let beast = if player.current_beast_id > 0 { + Option::Some(world.read_model((player_address, player.current_beast_id))) + } else { + Option::None + }; + + (player, inventory, position, beast) +} +``` + +## Systems Integration + +### Reading Models from Systems + +Efficient model querying patterns: + +```cairo +fn validate_battle_participants( + world: IWorldDispatcher, + player_address: ContractAddress, + opponent_address: ContractAddress +) -> (Player, Player, Beast, Beast) { + // Read player models + let player = world.read_model(player_address); + let opponent = world.read_model(opponent_address); + + // Validate players exist and are active + player.assert_exists(); + player.assert_active(); + opponent.assert_exists(); + opponent.assert_active(); + + // Read beast models with composite keys + let player_beast = world.read_model((player_address, player.current_beast_id)); + let opponent_beast = world.read_model((opponent_address, opponent.current_beast_id)); + + // Validate beasts can battle + player_beast.assert_can_battle(); + opponent_beast.assert_can_battle(); + + (player, opponent, player_beast, opponent_beast) +} +``` + +### Writing Models with Error Handling + +Safe model updates with rollback capabilities: + +```cairo +fn update_player_inventory_safe( + world: IWorldDispatcher, + player_address: ContractAddress, + gold_spent: u32, + potions_used: u8 +) { + let mut inventory = world.read_model(player_address); + + // Validate sufficient resources + assert(inventory.gold >= gold_spent, 'Insufficient gold'); + assert(inventory.potions >= potions_used, 'Insufficient potions'); + + // Update inventory + inventory.gold -= gold_spent; + inventory.potions -= potions_used; + + // Write updated model + world.write_model(@inventory); +} +``` + +### Batch Model Operations + +Optimize multiple model updates: + +```cairo +fn process_quest_completion( + world: IWorldDispatcher, + player_address: ContractAddress, + experience_reward: u16, + gold_reward: u32, + item_reward: u16 +) { + // Read all required models + let mut player = world.read_model(player_address); + let mut inventory = world.read_model(player_address); + let mut beast = world.read_model((player_address, player.current_beast_id)); + + // Update player stats + player.battles_won += 1; + player.last_active_day = get_current_day(); + + // Update inventory + inventory.gold += gold_reward; + inventory.potions += 1; // Bonus potion + + // Level up beast + let (leveled_up, new_level) = beast.level_up_with_rewards(experience_reward, 5); + + // Write all updates (batch operation) + world.write_model(@player); + world.write_model(@inventory); + world.write_model(@beast); + + // Emit events for client updates + if leveled_up { + emit!(world, BeastLevelUp { + player: player_address, + beast_id: player.current_beast_id, + new_level + }); + } +} +``` + +## Practical Battle System Example + +Here's a complete battle system demonstrating complex model coordination: + +```cairo +fn execute_battle( + world: IWorldDispatcher, + player_address: ContractAddress, + opponent_address: ContractAddress, + skill_type: SkillType +) { + // Validate and read all participants + let (mut player, mut opponent, mut player_beast, mut opponent_beast) = + validate_battle_participants(world, player_address, opponent_address); + + // Calculate battle outcome + let (damage, is_critical, is_super_effective) = calculate_battle_damage( + @player_beast, + @opponent_beast, + skill_type + ); + + // Apply damage with validation + let final_damage = min(damage, opponent_beast.health.into()); + opponent_beast.health -= final_damage.try_into().unwrap(); + + // Determine battle result + let player_wins = opponent_beast.health == 0; + + if player_wins { + // Update winner stats + player.battles_won += 1; + opponent.battles_lost += 1; + + // Experience and level up logic + let exp_gained = calculate_experience_reward(@opponent_beast); + let (leveled_up, new_level) = player_beast.level_up_with_rewards(exp_gained, 2); + + // Reward inventory updates + let mut player_inventory = world.read_model(player_address); + player_inventory.gold += calculate_gold_reward(@opponent_beast); + world.write_model(@player_inventory); + + // Handle level up rewards + if leveled_up { + emit!(world, BeastLevelUp { + player: player_address, + beast_id: player.current_beast_id, + new_level + }); + } + } else { + // Handle partial damage scenario + player.battles_lost += 1; + opponent.battles_won += 1; + + // Small experience gain for participation + let (_, _) = player_beast.level_up_with_rewards(10, 0); + } + + // Update activity timestamps + let current_day = get_current_day(); + player.last_active_day = current_day; + opponent.last_active_day = current_day; + + // Write all updated models + world.write_model(@player); + world.write_model(@opponent); + world.write_model(@player_beast); + world.write_model(@opponent_beast); + + // Emit battle result event + emit!(world, BattleResult { + player: player_address, + opponent: opponent_address, + winner: if player_wins { player_address } else { opponent_address }, + damage: final_damage, + is_critical, + is_super_effective + }); +} + +// Helper functions for battle calculations +fn calculate_battle_damage( + attacker: @Beast, + defender: @Beast, + skill_type: SkillType +) -> (u32, bool, bool) { + let base_damage = (attacker.level.into() * 10) + skill_type.get_power(); + let type_multiplier = attacker.calculate_damage_multiplier(*defender.beast_type); + let damage = (base_damage * type_multiplier.into()) / 100; + + // Critical hit calculation (10% chance) + let is_critical = get_random_u8() < 26; // 10% of 256 + let final_damage = if is_critical { damage * 2 } else { damage }; + + let is_super_effective = type_multiplier > 100; + + (final_damage, is_critical, is_super_effective) +} + +fn calculate_experience_reward(defeated_beast: @Beast) -> u16 { + let base_exp = *defeated_beast.level.into() * 15; + min(base_exp, 500) // Cap at 500 exp per battle +} + +fn calculate_gold_reward(defeated_beast: @Beast) -> u32 { + let base_gold = *defeated_beast.level.into() * 5; + base_gold + if defeated_beast.is_elite() { 100 } else { 0 } +} +``` + +## Advanced Pattern: State Machine Models + +Implement complex game states using model patterns: + +```cairo +#[derive(Copy, Drop, Serde, Debug, PartialEq)] +enum GamePhase { + Preparation, + Battle, + Resolution, + Ended +} + +#[derive(Copy, Drop, Serde)] +#[dojo::model] +struct GameSession { + #[key] + session_id: u64, + player1: ContractAddress, + player2: ContractAddress, + current_phase: GamePhase, + turn_count: u16, + winner: ContractAddress, +} + +#[generate_trait] +impl GameSessionImpl of GameSessionTrait { + fn advance_phase(ref self: GameSession) { + self.current_phase = match self.current_phase { + GamePhase::Preparation => GamePhase::Battle, + GamePhase::Battle => GamePhase::Resolution, + GamePhase::Resolution => GamePhase::Battle, // Next turn + GamePhase::Ended => GamePhase::Ended, // Stay ended + }; + + if matches!(self.current_phase, GamePhase::Resolution) { + self.turn_count += 1; + } + } + + fn can_perform_action(self: @GameSession, player: ContractAddress, action: ActionType) -> bool { + match (*self.current_phase, action) { + (GamePhase::Preparation, ActionType::SelectBeast) => true, + (GamePhase::Battle, ActionType::Attack | ActionType::UseItem) => true, + (GamePhase::Resolution, ActionType::ViewResults) => true, + _ => false, + } + } +} +``` + +## Optimizing Model Performance + +### Memory Layout Optimization + +Use `IntrospectPacked` for frequently accessed, fixed-size models: + +```cairo +#[derive(Drop, Serde, IntrospectPacked)] +#[dojo::model] +struct PlayerStats { + #[key] + player: ContractAddress, + health: u8, + mana: u8, + level: u8, + experience: u16, +} +``` + +### Lazy Loading Patterns + +Load complex models only when needed: + +```cairo +fn get_battle_ready_player( + world: IWorldDispatcher, + player_address: ContractAddress +) -> (Player, Beast) { + let player = world.read_model(player_address); + + // Only load beast if player has one + if player.current_beast_id > 0 { + let beast = world.read_model((player_address, player.current_beast_id)); + beast.assert_can_battle(); + (player, beast) + } else { + panic!("Player has no beast for battle"); + } +} +``` + +This comprehensive guide provides the patterns and integration techniques needed to build sophisticated game logic with Dojo models. Use these patterns as building blocks for your own game systems, adapting them to your specific requirements while maintaining the ECS principles that make Dojo powerful. \ No newline at end of file diff --git a/client-new/pages/getting-started/basics/store.md b/client-new/pages/getting-started/basics/store.md new file mode 100644 index 0000000..7d3d8e1 --- /dev/null +++ b/client-new/pages/getting-started/basics/store.md @@ -0,0 +1,3 @@ +# Store + +Under development... diff --git a/client-new/pages/getting-started/basics/systems.md b/client-new/pages/getting-started/basics/systems.md new file mode 100644 index 0000000..e836ca5 --- /dev/null +++ b/client-new/pages/getting-started/basics/systems.md @@ -0,0 +1,3 @@ +# Systems + +Under development... diff --git a/client-new/pages/getting-started/basics/testing/integration.md b/client-new/pages/getting-started/basics/testing/integration.md new file mode 100644 index 0000000..b3d4ac1 --- /dev/null +++ b/client-new/pages/getting-started/basics/testing/integration.md @@ -0,0 +1,3 @@ +# Integration Tests + +Under development... diff --git a/client-new/pages/getting-started/basics/testing/unit.md b/client-new/pages/getting-started/basics/testing/unit.md new file mode 100644 index 0000000..79111fd --- /dev/null +++ b/client-new/pages/getting-started/basics/testing/unit.md @@ -0,0 +1,130 @@ +# Unit tests + +Unit testing is a crucial aspect of software development, particularly in blockchain game development, where the integrity and reliability of smart contracts are paramount. This documentation provides a comprehensive overview of unit testing in the Dojo Engine, focusing on testing strategies, Cairo testing patterns, and practical examples using the Player model implementation. + +## Importance of Unit Testing in Blockchain Game Development + +Unit tests help ensure that individual components of the game function correctly. They allow developers to catch bugs early in the development process, facilitate code refactoring, and provide documentation for the expected behavior of the code. In the context of blockchain games, where transactions and state changes are immutable, thorough testing is essential to prevent costly errors. + +## Testing Strategies + +When testing models, systems, and helper functions in the Dojo Engine, consider the following strategies: + +1. **Isolation**: Each unit test should focus on a single component, ensuring that tests do not interfere with one another. +2. **Edge Cases**: Always test edge cases to ensure that the code behaves as expected under unusual conditions. +3. **Assertions**: Use assertions to validate the expected outcomes of tests, ensuring that the actual results match the expected results. +4. **Test Coverage**: Aim for high test coverage to ensure that all parts of the code are tested, reducing the likelihood of undetected bugs. + +## Cairo Testing Patterns + +Cairo provides a structured approach to testing smart contracts. Key patterns include: + +- **Setup and Teardown**: Use setup functions to initialize the state before tests and teardown functions to clean up afterward. +- **Mocking**: When testing components that depend on external systems, use mocking to simulate those dependencies. +- **Parameterized Tests**: Use parameterized tests to run the same test logic with different inputs, improving test coverage with less code. + +## Practical Examples Using the Player Model Implementation + +The Player model consists of a struct and several traits that facilitate its functionality. Below are examples of unit tests for the Player model. + +### Player Struct + +```cairo +struct Player { + address: ContractAddress, + current_beast_id: u16, + battles_won: u16, + battles_lost: u16, + last_active_day: u32, + creation_day: u32, +} +``` + +### PlayerAssert Trait + +```cairo +trait PlayerAssert { + func assert_exists(player: Player); + func assert_not_exists(player: Player); +} +``` + +### ZeroablePlayerTrait Trait + +```cairo +trait ZeroablePlayerTrait { + func zero() -> Player; + func is_zero(player: Player) -> bool; + func is_non_zero(player: Player) -> bool; +} +``` + +### Tests Module + +```cairo +mod Tests { + use super::*; + + #[test] + fn test_player_initialization() { + let player = Player { + address: /* some address */, + current_beast_id: 1, + battles_won: 0, + battles_lost: 0, + last_active_day: 0, + creation_day: 0, + }; + assert_eq!(player.current_beast_id, 1); + assert_eq!(player.battles_won, 0); + } + + #[test] + fn test_player_initialization_zero_values() { + let player = ZeroablePlayerTrait::zero(); + assert!(ZeroablePlayerTrait::is_zero(player)); + } + + #[test] + fn test_player_with_zero_beast() { + let player = Player { + address: /* some address */, + current_beast_id: 0, + battles_won: 0, + battles_lost: 0, + last_active_day: 0, + creation_day: 0, + }; + assert_eq!(player.current_beast_id, 0); + } + + #[test] + fn test_player_address_uniqueness() { + let player1 = Player { + address: /* address 1 */, + current_beast_id: 1, + battles_won: 0, + battles_lost: 0, + last_active_day: 0, + creation_day: 0, + }; + let player2 = Player { + address: /* address 2 */, + current_beast_id: 2, + battles_won: 0, + battles_lost: 0, + last_active_day: 0, + creation_day: 0, + }; + assert!(player1.address != player2.address); + } +} +``` + +## Best Practices for Test Organization + +- **Group Related Tests**: Organize tests into modules or files based on functionality to improve readability and maintainability. +- **Descriptive Naming**: Use descriptive names for test functions to clearly indicate what is being tested. +- **Continuous Integration**: Integrate unit tests into the development workflow to ensure that tests are run automatically with each code change. + +By following these guidelines and utilizing the provided examples, developers can effectively implement unit testing in the Dojo Engine, ensuring robust and reliable blockchain game applications. \ No newline at end of file diff --git a/client-new/pages/getting-started/basics/world.md b/client-new/pages/getting-started/basics/world.md new file mode 100644 index 0000000..a923495 --- /dev/null +++ b/client-new/pages/getting-started/basics/world.md @@ -0,0 +1,3 @@ +# World + +Under development... diff --git a/client-new/pages/getting-started/env_setup.md b/client-new/pages/getting-started/env_setup.md new file mode 100644 index 0000000..893a1a9 --- /dev/null +++ b/client-new/pages/getting-started/env_setup.md @@ -0,0 +1,107 @@ +# Local environment setup + +This guide walks through setting up a Dojo development environment, creating a project, and compiling your first dojo project. + +::::steps + +## Install toolchain + +Run this script developed by [Starkiro](https://github.com/KaizeNodeLabs/starkiro) to install asdf and the required Dojo plugins on the latest version: + +```bash [Terminal] +curl -s https://raw.githubusercontent.com/KaizeNodeLabs/starkiro/main/cli/install_dojo_dev_suit.sh | bash +``` + +If you need an specific version you can run: + +```bash [Terminal] +curl -s https://raw.githubusercontent.com/KaizeNodeLabs/starkiro/main/cli/install_dojo_dev_suit.sh -o install_dojo_dev_suit.sh +bash install_dojo_dev_suit.sh --scarb --dojo +``` + +This installs: +- [Scarb](https://docs.swmansion.com/scarb/docs.html) - Cairo package manager. +- [Dojo](https://book.dojoengine.org) - the framework. + +:::note[Community Standard] +While you could use a more minimal toolchains, this curated set provides: +- Active maintenance from core contributors. +- Cross-platform compatibility. +- Integrated dependency and version management. +::: + +## Create new project with `dojo-starter` + +Create a new project with Dojo: + +```bash [Terminal] +sozo init dojo-starter +``` + +This command creates a `dojo-starter` project in your current directory from the Dojo starter template. It's the ideal starting point for a new project and equips you with everything you need to begin hacking. + +Take a look at the anatomy of `dojo-starter` project. It manages: + +```bash [Terminal] +├── Scarb.toml +├── dojo_dev.toml +├── dojo_release.toml +└── src + ├── lib.cairo + ├── models.cairo + ├── systems + │   └── actions.cairo + └── tests + └── test_world.cairo +``` + +The scarb manifest `Scarb.toml` is a configuration file where project dependencies, metadata and other configurations are defined. Lets understand this file: + +```bash [Terminal] +[package] #indicates that the following statements are configuring a package +cairo-version = "=2.9.2" +name = "dojo-starter" #project name +version = "1.1.0" #project version +edition = "2024_07" #project edition + +[cairo] +sierra-replace-ids = true #specific configuration for sierra compile + +[scripts] #scripts for the project +migrate = "sozo build && sozo migrate" #custom script to migrate the project + +[dependencies] #list any of your project dependencies +dojo = { git = "https://github.com/dojoengine/dojo", tag = "v1.1.1" } #Dojo dependency with version 1.1.1 + +[[target.starknet-contract]] #allows to build Starknet smart contracts +build-external-contracts = ["dojo::world::world_contract::world"] #reference to the world contract + +[dev-dependencies] +cairo_test = "=2.9.2" #cairo tests version +dojo_cairo_test = { git = "https://github.com/dojoengine/dojo", tag = "v1.1.1" } #dojo tests tools dependencies +``` + +## Compile smart contract with `sozo build` + +The template includes a starter `model` and `system` in `src/lib.cairo{:md}`. Compile it with: + +```bash [Terminal] +sozo build +``` + +That compiled the models and systems into artifacts that can be deployed. + +If everything works as expected you would to see an output like this one: + +```bash [Terminal] +Compiling dojo-starter v1.1.1 (/your_path/dojo-starter/contract/Scarb.toml) + Finished `dev` profile target(s) in 5 seconds +``` + +## Next steps + +You're now ready to modify your `dojo-starter` by adding new models and systems. +We will cover the rest of the tools in the next sections. + +As a bonus step, we recommend you to explore the [Dojo](https://book.dojoengine.org/overview) and [Cairo](https://book.cairo-lang.org/title-page.html) Documentacion. + diff --git a/client-new/pages/guides/ai/daydreams.md b/client-new/pages/guides/ai/daydreams.md new file mode 100644 index 0000000..32696ea --- /dev/null +++ b/client-new/pages/guides/ai/daydreams.md @@ -0,0 +1,3 @@ +# Daydreams Integration + +Under development... diff --git a/client-new/pages/guides/ai/eliza.md b/client-new/pages/guides/ai/eliza.md new file mode 100644 index 0000000..6efc2df --- /dev/null +++ b/client-new/pages/guides/ai/eliza.md @@ -0,0 +1,3 @@ +# Eliza Integration + +Under development... diff --git a/client-new/pages/guides/react/bindings/contracts-bindings.md b/client-new/pages/guides/react/bindings/contracts-bindings.md new file mode 100644 index 0000000..e81ec79 --- /dev/null +++ b/client-new/pages/guides/react/bindings/contracts-bindings.md @@ -0,0 +1,369 @@ +# React Integration - Contracts Bindings + +The **contracts.gen.ts** file is the auto-generated bridge between your Cairo game contracts and React frontend, providing type-safe TypeScript functions that execute game actions on the blockchain. This file transforms complex blockchain interactions into simple function calls that feel like traditional game mechanics, enabling developers to focus on gameplay rather than blockchain complexity. + +## File Overview & Auto-Generation + +The `contracts.gen.ts` file contains auto-generated TypeScript bindings that mirror your Cairo contract functions, providing a seamless interface for game actions. This file is automatically created and updated whenever you deploy your Dojo contracts, ensuring your frontend always stays synchronized with your game logic. + +**Gaming Benefits**: + +- **Action-to-Function Mapping**: Every game action (train, mine, rest) becomes a simple TypeScript function call +- **Type Safety**: Prevents errors by ensuring contract parameters match your game's requirements +- **Automatic Updates**: Contract changes immediately reflect in your frontend without manual updates +- **Game-First API**: Functions are organized by game mechanics rather than technical contract structure + +**Auto-Generation Process**: + +```bash +# Deploy contracts and generate bindings +sozo migrate +# TypeScript bindings automatically created in contracts.gen.ts +``` + +> **Gaming Philosophy**: This file eliminates the complexity barrier between game designers and blockchain, making onchain game development feel like traditional game programming. + +## Complete Implementation + +```typescript +import { DojoProvider, DojoCall } from "@dojoengine/core"; +import { Account, AccountInterface } from "starknet"; + +export function setupWorld(provider: DojoProvider) { + const build_game_mine_calldata = (): DojoCall => { + return { + contractName: "game", + entrypoint: "mine", + calldata: [], + }; + }; + + const game_mine = async (snAccount: Account | AccountInterface) => { + try { + return await provider.execute( + snAccount as any, + build_game_mine_calldata(), + "full_starter_react" + ); + } catch (error) { + console.error(error); + throw error; + } + }; + + const build_game_rest_calldata = (): DojoCall => { + return { + contractName: "game", + entrypoint: "rest", + calldata: [], + }; + }; + + const game_rest = async (snAccount: Account | AccountInterface) => { + try { + return await provider.execute( + snAccount as any, + build_game_rest_calldata(), + "full_starter_react" + ); + } catch (error) { + console.error(error); + throw error; + } + }; + + const build_game_spawnPlayer_calldata = (): DojoCall => { + return { + contractName: "game", + entrypoint: "spawn_player", + calldata: [], + }; + }; + + const game_spawnPlayer = async (snAccount: Account | AccountInterface) => { + try { + return await provider.execute( + snAccount as any, + build_game_spawnPlayer_calldata(), + "full_starter_react" + ); + } catch (error) { + console.error(error); + throw error; + } + }; + + const build_game_train_calldata = (): DojoCall => { + return { + contractName: "game", + entrypoint: "train", + calldata: [], + }; + }; + + const game_train = async (snAccount: Account | AccountInterface) => { + try { + return await provider.execute( + snAccount as any, + build_game_train_calldata(), + "full_starter_react" + ); + } catch (error) { + console.error(error); + throw error; + } + }; + + return { + game: { + mine: game_mine, + buildMineCalldata: build_game_mine_calldata, + rest: game_rest, + buildRestCalldata: build_game_rest_calldata, + spawnPlayer: game_spawnPlayer, + buildSpawnPlayerCalldata: build_game_spawnPlayer_calldata, + train: game_train, + buildTrainCalldata: build_game_train_calldata, + }, + }; +} +``` + +## Imports and Core Dependencies + +### Dojo Engine Core + +```typescript +import { DojoProvider, DojoCall } from "@dojoengine/core"; +``` + +**DojoProvider**: The main interface for executing game actions on the blockchain, handling all communication between your game and the Dojo world. + +**DojoCall Interface**: Standardized structure for game action calls that ensures consistency and type safety: + +```typescript +interface DojoCall { + contractName: string; // Game contract identifier ("game") + entrypoint: string; // Game action name ("mine", "train", etc.) + calldata: any[]; // Action parameters (empty for basic actions) +} +``` + +**Gaming Context**: These imports provide the foundation for translating player actions into blockchain transactions seamlessly. + +### Starknet Account Types + +```typescript +import { Account, AccountInterface } from "starknet"; +``` + +**Purpose**: Represents the player's wallet account for transaction signing and execution. + +**Gaming Integration**: Enables players to execute game actions using their connected wallet while maintaining the gaming experience through session policies. + +## setupWorld Function Architecture + +### Main Function Structure + +```typescript +export function setupWorld(provider: DojoProvider) { + // Game action implementations + return { + game: { + mine: game_mine, + buildMineCalldata: build_game_mine_calldata, + rest: game_rest, + buildRestCalldata: build_game_rest_calldata, + spawnPlayer: game_spawnPlayer, + buildSpawnPlayerCalldata: build_game_spawnPlayer_calldata, + train: game_train, + buildTrainCalldata: build_game_train_calldata, + }, + }; +} +``` + +**Gaming Architecture Benefits**: + +- **Provider Injection**: Accepts DojoProvider for flexible configuration across different game environments +- **Namespace Organization**: Groups functions by game contract for clear game logic separation +- **Dual Function Pattern**: Each game action has both execution function and calldata builder for flexibility +- **Consistent API**: All game actions follow the same pattern for predictable development experience + +**Game Organization**: The returned object structure mirrors your game's logical organization, making it intuitive for game developers to find and use appropriate functions. + +## Calldata Builder Pattern + +### Builder Function Structure + +```typescript +const build_game_mine_calldata = (): DojoCall => { + return { + contractName: "game", + entrypoint: "mine", + calldata: [], + }; +}; +``` + +**Gaming Purpose**: Creates standardized call data for game actions, separating action definition from execution. + +**DojoCall Structure Breakdown**: + +- `contractName: "game"`: Identifies the game contract containing the action +- `entrypoint: "mine"`: Specifies the exact game action to execute +- `calldata: []`: Parameters for the action (empty for basic game actions) + +**Gaming Benefits**: + +- **Action Reusability**: Calldata can be built once and reused multiple times +- **Game Testing**: Easy to test game action data without executing transactions +- **Action Composition**: Can combine multiple game actions into sequences + +**Naming Convention**: `build_game_{action}_calldata` pattern ensures consistent and discoverable function names. + +## Contract Execution Methods + +### Game Action Execution Pattern + +```typescript +const game_mine = async (snAccount: Account | AccountInterface) => { + try { + return await provider.execute( + snAccount as any, + build_game_mine_calldata(), + "full_starter_react" + ); + } catch (error) { + console.error(error); + throw error; + } +}; +``` + +**Gaming Execution Flow**: + +1. **Player Action**: Player clicks "Mine" in game interface +2. **Account Validation**: Ensures player has connected wallet +3. **Action Building**: Creates DojoCall with game action data +4. **Blockchain Execution**: Executes action on game contract +5. **Result Handling**: Returns transaction result or throws error + +**Method Parameters**: + +- `snAccount`: Player's connected wallet account for signing game transactions +- `build_game_mine_calldata()`: Pre-built action data for the mining action +- `"full_starter_react"`: Dojo world namespace identifier for your game + +**Gaming Error Handling**: Comprehensive try-catch ensures game doesn't crash on failed actions, allowing for graceful error recovery and player feedback. + +## Game Functions Documentation + +### 1. `mine` - Resource Extraction Mechanic + +```typescript +const game_mine = async (snAccount: Account | AccountInterface) => { + /* ... */ +}; +``` + +**Game Mechanics**: Risk/reward mining system where players extract coins but lose health. + +**Gaming Strategy**: Players must balance coin earning with health management, creating strategic decision-making. + +**Player Impact**: + +- ⬆️ Increases player coins (resource gain) +- ⬇️ Decreases player health (risk cost) + +### 2. `rest` - Health Recovery System + +```typescript +const game_rest = async (snAccount: Account | AccountInterface) => { + /* ... */ +}; +``` + +**Game Mechanics**: Allows players to recover health, supporting resource management gameplay. + +**Gaming Strategy**: Essential for maintaining character viability after risky actions like mining. + +**Player Impact**: + +- ⬆️ Restores player health (recovery) +- 🛡️ Enables continued gameplay + +### 3. `spawnPlayer` - Character Initialization + +```typescript +const game_spawnPlayer = async (snAccount: Account | AccountInterface) => { + /* ... */ +}; +``` + +**Game Mechanics**: Creates a new player character in the game world with starting statistics. + +**Gaming Onboarding**: First action new players take to begin their gaming journey. + +**Player Impact**: + +- 🎮 Creates player character with default stats +- 🚀 Enables access to all other game functions + +### 4. `train` - Character Progression + +```typescript +const game_train = async (snAccount: Account | AccountInterface) => { + /* ... */ +}; +``` + +**Game Mechanics**: Increases player experience, enabling character development and progression. + +**Gaming Progression**: Core mechanic for long-term player engagement and character building. + +**Player Impact**: + +- ⬆️ Increases experience points (character growth) +- 📈 Enables progression-based gameplay + +## Relationship with Cairo Game Contracts + +### Cairo Contract Functions + +```cairo +// Cairo game contract functions +#[starknet::interface] +trait IGameActions { + fn mine(self: @ContractState); + fn rest(self: @ContractState); + fn spawn_player(self: @ContractState); + fn train(self: @ContractState); +} +``` + +### TypeScript Mapping + +```typescript +// Auto-generated TypeScript functions +const game_mine = async (snAccount: Account) => { + /* ... */ +}; +const game_rest = async (snAccount: Account) => { + /* ... */ +}; +const game_spawnPlayer = async (snAccount: Account) => { + /* ... */ +}; +const game_train = async (snAccount: Account) => { + /* ... */ +}; +``` + +**Gaming Synchronization**: Direct 1:1 mapping ensures that changes to your Cairo game logic automatically update your frontend functions, maintaining consistency across your entire game stack. + +**Developer Experience**: Game designers can modify Cairo contracts and immediately see those changes reflected in the TypeScript API without manual updates. + +--- + +*The contracts.gen.ts file transforms complex blockchain transactions into simple game function calls, enabling developers to build engaging fully on-chain games with traditional gaming development patterns.* diff --git a/client-new/pages/guides/react/bindings/models-bindings.md b/client-new/pages/guides/react/bindings/models-bindings.md new file mode 100644 index 0000000..c902f18 --- /dev/null +++ b/client-new/pages/guides/react/bindings/models-bindings.md @@ -0,0 +1,334 @@ +# React Integration - Models Bindings + +The **bindings.ts** file contains auto-generated TypeScript interfaces that mirror your Cairo game models, providing type-safe access to player data, achievements, and game entities from your React components. This file serves as the crucial bridge between your onchain game logic and frontend interface, ensuring that your game's data structures remain synchronized and type-safe across the entire application. + +## File Overview & Auto-Generation + +The `bindings.ts` file is automatically generated from your Cairo model definitions using the Dojo toolchain, creating TypeScript interfaces that exactly match your onchain game structures. This auto-generation process ensures that your frontend always stays synchronized with your smart contract models without manual type maintenance. + +**Gaming Benefits**: +- **Type Safety**: Prevents runtime errors when accessing player stats, achievements, and game data +- **Automatic Synchronization**: Model changes in Cairo automatically update frontend types +- **Developer Experience**: IntelliSense and autocomplete for all game data structures +- **Gaming-First Design**: Interfaces designed specifically for game entities like players, achievements, and progression systems + +**Auto-Generation Workflow**: +```bash +# After modifying Cairo models and deploying +sozo build —typescript +# TypeScript interfaces automatically updated in bindings.ts +``` + +> **Gaming Philosophy**: This file eliminates the friction between game logic design and frontend implementation, allowing game developers to focus on gameplay mechanics rather than type synchronization. + +## Complete Implementation + +You can see a complete bindings file here in our [Dojo Game Starter](https://github.com/AkatsukiLabs/Dojo-Game-Starter/blob/main/client/src/dojo/bindings.ts) + +Let's explain each part: + +## Import and Core Types + +### Dojo SDK Schema Integration +```typescript +import type { SchemaType as ISchemaType } from "@dojoengine/sdk"; +``` + +**Purpose**: Imports the base schema type from Dojo SDK that provides the foundation for all model type definitions. + +**Gaming Integration**: This import ensures your game models integrate seamlessly with Dojo's entity system, enabling efficient querying and state management for game data. + +**Type Safety**: Provides the base structure that all your game model types extend, ensuring consistency across your entire game data layer. + +## Player Model Interfaces + +### Main Player Interface +```typescript +export interface Player { + owner: string; + experience: number; + health: number; + coins: number; + creation_day: number; +} +``` + +**Gaming Purpose**: Represents a complete player entity in your game with all identifying and gameplay-related information. + +**Field Breakdown**: +- `owner: string`: Player's wallet address - unique identifier linking blockchain account to game character +- `experience: number`: Player's accumulated experience points for progression and leveling systems +- `health: number`: Current player health status affecting ability to perform risky actions like mining +- `coins: number`: Player's in-game currency for purchasing items, upgrades, or game actions +- `creation_day: number`: Timestamp when player character was created for tracking player tenure + +**Cairo Mapping**: Directly corresponds to the `Player` struct in `full_starter_react::models::player::Player`. + +### Player Value Interface +```typescript +export interface PlayerValue { + experience: number; + health: number; + coins: number; + creation_day: number; +} +``` + +**Gaming Purpose**: Represents player data without the owner identifier, used for operations that only need the game stats. + +**Key Difference**: Missing `owner` field makes this interface ideal for: +- Displaying player stats in UI components +- Calculating stat changes before applying them +- Comparing player statistics across different players + +**Usage Pattern**: Often used in combination with separate owner/address tracking for efficient data handling. + +## Achievement System Interfaces + +### Trophy Creation Interface +```typescript +export interface TrophyCreation { + id: number; + hidden: boolean; + index: number; + points: number; + start: number; + end: number; + group: number; + icon: number; + title: number; + description: string; + tasks: Array; + data: string; +} +``` + +**Gaming Purpose**: Defines the complete structure for creating achievements and trophies in your game. + +**Achievement System Fields**: +- `id: number`: Unique identifier for the trophy/achievement +- `hidden: boolean`: Whether achievement is visible to players before completion (secret achievements) +- `index: number`: Display order or category placement for achievement organization +- `points: number`: Score value awarded to players for completing this achievement +- `start: number`: Timestamp when achievement becomes available to players +- `end: number`: Expiration timestamp for time-limited achievements +- `group: number`: Achievement category or group classification +- `icon: number`: Icon identifier for visual representation in achievement galleries +- `title: number`: Title identifier for localized achievement names +- `description: string`: Human-readable description of achievement requirements +- `tasks: Array`: List of tasks required to complete the achievement +- `data: string`: Additional metadata or configuration data for complex achievements + +### Trophy Creation Value Interface +```typescript +export interface TrophyCreationValue { + hidden: boolean; + index: number; + points: number; + start: number; + end: number; + group: number; + icon: number; + title: number; + description: string; + tasks: Array; + data: string; +} +``` + +**Gaming Purpose**: Trophy data without the ID field, used for achievement creation and modification operations. + +**Usage**: Perfect for achievement editors, admin panels, or dynamic achievement generation systems. + +### Trophy Progression Interface +```typescript +export interface TrophyProgression { + player_id: number; + task_id: number; + count: number; + time: number; +} +``` + +**Gaming Purpose**: Tracks individual player progress toward specific achievement tasks. + +**Progress Tracking Fields**: +- `player_id: number`: Links progress to specific player +- `task_id: number`: Identifies which achievement task is being tracked +- `count: number`: Current progress count toward task completion +- `time: number`: Timestamp of last progress update for time-based achievements + +### Trophy Progression Value Interface +```typescript +export interface TrophyProgressionValue { + count: number; + time: number; +} +``` + +**Gaming Purpose**: Progress data without player and task identifiers, used for progress updates and calculations. + +### Task Interface +```typescript +export interface Task { + id: number; + total: number; + description: string; +} +``` + +**Gaming Purpose**: Defines individual tasks that players must complete for achievements. + +**Task Structure**: +- `id: number`: Unique task identifier +- `total: number`: Required completion count (e.g., "Kill 100 monsters", "Mine 50 resources") +- `description: string`: Human-readable task description for player display + +## Schema Type Definition + +### Complete Schema Structure +```typescript +export interface SchemaType extends ISchemaType { + full_starter_react: { + Player: Player, + PlayerValue: PlayerValue, + }, + achievement: { + TrophyCreation: TrophyCreation, + TrophyCreationValue: TrophyCreationValue, + TrophyProgression: TrophyProgression, + TrophyProgressionValue: TrophyProgressionValue, + Task: Task, + }, +} +``` + +**Gaming Organization**: The schema is organized into logical game modules: + +#### `full_starter_react` Namespace +**Purpose**: Contains core game models related to player entities and basic gameplay mechanics. + +**Gaming Context**: Houses the fundamental player model that tracks character stats, progression, and identity. + +#### `achievement` Namespace +**Purpose**: Contains all achievement and trophy system models for player progression tracking. + +**Gaming Context**: Provides comprehensive achievement system with trophies, tasks, and progress tracking for player engagement and retention. + +**Namespace Benefits**: +- **Logical Separation**: Game mechanics are grouped by functionality +- **Scalability**: Easy to add new namespaces for additional game systems +- **Clarity**: Developers can quickly locate relevant models for specific game features + +## Schema Object Implementation + +### Default Values Configuration +```typescript +export const schema: SchemaType = { + full_starter_react: { + Player: { + owner: "", + experience: 0, + health: 0, + coins: 0, + creation_day: 0, + }, + PlayerValue: { + experience: 0, + health: 0, + coins: 0, + creation_day: 0, + }, + }, + achievement: { + TrophyCreation: { + id: 0, + hidden: false, + index: 0, + points: 0, + start: 0, + end: 0, + group: 0, + icon: 0, + title: 0, + description: "", + tasks: [{ id: 0, total: 0, description: "", }], + data: "", + }, + // ... other achievement models with defaults + } +}; +``` + +**Gaming Purpose**: Provides default values for all game models, ensuring consistent initialization and preventing undefined state errors. + +**Default Value Strategy**: +- **Numbers**: Default to `0` for stats, currencies, and counters +- **Strings**: Default to empty strings for text fields +- **Booleans**: Default to `false` for flags and toggles +- **Arrays**: Default to single empty element for required array fields + +**Gaming Benefits**: +- **Consistent Initialization**: New players start with predictable stats +- **Error Prevention**: Prevents null/undefined errors in game calculations +- **Development Safety**: Provides fallback values during development and testing + +## Models Mapping Enum + +### Entity Identification System +```typescript +export enum ModelsMapping { + Player = 'full_starter_react-Player', + PlayerValue = 'full_starter_react-PlayerValue', + TrophyCreation = 'achievement-TrophyCreation', + TrophyCreationValue = 'achievement-TrophyCreationValue', + TrophyProgression = 'achievement-TrophyProgression', + TrophyProgressionValue = 'achievement-TrophyProgressionValue', + Task = 'achievement-Task', +} +``` + +**Gaming Purpose**: Provides standardized entity identifiers for querying and managing game data across the Dojo system. + +**Naming Convention**: `{namespace}-{ModelName}` pattern ensures unique identification across all game modules. + +## Relationship with Cairo Models + +### Cairo Player Model +```cairo +// Cairo struct in full_starter_react::models::player +#[derive(Model, Copy, Drop, Serde)] +struct Player { + #[key] + owner: ContractAddress, + experience: u32, + health: u32, + coins: u32, + creation_day: u64, +} +``` + +### TypeScript Interface Mapping +```typescript +// Auto-generated TypeScript interface +export interface Player { + owner: string; // ContractAddress -> string + experience: number; // u32 -> number + health: number; // u32 -> number + coins: number; // u32 -> number + creation_day: number; // u64 -> number +} +``` + +**Type Conversion**: +- **ContractAddress** → **string**: Wallet addresses as hex strings +- **u32/u64** → **number**: Integer types for game statistics +- **Array** → **Array**: Direct array mapping for complex structures + +**Gaming Synchronization**: This direct mapping ensures that any changes to your Cairo game models automatically reflect in your TypeScript interfaces, maintaining perfect synchronization between onchain logic and frontend display. + +--- + +**Next**: While bindings.ts provides the structural foundation with TypeScript interfaces that define what your game data looks like (Player stats, achievements, game entities), [contracts.gen.ts](./contracts-bindings.md) complements this by defining what your game can actually do. Where bindings establish the "nouns" of your game (player health, experience, coins), contracts.gen.ts creates the "verbs" - the executable actions. + +*Together, these files create a complete type-safe bridge: bindings ensure your data structures stay synchronized between Cairo and TypeScript, while contracts.gen.ts transforms complex blockchain transactions into simple game function calls.* diff --git a/client-new/pages/guides/react/controller-connector.md b/client-new/pages/guides/react/controller-connector.md new file mode 100644 index 0000000..599349c --- /dev/null +++ b/client-new/pages/guides/react/controller-connector.md @@ -0,0 +1,375 @@ +# Controller Connector + +The `cartridgeConnector.tsx` file configures the Cartridge Controller integration for your Dojo game. This connector enables seamless wallet functionality specifically designed for gaming, eliminating transaction popups and providing session-based authentication that keeps players focused on gameplay rather than blockchain complexity. + +## File Overview & Purpose + +The `cartridgeConnector.tsx` file creates and configures a Cartridge Controller connector that serves as the bridge between your game interface and player wallets. Unlike traditional DeFi wallet connectors, this configuration prioritizes gaming user experience through: + +- **Session-Based Authentication**: Pre-approved game actions that don't require individual transaction confirmations. +- **Multi-Environment Support**: Automatic network switching between localhost, sepolia, and mainnet. +- **Dynamic Contract Resolution**: Automatically resolves contract addresses from your Dojo manifest. +- **Gaming-Optimized RPC**: Uses Cartridge's gaming-focused endpoints for better performance. + +This connector transforms blockchain interactions from a technical hurdle into a seamless gaming experience, allowing players to focus on strategy and fun rather than transaction management. + +## Complete Implementation + +```typescript +import { Connector } from "@starknet-react/core"; +import { ControllerConnector } from "@cartridge/connector"; +import { ControllerOptions } from "@cartridge/controller"; +import { constants } from "starknet"; +import { manifest } from "./manifest"; + +const { VITE_PUBLIC_DEPLOY_TYPE } = import.meta.env; + +console.log("VITE_PUBLIC_DEPLOY_TYPE", VITE_PUBLIC_DEPLOY_TYPE); + +const getRpcUrl = () => { + switch (VITE_PUBLIC_DEPLOY_TYPE) { + case "localhost": + return "http://localhost:5050"; // Katana localhost default port + case "mainnet": + return "https://api.cartridge.gg/x/starknet/mainnet"; + case "sepolia": + return "https://api.cartridge.gg/x/starknet/sepolia"; + default: + return "https://api.cartridge.gg/x/starknet/sepolia"; + } +}; + +const getDefaultChainId = () => { + switch (VITE_PUBLIC_DEPLOY_TYPE) { + case "localhost": + return "0x4b4154414e41"; // KATANA in ASCII + case "mainnet": + return constants.StarknetChainId.SN_MAIN; + case "sepolia": + return constants.StarknetChainId.SN_SEPOLIA; + default: + return constants.StarknetChainId.SN_SEPOLIA; + } +}; + +const getGameContractAddress = () => { + return manifest.contracts[0].address; +}; + +const CONTRACT_ADDRESS_GAME = getGameContractAddress(); +console.log("Using game contract address:", CONTRACT_ADDRESS_GAME); + +const policies = { + contracts: { + [CONTRACT_ADDRESS_GAME]: { + methods: [ + { name: "spawn_player", entrypoint: "spawn_player" }, + { name: "train", entrypoint: "train" }, + { name: "mine", entrypoint: "mine" }, + { name: "rest", entrypoint: "rest" }, + ], + }, + }, +}; + +const options: ControllerOptions = { + chains: [{ rpcUrl: getRpcUrl() }], + defaultChainId: getDefaultChainId(), + policies, + namespace: "full_starter_react", + slot: "full-starter-react", +}; + +const cartridgeConnector = new ControllerConnector( + options +) as never as Connector; + +export default cartridgeConnector; +``` + +## Imports and Dependencies + +### Starknet React Integration + +```typescript +import { Connector } from "@starknet-react/core"; +``` + +- **Purpose**: Base interface that allows the Cartridge Controller to integrate seamlessly with Starknet React's provider system. + +### Cartridge Controller Core + +```typescript +import { ControllerConnector } from "@cartridge/connector"; +import { ControllerOptions } from "@cartridge/controller"; +``` + +- **Components**: + - **ControllerConnector**: The main connector class that implements gaming-optimized wallet functionality. + - **ControllerOptions**: TypeScript interface for connector configuration. +- **Gaming Benefits**: These imports provide session management, transaction batching, and user-friendly interfaces designed specifically for gaming applications. + +### Starknet Constants + +```typescript +import { constants } from "starknet"; +``` + +- **Purpose**: Provides standardized chain identifiers for different Starknet networks. +- **Usage**: Ensures consistent network identification across localhost (Katana), sepolia testnet, and mainnet deployments. + +### Dojo Manifest Integration + +```typescript +import { manifest } from "./manifest"; +``` + +- **Purpose**: Imports your Dojo deployment manifest containing contract addresses and metadata. +- **Gaming Advantage**: Eliminates hardcoded addresses, allowing seamless deployment across different networks without code changes. + +## Environment Configuration + +### Environment Detection + +```typescript +const { VITE_PUBLIC_DEPLOY_TYPE } = import.meta.env; +console.log("VITE_PUBLIC_DEPLOY_TYPE", VITE_PUBLIC_DEPLOY_TYPE); +``` + +- **Gaming Deployment Strategy**: + - **localhost**: Rapid development with local Katana node. + - **sepolia**: Safe testing with real network conditions. + - **mainnet**: Production environment with real player assets. +- **Developer Experience**: The `console.log` helps debug deployment configuration during development. + +### RPC Provider Configuration + +```typescript +const getRpcUrl = () => { + switch (VITE_PUBLIC_DEPLOY_TYPE) { + case "localhost": + return "http://localhost:5050"; // Katana localhost default port + case "mainnet": + return "https://api.cartridge.gg/x/starknet/mainnet"; + case "sepolia": + return "https://api.cartridge.gg/x/starknet/sepolia"; + default: + return "https://api.cartridge.gg/x/starknet/sepolia"; + } +}; +``` + +- **Network-Specific Configuration**: + +| Environment | Endpoint | Gaming Purpose | +| ----------- | ------------------------------------------- | ---------------------------------------------- | +| localhost | http://localhost:5050 | Local Katana for rapid development and testing | +| mainnet | https://api.cartridge.gg/x/starknet/mainnet | Production gaming with real assets | +| sepolia | https://api.cartridge.gg/x/starknet/sepolia | Safe testing environment | +| default | Sepolia fallback | Prevents accidental mainnet usage | + +- **Why Cartridge RPC Endpoints?**: + - **Gaming Optimization**: Endpoints tuned for gaming transaction patterns and session management. + - **Reliability**: High uptime crucial for uninterrupted gaming experiences. + - **Performance**: Reduced latency for real-time game interactions. + +### Chain ID Configuration + +```typescript +const getDefaultChainId = () => { + switch (VITE_PUBLIC_DEPLOY_TYPE) { + case "localhost": + return "0x4b4154414e41"; // KATANA in ASCII + case "mainnet": + return constants.StarknetChainId.SN_MAIN; + case "sepolia": + return constants.StarknetChainId.SN_SEPOLIA; + default: + return constants.StarknetChainId.SN_SEPOLIA; + } +}; +``` + +- **Chain ID Mapping**: + + - **localhost**: "0x4b4154414e41" (ASCII encoding of "KATANA"). + - **mainnet**: `constants.StarknetChainId.SN_MAIN` (Official Starknet mainnet ID). + - **sepolia**: `constants.StarknetChainId.SN_SEPOLIA` (Official Starknet testnet ID). + +- **Gaming Benefits**: Automatic chain selection ensures players connect to the correct network without manual configuration, maintaining the seamless experience expected in modern games. + +## Contract Address Resolution + +### Dynamic Address Resolution + +```typescript +const getGameContractAddress = () => { + return manifest.contracts[0].address; +}; + +const CONTRACT_ADDRESS_GAME = getGameContractAddress(); +console.log("Using game contract address:", CONTRACT_ADDRESS_GAME); +``` + +- **Manifest Integration Benefits**: + + - **Deployment Flexibility**: Contract addresses automatically update when deploying to different networks. + - **No Hardcoding**: Eliminates the need to manually update addresses in code. + - **Environment Safety**: Prevents using wrong contract addresses across different deployments. + +- **Gaming Context**: Players interact with the correct game contract regardless of whether they're on localhost development, sepolia testing, or mainnet production. + +## Session Policies Configuration + +### Gaming-Focused Session Policies + +```typescript +const policies = { + contracts: { + [CONTRACT_ADDRESS_GAME]: { + methods: [ + { name: "spawn_player", entrypoint: "spawn_player" }, + { name: "train", entrypoint: "train" }, + { name: "mine", entrypoint: "mine" }, + { name: "rest", entrypoint: "rest" }, + ], + }, + }, +}; +``` + +- **What Are Session Policies?**: Session policies define which contract methods players can execute without individual transaction approval popups. This creates a traditional gaming experience where actions happen immediately. + +- **Gaming UX Benefits**: + + - **No Transaction Interruptions**: Players can train, mine, and rest without constant wallet popups. + - **Seamless Gameplay Flow**: Actions execute immediately, maintaining game immersion. + - **Traditional Game Feel**: Blockchain interactions become invisible to players. + +- **Method Breakdown**: + + - **spawn_player**: Create new player character (one-time setup). + - **train**: Improve player experience and skills. + - **mine**: Earn in-game currency with resource gathering. + - **rest**: Restore player health and energy. + +- **Adding New Game Actions**: + +```typescript +// To add new methods to session policies: +{ name: "craft_item", entrypoint: "craft_item" }, +{ name: "battle_monster", entrypoint: "battle_monster" }, +``` + +## Controller Options Configuration + +### Complete Options Setup + +```typescript +const options: ControllerOptions = { + chains: [{ rpcUrl: getRpcUrl() }], + defaultChainId: getDefaultChainId(), + policies, + namespace: "full_starter_react", + slot: "full-starter-react", +}; +``` + +- **Option Properties Breakdown**: + + - **chains**: `[{ rpcUrl: getRpcUrl() }]` + + - **Purpose**: Defines available blockchain networks with their RPC endpoints. + - **Gaming Implementation**: Automatically configures the appropriate network based on deployment environment, ensuring players connect to the correct game instance. + + - **defaultChainId**: `getDefaultChainId()` + + - **Purpose**: Sets the primary network for wallet connections. + - **Gaming Benefit**: Players automatically connect to the intended game network without manual network switching. + + - **policies** + + - **Purpose**: Defines pre-approved contract methods for seamless execution. + - **Gaming Impact**: Transforms blockchain interactions from technical obstacles into smooth gaming actions. + + - **namespace**: `"full_starter_react"` + + - **Purpose**: Unique identifier for your game application within the Cartridge ecosystem. + - **Requirements**: Must match your registered Cartridge application namespace for proper session management and policies. + + - **slot**: `"full-starter-react"` + - **Purpose**: Specific session identifier for isolating different game instances or versions. + - **Gaming Use Cases**: Allows running multiple game versions or environments with separate session policies. + +## Connector Instantiation + +### TypeScript Integration + +```typescript +const cartridgeConnector = new ControllerConnector( + options +) as never as Connector; +``` + +- **Technical Explanation**: The `as never as Connector` casting ensures TypeScript compatibility between Cartridge's `ControllerConnector` and Starknet React's `Connector` interface. +- **Why This Casting?**: Different package versions may have slight interface differences, and this casting guarantees compatibility while maintaining full functionality. +- **Gaming Result**: Your game can use standard Starknet React hooks while benefiting from Cartridge's gaming-specific features. + +## Integration with StarknetProvider + +### Provider Usage + +```jsx +// In your StarknetProvider configuration + + {children} + +``` + +- **Gaming Flow**: The connector integrates seamlessly with your StarknetProvider, enabling gaming-optimized wallet functionality throughout your application. + +## Environment Setup Examples + +### Development Configuration + +```plaintext +# .env.development +VITE_PUBLIC_DEPLOY_TYPE=localhost +``` + +### Testing Configuration + +```plaintext +# .env.staging +VITE_PUBLIC_DEPLOY_TYPE=sepolia +``` + +### Production Configuration + +```plaintext +# .env.production +VITE_PUBLIC_DEPLOY_TYPE=mainnet +``` + +# Gaming Benefits Summary + +## For Players: + +- **No Transaction Popups**: Enjoy uninterrupted gameplay without transaction confirmation popups. +- **Automatic Network Connection**: Seamlessly connect to the correct game environment based on your deployment. +- **Traditional Gaming Experience**: Experience the benefits of blockchain technology while enjoying a familiar gaming interface. + +## For Developers: + +- **Environment-Based Deployment**: Deploy your game across different environments without needing to change the code. +- **Dynamic Contract Address Resolution**: Automatically resolve contract addresses from the manifest, eliminating hardcoded values. +- **Gaming-Optimized RPC Endpoints**: Benefit from RPC endpoints designed specifically for gaming, ensuring better performance. + +## For Game Operations: + +- **Session-Based Policies**: Reduce player friction by allowing pre-approved actions without constant confirmations. +- **Automatic Environment Detection**: Prevent deployment errors with automatic detection of the current environment. +- **Reliable Performance**: Leverage Cartridge's gaming infrastructure to ensure consistent and reliable game performance. diff --git a/client-new/pages/guides/react/dojo-config.md b/client-new/pages/guides/react/dojo-config.md new file mode 100644 index 0000000..633d67b --- /dev/null +++ b/client-new/pages/guides/react/dojo-config.md @@ -0,0 +1,122 @@ +# React Integration - Dojo Config + +The `dojoConfig.ts` file is the main configuration point that connects the React game frontend to our Dojo onchain gaming infrastructure. It establishes the connection between client side and the blockchain where your game state lives. + +## 📁 File Structure + +```typescript +// src/dojo/dojoConfig.ts +import { createDojoConfig } from "@dojoengine/core"; +import { manifest } from "../config/manifest"; + +const { + VITE_PUBLIC_NODE_URL, + VITE_PUBLIC_TORII, + VITE_PUBLIC_MASTER_ADDRESS, + VITE_PUBLIC_MASTER_PRIVATE_KEY, +} = import.meta.env; + +export const dojoConfig = createDojoConfig({ + manifest, + masterAddress: VITE_PUBLIC_MASTER_ADDRESS || '', + masterPrivateKey: VITE_PUBLIC_MASTER_PRIVATE_KEY || '', + rpcUrl: VITE_PUBLIC_NODE_URL || '', + toriiUrl: VITE_PUBLIC_TORII || '', +}); +``` + +## 🎮 Gaming Context + +In a Dojo game, your game state lives onchain as ECS (Entity Component System) data. The `dojoConfig` tells your React app: +- **Where to find the blockchain** (via RPC) +- **Where to query game data efficiently** (via Torii indexer) +- **Which game world to connect to** (via manifest) +- **How to submit game actions** (via master account in development) + +## 🔧 Configuration Parameters + +### `manifest` +The game's deployed contract information contains the: +- **World address**: The onchain location of your game world +- **Contract addresses**: Where your game systems (move, attack, craft, etc.) are deployed +- **Component schemas**: The structure of your game entities (Player, Position, Health, etc.) + +### `rpcUrl` (VITE_PUBLIC_NODE_URL) +The Starknet RPC endpoint for blockchain interactions: +- **Local development**: `http://localhost:5050` (Katana) +- **Testnet**: `https://api.cartridge.gg/x/starknet/sepolia` +- **Mainnet**: `https://api.cartridge.gg/x/starknet/mainnet` + +### `toriiUrl` (VITE_PUBLIC_TORII) +The Torii GraphQL indexer for fast game data queries: +- **Purpose**: Query game state without waiting for blockchain sync +- **Example queries**: "Get all players in this dungeon", "Show leaderboard", "Fetch my inventory" +- **Local development**: `http://localhost:8080/graphql` + +### `masterAddress` & `masterPrivateKey` +Development-only admin account for game actions: +- **Development**: Used for testing game mechanics +- **Production**: Should be empty strings for security +- **Purpose**: Submit transactions on behalf of players during development + +## 🌍 Environment Setup + +### Local Development (.env.local) +```bash +VITE_PUBLIC_NODE_URL=http://localhost:5050 +VITE_PUBLIC_TORII=http://localhost:8080/graphql +VITE_PUBLIC_MASTER_ADDRESS=0x123...abc +VITE_PUBLIC_MASTER_PRIVATE_KEY=0x456...def +``` + +### Testnet (.env.local) +```bash +VITE_PUBLIC_NODE_URL=https://api.cartridge.gg/x/starknet/sepolia +VITE_PUBLIC_TORII=https://api.cartridge.gg/x/your-game/torii/graphql +VITE_PUBLIC_MASTER_ADDRESS=0x123...abc +VITE_PUBLIC_MASTER_PRIVATE_KEY=0x456...def +``` + +### Production (.env.production) +```bash +VITE_PUBLIC_NODE_URL=https://api.cartridge.gg/x/starknet/mainnet +VITE_PUBLIC_TORII=https://api.cartridge.gg/x/your-game/torii/graphql +VITE_PUBLIC_MASTER_ADDRESS= +VITE_PUBLIC_MASTER_PRIVATE_KEY= +``` + +## 🔒 Security for Game Deployment + +```typescript +// ✅ Production-safe game configuration +export const dojoConfig = createDojoConfig({ + manifest, + masterAddress: '', // Never include in production games + masterPrivateKey: '', // Never include in production games + rpcUrl: VITE_PUBLIC_NODE_URL || 'https://api.cartridge.gg/x/starknet/mainnet', + toriiUrl: VITE_PUBLIC_TORII || 'https://api.cartridge.gg/x/your-game/torii/graphql', +}); +``` + +## 🎯 Common Game Setup Issues + +**"Can't connect to game world"** +- Check `VITE_PUBLIC_NODE_URL` is accessible +- Verify your game contracts are deployed to the target network +- Ensure `manifest.world.address` exists + +**"Game state not loading"** +- Confirm `VITE_PUBLIC_TORII` URL is correct +- Check if Torii indexer is running and synced +- Verify Torii is indexing your specific game world + +**"Transactions failing"** +- Ensure wallet is connected to same network as `VITE_PUBLIC_NODE_URL` +- Check if game contracts have proper permissions +- Verify account has sufficient tokens for gas + +--- + +This configuration connects the React game client to the Dojo onchain gaming infrastructure, allowing real-time multiplayer gameplay with persistent blockchain state. + +**Next**: While dojoConfig establishes how your React frontend connects to the Dojo infrastructure, the [Manifest](./manifest.md) handles the critical "where" question - determining which deployed contract addresses your app should use based on the current network environment. diff --git a/client-new/pages/guides/react/main.md b/client-new/pages/guides/react/main.md new file mode 100644 index 0000000..fbfbb87 --- /dev/null +++ b/client-new/pages/guides/react/main.md @@ -0,0 +1,248 @@ +# Dojo React Application Initialization: `main.tsx` + +This document provides a comprehensive guide to the `main.tsx` file, which serves as the entry point for a Dojo React application. It outlines the bootstrap process, Dojo SDK initialization, provider hierarchy setup, error handling, and integration with configuration files to create a production-ready onchain game application. + +## File Overview & Application Bootstrap + +The `main.tsx` file is the primary entry point for a Dojo React application. It orchestrates the initialization of the Dojo SDK, sets up the React provider hierarchy, and renders the main `App` component. This file coordinates all configuration pieces to ensure the application is properly initialized with Dojo's onchain capabilities and Starknet integration. + +The bootstrap process is asynchronous due to the need to initialize the Dojo SDK, which connects to the Torii indexer and the world contract. This async pattern ensures that the application only renders once all dependencies are correctly set up, providing a robust foundation for onchain game functionality. + +## Imports and Dependencies + +The `main.tsx` file imports several dependencies, each serving a specific role in the Dojo React ecosystem. These imports are grouped by their purpose: + +### React Core + +```typescript +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +``` + +- `StrictMode`: Enables React 18's strict mode, which provides development-time checks to identify potential issues in the application, such as unsafe lifecycle methods or legacy APIs. +- `createRoot`: The React 18 API for creating a root rendering context, used to mount the application to the DOM. + +### Dojo SDK and Configuration + +```typescript +import { init } from "@dojoengine/sdk"; +import { DojoSdkProvider } from "@dojoengine/sdk/react"; +import { dojoConfig } from "./dojo/dojoConfig"; +import type { SchemaType } from "./dojo/bindings"; +import { setupWorld } from "./dojo/contracts.gen"; +``` + +- `init`: The Dojo SDK initialization function, responsible for connecting to the Torii indexer and world contract. +- `DojoSdkProvider`: A React provider component that makes the initialized Dojo SDK available to the application via React context. +- `dojoConfig`: A configuration object containing settings like the Torii URL and world contract address, imported from `dojo/dojoConfig.ts`. +- `SchemaType`: A TypeScript type defining the schema for type-safe interactions with the Dojo SDK, imported from `dojo/bindings.ts`. +- `setupWorld`: A generated function from `dojo/contracts.gen.ts` that sets up contract bindings for interacting with the onchain world. + +### Starknet Integration + +```typescript +import StarknetProvider from "./dojo/starknet-provider"; +``` + +- `StarknetProvider`: A custom provider component that handles wallet connectivity and Starknet network configuration, ensuring seamless integration with the Starknet blockchain. + +### Application Entry + +```typescript +import App from "./app/app"; +import "./index.css"; +``` + +- `App`: The main application component, which serves as the root of the React component tree. +- `index.css`: Global CSS styles for the application. + +### Dependency Relationships + +- The React core imports (`StrictMode`, `createRoot`) provide the foundation for rendering the application. +- The Dojo SDK imports (`init`, `DojoSdkProvider`, `dojoConfig`, `SchemaType`, `setupWorld`) work together to initialize and integrate Dojo's onchain capabilities. +- The `StarknetProvider` bridges the application with the Starknet blockchain, enabling wallet interactions. +- The `App` component relies on the providers to access Dojo and Starknet functionality, while `index.css` ensures consistent styling. + +## Dojo SDK Initialization + +The Dojo SDK is initialized within an async `main` function using the `init` function from `@dojoengine/sdk`: + +```typescript +const sdk = await init({ + client: { + toriiUrl: dojoConfig.toriiUrl, + worldAddress: dojoConfig.manifest.world.address, + }, + domain: { + name: "DojoGameStarter", + version: "1.0", + chainId: "KATANA", + revision: "1", + }, +}); +``` + +### Key Components + +- `init`: The `init` function is generic, using `SchemaType` to ensure type-safe interactions with the Dojo SDK. It initializes the SDK by connecting to the Torii indexer and the world contract. +- **Configuration**: + - `client`: Specifies the connection details for the Torii indexer (`toriiUrl`) and the world contract (`worldAddress`), sourced from `dojoConfig`. + - `domain`: Defines application metadata for session management, including the application name, version, chain ID (e.g., "KATANA" for Starknet's testnet), and revision number. +- **Async Nature**: The `init` function is asynchronous because it involves network operations to connect to the Torii indexer and world contract. The `await` keyword ensures that the SDK is fully initialized before proceeding with rendering. + +### Role of `dojoConfig` + +The `dojoConfig` object, imported from `dojo/dojoConfig.ts`, provides critical configuration values such as `toriiUrl` and `manifest.world.address`. These values are used to establish connections to the Dojo infrastructure, ensuring the application can interact with the onchain world. + +## Provider Hierarchy Setup + +The application is rendered with a nested provider hierarchy to ensure that all components have access to Dojo and Starknet functionality: + +```typescript +createRoot(rootElement).render( + + + + + + + +); +``` + +### Provider Nesting Order + +The order of providers is critical for proper data flow and functionality: + +1. `StrictMode`: Wraps the entire application to enable React's development-time checks, ensuring best practices and identifying potential issues. +2. `DojoSdkProvider`: Provides the initialized Dojo SDK, configuration, and contract bindings to the component tree via React context. +3. `StarknetProvider`: Manages wallet connectivity and Starknet network configuration, enabling blockchain interactions. +4. `App`: The main application component, which consumes the Dojo and Starknet contexts to implement game logic. + +### Provider Props + +- `DojoSdkProvider`: + - `sdk`: The initialized Dojo SDK instance, providing access to onchain functionality. + - `dojoConfig`: The configuration object, used for SDK operations and contract interactions. + - `clientFn`: The `setupWorld` function, which provides contract bindings for interacting with the onchain world. +- `StarknetProvider`: Configures wallet and network connectivity, typically requiring no additional props in this context. + +### Data Flow + +The `DojoSdkProvider` makes the SDK and configuration available to all child components, while the `StarknetProvider` ensures wallet and network data are accessible. The `App` component, nested within both providers, can access these contexts to implement game features, such as querying the world contract or performing transactions. + +## Error Handling and Fallback UI + +The `main.tsx` file includes robust error handling to manage initialization failures: + +```typescript +} catch (error) { + console.error("❌ Failed to initialize Dojo:", error); + + const rootElement = document.getElementById("root"); + if (rootElement) { + createRoot(rootElement).render( + +
+
+

⚠️ Dojo Initialization Error

+

Failed to connect to Dojo SDK

+
+ Error Details: +
+                {error instanceof Error ? error.message : String(error)}
+              
+
+

+ Check your Dojo configuration and network connection +

+
+
+
+ ); + } +} + +``` + +### Error Handling Strategy + +- **Try-Catch Block**: The async `main` function wraps the initialization and rendering logic in a `try-catch` block to catch any errors during Dojo SDK initialization or DOM rendering. +- **Console Logging**: Errors are logged with `console.error` for debugging, prefixed with "❌ Failed to initialize Dojo:" for clarity. +- **Fallback UI**: If initialization fails, a user-friendly error UI is rendered, featuring: + - A prominent error message ("Dojo Initialization Error"). + - A details section with the error message, collapsible via a `
` element for debugging. + - A suggestion to check the Dojo configuration and network connection. +- **Root Element Check**: The code verifies the existence of the DOM root element before rendering, preventing runtime errors. + +### Why Initialization Might Fail + +Initialization failures can occur due to: + +- Network issues preventing connection to the Torii indexer. +- Incorrect `dojoConfig` values (e.g., invalid `toriiUrl` or `worldAddress`). +- Contract deployment issues on the Starknet network. +- Schema mismatches in `SchemaType`. + +### Production vs. Development + +- In development, the detailed error UI with stack traces aids debugging. +- In production, the error UI provides minimal information to users while logging detailed errors for developers to investigate. + +## Main Function Pattern + +The `main.tsx` file uses an async `main` function to wrap up (encapsulate) the bootstrap process: + +```typescript +async function main() { + try { + console.log("🚀 Initializing Dojo SDK..."); + // Initialization logic + console.log("✅ Dojo SDK initialized successfully"); + } catch (error) { + // Error handling + } +} +main(); +``` + +### Benefits of the Async Main Function + +- **Async Initialization**: The `async` keyword allows the function to handle the asynchronous nature of Dojo SDK initialization, ensuring proper sequencing of operations. +- **Error Boundary**: The `try-catch` block centralizes error handling, making the code more maintainable. +- **Logging Strategy**: Console logs (`🚀` for start, `✅` for success) provide clear debugging checkpoints during initialization. +- **Immediate Execution**: The `main()` call at the end of the file triggers the bootstrap process as soon as the script is loaded. + +### Error Boundary Considerations + +The `main` function serves as the primary error boundary for initialization. If an error occurs, the fallback UI ensures the application remains usable, even though Dojo functionality is unavailable, preventing a complete failure. + +## Integration Points + +The `main.tsx` file integrates with several configuration files to create a cohesive Dojo React application: + +- `dojoConfig.ts`: Provides the `dojoConfig` object, which supplies critical configuration data such as `toriiUrl` and `manifest.world.address` for SDK initialization. +- `bindings.ts`: Defines the `SchemaType` type, ensuring type-safe interactions with the Dojo SDK. +- `contracts.gen.ts`: Supplies the `setupWorld` function, which provides contract bindings for onchain interactions. +- `starknet-provider.tsx`: Implements the `StarknetProvider` component, handling wallet connectivity and network configuration. +- `app.tsx`: The main `App` component, which consumes the Dojo and Starknet contexts to implement game logic. + +### Data Flow + +1. **Configuration**: `dojoConfig` provides connection details and metadata. +2. **SDK Initialization**: The `init` function uses `dojoConfig` and `SchemaType` to create the SDK instance. +3. **Contract Bindings**: The `setupWorld` function integrates contract bindings into the SDK. +4. **Provider Setup**: The `DojoSdkProvider` and `StarknetProvider` make the SDK and wallet functionality available to the `App` component. +5. **Application Rendering**: The `App` component uses the provided contexts to implement onchain game features. + +## Initialization Flow Summary + +1. **Import Dependencies**: All necessary modules are imported, including React, Dojo SDK, Starknet, and application components. +2. **Initialize Dojo SDK**: The `init` function connects to the Torii indexer and world contract using `dojoConfig` and `SchemaType`. +3. **Setup Provider Hierarchy**: The `DojoSdkProvider` and `StarknetProvider` are nested to provide SDK and wallet functionality to the `App` component. +4. **Render Application**: The `createRoot` API mounts the application to the DOM, wrapped in `StrictMode`. +5. **Handle Errors**: A fallback UI is rendered if initialization fails, with detailed error information for debugging. + +## Conclusion + +The `main.tsx` file is the cornerstone of a Dojo React application's initialization process. It orchestrates the setup of the Dojo SDK, provider hierarchy, and error handling to create a robust, production-ready onchain game application. By following the patterns outlined in this document, developers can understand and implement a complete Dojo React application bootstrap process, ensuring seamless integration with Starknet and Dojo's onchain infrastructure. diff --git a/client-new/pages/guides/react/manifest.md b/client-new/pages/guides/react/manifest.md new file mode 100644 index 0000000..bf488c7 --- /dev/null +++ b/client-new/pages/guides/react/manifest.md @@ -0,0 +1,237 @@ +# React Integration - Manifest + +The `manifest.ts` file handles deployment-specific contract information across different networks in your Dojo game. It automatically switches between local development, testnet, and mainnet environments while providing sensible fallbacks for multi-network support. + +## 📁 File Structure + +```typescript +// src/config/manifest.ts +import localhost from "../../../contract/manifest_dev.json"; // local development manifest +import sepolia from "./manifest_sepolia.json"; // sepolia manifest +import mainnet from "./manifest_sepolia.json"; // change for the right mainnet manifest +import slot from "./manifest_sepolia.json"; // change for the right slot manifest + +// Define valid deploy types +type DeployType = keyof typeof manifests; + +// Create the manifests object +const manifests = { + localhost, + mainnet, + sepolia, + slot, +}; + +// Get deployment type from environment with fallback +const deployType = import.meta.env.VITE_PUBLIC_DEPLOY_TYPE as string; + +// Export the appropriate manifest with a fallback +export const manifest = deployType in manifests + ? manifests[deployType as DeployType] + : sepolia; + +export type Manifest = typeof manifest; +``` + +## 🎮 Gaming Context + +In a Dojo game, your contracts live onchain and need to be accessible from your React app. The `manifest.ts` file tells your game frontend: +- **Which game world to connect to** (via world address from deployment) +- **Where your game systems are deployed** (spawn_player, train, mine, rest, etc.) +- **How to structure your game data** (Player models, achievement events) +- **Which network environment you're targeting** (local, testnet, mainnet) + +When you deploy with Dojo, the system generates manifest files containing all the contract addresses and schemas your frontend needs. The manifest system automatically selects the right deployment data based on your environment. + +## 🔧 Manifest Sources and Networks + +### `localhost` - Local Development +```typescript +import localhost from "../../../contract/manifest_dev.json"; +``` +Your local Katana deployment manifest, automatically generated when you run contracts locally. +- **Generated by**: Dojo deployment in local development +- **Contains**: Local contract addresses (game system at `0x19d9e6b...`) +- **Network**: Katana (localhost:5050) +- **Game Systems**: All game functions (spawn_player, train, mine, rest) + +### `sepolia` - Testnet Deployment +```typescript +import sepolia from "./manifest_sepolia.json"; +``` +Sepolia testnet deployment with free testnet tokens for safe testing. +- **Purpose**: Safe testing environment before mainnet +- **Network**: Sepolia testnet +- **Default fallback**: Used when environment is invalid or missing +- **Game Contract**: Deployed at `0x31b119987...` on Sepolia + +### `mainnet` - Production Deployment +```typescript +import mainnet from "./manifest_sepolia.json"; // change for the right mainnet manifest +``` +**⚠️ Currently using sepolia placeholder** - update with actual mainnet manifest for production. +- **Network**: Starknet mainnet +- **Security**: Real assets and gameplay value at stake + +### `slot` - Slot Deployment +```typescript +import slot from "./manifest_sepolia.json"; // change for the right slot manifest +``` +**⚠️ Currently using sepolia placeholder** - update with actual slot manifest when deploying. +- **Purpose**: Specialized deployment environment for Slot infrastructure + +## 🏗️ Manifest Structure + +Each manifest contains complete deployment information: + +```json +{ + "world": { + "address": "0x11097187dc00f79265f35e73ba674b792624f77dfa239e381dfc6744e1c8265", + "class_hash": "0x4c60dc46a8ca8bb47675b7b914053cef769afbf0e340523187336b72bd71d1f", + "name": "Full-Starter-React" + }, + "contracts": [ + { + "address": "0x19d9e6beac2177d4f48014861f4eead47192b9c450431cf31908f5359f49562", + "systems": ["spawn_player", "train", "mine", "rest", "upgrade"] + } + ] +} +``` + +**Key Information**: +- **World Address**: Central registry for your game world +- **Contract Addresses**: Where game systems are deployed +- **System Functions**: Available game actions (train, mine, rest) +- **Class Hashes**: Contract implementation references + +## 🌍 Environment-Based Selection + +### Type Safety with DeployType +```typescript +type DeployType = keyof typeof manifests; +``` +Creates a union type `"localhost" | "mainnet" | "sepolia" | "slot"` ensuring only valid deployment types can be used. TypeScript will catch typos and invalid environment configurations at compile time. + +### Manifest Object Structure +```typescript +const manifests = { + localhost, + mainnet, + sepolia, + slot, +}; +``` +Centralizes all deployment configurations in one place. Keys match `VITE_PUBLIC_DEPLOY_TYPE` values for direct environment-based selection. + +### Smart Environment Selection +```typescript +const deployType = import.meta.env.VITE_PUBLIC_DEPLOY_TYPE as string; + +export const manifest = deployType in manifests + ? manifests[deployType as DeployType] + : sepolia; +``` + +**Selection Logic**: +1. Reads `VITE_PUBLIC_DEPLOY_TYPE` from environment +2. Checks if the value matches a valid manifest key +3. Uses the matching manifest or falls back to sepolia for safety + +**Fallback Strategy**: Defaults to sepolia testnet when: +- Environment variable is missing +- Environment variable has invalid value +- Build process doesn't include environment configuration + +## 🔄 Integration with Other Files + +### Dojo Configuration +The manifest feeds directly into your Dojo config: + +```typescript +// dojoConfig.ts +import { manifest } from "../config/manifest"; + +export const dojoConfig = createDojoConfig({ + manifest, // World address and contract data from deployment + masterAddress: VITE_PUBLIC_MASTER_ADDRESS || '', + masterPrivateKey: VITE_PUBLIC_MASTER_PRIVATE_KEY || '', + rpcUrl: VITE_PUBLIC_NODE_URL || '', + toriiUrl: VITE_PUBLIC_TORII || '', +}); +``` + +### Contract Functions (setupWorld) +Your auto-generated contract functions use manifest data through the Dojo provider: + +```typescript +// contracts.gen.ts +export function setupWorld(provider: DojoProvider) { + const game_train = async (snAccount: Account | AccountInterface) => { + return await provider.execute( + snAccount, + { contractName: "game", entrypoint: "train", calldata: [] }, + "full_starter_react" + ); + }; + + return { + game: { + train: game_train, + mine: game_mine, + rest: game_rest, + spawnPlayer: game_spawnPlayer, + }, + }; +} +``` + +### Cartridge Connector Integration +The manifest provides contract addresses for wallet session policies: + +```typescript +// cartridgeConnector.tsx +const getGameContractAddress = () => { + return manifest.contracts[0].address; // Gets first contract address +}; + +const CONTRACT_ADDRESS_GAME = getGameContractAddress(); + +const policies = { + contracts: { + [CONTRACT_ADDRESS_GAME]: { + methods: [ + { name: "spawn_player", entrypoint: "spawn_player" }, + { name: "train", entrypoint: "train" }, + { name: "mine", entrypoint: "mine" }, + { name: "rest", entrypoint: "rest" }, + ], + }, + }, +}; +``` + +### Main Application Bootstrap +The manifest world address is used in SDK initialization: + +```typescript +// main.tsx +const sdk = await init({ + client: { + toriiUrl: dojoConfig.toriiUrl, + worldAddress: dojoConfig.manifest.world.address, // From manifest + }, + domain: { + name: "DojoGameStarter", + version: "1.0", + chainId: "KATANA", + revision: "1", + }, +}); +``` +The manifest system provides automatic network switching without code changes, enabling smooth development-to-production workflows while maintaining type safety and preventing common deployment mistakes. + +--- + +**Next**: Once the manifest.ts configuration resolves the correct network deployments, the [Main](./main.md) file serves as the orchestration layer that brings everything together. This file takes the manifest's deployment information and dojoConfig settings to initialize the Dojo SDK, establish the React provider hierarchy, and bootstrap the entire onchain game application. diff --git a/client-new/pages/guides/react/overview.md b/client-new/pages/guides/react/overview.md new file mode 100644 index 0000000..3aa8098 --- /dev/null +++ b/client-new/pages/guides/react/overview.md @@ -0,0 +1,58 @@ +# React Integration Overview + +Welcome to the React integration section of Dojo By Example! This comprehensive guide will walk you through building production-ready onchain games using React and the Dojo framework. + +## What You'll Learn + +This section covers everything needed to integrate Dojo with React applications, from initial setup to advanced patterns. You'll discover how to build seamless gaming experiences that feel like traditional web apps while leveraging the power of blockchain technology. + +### 🏗️ **Core Architecture** + +Learn how Dojo's architecture enables smooth React integration: + +- **Main Setup** - Bootstrap your React app with proper Dojo SDK initialization +- **Provider Configuration** - Set up the provider hierarchy for Starknet and Dojo connectivity +- **Configuration Management** - Handle multi-network deployments with environment-based switching + +### 🔌 **Auto-Generated Bindings** + +Discover how Dojo automatically creates TypeScript interfaces from your Cairo contracts: + +- **Models Bindings** - Type-safe interfaces for your game entities and data structures +- **Contracts Bindings** - Auto-generated client functions for seamless contract interactions + +### 🎮 **Gaming-First UX** + +Implement controller integration that prioritizes player experience: + +- **Controller Connector** - Cartridge Controller integration for frictionless gaming +- **Session Policies** - Enable uninterrupted gameplay without transaction popups +- **Manifest Management** - Handle deployment configurations across different networks + +## Key Benefits + +**⚡ Type Safety** - Full TypeScript integration from Cairo contracts to React components + +**🎯 Gaming UX** - Controller integration designed specifically for gaming applications + +**🔄 Auto-Generation** - Contract changes automatically update your frontend types + +**🌐 Multi-Network** - Seamless switching between localhost, testnet, and mainnet + +**🏗️ Production Ready** - Patterns and configurations tested in real gaming applications + +## Getting Started + +Each section builds upon the previous one, so we recommend following them in order: + +1. **Overview** (you are here) - Understanding the integration landscape +2. **Main Setup** - Application initialization and bootstrap process +3. **Configuration** - Core configuration files and environment management +4. **Providers** - Starknet and wallet connectivity setup +5. **Data Bindings** - Working with auto-generated types and contract functions + +By the end of this section, you'll have a complete understanding of how to build robust, type-safe React applications that integrate seamlessly with Dojo smart contracts, providing players with an exceptional gaming experience. + +--- + +*Ready to dive in? Let's start with [Main Setup](/integrations/react/main) to see how it all comes together!* diff --git a/client-new/pages/guides/react/starknet-provider.md b/client-new/pages/guides/react/starknet-provider.md new file mode 100644 index 0000000..dd6ffb5 --- /dev/null +++ b/client-new/pages/guides/react/starknet-provider.md @@ -0,0 +1,300 @@ +# React Integration - Starknet Provider + +The **StarknetProvider.tsx** file is a crucial configuration component that establishes the connection between your Dojo game and the Starknet blockchain. This provider wrapper acts as the foundation for all blockchain interactions in your React application, coordinating wallet connections, network configurations, and RPC providers for seamless gaming experiences. + +## File Overview & Purpose + +The `StarknetProvider.tsx` file serves as the central configuration hub for Starknet React integration in Dojo games. It wraps your entire application with the necessary context providers that enable: + +- **Blockchain Connectivity**: Establishes connections to Starknet networks (mainnet, sepolia) +- **Gaming-Optimized Wallet Integration**: Configures Cartridge Controller for frictionless gaming UX +- **Environment-Based Network Management**: Handles automatic switching between different blockchain networks +- **Session Continuity**: Provides React context for persistent blockchain state throughout your game + +> **Gaming-First Design**: Unlike traditional DeFi applications, this provider is specifically optimized for gaming experiences, prioritizing fast transactions, session management, and user-friendly wallet interactions that don't interrupt gameplay flow. + +## Complete Implementation + +```typescript +import type { PropsWithChildren } from "react"; +import { sepolia, mainnet } from "@starknet-react/chains"; +import { + jsonRpcProvider, + StarknetConfig, + starkscan, +} from "@starknet-react/core"; +import cartridgeConnector from "../config/cartridgeConnector"; + +export default function StarknetProvider({ children }: PropsWithChildren) { + const { VITE_PUBLIC_DEPLOY_TYPE } = import.meta.env; + + // Get RPC URL based on environment + const getRpcUrl = () => { + switch (VITE_PUBLIC_DEPLOY_TYPE) { + case "mainnet": + return "https://api.cartridge.gg/x/starknet/mainnet"; + case "sepolia": + return "https://api.cartridge.gg/x/starknet/sepolia"; + default: + return "https://api.cartridge.gg/x/starknet/sepolia"; + } + }; + + // Create provider with the correct RPC URL + const provider = jsonRpcProvider({ + rpc: () => ({ nodeUrl: getRpcUrl() }), + }); + + // Determine which chain to use + const chains = VITE_PUBLIC_DEPLOY_TYPE === "mainnet" + ? [mainnet] + : [sepolia]; + + return ( + + {children} + + ); +} +``` + +## Imports and Dependencies + +### Core React Types +```typescript +import type { PropsWithChildren } from "react"; +``` + +**Purpose**: Provides TypeScript types for React components that accept children elements. + +**Gaming Context**: Enables the provider to wrap any React component tree with proper type safety, ensuring your entire game interface has access to blockchain functionality. + +### Starknet React Chains +```typescript +import { sepolia, mainnet } from "@starknet-react/chains"; +``` + +**Purpose**: Pre-configured chain objects containing network-specific settings for Starknet networks. + +**Gaming Benefits**: +- `sepolia`: Testnet perfect for game development and testing without real asset risk +- `mainnet`: Production network where players interact with real assets and achievements +- Each chain includes optimized RPC endpoints and network identifiers for gaming applications + +### Starknet React Core +```typescript +import { + jsonRpcProvider, + StarknetConfig, + starkscan, +} from "@starknet-react/core"; +``` + +**Component Breakdown**: +- `jsonRpcProvider`: Creates RPC providers optimized for gaming transaction patterns +- `StarknetConfig`: Main configuration wrapper that enables gaming-focused blockchain integration +- `starkscan`: Block explorer integration for players to view their game transactions and achievements + +### Gaming-Optimized Connector +```typescript +import cartridgeConnector from "../config/cartridgeConnector"; +``` + +**Purpose**: Imports the Cartridge Controller connector specifically designed for gaming applications. + +**Gaming Advantages**: Cartridge Controller provides session-based wallet management, eliminating the need for players to sign every transaction during gameplay, creating a smooth gaming experience similar to traditional games. + +## Component Structure and Props + +### Function Signature +```typescript +export default function StarknetProvider({ children }: PropsWithChildren) +``` + +**Gaming Pattern**: This follows the standard React provider pattern, allowing any game component (menus, gameplay interfaces, inventory systems) to access blockchain functionality seamlessly. + +**Typical Game Usage**: +```typescript + + + + + +``` + +## Environment Configuration + +### Environment-Based Network Targeting +```typescript +const { VITE_PUBLIC_DEPLOY_TYPE } = import.meta.env; +``` + +**Gaming Deployment Strategy**: +- **Development**: Uses sepolia testnet for safe game testing +- **Production**: Switches to mainnet for live gaming with real assets +- **Automatic Detection**: No manual network switching required for players + +**Environment Setup for Game Development**: + +```bash +# .env.development - Safe testing environment +VITE_PUBLIC_DEPLOY_TYPE=sepolia + +# .env.production - Live gaming environment +VITE_PUBLIC_DEPLOY_TYPE=mainnet +``` + +## RPC Provider Configuration + +### Gaming-Optimized RPC Selection +```typescript +const getRpcUrl = () => { + switch (VITE_PUBLIC_DEPLOY_TYPE) { + case "mainnet": + return "https://api.cartridge.gg/x/starknet/mainnet"; + case "sepolia": + return "https://api.cartridge.gg/x/starknet/sepolia"; + default: + return "https://api.cartridge.gg/x/starknet/sepolia"; + } +}; +``` + +**Why Cartridge RPC Endpoints?**: +- **Gaming Optimization**: Specifically tuned for game transaction patterns and session management +- **High Performance**: Reduced latency for real-time gaming interactions +- **Reliability**: Built for gaming applications that require consistent uptime +- **Safe Defaults**: Automatically falls back to testnet to prevent accidental mainnet usage during development + +### Provider Creation +```typescript +const provider = jsonRpcProvider({ + rpc: () => ({ nodeUrl: getRpcUrl() }), +}); +``` + +**Gaming Implementation**: Creates a JSON-RPC provider that automatically connects to the appropriate gaming-optimized endpoint based on your deployment environment, ensuring players always connect to the right network. + +## Chain Configuration + +### Dynamic Chain Selection for Gaming +```typescript +const chains = VITE_PUBLIC_DEPLOY_TYPE === "mainnet" + ? [mainnet] + : [sepolia]; +``` + +**Gaming Logic**: +- **Mainnet**: Production gaming environment where players' actions have real value +- **Sepolia**: Safe testing environment for game development and QA +- **Automatic Switching**: Players never need to manually configure networks + +**Player Experience**: The game automatically connects to the appropriate network, maintaining the seamless experience players expect from modern games. + +## StarknetConfig Properties + +### Gaming-Focused Configuration +```typescript + + {children} + +``` + +### Property Breakdown for Gaming + +#### `autoConnect` +**Gaming Benefit**: Automatically reconnects players to their wallet when they return to the game, eliminating the frustration of having to reconnect every session. + +**Player Experience**: Just like saving game progress, wallet connections persist between gaming sessions. + +#### `chains={chains}` +**Gaming Purpose**: Defines which blockchain networks your game supports, automatically selecting the appropriate environment. + +**Player Impact**: Players connect to the right network without technical configuration, maintaining the plug-and-play experience of traditional games. + +#### `connectors={[cartridgeConnector]}` +**Gaming Innovation**: Uses Cartridge Controller, designed specifically for gaming applications. + +**Unique Gaming Features**: +- **Session Management**: Pre-approved transactions for uninterrupted gameplay +- **Gas Optimization**: Efficient transaction batching for gaming actions +- **User-Friendly Interface**: Gaming-focused wallet UI that doesn't feel like DeFi + +#### `explorer={starkscan}` +**Gaming Utility**: Integrates Starkscan block explorer for players to view their game transactions, achievements, and asset history. + +**Player Value**: Players can track their gaming history, verify rare item acquisitions, and share achievement transactions. + +#### `provider={provider}` +**Gaming Infrastructure**: Provides the blockchain communication layer optimized for gaming transaction patterns. + +**Technical Gaming Benefits**: Handles all game-to-blockchain communication efficiently, ensuring smooth gameplay without blockchain complexity exposure to players. + +## Integration in Gaming Applications + +### Provider Hierarchy for Games +```typescript +// main.tsx - Typical gaming application structure + + + + + + + +``` + +### Using Gaming Hooks +Once wrapped by `StarknetProvider`, game components can access blockchain functionality: + +```typescript +import { useAccount, useContract } from "@starknet-react/core"; + +function PlayerDashboard() { + const { account, isConnected } = useAccount(); + + return ( +
+ {isConnected ? ( + + ) : ( + + )} +
+ ); +} +``` + +## Gaming Benefits Summary + +**For Players**: +- Seamless wallet connections that persist between gaming sessions +- Automatic network selection without technical configuration +- Gaming-optimized transaction flow that doesn't interrupt gameplay + +**For Developers**: +- Environment-based deployment without code changes +- Gaming-focused RPC endpoints optimized for game transaction patterns +- Clean integration with Dojo's gaming infrastructure + +**For Game Operations**: +- Reliable infrastructure designed for gaming applications +- Built-in explorer integration for player transaction transparency +- Session management that reduces transaction friction + +--- + +**Next**: While StarknetProvider handles the network infrastructure and RPC connections, the [Controller Connector](./controller-connector.md) +takes this foundation and transforms it into a gaming-optimized experience. diff --git a/client-new/pages/guides/unity.mdx b/client-new/pages/guides/unity.mdx new file mode 100644 index 0000000..b9c06af --- /dev/null +++ b/client-new/pages/guides/unity.mdx @@ -0,0 +1,3 @@ +# Unity Integration + +Under development... diff --git a/client-new/pages/reference/api.mdx b/client-new/pages/reference/api.mdx new file mode 100644 index 0000000..6514350 --- /dev/null +++ b/client-new/pages/reference/api.mdx @@ -0,0 +1,71 @@ +# API Reference + +Complete reference for Dojo Engine APIs and interfaces. + +## Core APIs + +### World API + +The World contract provides the central interface for all Dojo operations. + +```cairo +#[starknet::interface] +trait IWorld { + fn register_model(ref self: T, class_hash: ClassHash); + fn register_system(ref self: T, class_hash: ClassHash); + fn execute(ref self: T, system: felt252, calldata: Span); +} +``` + +### Model API + +Models define the structure of your game state. + +```cairo +#[derive(Model, Copy, Drop, Serde)] +struct Position { + #[key] + player: ContractAddress, + x: u32, + y: u32, +} +``` + +### System API + +Systems contain your game logic. + +```cairo +#[system] +impl MoveImpl of MoveTrait { + fn execute(world: IWorldDispatcher, direction: Direction) { + // System implementation + } +} +``` + +## JavaScript APIs + +### DojoProvider + +Connect to a Dojo world from JavaScript. + +```typescript +import { DojoProvider } from "@dojoengine/core"; + +const provider = new DojoProvider(manifest, rpcUrl); +``` + +### useModel Hook + +React hook for accessing model data. + +```typescript +import { useModel } from "@dojoengine/react"; + +const player = useModel(Player, playerId); +``` + +## CLI Reference + +See [CLI Commands](/reference/cli) for complete command reference. \ No newline at end of file diff --git a/client-new/pages/reference/cli.mdx b/client-new/pages/reference/cli.mdx new file mode 100644 index 0000000..ee7e12f --- /dev/null +++ b/client-new/pages/reference/cli.mdx @@ -0,0 +1,101 @@ +# CLI Commands + +Complete reference for Dojo CLI commands. + +## Installation + +```bash +curl -L https://install.dojoengine.org | bash +dojoup +``` + +## Project Commands + +### `dojo new` + +Create a new Dojo project. + +```bash +dojo new my-game +``` + +**Options:** +- `--template` - Use a specific template + +### `dojo build` + +Build your Dojo project. + +```bash +dojo build +``` + +**Options:** +- `--release` - Build in release mode +- `--stats` - Show build statistics + +### `dojo deploy` + +Deploy your world to a network. + +```bash +dojo deploy --rpc-url http://localhost:5050 +``` + +**Options:** +- `--rpc-url` - RPC endpoint URL +- `--account` - Account to use for deployment +- `--private-key` - Private key for deployment + +## Development Commands + +### `dojo test` + +Run tests for your project. + +```bash +dojo test +``` + +**Options:** +- `--filter` - Filter tests by name +- `--exact` - Use exact name matching + +### `dojo migrate` + +Run migrations to set up your world. + +```bash +dojo migrate +``` + +## Utility Commands + +### `dojo completions` + +Generate shell completions. + +```bash +dojo completions bash > /etc/bash_completion.d/dojo +``` + +### `dojo --version` + +Show version information. + +```bash +dojo --version +``` + +## Configuration + +Dojo uses `Scarb.toml` for project configuration: + +```toml +[package] +name = "my-game" +version = "0.1.0" + +[dependencies] +dojo = { git = "https://github.com/dojoengine/dojo" } +``` \ No newline at end of file diff --git a/client-new/pages/reference/config.mdx b/client-new/pages/reference/config.mdx new file mode 100644 index 0000000..6c3eb19 --- /dev/null +++ b/client-new/pages/reference/config.mdx @@ -0,0 +1,123 @@ +# Configuration + +How to configure your Dojo projects and deployments. + +## Project Configuration + +### Scarb.toml + +Your main project configuration file: + +```toml +[package] +name = "my-dojo-game" +version = "0.1.0" +edition = "2023_11" + +[dependencies] +dojo = { git = "https://github.com/dojoengine/dojo" } + +[[target.dojo]] + +[tool.dojo] +initializer_class_hash = "0x123..." +``` + +### Environment Variables + +Common environment variables for Dojo development: + +```bash +# RPC URL for network connection +export STARKNET_RPC_URL="http://localhost:5050" + +# Account configuration +export DOJO_ACCOUNT_ADDRESS="0x123..." +export DOJO_PRIVATE_KEY="0xabc..." + +# World configuration +export DOJO_WORLD_ADDRESS="0x456..." +``` + +## Network Configuration + +### Local Development + +For local development with Katana: + +```bash +# Start Katana +katana --dev + +# Deploy to local network +dojo build +dojo migrate --rpc-url http://localhost:5050 +``` + +### Testnet Configuration + +Deploy to Starknet Sepolia: + +```bash +export STARKNET_RPC_URL="https://starknet-sepolia.public.blastapi.io" +dojo migrate --rpc-url $STARKNET_RPC_URL +``` + +### Mainnet Configuration + +Deploy to Starknet Mainnet: + +```bash +export STARKNET_RPC_URL="https://starknet-mainnet.public.blastapi.io" +dojo migrate --rpc-url $STARKNET_RPC_URL +``` + +## World Configuration + +### Permissions + +Configure who can interact with your world: + +```cairo +// In your initializer +world.grant_writer(selector!("Position"), contract_address_const::<0x123>()); +``` + +### Models Registration + +Register your models with the world: + +```cairo +world.register_model(position::TEST_CLASS_HASH.try_into().unwrap()); +``` + +## Frontend Configuration + +### Manifest.json + +Generated after deployment, contains addresses and ABIs: + +```json +{ + "world": { + "address": "0x123...", + "transaction_hash": "0xabc...", + "class_hash": "0x456..." + }, + "models": [ + { + "name": "Position", + "class_hash": "0x789..." + } + ] +} +``` + +### Dojo Provider Setup + +```typescript +import { DojoProvider } from "@dojoengine/core"; +import manifest from "./manifest.json"; + +const provider = new DojoProvider(manifest, rpcUrl); +``` \ No newline at end of file diff --git a/client-new/pages/reference/troubleshooting.mdx b/client-new/pages/reference/troubleshooting.mdx new file mode 100644 index 0000000..980103a --- /dev/null +++ b/client-new/pages/reference/troubleshooting.mdx @@ -0,0 +1,197 @@ +# Troubleshooting + +Common issues and solutions when working with Dojo Engine. + +## Installation Issues + +### Dojo Command Not Found + +**Problem:** `dojo: command not found` + +**Solution:** +```bash +# Reinstall Dojo +curl -L https://install.dojoengine.org | bash +source ~/.bashrc # or ~/.zshrc +dojoup +``` + +### Permission Denied + +**Problem:** Permission denied when installing + +**Solution:** +```bash +# Use different installation directory +export DOJO_HOME="$HOME/.dojo" +curl -L https://install.dojoengine.org | bash +``` + +## Build Issues + +### Compilation Errors + +**Problem:** Cairo compilation fails + +**Solutions:** +1. Check your Cairo syntax +2. Ensure all dependencies are correct +3. Update to latest Dojo version + +```bash +dojoup +dojo build --release +``` + +### Missing Dependencies + +**Problem:** Missing Dojo dependencies + +**Solution:** +```toml +[dependencies] +dojo = { git = "https://github.com/dojoengine/dojo" } +``` + +## Deployment Issues + +### Network Connection + +**Problem:** Cannot connect to network + +**Solutions:** +1. Check RPC URL is correct +2. Ensure network is running +3. Check firewall settings + +```bash +# Test connection +curl -X POST -H "Content-Type: application/json" \ + --data '{"jsonrpc":"2.0","method":"starknet_chainId","params":[],"id":1}' \ + http://localhost:5050 +``` + +### Insufficient Funds + +**Problem:** Account has insufficient funds + +**Solution:** +```bash +# For testnet, use faucet +# For local development, fund the account +``` + +### Transaction Reverted + +**Problem:** Deployment transaction fails + +**Common causes:** +1. Insufficient gas +2. Invalid contract code +3. Permission issues + +**Debug steps:** +```bash +# Check transaction details +starknet get_transaction_receipt --hash 0x123... + +# Verify account balance +starknet get_balance --account my_account +``` + +## Runtime Issues + +### Model Not Found + +**Problem:** Model queries return empty results + +**Solutions:** +1. Ensure model is properly registered +2. Check entity exists +3. Verify permissions + +```cairo +// Check if model is registered +let model_hash = world.model_hash(selector!("Position")); +``` + +### System Execution Fails + +**Problem:** System calls revert + +**Debug steps:** +1. Check system permissions +2. Verify input parameters +3. Test with local network first + +```cairo +// Add debug prints +println!("Debug: executing system with params: {:?}", params); +``` + +## Performance Issues + +### Slow Queries + +**Problem:** Model queries are slow + +**Solutions:** +1. Optimize query patterns +2. Use appropriate indexes +3. Batch operations when possible + +### High Gas Costs + +**Problem:** Transactions consume too much gas + +**Solutions:** +1. Optimize Cairo code +2. Reduce storage operations +3. Use events instead of storage for logs + +## Common Patterns + +### Entity Not Found Pattern + +```cairo +match world.entity(entity_id) { + Option::Some(entity) => { + // Process entity + }, + Option::None => { + // Handle missing entity + panic!("Entity not found: {}", entity_id); + } +} +``` + +### Safe System Execution + +```cairo +fn safe_execute(world: IWorldDispatcher, system: felt252, calldata: Span) { + match world.execute(system, calldata) { + Result::Ok(_) => { + // Success + }, + Result::Err(err) => { + println!("System execution failed: {:?}", err); + } + } +} +``` + +## Getting Help + +1. **Discord:** Join the Dojo Discord server +2. **GitHub:** Check issues and discussions +3. **Documentation:** Review the official docs +4. **Examples:** Study working examples in this guide + +## Debug Mode + +Enable debug mode for more detailed error messages: + +```bash +export DOJO_DEBUG=1 +dojo build +``` \ No newline at end of file From 768e6a623f9ef82b816fd3c62153a9783eb99632 Mon Sep 17 00:00:00 2001 From: jimenezz22 Date: Wed, 20 Aug 2025 14:14:34 -0600 Subject: [PATCH 08/10] feat: Add MDX components for enhanced documentation experience - Introduced new MDX components including Callout, CodeBlock, Demo, Playground, Steps, Tabs, Terminal, and FileTree for better content presentation. - Implemented Callout component variations (Info, Warning, Error, Success, Tip) for contextual messaging. - Added CodeBlock component with syntax highlighting and line number options. - Created Steps component for step-by-step instructions with optional completion tracking. - Developed Tabs component for organizing content into tabbed sections. - Integrated Terminal and Command components for simulating command-line interactions. - Included FileTree component for visual representation of file structures. - Updated routes to include a reference page for MDX components. - Documented usage examples in the new MDX components reference page. --- client-new/components/mdx/Callout.tsx | 96 ++++++ client-new/components/mdx/CodeBlock.tsx | 99 +++++++ client-new/components/mdx/Demo.tsx | 158 ++++++++++ client-new/components/mdx/Diff.tsx | 106 +++++++ client-new/components/mdx/FileTree.tsx | 96 ++++++ client-new/components/mdx/Steps.tsx | 123 ++++++++ client-new/components/mdx/Tabs.tsx | 75 +++++ client-new/components/mdx/Terminal.tsx | 87 ++++++ client-new/components/mdx/index.tsx | 134 +++++++++ client-new/pages/reference/mdx-components.mdx | 278 ++++++++++++++++++ client-new/src/routes.ts | 4 + 11 files changed, 1256 insertions(+) create mode 100644 client-new/components/mdx/Callout.tsx create mode 100644 client-new/components/mdx/CodeBlock.tsx create mode 100644 client-new/components/mdx/Demo.tsx create mode 100644 client-new/components/mdx/Diff.tsx create mode 100644 client-new/components/mdx/FileTree.tsx create mode 100644 client-new/components/mdx/Steps.tsx create mode 100644 client-new/components/mdx/Tabs.tsx create mode 100644 client-new/components/mdx/Terminal.tsx create mode 100644 client-new/components/mdx/index.tsx create mode 100644 client-new/pages/reference/mdx-components.mdx diff --git a/client-new/components/mdx/Callout.tsx b/client-new/components/mdx/Callout.tsx new file mode 100644 index 0000000..8fd7ae8 --- /dev/null +++ b/client-new/components/mdx/Callout.tsx @@ -0,0 +1,96 @@ +import { ReactNode } from 'react' + +interface CalloutProps { + type?: 'info' | 'warning' | 'error' | 'success' | 'tip' + title?: string + children: ReactNode + emoji?: string +} + +export function Callout({ type = 'info', title, children, emoji }: CalloutProps) { + const styles = { + info: { + bg: 'bg-gradient-to-r from-blue-50 to-blue-100/50 dark:from-blue-950/30 dark:to-blue-900/20', + border: 'border-blue-200 dark:border-blue-800', + text: 'text-blue-700 dark:text-blue-300', + iconBg: 'bg-blue-100 dark:bg-blue-900/50', + iconText: 'text-blue-600 dark:text-blue-400', + icon: emoji || 'ℹ️' + }, + warning: { + bg: 'bg-gradient-to-r from-amber-50 to-orange-100/50 dark:from-amber-950/30 dark:to-orange-900/20', + border: 'border-amber-200 dark:border-amber-800', + text: 'text-amber-700 dark:text-amber-300', + iconBg: 'bg-amber-100 dark:bg-amber-900/50', + iconText: 'text-amber-600 dark:text-amber-400', + icon: emoji || '⚠️' + }, + error: { + bg: 'bg-gradient-to-r from-red-50 to-red-100/50 dark:from-red-950/30 dark:to-red-900/20', + border: 'border-red-200 dark:border-red-800', + text: 'text-red-700 dark:text-red-300', + iconBg: 'bg-red-100 dark:bg-red-900/50', + iconText: 'text-red-600 dark:text-red-400', + icon: emoji || '❌' + }, + success: { + bg: 'bg-gradient-to-r from-emerald-50 to-green-100/50 dark:from-emerald-950/30 dark:to-green-900/20', + border: 'border-emerald-200 dark:border-emerald-800', + text: 'text-emerald-700 dark:text-emerald-300', + iconBg: 'bg-emerald-100 dark:bg-emerald-900/50', + iconText: 'text-emerald-600 dark:text-emerald-400', + icon: emoji || '✅' + }, + tip: { + bg: 'bg-gradient-to-r from-violet-50 to-purple-100/50 dark:from-violet-950/30 dark:to-purple-900/20', + border: 'border-violet-200 dark:border-violet-800', + text: 'text-violet-700 dark:text-violet-300', + iconBg: 'bg-violet-100 dark:bg-violet-900/50', + iconText: 'text-violet-600 dark:text-violet-400', + icon: emoji || '💡' + } + } + + const style = styles[type] + + return ( +
+
+
+ {style.icon} +
+
+ {title && ( +

+ {title} +

+ )} +
+ {children} +
+
+
+
+ ) +} + +// Alias components for convenience +export function Info({ children, title }: Omit) { + return {children} +} + +export function Warning({ children, title }: Omit) { + return {children} +} + +export function Error({ children, title }: Omit) { + return {children} +} + +export function Success({ children, title }: Omit) { + return {children} +} + +export function Tip({ children, title }: Omit) { + return {children} +} \ No newline at end of file diff --git a/client-new/components/mdx/CodeBlock.tsx b/client-new/components/mdx/CodeBlock.tsx new file mode 100644 index 0000000..b0a887a --- /dev/null +++ b/client-new/components/mdx/CodeBlock.tsx @@ -0,0 +1,99 @@ +import { useState } from 'react' + +interface CodeBlockProps { + children: string + language?: string + filename?: string + highlight?: string // e.g., "1,3-5,10" + showLineNumbers?: boolean + title?: string +} + +export function CodeBlock({ + children, + language = 'text', + filename, + highlight, + showLineNumbers = false, + title +}: CodeBlockProps) { + const [copied, setCopied] = useState(false) + + const copyToClipboard = async () => { + await navigator.clipboard.writeText(children) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } + + // Parse highlighted lines + const highlightedLines = new Set() + if (highlight) { + highlight.split(',').forEach(part => { + if (part.includes('-')) { + const [start, end] = part.split('-').map(Number) + for (let i = start; i <= end; i++) { + highlightedLines.add(i) + } + } else { + highlightedLines.add(Number(part)) + } + }) + } + + const lines = children.split('\n') + + return ( +
+ {(filename || title) && ( +
+ + {filename || title} + + {language} +
+ )} + +
+ + +
+          
+            {showLineNumbers ? (
+              
+
+ {lines.map((_, i) => ( + + {i + 1} + + ))} +
+
+ {lines.map((line, i) => ( +
+ {line} +
+ ))} +
+
+ ) : ( + children + )} +
+
+
+
+ ) +} \ No newline at end of file diff --git a/client-new/components/mdx/Demo.tsx b/client-new/components/mdx/Demo.tsx new file mode 100644 index 0000000..3f86ecb --- /dev/null +++ b/client-new/components/mdx/Demo.tsx @@ -0,0 +1,158 @@ +import { useState, ReactNode } from 'react' + +interface DemoProps { + children: ReactNode + title?: string + description?: string + showCode?: boolean + code?: string +} + +export function Demo({ children, title, description, showCode = true, code }: DemoProps) { + const [isCodeVisible, setIsCodeVisible] = useState(false) + + return ( +
+ {(title || description) && ( +
+ {title && ( +

+ + {title} +

+ )} + {description && ( +

+ {description} +

+ )} +
+ )} + +
+ {children} +
+ + {showCode && code && ( + <> +
+ +
+ + {isCodeVisible && ( +
+
+                {code}
+              
+
+ )} + + )} +
+ ) +} + +interface PlaygroundProps { + children: ReactNode + title?: string + controls?: ReactNode +} + +export function Playground({ children, title, controls }: PlaygroundProps) { + return ( +
+ {title && ( +
+

+ + {title} + Interactive +

+
+ )} + + {controls && ( +
+
+ {controls} +
+
+ )} + +
+ {children} +
+
+ ) +} + +interface InteractiveExampleProps { + initialCode: string + onRun: (code: string) => void + output?: string + language?: string +} + +export function InteractiveExample({ + initialCode, + onRun, + output +}: InteractiveExampleProps) { + const [code, setCode] = useState(initialCode) + const [isRunning, setIsRunning] = useState(false) + + const handleRun = () => { + setIsRunning(true) + onRun(code) + setIsRunning(false) + } + + return ( +
+
+
+ Code Editor + +
+