dylanebert HF Staff commited on
Commit
794cf6c
·
0 Parent(s):

initial commit

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .claude/commands/nourish.md +51 -0
  2. .claude/commands/peel.md +35 -0
  3. .claude/commands/plant.md +40 -0
  4. .gitattributes +35 -0
  5. .gitignore +90 -0
  6. CLAUDE.md +36 -0
  7. Dockerfile +38 -0
  8. PLAN.md +870 -0
  9. README.md +19 -0
  10. auth-callback.html +62 -0
  11. bun.lock +769 -0
  12. eslint.config.js +62 -0
  13. index.html +33 -0
  14. layers/context-template.md +34 -0
  15. layers/structure.md +106 -0
  16. llms.txt +1107 -0
  17. package.json +46 -0
  18. src/App.svelte +65 -0
  19. src/app.css +16 -0
  20. src/context.md +18 -0
  21. src/lib/components/Editor.svelte +128 -0
  22. src/lib/components/auth/LoginButton.svelte +167 -0
  23. src/lib/components/auth/context.md +28 -0
  24. src/lib/components/chat/ChatPanel.svelte +430 -0
  25. src/lib/components/chat/context.md +14 -0
  26. src/lib/components/console/ConsoleMessage.svelte +109 -0
  27. src/lib/components/console/ConsolePanel.svelte +131 -0
  28. src/lib/components/console/context.md +32 -0
  29. src/lib/components/context.md +45 -0
  30. src/lib/components/editor/CodeEditor.svelte +28 -0
  31. src/lib/components/editor/context.md +31 -0
  32. src/lib/components/game/GameCanvas.svelte +81 -0
  33. src/lib/components/game/GameError.svelte +30 -0
  34. src/lib/components/game/context.md +33 -0
  35. src/lib/components/layout/AppHeader.svelte +318 -0
  36. src/lib/components/layout/LoadingScreen.svelte +141 -0
  37. src/lib/components/layout/SplitView.svelte +355 -0
  38. src/lib/components/layout/context.md +33 -0
  39. src/lib/config/animations.ts +43 -0
  40. src/lib/config/context.md +34 -0
  41. src/lib/config/shortcuts.ts +57 -0
  42. src/lib/server/agent-runner.ts +128 -0
  43. src/lib/server/api.ts +165 -0
  44. src/lib/server/context.md +20 -0
  45. src/lib/services/auth.ts +172 -0
  46. src/lib/services/console-capture.ts +90 -0
  47. src/lib/services/context.md +43 -0
  48. src/lib/services/game-engine.ts +77 -0
  49. src/lib/services/html-parser.ts +18 -0
  50. src/lib/stores/agent.ts +271 -0
.claude/commands/nourish.md ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🍃 /nourish
2
+
3
+ Complete conversation by updating context and applying cleanup.
4
+
5
+ ## Auto-Loaded Context:
6
+
7
+ @CLAUDE.md
8
+ @layers/structure.md
9
+ @llms.txt
10
+
11
+ User arguments: "$ARGUMENTS"
12
+
13
+ ## Steps
14
+
15
+ ### 1. Identify Changes
16
+
17
+ - Detect modified, added, or deleted files in conversation
18
+ - Map changes to their parent folders and components
19
+
20
+ ### 2. Update Context Chain
21
+
22
+ Traverse upward through context tiers (see CLAUDE.md):
23
+
24
+ - **Tier 2**: Update relevant `context.md` files to reflect current code state
25
+ - **Tier 1**: Update `layers/structure.md` if structure/commands/stack changed
26
+ - Follow all rules from CLAUDE.md, especially "No History" principle
27
+
28
+ ### 3. Apply Cleanup
29
+
30
+ Fix obvious issues encountered:
31
+
32
+ - Remove comments; code should be self-explanatory without comments
33
+ - Remove dead code and unused files
34
+ - Consolidate duplicate patterns
35
+ - Apply CLAUDE.md principles (simplicity, reuse, single responsibility)
36
+
37
+ ### 4. Verify
38
+
39
+ - Context accurately reflects current state
40
+ - Project is leaner or same size as before
41
+ - No history references in code or context
42
+
43
+ ## Output
44
+
45
+ Report conversation completion: updated context files and improvements made.
46
+
47
+ ## Guidelines
48
+
49
+ - When updating context, don't over-specify implementation details
50
+ - If changes were internal (e.g. business logic), it may not be necessary to update context
51
+ - Context should be even shorter after updates, avoiding context rot
.claude/commands/peel.md ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🧄 /peel
2
+
3
+ Load relevant context for the current conversation.
4
+
5
+ ## Auto-Loaded Context:
6
+
7
+ @CLAUDE.md
8
+ @layers/structure.md
9
+ @llms.txt
10
+
11
+ User arguments: "$ARGUMENTS"
12
+
13
+ ## Steps
14
+
15
+ ### 1. Parse Work Area
16
+
17
+ - Analyze user request or arguments
18
+ - Determine relevant components or features
19
+ - Assess required context depth
20
+
21
+ ### 2. Load Targeted Context
22
+
23
+ - Read relevant `context.md` files for identified areas
24
+ - Skip unrelated component contexts to minimize tokens
25
+
26
+ ### 3. Confirm Scope
27
+
28
+ - Brief summary of loaded context
29
+ - State understanding of work focus
30
+ - Note any assumptions made
31
+
32
+ ## Guidelines
33
+
34
+ - Load only what's needed for the current task
35
+ - Defer code reading until necessary
.claude/commands/plant.md ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🌱 /plant
2
+
3
+ Initialize context management structure for the project.
4
+
5
+ ## Auto-Loaded Context:
6
+
7
+ @CLAUDE.md
8
+ @layers/structure.md
9
+
10
+ User arguments: "$ARGUMENTS"
11
+
12
+ ## Steps
13
+
14
+ ### 1. Analyze Project
15
+
16
+ - Scan technology stack, build tools, directory structure
17
+ - Identify major components and entry points
18
+ - Understand existing patterns and conventions
19
+
20
+ ### 2. Fill Core Templates
21
+
22
+ - Update `CLAUDE.md` with project-specific details
23
+ - Complete `layers/structure.md` with actual stack, commands, layout
24
+ - Remove template placeholders
25
+
26
+ ### 3. Create Component Context
27
+
28
+ - Generate `context.md` files for major folders using templates
29
+ - Document purpose, scope, dependencies for each component
30
+ - Place in appropriate directories
31
+
32
+ ### 4. Validate
33
+
34
+ - Ensure coverage of main components
35
+ - Check that context hierarchy makes sense
36
+ - Verify no placeholder text remains
37
+
38
+ ## Output
39
+
40
+ List created/updated files by tier and any areas needing attention.
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Dependencies
2
+ node_modules/
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Build outputs
7
+ dist/
8
+ dist-ssr/
9
+ build/
10
+ *.local
11
+
12
+ # Vite
13
+ .vite/
14
+
15
+ # Logs
16
+ logs/
17
+ *.log
18
+ npm-debug.log*
19
+ yarn-debug.log*
20
+ yarn-error.log*
21
+ pnpm-debug.log*
22
+ lerna-debug.log*
23
+
24
+ # Environment files
25
+ .env
26
+ .env.local
27
+ .env.development.local
28
+ .env.test.local
29
+ .env.production.local
30
+ *.env
31
+
32
+ # IDE
33
+ .vscode/*
34
+ !.vscode/extensions.json
35
+ !.vscode/settings.json
36
+ .idea/
37
+ *.swp
38
+ *.swo
39
+ *~
40
+ .DS_Store
41
+
42
+ # OS
43
+ Thumbs.db
44
+ .DS_Store
45
+
46
+ # Testing
47
+ coverage/
48
+ *.lcov
49
+ .nyc_output/
50
+
51
+ # TypeScript
52
+ *.tsbuildinfo
53
+
54
+ # Package managers
55
+ .npm
56
+ .yarn/
57
+ .pnpm-store/
58
+
59
+ # Temporary files
60
+ *.tmp
61
+ .temp/
62
+ tmp/
63
+
64
+ # HuggingFace Spaces
65
+ .huggingface/
66
+ flagged/
67
+
68
+ # Python (for future AI integration)
69
+ __pycache__/
70
+ *.py[cod]
71
+ *$py.class
72
+ *.so
73
+ .Python
74
+ venv/
75
+ ENV/
76
+ env/
77
+ .venv
78
+
79
+ # Jupyter Notebooks
80
+ .ipynb_checkpoints/
81
+
82
+ # Bun
83
+ bun.lockb
84
+
85
+ # LLMs
86
+ .vscode/
87
+ .claude/settings.local.json
88
+
89
+ # Dev Scripts
90
+ scripts/
CLAUDE.md ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AI Context - Working Agreement
2
+
3
+ <project-description>
4
+ AI-assisted game development environment using the VibeGame engine. Iterative development with Svelte UI, Monaco editor, and Smolagents for AI-driven game modifications with console feedback loops.
5
+ </project-description>
6
+
7
+ **Required**: Read [layers/structure.md](layers/structure.md) before proceeding with any task
8
+
9
+ ## Context Management System
10
+
11
+ - **Tier 0 — global**: `CLAUDE.md` (root). Global standards and system overview
12
+ - **Tier 1 — project**: `layers/structure.md`. Project map (stack, commands, layout, entry points)
13
+ - **Tier 2 — folder context**: `context.md` in any folder; one per folder; explains purpose/structure of that folder
14
+ - **Tier 3 — implementation**: Code files (scripts)
15
+
16
+ ## Rules
17
+
18
+ - **Priority**: Your number one priority is to manage your own context; always load appropriate context before doing anything else
19
+ - **No History**: CRITICAL - Code and context must NEVER reference their own history. Write everything as the current, final state. Never include comments like "changed from X to Y" or "previously was Z". This is a severe form of context rot
20
+ - **Simplicity**: Keep code simple, elegant, concise, and readable
21
+ - **Structure**: Keep files small and single-responsibility; separate concerns (MVC/ECS as appropriate)
22
+ - **Reuse**: Reuse before adding new code; avoid repetition
23
+ - **Comments**: Code should be self-explanatory without comments; use concise comments only when necessary
24
+ - **State**: Single source of truth; caches/derivations only
25
+ - **Data**: Favor data-driven/declarative design
26
+ - **Fail Fast**: Make bugs immediately visible rather than hiding them; favor simplicity over defensive patterns
27
+ - **Backwards Compatibility**: Unless stated otherwise, favor simplicity over backwards compatibility; the design rules above should make breaking changes easy to trace and fix
28
+
29
+ ## Security
30
+
31
+ - **Inputs & secrets**: Validate inputs; secrets only in env; never log sensitive data
32
+ - **Auth**: Gateway auth; server-side token validation; sanitize inputs
33
+
34
+ ## Tools
35
+
36
+ - **Context7**: Use as needed to fetch documentation
Dockerfile ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:20-slim
2
+
3
+ # Install dependencies as root
4
+ RUN apt-get update && apt-get install -y \
5
+ curl unzip \
6
+ && rm -rf /var/lib/apt/lists/*
7
+
8
+ # Use existing node user (UID 1000) for Hugging Face Spaces compatibility
9
+ # The node:20-slim image already has a 'node' user with UID 1000
10
+
11
+ # Install bun globally
12
+ RUN curl -fsSL https://bun.sh/install | BUN_INSTALL=/usr/local bash
13
+ ENV PATH="/usr/local/bin:${PATH}"
14
+
15
+ # Set working directory with proper permissions
16
+ WORKDIR /app
17
+ RUN chown -R node:node /app
18
+
19
+ # Switch to non-root user
20
+ USER node
21
+
22
+ # Copy package files and install dependencies
23
+ COPY --chown=node:node package.json bun.lock* ./
24
+ RUN bun install
25
+
26
+ # Copy application files
27
+ COPY --chown=node:node . .
28
+
29
+ # Create writable directory for Vite temp files
30
+
31
+ RUN mkdir -p /app/.vite && chmod 755 /app/.vite
32
+
33
+ EXPOSE 7860
34
+ ENV NODE_ENV=production
35
+ ENV HOME=/home/node
36
+
37
+ ENTRYPOINT []
38
+ CMD ["bun", "run", "dev", "--host", "0.0.0.0", "--port", "7860"]
PLAN.md ADDED
@@ -0,0 +1,870 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AI Agent Development Plan - Refined Strategy
2
+
3
+ ## Overview
4
+
5
+ Iterative AI-driven game development system using **browser-native TypeScript architecture** with streaming AI agents for real-time VibeGame game modification and self-correcting feedback loops.
6
+
7
+ ## Current Status
8
+
9
+ **Phase 1 - Foundation COMPLETED** ✅
10
+
11
+ - ✅ WebSocket server integrated with Vite
12
+ - ✅ HuggingFace Inference API connected
13
+ - ✅ Real-time streaming chat interface
14
+ - ✅ Agent state management with Svelte stores
15
+ - ✅ Bidirectional communication working
16
+
17
+ **Next: Tool Implementation** 🚀
18
+
19
+ ## Core Strategy: Small, Testable Iterations
20
+
21
+ ### Guiding Principles
22
+
23
+ 1. **Start Ultra-Simple** - First tool in ~10 lines of code
24
+ 2. **Test Continuously** - Every iteration delivers testable value
25
+ 3. **Fail Visibly** - Errors shown immediately in UI
26
+ 4. **Incremental Complexity** - Add features one at a time
27
+ 5. **User-Centric Progress** - Each day delivers visible improvement
28
+
29
+ ### Development Phases
30
+
31
+ - **Week 1**: Make it Work (basic tools)
32
+ - **Week 2**: Make it Good (error handling)
33
+ - **Week 3**: Make it Fast (optimization)
34
+
35
+ ## Architecture Evolution
36
+
37
+ ### Current Architecture (Simple)
38
+
39
+ ```
40
+ Browser → WebSocket → Agent → Tools → Stores → UI
41
+ ```
42
+
43
+ ### Target Architecture (Advanced)
44
+
45
+ ```
46
+ Browser → SSE/WebSocket → Composite Agent System → MCP Tools → Stores → UI
47
+ ├── Base Model (Complex reasoning)
48
+ ├── Quick Edit Model (Fast edits)
49
+ └── AutoFix Model (Error correction)
50
+ ```
51
+
52
+ ## Implementation Phases
53
+
54
+ ### Phase 1: Minimal Viable Tools (Days 1-7)
55
+
56
+ **Goal:** Agent can read and edit game code
57
+
58
+ #### Day 1: First Tool - Read Game Code
59
+
60
+ - [ ] Create `src/lib/tools/registry.ts` with simple tool interface
61
+ - [ ] Implement `read-game-code.ts` (returns editor content)
62
+ - [ ] Update agent-runner to detect tool calls
63
+ - **Test:** "What's in the game?" → Agent describes scene
64
+
65
+ #### Day 2: Tool Execution
66
+
67
+ - [ ] Parse tool requests from agent responses
68
+ - [ ] Execute tools and return results
69
+ - [ ] Add tool context to agent
70
+ - **Test:** Agent accurately describes game elements
71
+
72
+ #### Day 3: Edit Game Code
73
+
74
+ - [ ] Implement `edit-game-code.ts` with string replacement
75
+ - [ ] Connect to editor store
76
+ - [ ] Basic XML validation
77
+ - **Test:** "Add a red box" → Box appears
78
+
79
+ #### Day 4: Console Reading
80
+
81
+ - [ ] Implement `read-console.ts`
82
+ - [ ] Filter and format messages
83
+ - **Test:** Agent reports console errors
84
+
85
+ #### Day 5-6: Tool Chaining
86
+
87
+ - [ ] Multiple tools per response
88
+ - [ ] Simple sequencing
89
+ - [ ] Context preservation
90
+ - **Test:** Multi-step operations work
91
+
92
+ #### Day 7: Testing & Stabilization
93
+
94
+ - [ ] Fix discovered bugs
95
+ - [ ] Improve error messages
96
+ - [ ] Add logging
97
+ - **Success Metrics:**
98
+ - ✅ Agent can describe game content
99
+ - ✅ Agent can add/modify elements
100
+ - ✅ Agent can read console
101
+ - ✅ 5 basic operations work reliably
102
+
103
+ ### Phase 2: Error Detection & Correction (Days 8-14)
104
+
105
+ **Goal:** Agent detects and fixes simple errors
106
+
107
+ #### Day 8: Error Pattern Recognition
108
+
109
+ - [ ] Parse common VibeGame errors
110
+ - [ ] Categorize: syntax, physics, missing components
111
+ - **Test:** Agent identifies "no ground" error
112
+
113
+ #### Day 9: Simple Self-Correction
114
+
115
+ - [ ] Single retry on error
116
+ - [ ] Generate fix attempts
117
+ - **Test:** Agent adds missing ground
118
+
119
+ #### Day 10: Undo/Redo
120
+
121
+ - [ ] Edit history in editor store
122
+ - [ ] Rollback on failure
123
+ - **Test:** Failed edits can be undone
124
+
125
+ #### Day 11: Validation Tool
126
+
127
+ - [ ] Check required components
128
+ - [ ] Pre-validate changes
129
+ - **Test:** Prevents invalid states
130
+
131
+ #### Day 12-13: Better Prompting
132
+
133
+ - [ ] VibeGame-specific examples
134
+ - [ ] Few-shot learning
135
+ - **Test:** Higher first-attempt success
136
+
137
+ #### Day 14: Polish
138
+
139
+ - [ ] Clear error messages
140
+ - [ ] Better explanations
141
+ - **Success Metrics:**
142
+ - ✅ Agent detects common errors
143
+ - ✅ Agent fixes simple mistakes
144
+ - ✅ Edit history prevents data loss
145
+ - ✅ 80% success rate on common tasks
146
+
147
+ ### Phase 3: Advanced Features (Days 15-21)
148
+
149
+ **Goal:** Faster, smarter, more capable
150
+
151
+ #### Day 15: Code-Based Tools
152
+
153
+ - [ ] Agent generates TypeScript for tools
154
+ - [ ] Controlled execution environment
155
+ - **Test:** More flexible tool usage
156
+
157
+ #### Day 16: Streaming Improvements
158
+
159
+ - [ ] Migrate to Server-Sent Events (SSE)
160
+ - [ ] Real-time tool visualization
161
+ - **Test:** Better feedback
162
+
163
+ #### Day 17: Quick Edit Model
164
+
165
+ - [ ] Route simple edits to Qwen3-Coder-7B
166
+ - [ ] Instant text/color changes
167
+ - **Test:** Sub-second simple edits
168
+
169
+ #### Day 18: Context Management
170
+
171
+ - [ ] Sliding window for long chats
172
+ - [ ] Iteration summarization
173
+ - **Test:** 50+ message sessions
174
+
175
+ #### Day 19: Template System
176
+
177
+ - [ ] Pre-built game templates
178
+ - [ ] Quick start patterns
179
+ - **Test:** "Make a platformer" works
180
+
181
+ #### Day 20: Thinking Visualization
182
+
183
+ - [ ] Show reasoning process
184
+ - [ ] Chain-of-thought UI
185
+ - **Test:** Users understand logic
186
+
187
+ #### Day 21: Final Polish
188
+
189
+ - [ ] Performance optimization
190
+ - [ ] Documentation
191
+ - **Success Metrics:**
192
+ - ✅ Sub-second simple edits
193
+ - ✅ Complex multi-step tasks work
194
+ - ✅ Users understand process
195
+ - ✅ Production-ready quality
196
+
197
+ ## Tool Specifications
198
+
199
+ ### Core Tool Interface (MCP-Compatible)
200
+
201
+ ```typescript
202
+ interface Tool {
203
+ name: string;
204
+ description: string;
205
+ execute: (params: any) => Promise<ToolResult>;
206
+ }
207
+
208
+ interface ToolResult {
209
+ success: boolean;
210
+ data?: any;
211
+ error?: string;
212
+ }
213
+ ```
214
+
215
+ ### Initial Tool Set
216
+
217
+ 1. **read_game_code** - Get current editor content
218
+ 2. **edit_game_code** - Modify via search/replace
219
+ 3. **read_console** - Get console messages
220
+ 4. **validate_game** - Check VibeGame rules
221
+
222
+ ### Future Tools
223
+
224
+ 5. **list_entities** - Get all scene entities
225
+ 6. **add_entity** - Add new entity
226
+ 7. **remove_entity** - Delete entity
227
+ 8. **test_physics** - Simulate and check
228
+ 9. **reset_game** - Restart scene
229
+
230
+ ## Model Strategy
231
+
232
+ ### Phase 1: Single Model
233
+
234
+ - **Primary:** DeepSeek-R1-Distill-Qwen-1.5B (current)
235
+ - Simple prompting, basic tool use
236
+
237
+ ### Phase 2: Fallback Chain
238
+
239
+ - **Primary:** DeepSeek-R1-Distill
240
+ - **Fallback:** Qwen3-Coder-7B
241
+ - Error recovery and retry logic
242
+
243
+ ### Phase 3: Composite System
244
+
245
+ - **Complex Tasks:** ERNIE-4.5-21B-A3B-Thinking (128K context)
246
+ - **Quick Edits:** Qwen3-Coder-7B-Instruct
247
+ - **Error Fix:** Dedicated correction model
248
+ - **Streaming Post-Processor:** Real-time validation
249
+
250
+ ## Key Improvements from Research
251
+
252
+ ### From v0/Vercel
253
+
254
+ - Composite model architecture
255
+ - Streaming post-processing
256
+ - Quick edit optimization
257
+ - Real-time error correction
258
+
259
+ ### From Smolagents
260
+
261
+ - Code-based tools (TypeScript instead of JSON)
262
+ - Direct execution without translation
263
+ - Simpler debugging
264
+
265
+ ### From Modern Thinking Models
266
+
267
+ - 128K context windows
268
+ - Chain-of-thought reasoning
269
+ - Sparse MoE activation (3B active params)
270
+
271
+ ### From MCP/Agentic Web
272
+
273
+ - Standardized tool protocols
274
+ - Browser-native execution
275
+ - SSE for streaming
276
+ - Direct store integration
277
+
278
+ ## Testing Strategy
279
+
280
+ ### Unit Tests
281
+
282
+ - Individual tool validation
283
+ - Mock stores for isolation
284
+
285
+ ### Integration Tests
286
+
287
+ - Full flow: request → tools → response
288
+ - Multi-tool sequences
289
+ - Error recovery
290
+
291
+ ### User Tests
292
+
293
+ - "Add jumping platforms"
294
+ - "Fix the bouncing balls"
295
+ - "Create a coin collector"
296
+
297
+ ## Deployment
298
+
299
+ ### Environment Variables
300
+
301
+ ```env
302
+ HF_TOKEN=<user_token>
303
+ MODEL_PRIMARY=deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
304
+ MODEL_QUICK=Qwen/Qwen3-Coder-7B-Instruct
305
+ MAX_ITERATIONS=10
306
+ ITERATION_TIMEOUT=30000
307
+ PORT=7860
308
+ ```
309
+
310
+ ### Single Container (HuggingFace Spaces)
311
+
312
+ ```dockerfile
313
+ FROM oven/bun:1-alpine
314
+ WORKDIR /app
315
+ COPY package.json bun.lockb ./
316
+ RUN bun install --frozen-lockfile
317
+ COPY . .
318
+ RUN bun run build
319
+ EXPOSE 7860
320
+ CMD ["bun", "run", "preview", "--host", "0.0.0.0", "--port", "7860"]
321
+ ```
322
+
323
+ ## Implementation Details
324
+
325
+ ### Tool System Architecture
326
+
327
+ #### Pattern Recognition in Agent Responses
328
+
329
+ The agent will naturally include tool calls in its responses using a simple pattern:
330
+
331
+ ```
332
+ [TOOL: tool_name {"param": "value"}]
333
+ ```
334
+
335
+ Example agent response:
336
+
337
+ ```
338
+ I'll check what's currently in your game.
339
+
340
+ [TOOL: read_game_code]
341
+
342
+ Based on the code, I can see you have a ground platform and a red ball...
343
+ ```
344
+
345
+ #### Complete Tool Registry Implementation
346
+
347
+ ```typescript
348
+ // src/lib/tools/registry.ts - FULL CODE TO CREATE
349
+
350
+ export interface Tool {
351
+ name: string;
352
+ description: string;
353
+ execute: (params: any) => Promise<ToolResult>;
354
+ }
355
+
356
+ export interface ToolResult {
357
+ success: boolean;
358
+ data?: any;
359
+ error?: string;
360
+ }
361
+
362
+ export interface ToolCall {
363
+ tool: string;
364
+ parameters?: any;
365
+ }
366
+
367
+ class ToolRegistry {
368
+ private tools: Map<string, Tool> = new Map();
369
+
370
+ register(tool: Tool) {
371
+ if (this.tools.has(tool.name)) {
372
+ console.warn(`Tool ${tool.name} already registered, overwriting`);
373
+ }
374
+ this.tools.set(tool.name, tool);
375
+ console.log(`Registered tool: ${tool.name}`);
376
+ }
377
+
378
+ async execute(toolName: string, params?: any): Promise<ToolResult> {
379
+ const tool = this.tools.get(toolName);
380
+
381
+ if (!tool) {
382
+ return {
383
+ success: false,
384
+ error: `Tool '${toolName}' not found. Available: ${Array.from(this.tools.keys()).join(", ")}`,
385
+ };
386
+ }
387
+
388
+ try {
389
+ console.log(`Executing tool: ${toolName}`, params);
390
+ const result = await tool.execute(params);
391
+ console.log(`Tool ${toolName} result:`, result);
392
+ return result;
393
+ } catch (error) {
394
+ console.error(`Tool ${toolName} error:`, error);
395
+ return {
396
+ success: false,
397
+ error: error instanceof Error ? error.message : "Unknown error",
398
+ };
399
+ }
400
+ }
401
+
402
+ getTools(): Tool[] {
403
+ return Array.from(this.tools.values());
404
+ }
405
+
406
+ getToolNames(): string[] {
407
+ return Array.from(this.tools.keys());
408
+ }
409
+
410
+ getToolDescriptions(): string {
411
+ return Array.from(this.tools.values())
412
+ .map((tool) => `- ${tool.name}: ${tool.description}`)
413
+ .join("\n");
414
+ }
415
+ }
416
+
417
+ // Global registry instance
418
+ export const toolRegistry = new ToolRegistry();
419
+
420
+ // Helper function to parse tool calls from agent response
421
+ export function parseToolCalls(response: string): ToolCall[] {
422
+ const toolCalls: ToolCall[] = [];
423
+
424
+ // Pattern: [TOOL: tool_name] or [TOOL: tool_name {"param": "value"}]
425
+ const toolPattern = /\[TOOL:\s*(\w+)(?:\s+({[^}]+}))?\]/g;
426
+
427
+ let match;
428
+ while ((match = toolPattern.exec(response)) !== null) {
429
+ const toolName = match[1];
430
+ const paramsStr = match[2];
431
+
432
+ let parameters = undefined;
433
+ if (paramsStr) {
434
+ try {
435
+ parameters = JSON.parse(paramsStr);
436
+ } catch (e) {
437
+ console.warn(`Failed to parse tool parameters: ${paramsStr}`);
438
+ }
439
+ }
440
+
441
+ toolCalls.push({ tool: toolName, parameters });
442
+ }
443
+
444
+ return toolCalls;
445
+ }
446
+
447
+ // Helper to format tool results for agent context
448
+ export function formatToolResult(toolName: string, result: ToolResult): string {
449
+ if (result.success) {
450
+ return `[TOOL_RESULT: ${toolName}]\n${JSON.stringify(result.data, null, 2)}\n[/TOOL_RESULT]`;
451
+ } else {
452
+ return `[TOOL_ERROR: ${toolName}]\n${result.error}\n[/TOOL_ERROR]`;
453
+ }
454
+ }
455
+ ```
456
+
457
+ #### Tool Implementation Examples
458
+
459
+ **read-game-code.ts** (Ultra-simple first tool):
460
+
461
+ ```typescript
462
+ import { editorStore } from "$lib/stores/editor";
463
+ import { get } from "svelte/store";
464
+
465
+ export const readGameCodeTool: Tool = {
466
+ name: "read_game_code",
467
+ description: "Get the current game code from the editor",
468
+ execute: async () => {
469
+ const state = get(editorStore);
470
+ return {
471
+ success: true,
472
+ data: {
473
+ content: state.content,
474
+ language: state.language,
475
+ },
476
+ };
477
+ },
478
+ };
479
+ ```
480
+
481
+ **edit-game-code.ts** (Simple string replacement):
482
+
483
+ ```typescript
484
+ export const editGameCodeTool: Tool = {
485
+ name: "edit_game_code",
486
+ description: "Edit game code using search and replace",
487
+ execute: async (params: { search: string; replace: string }) => {
488
+ const state = get(editorStore);
489
+ const newContent = state.content.replace(params.search, params.replace);
490
+ editorStore.setContent(newContent);
491
+ return {
492
+ success: true,
493
+ data: { modified: true, newContent },
494
+ };
495
+ },
496
+ };
497
+ ```
498
+
499
+ #### Agent Runner Updates
500
+
501
+ Add to `src/lib/server/agent-runner.ts`:
502
+
503
+ ```typescript
504
+ import { parseToolCalls, toolRegistry, formatToolResult } from '../tools/registry';
505
+
506
+ async processMessage(message: string, onStream?: (chunk: string) => void) {
507
+ // ... existing code ...
508
+
509
+ // After getting response, check for tool calls
510
+ const toolCalls = parseToolCalls(fullResponse);
511
+
512
+ if (toolCalls.length > 0) {
513
+ // Execute tools and add results to context
514
+ for (const call of toolCalls) {
515
+ const result = await toolRegistry.execute(call.tool, call.parameters);
516
+ const formatted = formatToolResult(call.tool, result);
517
+
518
+ // Add to message history for context
519
+ this.messageHistory.push({
520
+ id: this.generateId(),
521
+ role: 'system',
522
+ content: formatted,
523
+ timestamp: Date.now()
524
+ });
525
+ }
526
+
527
+ // Continue conversation with tool results
528
+ // (In phase 2, we'll make this recursive for self-correction)
529
+ }
530
+ }
531
+ ```
532
+
533
+ #### System Prompt Enhancement
534
+
535
+ ```typescript
536
+ const systemPrompt = `You are an AI assistant helping to build games with VibeGame.
537
+
538
+ Available tools:
539
+ ${toolRegistry.getToolDescriptions()}
540
+
541
+ To use a tool, include in your response: [TOOL: tool_name {"param": "value"}]
542
+
543
+ Example:
544
+ - To read game code: [TOOL: read_game_code]
545
+ - To edit: [TOOL: edit_game_code {"search": "old text", "replace": "new text"}]
546
+
547
+ Always validate changes and ensure the game remains playable.
548
+ Use small, incremental changes rather than large rewrites.`;
549
+ ```
550
+
551
+ ### Testing Scenarios
552
+
553
+ #### Phase 1 Test Cases
554
+
555
+ 1. **"What's in the game?"**
556
+ - Expected: Agent uses `read_game_code`, describes scene elements
557
+
558
+ 2. **"Add a blue box at position 5,2,0"**
559
+ - Expected: Agent uses `edit_game_code` to insert `<dynamic-part>`
560
+
561
+ 3. **"Change the ball color to green"**
562
+ - Expected: Agent finds and replaces color attribute
563
+
564
+ 4. **"What errors are in the console?"**
565
+ - Expected: Agent uses `read_console` tool
566
+
567
+ 5. **"Check the code and fix any issues"**
568
+ - Expected: Agent chains multiple tools
569
+
570
+ ### Current File Structure
571
+
572
+ ```
573
+ src/lib/
574
+ ├── server/
575
+ │ ├── agent-runner.ts (✅ exists - needs tool integration)
576
+ │ └── api.ts (✅ exists - WebSocket handler)
577
+ ├── tools/
578
+ │ └── (empty directory - needs implementation)
579
+ └── stores/
580
+ ├── agent.ts (✅ exists)
581
+ ├── editor.ts (✅ exists)
582
+ ├── console.ts (✅ exists)
583
+ ├── game.ts (✅ exists)
584
+ └── ui.ts (✅ exists)
585
+ ```
586
+
587
+ ### Target File Structure After Implementation
588
+
589
+ ```
590
+ src/lib/
591
+ ├── server/
592
+ │ ├── agent-runner.ts (updated with tool execution)
593
+ │ └── api.ts (existing WebSocket handler)
594
+ ├── tools/
595
+ │ ├── registry.ts (to create)
596
+ │ ├── read-game-code.ts (to create)
597
+ │ ├── edit-game-code.ts (to create)
598
+ │ ├── read-console.ts (to create)
599
+ │ └── index.ts (to create - exports all tools)
600
+ └── stores/
601
+ └── (all existing)
602
+ ```
603
+
604
+ ## Next Immediate Steps
605
+
606
+ 1. ✅ Update PLAN.md with implementation details
607
+ 2. ⏳ Create tool registry (`src/lib/tools/registry.ts`)
608
+ 3. ⏳ Implement read-game-code tool
609
+ 4. ⏳ Update agent-runner for tool execution
610
+ 5. ⏳ Test in UI with "What's in the game?"
611
+
612
+ ## Success Criteria
613
+
614
+ ### Week 1
615
+
616
+ - [ ] Basic tools working
617
+ - [ ] Agent can modify games
618
+ - [ ] Console feedback visible
619
+
620
+ ### Week 2
621
+
622
+ - [ ] Error detection working
623
+ - [ ] Self-correction attempts
624
+ - [ ] Higher success rate
625
+
626
+ ### Week 3
627
+
628
+ - [ ] Fast response times
629
+ - [ ] Advanced features
630
+ - [ ] Production ready
631
+
632
+ ## Model Configuration Details
633
+
634
+ ### HuggingFace Inference API Setup
635
+
636
+ #### Available Models (via Serverless API)
637
+
638
+ ```typescript
639
+ // Phase 1: Simple model
640
+ const MODELS = {
641
+ primary: "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B",
642
+
643
+ // Phase 2: Fallback chain
644
+ fallback: "Qwen/Qwen2.5-Coder-7B-Instruct",
645
+
646
+ // Phase 3: Thinking models (require special handling)
647
+ thinking: {
648
+ ernie: "baidu/ERNIE-4.5-21B-A3B-Thinking", // Apache 2.0, 128K context
649
+ qwen: "Qwen/Qwen3-Next-80B-A3B-Thinking", // Longer thinking chains
650
+ },
651
+ };
652
+ ```
653
+
654
+ #### Thinking Model Integration
655
+
656
+ For thinking models, parse and display reasoning:
657
+
658
+ ```typescript
659
+ // Response may contain thinking process
660
+ const thinkingPattern = /<thinking>(.*?)<\/thinking>/s;
661
+ const match = response.match(thinkingPattern);
662
+ if (match) {
663
+ // Store thinking for UI display
664
+ const thinking = match[1];
665
+ // Extract actual response
666
+ const answer = response.replace(thinkingPattern, "");
667
+ }
668
+ ```
669
+
670
+ ### Advanced Features Implementation
671
+
672
+ #### Server-Sent Events (SSE) Migration
673
+
674
+ Replace WebSocket with SSE for simpler streaming:
675
+
676
+ ```typescript
677
+ // src/lib/server/sse.ts
678
+ export function createSSEStream(req: Request) {
679
+ const stream = new ReadableStream({
680
+ start(controller) {
681
+ controller.enqueue('data: {"type":"connected"}\n\n');
682
+ },
683
+ async pull(controller) {
684
+ // Stream agent responses
685
+ const chunk = await getNextChunk();
686
+ controller.enqueue(`data: ${JSON.stringify(chunk)}\n\n`);
687
+ },
688
+ });
689
+
690
+ return new Response(stream, {
691
+ headers: {
692
+ "Content-Type": "text/event-stream",
693
+ "Cache-Control": "no-cache",
694
+ Connection: "keep-alive",
695
+ },
696
+ });
697
+ }
698
+ ```
699
+
700
+ #### Code-Based Tool Execution (Smolagents-inspired)
701
+
702
+ Allow agent to write TypeScript code for tools:
703
+
704
+ ```typescript
705
+ // Agent generates code like:
706
+ const code = `
707
+ const editor = await tools.readGameCode();
708
+ const content = editor.data.content;
709
+ const modified = content.replace('color="#ff0000"', 'color="#00ff00"');
710
+ await tools.editGameCode({ search: content, replace: modified });
711
+ return "Changed red to green";
712
+ `;
713
+
714
+ // Execute in sandboxed context
715
+ const sandbox = {
716
+ tools: toolRegistry,
717
+ console: { log: (...args) => consoleStore.addMessage("log", args.join(" ")) },
718
+ };
719
+ const result = await executeInSandbox(code, sandbox);
720
+ ```
721
+
722
+ #### Composite Model Router
723
+
724
+ Route requests based on complexity:
725
+
726
+ ```typescript
727
+ class ModelRouter {
728
+ async route(message: string, context: AgentMessage[]): Promise<string> {
729
+ const complexity = this.assessComplexity(message);
730
+
731
+ if (complexity === "simple") {
732
+ // Text changes, color modifications
733
+ return this.quickEditModel(message);
734
+ } else if (complexity === "complex") {
735
+ // Multi-step reasoning, debugging
736
+ return this.thinkingModel(message);
737
+ } else {
738
+ // Default
739
+ return this.primaryModel(message);
740
+ }
741
+ }
742
+
743
+ private assessComplexity(message: string): "simple" | "medium" | "complex" {
744
+ // Simple heuristics
745
+ if (message.match(/change|color|text|rename/i)) return "simple";
746
+ if (message.match(/debug|fix|error|why/i)) return "complex";
747
+ return "medium";
748
+ }
749
+ }
750
+ ```
751
+
752
+ ## Common Patterns & Solutions
753
+
754
+ ### Pattern: Adding Game Elements
755
+
756
+ ```typescript
757
+ // User: "Add a platform at 0,3,0"
758
+ // Agent response with tool:
759
+ `I'll add a platform at position 0,3,0 for you.
760
+
761
+ [TOOL: edit_game_code {"search": "</world>", "replace": " <static-part pos=\"0 3 0\" shape=\"box\" size=\"3 0.5 3\" color=\"#808080\"></static-part>\n</world>"}]
762
+
763
+ I've added a gray platform at position (0, 3, 0).`;
764
+ ```
765
+
766
+ ### Pattern: Debugging Errors
767
+
768
+ ```typescript
769
+ // User: "The player keeps falling"
770
+ // Agent workflow:
771
+ 1. [TOOL: read_game_code] - Check for ground
772
+ 2. [TOOL: read_console] - Check for physics errors
773
+ 3. Identify: No ground platform
774
+ 4. [TOOL: edit_game_code] - Add ground
775
+ 5. [TOOL: validate_game] - Verify fix
776
+ ```
777
+
778
+ ### Pattern: Complex Modifications
779
+
780
+ ```typescript
781
+ // User: "Make this into a platformer"
782
+ // Agent uses template:
783
+ const platformerTemplate = `
784
+ <!-- Platforms -->
785
+ <static-part pos="-5 2 0" shape="box" size="3 0.5 3" color="#808080"></static-part>
786
+ <static-part pos="0 4 0" shape="box" size="3 0.5 3" color="#808080"></static-part>
787
+ <static-part pos="5 6 0" shape="box" size="3 0.5 3" color="#808080"></static-part>
788
+
789
+ <!-- Moving platform -->
790
+ <kinematic-part pos="0 3 5" shape="box" size="4 0.5 4" color="#4169e1">
791
+ <tween target="body.pos-x" from="-10" to="10" duration="5" loop="ping-pong"></tween>
792
+ </kinematic-part>
793
+ `;
794
+ ```
795
+
796
+ ## Troubleshooting Guide
797
+
798
+ ### Issue: Agent doesn't use tools
799
+
800
+ **Solution**: Enhance system prompt with examples
801
+
802
+ ```typescript
803
+ const systemPrompt = `
804
+ IMPORTANT: You have tools available. Use them!
805
+
806
+ Examples of when to use tools:
807
+ - User asks "what's in the game?" → Use [TOOL: read_game_code]
808
+ - User says "add a box" → Use [TOOL: edit_game_code]
809
+ - User mentions "error" → Use [TOOL: read_console]
810
+ `;
811
+ ```
812
+
813
+ ### Issue: Tool execution fails
814
+
815
+ **Solution**: Add error recovery
816
+
817
+ ```typescript
818
+ try {
819
+ const result = await tool.execute(params);
820
+ if (!result.success) {
821
+ // Retry with adjusted parameters
822
+ const adjusted = this.adjustParameters(params, result.error);
823
+ return await tool.execute(adjusted);
824
+ }
825
+ } catch (error) {
826
+ // Fallback to manual instruction
827
+ return {
828
+ success: false,
829
+ error: `Tool failed. Manual fix: ${this.getManualInstructions(tool.name)}`,
830
+ };
831
+ }
832
+ ```
833
+
834
+ ### Issue: Context overflow
835
+
836
+ **Solution**: Implement sliding window
837
+
838
+ ```typescript
839
+ class ContextManager {
840
+ private maxTokens = 4000;
841
+
842
+ summarize(messages: AgentMessage[]): AgentMessage[] {
843
+ if (this.countTokens(messages) < this.maxTokens) {
844
+ return messages;
845
+ }
846
+
847
+ // Keep system, first user, and last N messages
848
+ const summary = this.createSummary(messages.slice(1, -5));
849
+ return [
850
+ messages[0], // system
851
+ { role: "system", content: `Previous conversation summary: ${summary}` },
852
+ ...messages.slice(-5), // recent context
853
+ ];
854
+ }
855
+ }
856
+ ```
857
+
858
+ ## Resources
859
+
860
+ - [HuggingFace Inference API](https://huggingface.co/docs/api-inference/index)
861
+ - [MCP Specification](https://modelcontextprotocol.io/specification)
862
+ - [VibeGame Docs](llms.txt)
863
+ - [Smolagents](https://github.com/huggingface/smolagents)
864
+ - [AI SDK](https://ai-sdk.dev)
865
+ - [ERNIE-4.5 Model](https://huggingface.co/baidu/ERNIE-4.5-21B-A3B-Thinking)
866
+ - [Qwen3-Next Model](https://huggingface.co/Qwen/Qwen3-Next-80B-A3B-Thinking)
867
+
868
+ ---
869
+
870
+ _This plan provides a complete roadmap for implementing an AI agent system for VibeGame game development. Start with Phase 1 for immediate value, then progressively add sophistication. Each iteration is designed to be completed in hours, not days, with immediate testing in the UI._
README.md ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: VibeGame
3
+ emoji: 🥕
4
+ colorFrom: purple
5
+ colorTo: green
6
+ sdk: docker
7
+ app_port: 7860
8
+ pinned: false
9
+ license: mit
10
+ short_description: Vibe code 3D games
11
+ hf_oauth: true
12
+ hf_oauth_expiration_minutes: 43200
13
+ hf_oauth_scopes:
14
+ - inference-api
15
+ ---
16
+
17
+ # 🥕 VibeGame
18
+
19
+ Vibe code 3D games with [VibeGame](https://github.com/dylanebert/vibegame).
auth-callback.html ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Authentication - VibeGame</title>
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ padding: 0;
11
+ background: linear-gradient(135deg, #0b0a09 0%, #0f0e0c 100%);
12
+ color: #ffffff;
13
+ font-family:
14
+ -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", system-ui,
15
+ sans-serif;
16
+ display: flex;
17
+ justify-content: center;
18
+ align-items: center;
19
+ height: 100vh;
20
+ }
21
+ .container {
22
+ text-align: center;
23
+ padding: 2rem;
24
+ }
25
+ .spinner {
26
+ width: 40px;
27
+ height: 40px;
28
+ border: 4px solid rgba(255, 255, 255, 0.1);
29
+ border-top-color: #667eea;
30
+ border-radius: 50%;
31
+ animation: spin 1s linear infinite;
32
+ margin: 0 auto 1rem;
33
+ }
34
+ @keyframes spin {
35
+ to {
36
+ transform: rotate(360deg);
37
+ }
38
+ }
39
+ h1 {
40
+ font-size: 1.5rem;
41
+ font-weight: 500;
42
+ margin: 0 0 0.5rem;
43
+ }
44
+ p {
45
+ color: rgba(255, 255, 255, 0.6);
46
+ margin: 0;
47
+ }
48
+ </style>
49
+ </head>
50
+ <body>
51
+ <div class="container">
52
+ <div class="spinner"></div>
53
+ <h1>Authenticating...</h1>
54
+ <p>Please wait while we complete your login.</p>
55
+ </div>
56
+ <script>
57
+ setTimeout(() => {
58
+ window.location.href = "/";
59
+ }, 5000);
60
+ </script>
61
+ </body>
62
+ </html>
bun.lock ADDED
@@ -0,0 +1,769 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "lockfileVersion": 1,
3
+ "workspaces": {
4
+ "": {
5
+ "name": "vibegame",
6
+ "dependencies": {
7
+ "@huggingface/hub": "^2.6.3",
8
+ "@huggingface/inference": "^4.8.0",
9
+ "@types/node": "^24.3.3",
10
+ "gsap": "^3.13.0",
11
+ "monaco-editor": "^0.50.0",
12
+ "svelte-splitpanes": "^8.0.5",
13
+ "vibegame": "^0.1.1",
14
+ },
15
+ "devDependencies": {
16
+ "@eslint/js": "^9.33.0",
17
+ "@sveltejs/vite-plugin-svelte": "^3.1.1",
18
+ "@types/ws": "^8.18.1",
19
+ "@typescript-eslint/eslint-plugin": "^8.40.0",
20
+ "@typescript-eslint/parser": "^8.40.0",
21
+ "eslint": "^9.33.0",
22
+ "eslint-config-prettier": "^10.1.8",
23
+ "eslint-plugin-import": "^2.32.0",
24
+ "eslint-plugin-prettier": "^5.5.4",
25
+ "prettier": "^3.6.2",
26
+ "svelte": "^4.2.18",
27
+ "svelte-check": "^3.8.4",
28
+ "typescript": "^5.6.0",
29
+ "vite": "^5.4.10",
30
+ "ws": "^8.18.3",
31
+ },
32
+ },
33
+ },
34
+ "packages": {
35
+ "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
36
+
37
+ "@dimforge/rapier3d-compat": ["@dimforge/rapier3d-compat@0.18.2", "", {}, "sha512-DTXrOsn3ra9ZonB+VyqJc16xnRXWsHVa5FK230Z+R1PJ7q8oSRmWQ+AU6e+IJYBHxkM0a5QVDqd729DyeEhHPA=="],
38
+
39
+ "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
40
+
41
+ "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
42
+
43
+ "@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="],
44
+
45
+ "@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="],
46
+
47
+ "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="],
48
+
49
+ "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="],
50
+
51
+ "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="],
52
+
53
+ "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="],
54
+
55
+ "@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="],
56
+
57
+ "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="],
58
+
59
+ "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="],
60
+
61
+ "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="],
62
+
63
+ "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="],
64
+
65
+ "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="],
66
+
67
+ "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="],
68
+
69
+ "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="],
70
+
71
+ "@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="],
72
+
73
+ "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="],
74
+
75
+ "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="],
76
+
77
+ "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="],
78
+
79
+ "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="],
80
+
81
+ "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="],
82
+
83
+ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="],
84
+
85
+ "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="],
86
+
87
+ "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
88
+
89
+ "@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="],
90
+
91
+ "@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="],
92
+
93
+ "@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="],
94
+
95
+ "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
96
+
97
+ "@eslint/js": ["@eslint/js@9.35.0", "", {}, "sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw=="],
98
+
99
+ "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
100
+
101
+ "@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "", { "dependencies": { "@eslint/core": "^0.15.2", "levn": "^0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="],
102
+
103
+ "@huggingface/hub": ["@huggingface/hub@2.6.3", "", { "dependencies": { "@huggingface/tasks": "^0.19.45" }, "optionalDependencies": { "cli-progress": "^3.12.0" }, "bin": { "hfjs": "dist/cli.js" } }, "sha512-IEZ67adV+gWqg98A//mU0Ed+Q6xGPQxMfK+aV36b0Ww7R4EXG1O0zyiCcbLE/cvryfCD8+PNEwQgiPU+v63tsQ=="],
104
+
105
+ "@huggingface/inference": ["@huggingface/inference@4.8.0", "", { "dependencies": { "@huggingface/jinja": "^0.5.1", "@huggingface/tasks": "^0.19.45" } }, "sha512-Eq98EAXqYn4rKMfrbEXuhc3IjKfaeIO6eXNOZk9xk6v5akrIWRtd6d1h0fjAWyX4zRbdUpXRh6MvsqXnzGvXCA=="],
106
+
107
+ "@huggingface/jinja": ["@huggingface/jinja@0.5.1", "", {}, "sha512-yUZLld4lrM9iFxHCwFQ7D1HW2MWMwSbeB7WzWqFYDWK+rEb+WldkLdAJxUPOmgICMHZLzZGVcVjFh3w/YGubng=="],
108
+
109
+ "@huggingface/tasks": ["@huggingface/tasks@0.19.45", "", {}, "sha512-lM3QOgbfkGZ5gAZOYWOmzMM6BbKcXOIHjgnUAoymTdZEcEcGSr0vy/LWGEiK+vBXC4vU+sCT+WNoA/JZ8TEWdA=="],
110
+
111
+ "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
112
+
113
+ "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
114
+
115
+ "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
116
+
117
+ "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
118
+
119
+ "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
120
+
121
+ "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
122
+
123
+ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
124
+
125
+ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
126
+
127
+ "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
128
+
129
+ "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
130
+
131
+ "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
132
+
133
+ "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="],
134
+
135
+ "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.50.1", "", { "os": "android", "cpu": "arm" }, "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag=="],
136
+
137
+ "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.50.1", "", { "os": "android", "cpu": "arm64" }, "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw=="],
138
+
139
+ "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.50.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw=="],
140
+
141
+ "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.50.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw=="],
142
+
143
+ "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.50.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA=="],
144
+
145
+ "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.50.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ=="],
146
+
147
+ "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.50.1", "", { "os": "linux", "cpu": "arm" }, "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg=="],
148
+
149
+ "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.50.1", "", { "os": "linux", "cpu": "arm" }, "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw=="],
150
+
151
+ "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.50.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw=="],
152
+
153
+ "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.50.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w=="],
154
+
155
+ "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.50.1", "", { "os": "linux", "cpu": "none" }, "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q=="],
156
+
157
+ "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.50.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q=="],
158
+
159
+ "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.50.1", "", { "os": "linux", "cpu": "none" }, "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ=="],
160
+
161
+ "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.50.1", "", { "os": "linux", "cpu": "none" }, "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg=="],
162
+
163
+ "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.50.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg=="],
164
+
165
+ "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.50.1", "", { "os": "linux", "cpu": "x64" }, "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA=="],
166
+
167
+ "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.50.1", "", { "os": "linux", "cpu": "x64" }, "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg=="],
168
+
169
+ "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.50.1", "", { "os": "none", "cpu": "arm64" }, "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA=="],
170
+
171
+ "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.50.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ=="],
172
+
173
+ "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.50.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A=="],
174
+
175
+ "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.50.1", "", { "os": "win32", "cpu": "x64" }, "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA=="],
176
+
177
+ "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
178
+
179
+ "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@3.1.2", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^2.1.0", "debug": "^4.3.4", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.10", "svelte-hmr": "^0.16.0", "vitefu": "^0.2.5" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.0" } }, "sha512-Txsm1tJvtiYeLUVRNqxZGKR/mI+CzuIQuc2gn+YCs9rMTowpNZ2Nqt53JdL8KF9bLhAf2ruR/dr9eZCwdTriRA=="],
180
+
181
+ "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@2.1.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "vite": "^5.0.0" } }, "sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg=="],
182
+
183
+ "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
184
+
185
+ "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
186
+
187
+ "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
188
+
189
+ "@types/node": ["@types/node@24.3.3", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-GKBNHjoNw3Kra1Qg5UXttsY5kiWMEfoHq2TmXb+b1rcm6N7B3wTrFYIf/oSZ1xNQ+hVVijgLkiDZh7jRRsh+Gw=="],
190
+
191
+ "@types/pug": ["@types/pug@2.0.10", "", {}, "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA=="],
192
+
193
+ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
194
+
195
+ "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.43.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/type-utils": "8.43.0", "@typescript-eslint/utils": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.43.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-8tg+gt7ENL7KewsKMKDHXR1vm8tt9eMxjJBYINf6swonlWgkYn5NwyIgXpbbDxTNU5DgpDFfj95prcTq2clIQQ=="],
196
+
197
+ "@typescript-eslint/parser": ["@typescript-eslint/parser@8.43.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/types": "8.43.0", "@typescript-eslint/typescript-estree": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw=="],
198
+
199
+ "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.43.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.43.0", "@typescript-eslint/types": "^8.43.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-htB/+D/BIGoNTQYffZw4uM4NzzuolCoaA/BusuSIcC8YjmBYQioew5VUZAYdAETPjeed0hqCaW7EHg+Robq8uw=="],
200
+
201
+ "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.43.0", "", { "dependencies": { "@typescript-eslint/types": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0" } }, "sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg=="],
202
+
203
+ "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.43.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ALC2prjZcj2YqqL5X/bwWQmHA2em6/94GcbB/KKu5SX3EBDOsqztmmX1kMkvAJHzxk7TazKzJfFiEIagNV3qEA=="],
204
+
205
+ "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.43.0", "", { "dependencies": { "@typescript-eslint/types": "8.43.0", "@typescript-eslint/typescript-estree": "8.43.0", "@typescript-eslint/utils": "8.43.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-qaH1uLBpBuBBuRf8c1mLJ6swOfzCXryhKND04Igr4pckzSEW9JX5Aw9AgW00kwfjWJF0kk0ps9ExKTfvXfw4Qg=="],
206
+
207
+ "@typescript-eslint/types": ["@typescript-eslint/types@8.43.0", "", {}, "sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw=="],
208
+
209
+ "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.43.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.43.0", "@typescript-eslint/tsconfig-utils": "8.43.0", "@typescript-eslint/types": "8.43.0", "@typescript-eslint/visitor-keys": "8.43.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-7Vv6zlAhPb+cvEpP06WXXy/ZByph9iL6BQRBDj4kmBsW98AqEeQHlj/13X+sZOrKSo9/rNKH4Ul4f6EICREFdw=="],
210
+
211
+ "@typescript-eslint/utils": ["@typescript-eslint/utils@8.43.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/types": "8.43.0", "@typescript-eslint/typescript-estree": "8.43.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-S1/tEmkUeeswxd0GGcnwuVQPFWo8NzZTOMxCvw8BX7OMxnNae+i8Tm7REQen/SwUIPoPqfKn7EaZ+YLpiB3k9g=="],
212
+
213
+ "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.43.0", "", { "dependencies": { "@typescript-eslint/types": "8.43.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw=="],
214
+
215
+ "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
216
+
217
+ "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
218
+
219
+ "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
220
+
221
+ "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
222
+
223
+ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
224
+
225
+ "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
226
+
227
+ "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
228
+
229
+ "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="],
230
+
231
+ "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="],
232
+
233
+ "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="],
234
+
235
+ "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-shim-unscopables": "^1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="],
236
+
237
+ "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="],
238
+
239
+ "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="],
240
+
241
+ "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="],
242
+
243
+ "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="],
244
+
245
+ "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
246
+
247
+ "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
248
+
249
+ "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
250
+
251
+ "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
252
+
253
+ "bitecs": ["bitecs@0.3.40", "", {}, "sha512-wAylY4pNfX8IeIH5phtwt1lUNtHKrkoSNrArI7Ris2Y4nEQWFIVvXdgAuqprEg9bq8Wolmlj0gVfeG6MFmtI2Q=="],
254
+
255
+ "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
256
+
257
+ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
258
+
259
+ "buffer-crc32": ["buffer-crc32@1.0.0", "", {}, "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w=="],
260
+
261
+ "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
262
+
263
+ "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
264
+
265
+ "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
266
+
267
+ "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
268
+
269
+ "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
270
+
271
+ "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
272
+
273
+ "cli-progress": ["cli-progress@3.12.0", "", { "dependencies": { "string-width": "^4.2.3" } }, "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A=="],
274
+
275
+ "code-red": ["code-red@1.0.4", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@types/estree": "^1.0.1", "acorn": "^8.10.0", "estree-walker": "^3.0.3", "periscopic": "^3.1.0" } }, "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw=="],
276
+
277
+ "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
278
+
279
+ "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
280
+
281
+ "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
282
+
283
+ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
284
+
285
+ "css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="],
286
+
287
+ "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="],
288
+
289
+ "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="],
290
+
291
+ "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="],
292
+
293
+ "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
294
+
295
+ "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
296
+
297
+ "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="],
298
+
299
+ "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="],
300
+
301
+ "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
302
+
303
+ "detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="],
304
+
305
+ "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
306
+
307
+ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
308
+
309
+ "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
310
+
311
+ "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="],
312
+
313
+ "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
314
+
315
+ "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
316
+
317
+ "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
318
+
319
+ "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
320
+
321
+ "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="],
322
+
323
+ "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="],
324
+
325
+ "es6-promise": ["es6-promise@3.3.1", "", {}, "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg=="],
326
+
327
+ "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
328
+
329
+ "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
330
+
331
+ "eslint": ["eslint@9.35.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.35.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg=="],
332
+
333
+ "eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="],
334
+
335
+ "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", "resolve": "^1.22.4" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="],
336
+
337
+ "eslint-module-utils": ["eslint-module-utils@2.12.1", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw=="],
338
+
339
+ "eslint-plugin-import": ["eslint-plugin-import@2.32.0", "", { "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", "array.prototype.findlastindex": "^1.2.6", "array.prototype.flat": "^1.3.3", "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.12.1", "hasown": "^2.0.2", "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", "object.values": "^1.2.1", "semver": "^6.3.1", "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA=="],
340
+
341
+ "eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.4", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.7" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg=="],
342
+
343
+ "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
344
+
345
+ "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
346
+
347
+ "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="],
348
+
349
+ "esm-env-robust": ["esm-env-robust@0.0.3", "", { "dependencies": { "esm-env": "^1.0.0" } }, "sha512-90Gnuw2DALOqlL1581VxP3GHPUNHX9U+fQ+8FNcTTFClhY5gEggAAnJ3q1b2Oq23knRsjv8YpNeMRPaMLUymOA=="],
350
+
351
+ "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
352
+
353
+ "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
354
+
355
+ "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
356
+
357
+ "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
358
+
359
+ "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
360
+
361
+ "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
362
+
363
+ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
364
+
365
+ "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="],
366
+
367
+ "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
368
+
369
+ "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
370
+
371
+ "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
372
+
373
+ "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
374
+
375
+ "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
376
+
377
+ "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
378
+
379
+ "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
380
+
381
+ "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
382
+
383
+ "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
384
+
385
+ "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="],
386
+
387
+ "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
388
+
389
+ "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
390
+
391
+ "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
392
+
393
+ "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="],
394
+
395
+ "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="],
396
+
397
+ "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
398
+
399
+ "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
400
+
401
+ "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="],
402
+
403
+ "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
404
+
405
+ "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
406
+
407
+ "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
408
+
409
+ "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
410
+
411
+ "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
412
+
413
+ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
414
+
415
+ "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
416
+
417
+ "gsap": ["gsap@3.13.0", "", {}, "sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw=="],
418
+
419
+ "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="],
420
+
421
+ "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
422
+
423
+ "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="],
424
+
425
+ "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="],
426
+
427
+ "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
428
+
429
+ "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
430
+
431
+ "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
432
+
433
+ "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
434
+
435
+ "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
436
+
437
+ "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
438
+
439
+ "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
440
+
441
+ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
442
+
443
+ "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
444
+
445
+ "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="],
446
+
447
+ "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="],
448
+
449
+ "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="],
450
+
451
+ "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
452
+
453
+ "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="],
454
+
455
+ "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="],
456
+
457
+ "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
458
+
459
+ "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="],
460
+
461
+ "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="],
462
+
463
+ "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
464
+
465
+ "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="],
466
+
467
+ "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
468
+
469
+ "is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="],
470
+
471
+ "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
472
+
473
+ "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="],
474
+
475
+ "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="],
476
+
477
+ "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
478
+
479
+ "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="],
480
+
481
+ "is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
482
+
483
+ "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="],
484
+
485
+ "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="],
486
+
487
+ "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="],
488
+
489
+ "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="],
490
+
491
+ "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="],
492
+
493
+ "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="],
494
+
495
+ "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="],
496
+
497
+ "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="],
498
+
499
+ "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="],
500
+
501
+ "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
502
+
503
+ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
504
+
505
+ "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
506
+
507
+ "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
508
+
509
+ "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
510
+
511
+ "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
512
+
513
+ "json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="],
514
+
515
+ "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
516
+
517
+ "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
518
+
519
+ "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
520
+
521
+ "locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
522
+
523
+ "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
524
+
525
+ "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
526
+
527
+ "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="],
528
+
529
+ "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
530
+
531
+ "mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="],
532
+
533
+ "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
534
+
535
+ "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
536
+
537
+ "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="],
538
+
539
+ "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
540
+
541
+ "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
542
+
543
+ "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="],
544
+
545
+ "monaco-editor": ["monaco-editor@0.50.0", "", {}, "sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA=="],
546
+
547
+ "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
548
+
549
+ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
550
+
551
+ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
552
+
553
+ "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
554
+
555
+ "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
556
+
557
+ "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
558
+
559
+ "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
560
+
561
+ "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="],
562
+
563
+ "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="],
564
+
565
+ "object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="],
566
+
567
+ "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="],
568
+
569
+ "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
570
+
571
+ "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
572
+
573
+ "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="],
574
+
575
+ "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
576
+
577
+ "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
578
+
579
+ "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
580
+
581
+ "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
582
+
583
+ "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
584
+
585
+ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
586
+
587
+ "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
588
+
589
+ "periscopic": ["periscopic@3.1.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^3.0.0", "is-reference": "^3.0.0" } }, "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw=="],
590
+
591
+ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
592
+
593
+ "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
594
+
595
+ "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
596
+
597
+ "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
598
+
599
+ "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
600
+
601
+ "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
602
+
603
+ "prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="],
604
+
605
+ "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
606
+
607
+ "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
608
+
609
+ "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
610
+
611
+ "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
612
+
613
+ "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="],
614
+
615
+ "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="],
616
+
617
+ "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
618
+
619
+ "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
620
+
621
+ "rimraf": ["rimraf@2.7.1", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="],
622
+
623
+ "rollup": ["rollup@4.50.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.50.1", "@rollup/rollup-android-arm64": "4.50.1", "@rollup/rollup-darwin-arm64": "4.50.1", "@rollup/rollup-darwin-x64": "4.50.1", "@rollup/rollup-freebsd-arm64": "4.50.1", "@rollup/rollup-freebsd-x64": "4.50.1", "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", "@rollup/rollup-linux-arm-musleabihf": "4.50.1", "@rollup/rollup-linux-arm64-gnu": "4.50.1", "@rollup/rollup-linux-arm64-musl": "4.50.1", "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", "@rollup/rollup-linux-ppc64-gnu": "4.50.1", "@rollup/rollup-linux-riscv64-gnu": "4.50.1", "@rollup/rollup-linux-riscv64-musl": "4.50.1", "@rollup/rollup-linux-s390x-gnu": "4.50.1", "@rollup/rollup-linux-x64-gnu": "4.50.1", "@rollup/rollup-linux-x64-musl": "4.50.1", "@rollup/rollup-openharmony-arm64": "4.50.1", "@rollup/rollup-win32-arm64-msvc": "4.50.1", "@rollup/rollup-win32-ia32-msvc": "4.50.1", "@rollup/rollup-win32-x64-msvc": "4.50.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA=="],
624
+
625
+ "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
626
+
627
+ "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="],
628
+
629
+ "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="],
630
+
631
+ "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="],
632
+
633
+ "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="],
634
+
635
+ "sander": ["sander@0.5.1", "", { "dependencies": { "es6-promise": "^3.1.2", "graceful-fs": "^4.1.3", "mkdirp": "^0.5.1", "rimraf": "^2.5.2" } }, "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA=="],
636
+
637
+ "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
638
+
639
+ "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="],
640
+
641
+ "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="],
642
+
643
+ "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="],
644
+
645
+ "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
646
+
647
+ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
648
+
649
+ "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
650
+
651
+ "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
652
+
653
+ "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
654
+
655
+ "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
656
+
657
+ "sorcery": ["sorcery@0.11.1", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.14", "buffer-crc32": "^1.0.0", "minimist": "^1.2.0", "sander": "^0.5.0" }, "bin": { "sorcery": "bin/sorcery" } }, "sha512-o7npfeJE6wi6J9l0/5LKshFzZ2rMatRiCDwYeDQaOzqdzRJwALhX7mk/A/ecg6wjMu7wdZbmXfD2S/vpOg0bdQ=="],
658
+
659
+ "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
660
+
661
+ "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="],
662
+
663
+ "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
664
+
665
+ "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="],
666
+
667
+ "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="],
668
+
669
+ "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="],
670
+
671
+ "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
672
+
673
+ "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="],
674
+
675
+ "strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="],
676
+
677
+ "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
678
+
679
+ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
680
+
681
+ "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
682
+
683
+ "svelte": ["svelte@4.2.20", "", { "dependencies": { "@ampproject/remapping": "^2.2.1", "@jridgewell/sourcemap-codec": "^1.4.15", "@jridgewell/trace-mapping": "^0.3.18", "@types/estree": "^1.0.1", "acorn": "^8.9.0", "aria-query": "^5.3.0", "axobject-query": "^4.0.0", "code-red": "^1.0.3", "css-tree": "^2.3.1", "estree-walker": "^3.0.3", "is-reference": "^3.0.1", "locate-character": "^3.0.0", "magic-string": "^0.30.4", "periscopic": "^3.1.0" } }, "sha512-eeEgGc2DtiUil5ANdtd8vPwt9AgaMdnuUFnPft9F5oMvU/FHu5IHFic+p1dR/UOB7XU2mX2yHW+NcTch4DCh5Q=="],
684
+
685
+ "svelte-check": ["svelte-check@3.8.6", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.17", "chokidar": "^3.4.1", "picocolors": "^1.0.0", "sade": "^1.7.4", "svelte-preprocess": "^5.1.3", "typescript": "^5.0.3" }, "peerDependencies": { "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-ij0u4Lw/sOTREP13BdWZjiXD/BlHE6/e2e34XzmVmsp5IN4kVa3PWP65NM32JAgwjZlwBg/+JtiNV1MM8khu0Q=="],
686
+
687
+ "svelte-hmr": ["svelte-hmr@0.16.0", "", { "peerDependencies": { "svelte": "^3.19.0 || ^4.0.0" } }, "sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA=="],
688
+
689
+ "svelte-preprocess": ["svelte-preprocess@5.1.4", "", { "dependencies": { "@types/pug": "^2.0.6", "detect-indent": "^6.1.0", "magic-string": "^0.30.5", "sorcery": "^0.11.0", "strip-indent": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.10.2", "coffeescript": "^2.5.1", "less": "^3.11.3 || ^4.0.0", "postcss": "^7 || ^8", "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", "pug": "^3.0.0", "sass": "^1.26.8", "stylus": "^0.55.0", "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0", "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["@babel/core", "coffeescript", "less", "postcss", "postcss-load-config", "pug", "sass", "stylus", "sugarss", "typescript"] }, "sha512-IvnbQ6D6Ao3Gg6ftiM5tdbR6aAETwjhHV+UKGf5bHGYR69RQvF1ho0JKPcbUON4vy4R7zom13jPjgdOWCQ5hDA=="],
690
+
691
+ "svelte-splitpanes": ["svelte-splitpanes@8.0.9", "", { "dependencies": { "esm-env-robust": "0.0.3" }, "peerDependencies": { "svelte": "^4.2.19 || ^5.1.0" } }, "sha512-L3oLXTC99M191FInTXJ/f/2i0welRql1QuVbPaU8iy6nvCR6X9VyjHCsCpLqKGWHwqkWo/AM9CQ1c0nzlb+MkA=="],
692
+
693
+ "synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="],
694
+
695
+ "three": ["three@0.180.0", "", {}, "sha512-o+qycAMZrh+TsE01GqWUxUIKR1AL0S8pq7zDkYOQw8GqfX8b8VoCKYUoHbhiX5j+7hr8XsuHDVU6+gkQJQKg9w=="],
696
+
697
+ "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
698
+
699
+ "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
700
+
701
+ "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="],
702
+
703
+ "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
704
+
705
+ "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="],
706
+
707
+ "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="],
708
+
709
+ "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="],
710
+
711
+ "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="],
712
+
713
+ "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
714
+
715
+ "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
716
+
717
+ "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
718
+
719
+ "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
720
+
721
+ "vibegame": ["vibegame@0.1.1", "", { "dependencies": { "@dimforge/rapier3d-compat": "^0.18.2", "gsap": "^3.13.0", "zod": "^4.1.5" }, "peerDependencies": { "bitecs": ">=0.3.40", "three": ">=0.170.0" } }, "sha512-HjWMlO4qUus9ChEBsD+abS9UGle/qiDZWukIqkve811N2oliKjWE7WYCDhqaDhWS18FaaYaY1a/Vc8yF0HaS1Q=="],
722
+
723
+ "vite": ["vite@5.4.20", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g=="],
724
+
725
+ "vitefu": ["vitefu@0.2.5", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["vite"] }, "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q=="],
726
+
727
+ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
728
+
729
+ "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="],
730
+
731
+ "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="],
732
+
733
+ "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="],
734
+
735
+ "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="],
736
+
737
+ "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
738
+
739
+ "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
740
+
741
+ "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
742
+
743
+ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
744
+
745
+ "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="],
746
+
747
+ "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
748
+
749
+ "@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
750
+
751
+ "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
752
+
753
+ "@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
754
+
755
+ "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
756
+
757
+ "eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
758
+
759
+ "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
760
+
761
+ "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
762
+
763
+ "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
764
+
765
+ "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
766
+
767
+ "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
768
+ }
769
+ }
eslint.config.js ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import js from "@eslint/js";
2
+ import tseslint from "@typescript-eslint/eslint-plugin";
3
+ import tsparser from "@typescript-eslint/parser";
4
+ import prettierConfig from "eslint-config-prettier";
5
+ import importPlugin from "eslint-plugin-import";
6
+ import prettier from "eslint-plugin-prettier";
7
+
8
+ export default [
9
+ js.configs.recommended,
10
+ {
11
+ files: ["**/*.ts", "**/*.tsx"],
12
+ languageOptions: {
13
+ parser: tsparser,
14
+ parserOptions: {
15
+ ecmaVersion: "latest",
16
+ sourceType: "module",
17
+ },
18
+ globals: {
19
+ console: "readonly",
20
+ window: "readonly",
21
+ document: "readonly",
22
+ HTMLElement: "readonly",
23
+ HTMLCanvasElement: "readonly",
24
+ KeyboardEvent: "readonly",
25
+ MouseEvent: "readonly",
26
+ WheelEvent: "readonly",
27
+ requestAnimationFrame: "readonly",
28
+ cancelAnimationFrame: "readonly",
29
+ performance: "readonly",
30
+ process: "readonly",
31
+ WebSocket: "readonly",
32
+ setTimeout: "readonly",
33
+ clearTimeout: "readonly",
34
+ setInterval: "readonly",
35
+ clearInterval: "readonly",
36
+ sessionStorage: "readonly",
37
+ localStorage: "readonly",
38
+ },
39
+ },
40
+ plugins: {
41
+ "@typescript-eslint": tseslint,
42
+ prettier: prettier,
43
+ import: importPlugin,
44
+ },
45
+ rules: {
46
+ ...tseslint.configs.recommended.rules,
47
+ ...prettierConfig.rules,
48
+ "prettier/prettier": "error",
49
+ "@typescript-eslint/no-unused-vars": [
50
+ "error",
51
+ { argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
52
+ ],
53
+ "@typescript-eslint/explicit-function-return-type": "off",
54
+ "@typescript-eslint/explicit-module-boundary-types": "off",
55
+ "@typescript-eslint/no-explicit-any": "warn",
56
+ "no-console": "off",
57
+ },
58
+ },
59
+ {
60
+ ignores: ["dist/**", "node_modules/**"],
61
+ },
62
+ ];
index.html ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>🥕 VibeGame</title>
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ padding: 0;
11
+ background: linear-gradient(135deg, #0b0a09 0%, #0f0e0c 100%);
12
+ color: #ffffff;
13
+ overflow: hidden;
14
+ min-height: 100vh;
15
+ }
16
+
17
+ #app {
18
+ opacity: 0;
19
+ animation: fadeIn 0.3s ease-out 0.1s forwards;
20
+ }
21
+
22
+ @keyframes fadeIn {
23
+ to {
24
+ opacity: 1;
25
+ }
26
+ }
27
+ </style>
28
+ </head>
29
+ <body>
30
+ <div id="app"></div>
31
+ <script type="module" src="/src/main.ts"></script>
32
+ </body>
33
+ </html>
layers/context-template.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Context Template
2
+
3
+ Concise context for any folder; link to code or subfolders for deeper context
4
+
5
+ ## Purpose
6
+
7
+ - [What this folder/module does]
8
+
9
+ ## Layout
10
+
11
+ ```
12
+ [FOLDER]/
13
+ context.md # This file, folder context (Tier 2)
14
+ ├── [FILE1].[ext] # File
15
+ ├── [FILE2].[ext] # File
16
+ ├── [subfolder]/ # Subfolder
17
+ │ ├── context.md # Subfolder context
18
+ │ ├── [FILE3].[ext] # File
19
+ │ └── [FILE4].[ext] # File
20
+ ```
21
+
22
+ ## Scope
23
+
24
+ - [In-scope]
25
+ - [Out-of-scope]
26
+
27
+ ## Entrypoints
28
+
29
+ - [Primary entry files or functions and when they are called]
30
+
31
+ ## Dependencies
32
+
33
+ - [Internal modules]
34
+ - [External libraries/services]
layers/structure.md ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Project Structure
2
+
3
+ AI-assisted iterative game development environment with real-time feedback
4
+
5
+ ## Stack
6
+
7
+ - Runtime: Bun
8
+ - Language: TypeScript
9
+ - UI Framework: Svelte
10
+ - Game Engine: VibeGame (3D physics, ECS)
11
+ - Code Editor: Monaco Editor
12
+ - AI Agent: Hugging Face Inference API
13
+ - WebSocket: ws (for real-time communication)
14
+ - Build: Vite
15
+ - Animation: GSAP (bundled with VibeGame)
16
+ - Physics: Rapier (via VibeGame)
17
+ - Rendering: Three.js (via VibeGame)
18
+
19
+ ## Commands
20
+
21
+ - `bun dev` - Development server with hot reload on port 7860
22
+ - `bun run build` - Build for production
23
+ - `bun run preview` - Preview production build
24
+ - `bun run check` - TypeScript + Svelte type checking
25
+ - `bun run lint` - ESLint code quality check
26
+ - `bun run format` - Auto-format with Prettier
27
+ - `bun run validate` - Complete validation (format, lint, type check)
28
+ - `bun run update` - Update llms.txt from VibeGame
29
+
30
+ ## Layout
31
+
32
+ ```
33
+ vibegame/
34
+ ├── CLAUDE.md # Global context (Tier 0)
35
+ ├── PLAN.md # Development roadmap
36
+ ├── layers/
37
+ │ ├── structure.md # Project structure (Tier 1)
38
+ │ └── context-template.md
39
+ ├── src/
40
+ │ ├── main.ts # Svelte app initialization
41
+ │ ├── App.svelte # Root UI component (declarative)
42
+ │ └── lib/
43
+ │ ├── stores/ # State management
44
+ │ ├── services/ # Business logic
45
+ │ ├── server/ # WebSocket server & agent
46
+ │ ├── components/ # UI components
47
+ │ │ ├── chat/ # AI chat interface
48
+ │ │ ├── console/
49
+ │ │ ├── editor/
50
+ │ │ ├── game/
51
+ │ │ └── layout/
52
+ │ └── config/ # Configuration
53
+ ├── index.html # Entry point
54
+ ├── package.json # Dependencies and scripts
55
+ ├── tsconfig.json # TypeScript configuration
56
+ ├── vite.config.ts # Vite + Svelte + VibeGame config
57
+ ├── bun.lock # Dependency lock file
58
+ ├── llms.txt # VibeGame documentation
59
+ └── README.md
60
+ ```
61
+
62
+ ## Architecture
63
+
64
+ Three-layer architecture: UI (Svelte) → Agent (Hugging Face) → Game (VibeGame)
65
+
66
+ - **UI Layer**: Svelte components for chat, code editing, console display
67
+ - **Agent Layer**: Hugging Face models via WebSocket for game assistance
68
+ - **Game Layer**: VibeGame ECS with declarative XML scene definition
69
+ - **Feedback Loop**: Console output → Agent parsing → Self-correction (planned)
70
+
71
+ ## Entry points
72
+
73
+ - Main entry: `index.html` (HTML shell)
74
+ - UI entry: `src/main.ts` (Svelte app mount)
75
+ - App root: `src/App.svelte` (Component tree root)
76
+ - Game definition: `<world>` tag in editor (Live-editable XML)
77
+
78
+ ## Naming Conventions
79
+
80
+ TypeScript/Web standards with Svelte and ECS conventions
81
+
82
+ - Files: kebab-case for utilities, PascalCase for components (e.g., `Chat.svelte`, `mcp-tools.js`)
83
+ - Directories: lowercase (e.g., `src/`, `components/`, `stores/`)
84
+ - Svelte components: PascalCase (e.g., `Editor.svelte`, `Preview.svelte`)
85
+ - Stores: camelCase (e.g., `gameState`, `consoleMessages`)
86
+ - ECS Components: PascalCase (e.g., `Health`, `Transform`)
87
+ - Systems: PascalCase with "System" suffix (e.g., `HealthSystem`)
88
+
89
+ ## Configuration
90
+
91
+ - TypeScript: `tsconfig.json` (Strict mode, ESNext target)
92
+ - Build: `vite.config.ts` (Vite with Svelte, VibeGame, WebSocket plugins)
93
+ - Dependencies: `package.json` (Svelte, VibeGame, Monaco, Hugging Face, ws)
94
+ - Game Scene: Live-editable in Monaco editor
95
+
96
+ ## Where to add code
97
+
98
+ - UI components → `src/lib/components/[feature]/[Component].svelte`
99
+ - State management → `src/lib/stores/[store].ts`
100
+ - Business logic → `src/lib/services/[service].ts`
101
+ - Server/Agent logic → `src/lib/server/[module].ts`
102
+ - MCP tools → `src/lib/tools/[tool].ts`
103
+ - Configuration → `src/lib/config/[config].ts`
104
+ - Game entities → XML in Monaco editor
105
+ - Custom ECS components → `src/lib/game/components/[Component].ts`
106
+ - Custom systems → `src/lib/game/systems/[System].ts`
llms.txt ADDED
@@ -0,0 +1,1107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # VibeGame
2
+
3
+ A 3D game engine with declarative XML syntax and ECS architecture. Start playing immediately with automatic player, camera, and lighting - just add a ground to prevent falling.
4
+
5
+ ## Instant Playable Game
6
+
7
+ ```html
8
+ <script src="https://cdn.jsdelivr.net/npm/vibegame@latest/dist/cdn/vibegame.standalone.iife.js"></script>
9
+
10
+ <world canvas="#game-canvas" sky="#87ceeb">
11
+ <!-- Ground (REQUIRED to prevent player falling) -->
12
+ <static-part pos="0 -0.5 0" shape="box" size="20 1 20" color="#90ee90"></static-part>
13
+ </world>
14
+
15
+ <canvas id="game-canvas"></canvas>
16
+ <script>
17
+ GAME.run();
18
+ </script>
19
+ ```
20
+
21
+ This creates a complete game with:
22
+ - ✅ Player character (auto-created)
23
+ - ✅ Orbital camera (auto-created)
24
+ - ✅ Directional + ambient lighting (auto-created)
25
+ - ✅ Ground platform (you provide this)
26
+ - ✅ WASD movement, mouse camera, space to jump
27
+
28
+ ## Development Setup
29
+
30
+ After installation with `npm create vibegame@latest my-game`:
31
+
32
+ ```bash
33
+ cd my-game
34
+ bun dev # Start dev server with hot reload
35
+ ```
36
+
37
+ ### Project Structure
38
+ - **TypeScript** - Full TypeScript support with strict type checking
39
+ - **src/main.ts** - Entry point for your game
40
+ - **index.html** - HTML template with canvas element
41
+ - **vite.config.ts** - Build configuration
42
+
43
+ ### Commands
44
+ - `bun dev` - Development server with hot reload
45
+ - `bun run build` - Production build
46
+ - `bun run preview` - Preview production build
47
+ - `bun run check` - TypeScript type checking
48
+ - `bun run lint` - Lint code with ESLint
49
+ - `bun run format` - Format code with Prettier
50
+ - `bun run update` - Update llms.txt after upgrading vibegame
51
+
52
+ ## Physics Objects
53
+
54
+ ```xml
55
+ <world canvas="#game-canvas">
56
+ <!-- 1. Static: Never moves (grounds, walls, platforms) -->
57
+ <static-part pos="0 -0.5 0" shape="box" size="20 1 20" color="#808080"></static-part>
58
+
59
+ <!-- 2. Dynamic: Falls with gravity (balls, crates, debris) -->
60
+ <dynamic-part pos="0 5 0" shape="sphere" size="1" color="#ff0000"></dynamic-part>
61
+
62
+ <!-- 3. Kinematic: Script-controlled movement (moving platforms, doors) -->
63
+ <kinematic-part pos="5 2 0" shape="box" size="3 0.5 3" color="#0000ff">
64
+ <!-- Animate the platform up and down -->
65
+ <tween target="body.pos-y" from="2" to="5" duration="3" loop="ping-pong"></tween>
66
+ </kinematic-part>
67
+ </world>
68
+ ```
69
+
70
+ ## CRITICAL: Physics Position vs Transform Position
71
+
72
+ <warning>
73
+ ⚠️ **Physics bodies override transform positions!**
74
+ Always set position on the body, not the transform, for physics entities.
75
+ </warning>
76
+
77
+ ```xml
78
+ <!-- ✅ BEST: Use recipe with pos shorthand -->
79
+ <dynamic-part pos="0 5 0" shape="sphere" size="1"></dynamic-part>
80
+
81
+ <!-- ❌ WRONG: Transform position ignored if body exists -->
82
+ <entity transform="pos: 0 5 0" body collider></entity> <!-- Falls to 0,0,0! -->
83
+
84
+ <!-- ✅ CORRECT: Set body position explicitly (if using raw entity) -->
85
+ <entity transform body="pos: 0 5 0" collider></entity>
86
+ ```
87
+
88
+ ## ECS Architecture Explained
89
+
90
+ Unlike traditional game engines with GameObjects, VibeGame uses Entity-Component-System:
91
+
92
+ - **Entities**: Just numbers (IDs), no data or behavior
93
+ - **Components**: Pure data containers (position, health, color)
94
+ - **Systems**: Functions that process entities with specific components
95
+
96
+ ```typescript
97
+ // Component = Data only
98
+ const Health = GAME.defineComponent({
99
+ current: GAME.Types.f32,
100
+ max: GAME.Types.f32
101
+ });
102
+
103
+ // System = Logic only
104
+ const DamageSystem: GAME.System = {
105
+ update: (state) => {
106
+ const entities = GAME.defineQuery([Health])(state.world);
107
+ for (const entity of entities) {
108
+ Health.current[entity] -= 1 * state.time.delta;
109
+ if (Health.current[entity] <= 0) {
110
+ state.destroyEntity(entity);
111
+ }
112
+ }
113
+ }
114
+ };
115
+ ```
116
+
117
+ ## What's Auto-Created (Game Engine Defaults)
118
+
119
+ The engine automatically creates these if missing:
120
+ 1. **Player** - Character with physics, controls, and respawn (at 0, 1, 0)
121
+ 2. **Camera** - Orbital camera following the player
122
+ 3. **Lighting** - Ambient + directional light with shadows
123
+
124
+ You only need to provide:
125
+ - **Ground/platforms** - Or the player falls forever
126
+ - **Game objects** - Whatever makes your game unique
127
+
128
+ ### Override Auto-Creation (When Needed)
129
+
130
+ While auto-creation is recommended, you can manually create these for customization:
131
+
132
+ ```xml
133
+ <world canvas="#game-canvas">
134
+ <static-part pos="0 -0.5 0" shape="box" size="20 1 20" color="#90ee90"></static-part>
135
+
136
+ <!-- Custom player spawn position and properties -->
137
+ <player pos="0 10 0" speed="8" jump-height="3"></player>
138
+
139
+ <!-- Custom camera settings -->
140
+ <camera orbit-camera="distance: 10; target-pitch: 0.5"></camera>
141
+
142
+ <!-- Custom lighting (or use <light> for both ambient + directional) -->
143
+ <ambient-light sky-color="#ff6b6b" ground-color="#4ecdc4" intensity="0.8"></ambient-light>
144
+ <directional-light color="#ffffff" intensity="0.5" direction="-1 -2 -1"></directional-light>
145
+ </world>
146
+ ```
147
+
148
+ **Best Practice**: Use auto-creation unless you specifically need custom positions, properties, or multiple instances. The defaults are well-tuned for most games.
149
+
150
+ ## Common Game Patterns
151
+
152
+ ### Basic Platformer
153
+ ```xml
154
+ <world canvas="#game-canvas">
155
+ <!-- Ground -->
156
+ <static-part pos="0 -0.5 0" shape="box" size="50 1 50" color="#90ee90"></static-part>
157
+
158
+ <!-- Platforms at different heights -->
159
+ <static-part pos="-5 2 0" shape="box" size="3 0.5 3" color="#808080"></static-part>
160
+ <static-part pos="0 4 0" shape="box" size="3 0.5 3" color="#808080"></static-part>
161
+ <static-part pos="5 6 0" shape="box" size="3 0.5 3" color="#808080"></static-part>
162
+
163
+ <!-- Moving platform -->
164
+ <kinematic-part pos="0 3 5" shape="box" size="4 0.5 4" color="#4169e1">
165
+ <tween target="body.pos-x" from="-10" to="10" duration="5" loop="ping-pong"></tween>
166
+ </kinematic-part>
167
+
168
+ <!-- Goal area -->
169
+ <static-part pos="10 8 0" shape="box" size="5 0.5 5" color="#ffd700"></static-part>
170
+ </world>
171
+ ```
172
+
173
+ ### Collectible Coins (Collision-based)
174
+ ```xml
175
+ <world canvas="#game-canvas">
176
+ <static-part pos="0 -0.5 0" shape="box" size="20 1 20" color="#90ee90"></static-part>
177
+
178
+ <!-- Spinning coins -->
179
+ <kinematic-part pos="2 1 0" shape="cylinder" size="0.5 0.1 0.5" color="#ffd700">
180
+ <tween target="body.euler-y" from="0" to="360" duration="2" loop="loop"></tween>
181
+ </kinematic-part>
182
+
183
+ <kinematic-part pos="-2 1 0" shape="cylinder" size="0.5 0.1 0.5" color="#ffd700">
184
+ <tween target="body.euler-y" from="0" to="360" duration="2" loop="loop"></tween>
185
+ </kinematic-part>
186
+ </world>
187
+ ```
188
+
189
+ ### Physics Playground
190
+ ```xml
191
+ <world canvas="#game-canvas">
192
+ <!-- Ground -->
193
+ <static-part pos="0 -0.5 0" shape="box" size="30 1 30" color="#90ee90"></static-part>
194
+
195
+ <!-- Walls -->
196
+ <static-part pos="15 5 0" shape="box" size="1 10 30" color="#808080"></static-part>
197
+ <static-part pos="-15 5 0" shape="box" size="1 10 30" color="#808080"></static-part>
198
+ <static-part pos="0 5 15" shape="box" size="30 10 1" color="#808080"></static-part>
199
+ <static-part pos="0 5 -15" shape="box" size="30 10 1" color="#808080"></static-part>
200
+
201
+ <!-- Spawn balls at different positions -->
202
+ <dynamic-part pos="-5 10 0" shape="sphere" size="1" color="#ff0000"></dynamic-part>
203
+ <dynamic-part pos="0 12 0" shape="sphere" size="1.5" color="#00ff00"></dynamic-part>
204
+ <dynamic-part pos="5 8 0" shape="sphere" size="0.8" color="#0000ff"></dynamic-part>
205
+
206
+ <!-- Bouncy ball (high restitution) -->
207
+ <dynamic-part pos="0 15 5" shape="sphere" size="1" color="#ff00ff"
208
+ collider="restitution: 0.9"></dynamic-part>
209
+ </world>
210
+ ```
211
+
212
+ ## Recipe Reference
213
+
214
+ | Recipe | Purpose | Key Attributes | Common Use |
215
+ |--------|---------|---------------|------------|
216
+ | `<static-part>` | Immovable objects | `pos`, `shape`, `size`, `color` | Grounds, walls, platforms |
217
+ | `<dynamic-part>` | Gravity-affected objects | `pos`, `shape`, `size`, `color`, `mass` | Balls, crates, falling objects |
218
+ | `<kinematic-part>` | Script-controlled physics | `pos`, `shape`, `size`, `color` | Moving platforms, doors |
219
+ | `<player>` | Player character | `pos`, `speed`, `jump-height` | Main character (auto-created) |
220
+ | `<entity>` | Base entity | Any components via attributes | Custom entities |
221
+
222
+ ### Shape Options
223
+ - `box` - Rectangular solid (default)
224
+ - `sphere` - Ball shape
225
+ - `cylinder` - Cylindrical shape
226
+ - `capsule` - Pill shape (good for characters)
227
+
228
+ ### Size Attribute
229
+ - Box: `size="width height depth"` or `size="2 1 2"`
230
+ - Sphere: `size="diameter"` or `size="1"`
231
+ - Cylinder: `size="diameter height"` or `size="1 2"`
232
+ - Broadcast: `size="2"` becomes `size="2 2 2"`
233
+
234
+ ## How Recipes and Shorthands Work
235
+
236
+ ### Everything is an Entity
237
+ Every XML tag creates an entity. Recipes like `<static-part>` are just shortcuts for `<entity>` with preset components.
238
+
239
+ ```xml
240
+ <!-- These are equivalent: -->
241
+ <static-part pos="0 0 0" color="#ff0000"></static-part>
242
+
243
+ <entity
244
+ transform
245
+ body="type: fixed"
246
+ collider
247
+ renderer="color: 0xff0000"
248
+ pos="0 0 0"></entity>
249
+ ```
250
+
251
+ ### Component Attributes
252
+ Components are declared using bare attributes (no value means "use defaults"):
253
+
254
+ ```xml
255
+ <!-- Bare attributes declare components with default values -->
256
+ <entity transform body collider renderer></entity>
257
+
258
+ <!-- Add properties to override defaults -->
259
+ <entity transform="pos-x: 5; pos-y: 2; pos-z: -3; scale: 2"></entity>
260
+
261
+ <!-- Mix bare and valued attributes -->
262
+ <entity transform="pos: 0 5 0" body="type: dynamic; mass: 10" collider renderer></entity>
263
+
264
+ <!-- Property groups -->
265
+ <entity transform="pos: 5 2 -3; scale: 2 2 2"></entity>
266
+ ```
267
+
268
+ **Important**: Bare attributes like `transform` mean "include this component with default values", NOT "empty" or "disabled".
269
+
270
+ ### Automatic Shorthand Expansion
271
+ Shorthands expand to ANY component with matching properties:
272
+
273
+ ```xml
274
+ <!-- "pos" shorthand applies to components with posX, posY, posZ -->
275
+ <entity transform body pos="0 5 0"></entity>
276
+ <!-- Both transform AND body get pos values -->
277
+
278
+ <!-- "color" shorthand applies to renderer.color -->
279
+ <entity renderer color="#ff0000"></entity>
280
+
281
+ <!-- "size" shorthand (broadcasts single value) -->
282
+ <entity collider size="2"></entity>
283
+ <!-- Expands to: sizeX: 2, sizeY: 2, sizeZ: 2 -->
284
+
285
+ <!-- Multiple shorthands together -->
286
+ <entity transform body collider renderer pos="0 5 0" size="1" color="#ff0000"></entity>
287
+ ```
288
+
289
+ ### Recipe Internals
290
+ Recipes are registered component bundles with defaults:
291
+
292
+ ```xml
293
+ <!-- What <dynamic-part> actually is: -->
294
+ <entity
295
+ transform
296
+ body="type: dynamic" <!-- Override -->
297
+ collider
298
+ renderer
299
+ respawn
300
+ ></entity>
301
+
302
+ <!-- So this: -->
303
+ <dynamic-part pos="0 5 0" color="#ff0000"></dynamic-part>
304
+
305
+ <!-- Is really: -->
306
+ <entity
307
+ transform="pos: 0 5 0"
308
+ body="type: dynamic; pos: 0 5 0" <!-- pos applies to body too! -->
309
+ collider
310
+ renderer="color: 0xff0000"
311
+ respawn
312
+ ></entity>
313
+ ```
314
+
315
+ ### Common Pitfall: Component Requirements
316
+ ```xml
317
+ <!-- ❌ BAD: Missing required components -->
318
+ <entity pos="0 5 0"></entity> <!-- No transform component! -->
319
+
320
+ <!-- ✅ GOOD: Explicit components -->
321
+ <entity transform="pos: 0 5 0"></entity>
322
+
323
+ <!-- ✅ BEST: Use recipe with built-in components -->
324
+ <static-part pos="0 5 0"></static-part>
325
+ ```
326
+
327
+ ### Best Practices Summary
328
+ 1. **Use recipes** (`<static-part>`, `<dynamic-part>`, etc.) instead of raw `<entity>` tags
329
+ 2. **Use shorthands** (`pos`, `size`, `color`) for cleaner code
330
+ 3. **Override only what you need** - recipes have good defaults
331
+ 4. **Mix recipes with custom components** - e.g., `<dynamic-part health="max: 100">`
332
+
333
+ ## Currently Supported Features
334
+
335
+ ### ✅ What Works Well
336
+ - **Basic platforming** - Jump puzzles, obstacle courses
337
+ - **Physics interactions** - Balls, dominoes, stacking
338
+ - **Moving platforms** - Via kinematic bodies + tweening
339
+ - **Collectibles** - Using collision detection in systems
340
+ - **Third-person character control** - WASD + mouse camera
341
+ - **Gamepad support** - Xbox/PlayStation controllers
342
+ - **Visual effects** - Tweening colors, positions, rotations
343
+
344
+ ### Example Prompts That Work
345
+ - "Create a platformer with moving platforms and collectible coins"
346
+ - "Make bouncing balls that collide with walls"
347
+ - "Build an obstacle course with rotating platforms"
348
+ - "Add falling crates that stack up"
349
+ - "Create a simple parkour level"
350
+
351
+ ## Features Not Yet Built-In
352
+
353
+ ### ❌ Engine Features Not Available
354
+ - **Multiplayer/Networking** - No server sync
355
+ - **Sound/Audio** - No audio system yet
356
+ - **Save/Load** - No persistence system
357
+ - **Inventory** - No item management
358
+ - **Dialog/NPCs** - No conversation system
359
+ - **AI/Pathfinding** - No enemy AI
360
+ - **Particles** - No particle effects
361
+ - **Custom shaders** - Fixed rendering pipeline
362
+ - **Terrain** - Use box platforms instead
363
+
364
+ ### ✅ Available Through Web Platform
365
+ - **UI/HUD** - Use standard HTML/CSS overlays on the canvas
366
+ - **Animations** - GSAP is included for advanced UI animations
367
+ - **Score display** → HTML elements positioned over canvas
368
+ - **Menus** → Standard web UI (divs, buttons, etc.)
369
+
370
+ ### Recommended Approaches
371
+ - **UI** → Position HTML elements over the canvas with CSS
372
+ - **Animations** → Use GSAP for smooth UI transitions
373
+ - **Level progression** → Reload with different XML or hide/show worlds
374
+ - **Enemy behavior** → Tweened movement patterns
375
+ - **Interactions** → Collision detection in custom systems
376
+
377
+ ## Common Mistakes to Avoid
378
+
379
+ ### ❌ Forgetting the Ground
380
+ ```xml
381
+ <!-- BAD: No ground, player falls forever -->
382
+ <world canvas="#game-canvas">
383
+ <dynamic-part pos="0 5 0" shape="sphere"></dynamic-part>
384
+ </world>
385
+ ```
386
+
387
+ ### ❌ Setting Transform Position on Physics Objects
388
+ ```xml
389
+ <!-- BAD: Transform position ignored -->
390
+ <entity transform="pos: 0 5 0" body collider></entity>
391
+
392
+ <!-- GOOD: Set body position (raw entity) -->
393
+ <entity transform body="pos: 0 5 0" collider></entity>
394
+
395
+ <!-- BEST: Use recipes with pos shorthand -->
396
+ <dynamic-part pos="0 5 0" shape="sphere"></dynamic-part>
397
+ ```
398
+
399
+ ### ❌ Missing World Tag
400
+ ```xml
401
+ <!-- BAD: Entities outside world tag -->
402
+ <static-part pos="0 0 0" shape="box"></static-part>
403
+
404
+ <!-- GOOD: Everything inside world -->
405
+ <world canvas="#game-canvas">
406
+ <static-part pos="0 0 0" shape="box"></static-part>
407
+ </world>
408
+ ```
409
+
410
+ ### ❌ Wrong Physics Type
411
+ ```xml
412
+ <!-- BAD: Dynamic platform (falls with gravity) -->
413
+ <dynamic-part pos="0 3 0" shape="box">
414
+ <tween target="body.pos-x" from="-5" to="5"></tween>
415
+ </dynamic-part>
416
+
417
+ <!-- GOOD: Kinematic for controlled movement -->
418
+ <kinematic-part pos="0 3 0" shape="box">
419
+ <tween target="body.pos-x" from="-5" to="5"></tween>
420
+ </kinematic-part>
421
+ ```
422
+
423
+ ## Custom Components and Systems
424
+
425
+ ### Creating a Health System
426
+ ```typescript
427
+ import * as GAME from 'vibegame';
428
+
429
+ // Define the component
430
+ const Health = GAME.defineComponent({
431
+ current: GAME.Types.f32,
432
+ max: GAME.Types.f32
433
+ });
434
+
435
+ // Create the system
436
+ const HealthSystem: GAME.System = {
437
+ update: (state) => {
438
+ const entities = GAME.defineQuery([Health])(state.world);
439
+ for (const entity of entities) {
440
+ // Regenerate health over time
441
+ if (Health.current[entity] < Health.max[entity]) {
442
+ Health.current[entity] += 5 * state.time.delta;
443
+ }
444
+ }
445
+ }
446
+ };
447
+
448
+ // Bundle as plugin
449
+ const HealthPlugin: GAME.Plugin = {
450
+ components: { Health },
451
+ systems: [HealthSystem],
452
+ config: {
453
+ defaults: {
454
+ "health": { current: 100, max: 100 }
455
+ }
456
+ }
457
+ };
458
+
459
+ // Use in game
460
+ GAME.withPlugin(HealthPlugin).run();
461
+ ```
462
+
463
+ ### Using in XML
464
+ ```xml
465
+ <world canvas="#game-canvas">
466
+ <!-- Add health to a dynamic entity (best practice: use recipes) -->
467
+ <dynamic-part pos="0 2 0" shape="sphere" color="#ff0000"
468
+ health="current: 50; max: 100"></dynamic-part>
469
+ </world>
470
+ ```
471
+
472
+ ## State API Reference
473
+
474
+ Available in all systems via the `state` parameter:
475
+
476
+ ### Entity Management
477
+ - `createEntity(): number` - Create new entity
478
+ - `destroyEntity(entity: number)` - Remove entity
479
+ - `query(...Components): number[]` - Find entities with components
480
+
481
+ ### Component Operations
482
+ - `addComponent(entity, Component, data?)` - Add component
483
+ - `removeComponent(entity, Component)` - Remove component
484
+ - `hasComponent(entity, Component): boolean` - Check component
485
+ - `getComponent(name: string): Component | null` - Get by name
486
+
487
+ ### Time
488
+ - `time.delta: number` - Frame time in seconds
489
+ - `time.elapsed: number` - Total time in seconds
490
+ - `time.fixed: number` - Fixed timestep (1/60)
491
+
492
+ ### Physics Helpers
493
+ - `addComponent(entity, ApplyImpulse, {x, y, z})` - One-time push
494
+ - `addComponent(entity, ApplyForce, {x, y, z})` - Continuous force
495
+ - `addComponent(entity, KinematicMove, {x, y, z})` - Move kinematic
496
+
497
+ ## Plugin System
498
+
499
+ ### Using Specific Plugins
500
+ ```typescript
501
+ import * as GAME from 'vibegame';
502
+
503
+ // Start with no plugins
504
+ GAME
505
+ .withoutDefaultPlugins()
506
+ .withPlugin(TransformsPlugin) // Just transforms
507
+ .withPlugin(RenderingPlugin) // Add rendering
508
+ .withPlugin(PhysicsPlugin) // Add physics
509
+ .run();
510
+ ```
511
+
512
+ ### Default Plugin Bundle
513
+ - **RecipesPlugin** - XML parsing and entity creation
514
+ - **TransformsPlugin** - Position, rotation, scale, hierarchy
515
+ - **RenderingPlugin** - Three.js meshes, lights, camera
516
+ - **PhysicsPlugin** - Rapier physics simulation
517
+ - **InputPlugin** - Keyboard, mouse, gamepad input
518
+ - **OrbitCameraPlugin** - Third-person camera
519
+ - **PlayerPlugin** - Character controller
520
+ - **TweenPlugin** - Animation system
521
+ - **RespawnPlugin** - Fall detection and reset
522
+ - **StartupPlugin** - Auto-create player/camera/lights
523
+
524
+ ## Module Documentation
525
+
526
+ ### Core
527
+ Math utilities for interpolation and 3D transformations.
528
+
529
+ ### Animation
530
+ Procedural character animation with body parts that respond to movement states.
531
+
532
+ ### Input
533
+ Focus-aware input handling for mouse, keyboard, and gamepad with buffered actions. Keyboard input only responds when canvas has focus.
534
+
535
+ ### Orbit Camera
536
+ Orbital camera controller for third-person views and smooth target following.
537
+
538
+ ### Physics
539
+ 3D physics simulation with Rapier including rigid bodies, collisions, and character controllers.
540
+
541
+ ### Player
542
+ Complete player character controller with physics movement and jumping.
543
+
544
+ ### Recipes
545
+ Foundation for declarative XML entity creation with parent-child hierarchies and attribute shorthands.
546
+
547
+ ### Rendering
548
+ Three.js rendering pipeline with meshes, lights, and cameras.
549
+
550
+ ### Respawn
551
+ Automatic respawn system that resets entities when falling below Y=-100.
552
+
553
+ ### Startup
554
+ Auto-creates player, camera, and lighting entities at startup if missing.
555
+
556
+ ### Transforms
557
+ 3D transforms with position, rotation, scale, and parent-child hierarchies.
558
+
559
+ ### Tweening
560
+ Animates component properties with easing functions and loop modes.
561
+
562
+ ## Plugin Reference
563
+
564
+ ### Core
565
+
566
+ ### Functions
567
+
568
+ #### lerp(a, b, t): number
569
+ Linear interpolation
570
+
571
+ #### slerp(fromX, fromY, fromZ, fromW, toX, toY, toZ, toW, t): Quaternion
572
+ Quaternion spherical interpolation
573
+
574
+ ### Animation
575
+
576
+ ### Components
577
+
578
+ #### AnimatedCharacter
579
+ - headEntity: eid
580
+ - torsoEntity: eid
581
+ - leftArmEntity: eid
582
+ - rightArmEntity: eid
583
+ - leftLegEntity: eid
584
+ - rightLegEntity: eid
585
+ - phase: f32 - Walk cycle phase (0-1)
586
+ - jumpTime: f32
587
+ - fallTime: f32
588
+ - animationState: ui8 - 0=IDLE, 1=WALKING, 2=JUMPING, 3=FALLING, 4=LANDING
589
+ - stateTransition: f32
590
+
591
+ #### HasAnimator
592
+ Tag component (no properties)
593
+
594
+ ### Systems
595
+
596
+ #### AnimatedCharacterInitializationSystem
597
+ - Group: setup
598
+ - Creates body part entities for AnimatedCharacter components
599
+
600
+ #### AnimatedCharacterUpdateSystem
601
+ - Group: simulation
602
+ - Updates character animation based on movement and physics state
603
+
604
+ ### Input
605
+
606
+ ### Components
607
+
608
+ #### InputState
609
+ - moveX: f32 - Horizontal axis (-1 left, 1 right)
610
+ - moveY: f32 - Forward/backward (-1 back, 1 forward)
611
+ - moveZ: f32 - Vertical axis (-1 down, 1 up)
612
+ - lookX: f32 - Mouse delta X
613
+ - lookY: f32 - Mouse delta Y
614
+ - scrollDelta: f32 - Mouse wheel delta
615
+ - jump: ui8 - Jump available (0/1)
616
+ - primaryAction: ui8 - Primary action (0/1)
617
+ - secondaryAction: ui8 - Secondary action (0/1)
618
+ - leftMouse: ui8 - Left button (0/1)
619
+ - rightMouse: ui8 - Right button (0/1)
620
+ - middleMouse: ui8 - Middle button (0/1)
621
+ - jumpBufferTime: f32
622
+ - primaryBufferTime: f32
623
+ - secondaryBufferTime: f32
624
+
625
+ ### Systems
626
+
627
+ #### InputSystem
628
+ - Group: simulation
629
+ - Updates InputState components with current input data
630
+
631
+ ### Functions
632
+
633
+ #### setTargetCanvas(canvas: HTMLCanvasElement | null): void
634
+ Registers canvas for focus-based keyboard input
635
+
636
+ #### consumeJump(): boolean
637
+ Consumes buffered jump input
638
+
639
+ #### consumePrimary(): boolean
640
+ Consumes buffered primary action
641
+
642
+ #### consumeSecondary(): boolean
643
+ Consumes buffered secondary action
644
+
645
+ #### handleMouseMove(event: MouseEvent): void
646
+ Processes mouse movement
647
+
648
+ #### handleMouseDown(event: MouseEvent): void
649
+ Processes mouse button press
650
+
651
+ #### handleMouseUp(event: MouseEvent): void
652
+ Processes mouse button release
653
+
654
+ #### handleWheel(event: WheelEvent): void
655
+ Processes mouse wheel
656
+
657
+ ### Constants
658
+
659
+ #### INPUT_CONFIG
660
+ Default input mappings and sensitivity settings
661
+
662
+ ### Orbit Camera
663
+
664
+ ### Components
665
+
666
+ #### OrbitCamera
667
+ - target: eid (0) - Target entity ID
668
+ - current-yaw: f32 (π) - Current horizontal angle
669
+ - current-pitch: f32 (π/6) - Current vertical angle
670
+ - current-distance: f32 (4) - Current distance
671
+ - target-yaw: f32 (π) - Target horizontal angle
672
+ - target-pitch: f32 (π/6) - Target vertical angle
673
+ - target-distance: f32 (4) - Target distance
674
+ - min-distance: f32 (1)
675
+ - max-distance: f32 (25)
676
+ - min-pitch: f32 (0)
677
+ - max-pitch: f32 (π/2)
678
+ - smoothness: f32 (0.5) - Interpolation speed
679
+ - offset-x: f32 (0)
680
+ - offset-y: f32 (1.25)
681
+ - offset-z: f32 (0)
682
+
683
+ ### Systems
684
+
685
+ #### OrbitCameraSystem
686
+ - Group: draw
687
+ - Updates camera position and rotation around target
688
+
689
+ ### Recipes
690
+
691
+ #### camera
692
+ - Creates orbital camera with default settings
693
+ - Components: orbit-camera, transform, world-transform, main-camera
694
+
695
+ ### Physics
696
+
697
+ ### Constants
698
+
699
+ - DEFAULT_GRAVITY: -60
700
+
701
+ ### Enums
702
+
703
+ #### BodyType
704
+ - Dynamic = 0 - Affected by forces
705
+ - Fixed = 1 - Immovable static
706
+ - KinematicPositionBased = 2 - Script position
707
+ - KinematicVelocityBased = 3 - Script velocity
708
+
709
+ #### ColliderShape
710
+ - Box = 0
711
+ - Sphere = 1
712
+ - Capsule = 2
713
+
714
+ ### Components
715
+
716
+ #### PhysicsWorld
717
+ - gravityX: f32 (0)
718
+ - gravityY: f32 (-60)
719
+ - gravityZ: f32 (0)
720
+
721
+ #### Body
722
+ - type: ui8 - BodyType enum (Fixed)
723
+ - mass: f32 (1)
724
+ - linearDamping: f32 (0)
725
+ - angularDamping: f32 (0)
726
+ - gravityScale: f32 (1)
727
+ - ccd: ui8 (0)
728
+ - lockRotX: ui8 (0)
729
+ - lockRotY: ui8 (0)
730
+ - lockRotZ: ui8 (0)
731
+ - posX, posY, posZ: f32
732
+ - rotX, rotY, rotZ, rotW: f32 (rotW=1)
733
+ - eulerX, eulerY, eulerZ: f32
734
+ - velX, velY, velZ: f32
735
+ - rotVelX, rotVelY, rotVelZ: f32
736
+
737
+ #### Collider
738
+ - shape: ui8 - ColliderShape enum (Box)
739
+ - sizeX, sizeY, sizeZ: f32 (1)
740
+ - radius: f32 (0.5)
741
+ - height: f32 (1)
742
+ - friction: f32 (0.5)
743
+ - restitution: f32 (0)
744
+ - density: f32 (1)
745
+ - isSensor: ui8 (0)
746
+ - membershipGroups: ui16 (0xffff)
747
+ - filterGroups: ui16 (0xffff)
748
+ - posOffsetX, posOffsetY, posOffsetZ: f32
749
+ - rotOffsetX, rotOffsetY, rotOffsetZ, rotOffsetW: f32 (rotOffsetW=1)
750
+
751
+ #### CharacterController
752
+ - offset: f32 (0.08)
753
+ - maxSlope: f32 (45°)
754
+ - maxSlide: f32 (30°)
755
+ - snapDist: f32 (0.5)
756
+ - autoStep: ui8 (1)
757
+ - maxStepHeight: f32 (0.3)
758
+ - minStepWidth: f32 (0.05)
759
+ - upX, upY, upZ: f32 (upY=1)
760
+ - moveX, moveY, moveZ: f32
761
+ - grounded: ui8
762
+
763
+ #### CharacterMovement
764
+ - desiredVelX, desiredVelY, desiredVelZ: f32
765
+ - velocityY: f32
766
+ - actualMoveX, actualMoveY, actualMoveZ: f32
767
+
768
+ #### InterpolatedTransform
769
+ - prevPosX, prevPosY, prevPosZ: f32
770
+ - prevRotX, prevRotY, prevRotZ, prevRotW: f32
771
+ - posX, posY, posZ: f32
772
+ - rotX, rotY, rotZ, rotW: f32
773
+
774
+ #### Force/Impulse Components
775
+ - ApplyForce: x, y, z (f32)
776
+ - ApplyTorque: x, y, z (f32)
777
+ - ApplyImpulse: x, y, z (f32)
778
+ - ApplyAngularImpulse: x, y, z (f32)
779
+ - SetLinearVelocity: x, y, z (f32)
780
+ - SetAngularVelocity: x, y, z (f32)
781
+ - KinematicMove: x, y, z (f32)
782
+ - KinematicRotate: x, y, z, w (f32)
783
+
784
+ #### Collision Events
785
+ - CollisionEvents: activeEvents (ui8)
786
+ - TouchedEvent: other, handle1, handle2 (ui32)
787
+ - TouchEndedEvent: other, handle1, handle2 (ui32)
788
+
789
+ ### Systems
790
+
791
+ - PhysicsWorldSystem - Initializes physics world
792
+ - PhysicsInitializationSystem - Creates bodies and colliders
793
+ - CharacterMovementSystem - Character controller movement
794
+ - PhysicsCleanupSystem - Removes physics on entity destroy
795
+ - CollisionEventCleanupSystem - Clears collision events
796
+ - ApplyForcesSystem - Applies forces
797
+ - ApplyTorquesSystem - Applies torques
798
+ - ApplyImpulsesSystem - Applies impulses
799
+ - ApplyAngularImpulsesSystem - Applies angular impulses
800
+ - SetVelocitySystem - Sets velocities
801
+ - TeleportationSystem - Instant position changes
802
+ - KinematicMovementSystem - Kinematic movement
803
+ - PhysicsStepSystem - Steps simulation
804
+ - PhysicsRapierSyncSystem - Syncs Rapier to ECS
805
+ - PhysicsInterpolationSystem - Interpolates for rendering
806
+
807
+ ### Functions
808
+
809
+ #### initializePhysics(): Promise<void>
810
+ Initializes Rapier WASM physics engine
811
+
812
+ ### Recipes
813
+
814
+ - static-part - Immovable physics objects
815
+ - dynamic-part - Gravity-affected objects
816
+ - kinematic-part - Script-controlled objects
817
+
818
+ ### Player
819
+
820
+ ### Components
821
+
822
+ #### Player
823
+ - speed: f32 (5.3)
824
+ - jumpHeight: f32 (2.3)
825
+ - rotationSpeed: f32 (10)
826
+ - canJump: ui8 (1)
827
+ - isJumping: ui8 (0)
828
+ - jumpCooldown: f32 (0)
829
+ - lastGroundedTime: f32 (0)
830
+ - jumpBufferTime: f32 (-10000)
831
+ - cameraSensitivity: f32 (0.007)
832
+ - cameraZoomSensitivity: f32 (1.5)
833
+ - cameraEntity: eid (0)
834
+
835
+ ### Systems
836
+
837
+ #### PlayerMovementSystem
838
+ - Group: fixed
839
+ - Handles movement, rotation, and jumping from input
840
+
841
+ #### PlayerGroundedSystem
842
+ - Group: fixed
843
+ - Tracks grounded state and jump availability
844
+
845
+ #### PlayerCameraLinkingSystem
846
+ - Group: simulation
847
+ - Links player to orbit camera
848
+
849
+ #### PlayerCameraControlSystem
850
+ - Group: simulation
851
+ - Camera control via mouse input
852
+
853
+ ### Recipes
854
+
855
+ #### player
856
+ - Complete player setup with physics
857
+ - Components: player, character-movement, transform, world-transform, body, collider, character-controller, input-state, respawn
858
+
859
+ ### Functions
860
+
861
+ #### processInput(moveForward, moveRight, cameraYaw): Vector3
862
+ Converts input to world-space movement
863
+
864
+ #### handleJump(entity, jumpPressed, currentTime): number
865
+ Processes jump with buffering
866
+
867
+ #### updateRotation(entity, inputVector, deltaTime, rotationData): Quaternion
868
+ Smooth rotation towards movement
869
+
870
+ ### Recipes
871
+
872
+ ### Components
873
+
874
+ #### Parent
875
+ - entity: i32 - Parent entity ID
876
+
877
+ ### Functions
878
+
879
+ #### parseXMLToEntities(state, xmlContent): EntityCreationResult[]
880
+ Converts XML elements to ECS entities with hierarchy
881
+
882
+ #### createEntityFromRecipe(state, recipeName, attributes?): number
883
+ Creates entity from recipe with attributes
884
+
885
+ #### fromEuler(x, y, z): Quaternion
886
+ Converts Euler angles (radians) to quaternion
887
+
888
+ ### Types
889
+
890
+ #### EntityCreationResult
891
+ - entity: number - Entity ID
892
+ - tagName: string - Recipe name
893
+ - children: EntityCreationResult[]
894
+
895
+ ### Recipes
896
+
897
+ #### entity
898
+ - Base recipe with no default components
899
+
900
+ ### Property Formats
901
+
902
+ - Single value: `transform="scale: 2"`
903
+ - Vector3: `transform="pos: 0 5 -3"`
904
+ - Broadcast: `transform="scale: 2"` → scale: 2 2 2
905
+ - Euler angles: `transform="euler: 0 45 0"` (degrees)
906
+ - Multiple: `transform="pos: 0 5 0; euler: 0 45 0"`
907
+ - Shorthands: `pos="0 5 0"` → transform component
908
+
909
+ ### Rendering
910
+
911
+ ### Components
912
+
913
+ #### Renderer
914
+ - shape: ui8 - 0=box, 1=sphere, 2=cylinder, 3=plane
915
+ - sizeX, sizeY, sizeZ: f32 (1)
916
+ - color: ui32 (0xffffff)
917
+ - visible: ui8 (1)
918
+
919
+ #### RenderContext
920
+ - clearColor: ui32 (0x000000)
921
+ - hasCanvas: ui8
922
+
923
+ #### MainCamera
924
+ Tag component (no properties)
925
+
926
+ #### Ambient
927
+ - skyColor: ui32 (0x87ceeb)
928
+ - groundColor: ui32 (0x4a4a4a)
929
+ - intensity: f32 (0.6)
930
+
931
+ #### Directional
932
+ - color: ui32 (0xffffff)
933
+ - intensity: f32 (1)
934
+ - castShadow: ui8 (1)
935
+ - shadowMapSize: ui32 (4096)
936
+ - directionX: f32 (-1)
937
+ - directionY: f32 (2)
938
+ - directionZ: f32 (-1)
939
+ - distance: f32 (30)
940
+
941
+ ### Systems
942
+
943
+ #### MeshInstanceSystem
944
+ - Group: draw
945
+ - Synchronizes transforms with Three.js meshes
946
+
947
+ #### LightSyncSystem
948
+ - Group: draw
949
+ - Updates Three.js lights
950
+
951
+ #### CameraSyncSystem
952
+ - Group: draw
953
+ - Updates Three.js camera
954
+
955
+ #### WebGLRenderSystem
956
+ - Group: draw (last)
957
+ - Renders scene to canvas
958
+
959
+ ### Functions
960
+
961
+ #### setCanvasElement(entity, canvas): void
962
+ Associates canvas with RenderContext
963
+
964
+ ### Recipes
965
+
966
+ - ambient-light - Ambient hemisphere lighting
967
+ - directional-light - Directional light with shadows
968
+ - light - Both ambient and directional
969
+
970
+ ### Respawn
971
+
972
+ ### Components
973
+
974
+ #### Respawn
975
+ - posX, posY, posZ: f32 - Spawn position
976
+ - eulerX, eulerY, eulerZ: f32 - Spawn rotation (degrees)
977
+
978
+ ### Systems
979
+
980
+ #### RespawnSystem
981
+ - Group: simulation
982
+ - Resets entities when Y < -100
983
+
984
+ ### Startup
985
+
986
+ ### Systems
987
+
988
+ #### LightingStartupSystem
989
+ - Group: setup
990
+ - Creates default lighting if none exists
991
+
992
+ #### CameraStartupSystem
993
+ - Group: setup
994
+ - Creates main camera if none exists
995
+
996
+ #### PlayerStartupSystem
997
+ - Group: setup
998
+ - Creates player entity if none exists
999
+
1000
+ #### PlayerCharacterSystem
1001
+ - Group: setup
1002
+ - Adds animated character to players
1003
+
1004
+ ### Transforms
1005
+
1006
+ ### Components
1007
+
1008
+ #### Transform
1009
+ - posX, posY, posZ: f32 (0)
1010
+ - rotX, rotY, rotZ, rotW: f32 (rotW=1) - Quaternion
1011
+ - eulerX, eulerY, eulerZ: f32 (0) - Degrees
1012
+ - scaleX, scaleY, scaleZ: f32 (1)
1013
+
1014
+ #### WorldTransform
1015
+ - Same properties as Transform
1016
+ - Auto-computed from hierarchy (read-only)
1017
+
1018
+ ### Systems
1019
+
1020
+ #### TransformHierarchySystem
1021
+ - Group: simulation (last)
1022
+ - Syncs euler/quaternion and computes world transforms
1023
+
1024
+ ### Tweening
1025
+
1026
+ ### Components
1027
+
1028
+ #### Tween
1029
+ - duration: f32 (1) - Seconds
1030
+ - elapsed: f32
1031
+ - easingIndex: ui8
1032
+ - loopMode: ui8 - 0=Once, 1=Loop, 2=PingPong
1033
+
1034
+ #### TweenValue
1035
+ - source: ui32 - Tween entity
1036
+ - target: ui32 - Target entity
1037
+ - componentId: ui32
1038
+ - fieldIndex: ui32
1039
+ - from: f32
1040
+ - to: f32
1041
+ - value: f32 - Current value
1042
+
1043
+ ### Systems
1044
+
1045
+ #### TweenSystem
1046
+ - Group: simulation
1047
+ - Interpolates values with easing and auto-cleanup
1048
+
1049
+ ### Functions
1050
+
1051
+ #### createTween(state, entity, target, options): number | null
1052
+ Animates component property
1053
+
1054
+ ### Easing Functions
1055
+
1056
+ - linear
1057
+ - sine-in, sine-out, sine-in-out
1058
+ - quad-in, quad-out, quad-in-out
1059
+ - cubic-in, cubic-out, cubic-in-out
1060
+ - quart-in, quart-out, quart-in-out
1061
+ - expo-in, expo-out, expo-in-out
1062
+ - circ-in, circ-out, circ-in-out
1063
+ - back-in, back-out, back-in-out
1064
+ - elastic-in, elastic-out, elastic-in-out
1065
+ - bounce-in, bounce-out, bounce-in-out
1066
+
1067
+ ### Loop Modes
1068
+
1069
+ - once - Play once and destroy
1070
+ - loop - Repeat indefinitely
1071
+ - ping-pong - Alternate directions
1072
+
1073
+ ### Shorthand Targets
1074
+
1075
+ - rotation - body.eulerX/Y/Z
1076
+ - at - body.posX/Y/Z
1077
+ - scale - transform.scaleX/Y/Z
1078
+
1079
+ ## API Reference (External Links)
1080
+
1081
+ - [Core](https://dylanebert.github.io/vibegame/reference/core)
1082
+ - [Animation](https://dylanebert.github.io/vibegame/reference/animation)
1083
+ - [Input](https://dylanebert.github.io/vibegame/reference/input)
1084
+ - [Orbit Camera](https://dylanebert.github.io/vibegame/reference/orbit-camera)
1085
+ - [Physics](https://dylanebert.github.io/vibegame/reference/physics)
1086
+ - [Player](https://dylanebert.github.io/vibegame/reference/player)
1087
+ - [Recipes](https://dylanebert.github.io/vibegame/reference/recipes)
1088
+ - [Rendering](https://dylanebert.github.io/vibegame/reference/rendering)
1089
+ - [Respawn](https://dylanebert.github.io/vibegame/reference/respawn)
1090
+ - [Startup](https://dylanebert.github.io/vibegame/reference/startup)
1091
+ - [Transforms](https://dylanebert.github.io/vibegame/reference/transforms)
1092
+ - [Tweening](https://dylanebert.github.io/vibegame/reference/tweening)
1093
+
1094
+ ## Examples (External Links)
1095
+
1096
+ - [Core](https://dylanebert.github.io/vibegame/examples/core)
1097
+ - [Animation](https://dylanebert.github.io/vibegame/examples/animation)
1098
+ - [Input](https://dylanebert.github.io/vibegame/examples/input)
1099
+ - [Orbit Camera](https://dylanebert.github.io/vibegame/examples/orbit-camera)
1100
+ - [Physics](https://dylanebert.github.io/vibegame/examples/physics)
1101
+ - [Player](https://dylanebert.github.io/vibegame/examples/player)
1102
+ - [Recipes](https://dylanebert.github.io/vibegame/examples/recipes)
1103
+ - [Rendering](https://dylanebert.github.io/vibegame/examples/rendering)
1104
+ - [Respawn](https://dylanebert.github.io/vibegame/examples/respawn)
1105
+ - [Startup](https://dylanebert.github.io/vibegame/examples/startup)
1106
+ - [Transforms](https://dylanebert.github.io/vibegame/examples/transforms)
1107
+ - [Tweening](https://dylanebert.github.io/vibegame/examples/tweening)
package.json ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "vibegame",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "preview": "vite preview",
9
+ "check": "tsc --noEmit && svelte-check",
10
+ "check:ts": "tsc --noEmit",
11
+ "check:svelte": "svelte-check",
12
+ "update": "cp node_modules/vibegame/llms.txt ./llms.txt && echo '✓ Updated llms.txt from VibeGame'",
13
+ "postinstall": "test -f node_modules/vibegame/llms.txt && cp node_modules/vibegame/llms.txt ./llms.txt || true",
14
+ "format": "prettier --write .",
15
+ "format:check": "prettier --check .",
16
+ "lint": "eslint .",
17
+ "lint:fix": "eslint . --fix",
18
+ "validate": "bun run format:check && bun run lint && bun run check"
19
+ },
20
+ "devDependencies": {
21
+ "@eslint/js": "^9.33.0",
22
+ "@sveltejs/vite-plugin-svelte": "^3.1.1",
23
+ "@types/ws": "^8.18.1",
24
+ "@typescript-eslint/eslint-plugin": "^8.40.0",
25
+ "@typescript-eslint/parser": "^8.40.0",
26
+ "eslint": "^9.33.0",
27
+ "eslint-config-prettier": "^10.1.8",
28
+ "eslint-plugin-import": "^2.32.0",
29
+ "eslint-plugin-prettier": "^5.5.4",
30
+ "prettier": "^3.6.2",
31
+ "svelte": "^4.2.18",
32
+ "svelte-check": "^3.8.4",
33
+ "typescript": "^5.6.0",
34
+ "vite": "^5.4.10",
35
+ "ws": "^8.18.3"
36
+ },
37
+ "dependencies": {
38
+ "@huggingface/hub": "^2.6.3",
39
+ "@huggingface/inference": "^4.8.0",
40
+ "@types/node": "^24.3.3",
41
+ "gsap": "^3.13.0",
42
+ "monaco-editor": "^0.50.0",
43
+ "svelte-splitpanes": "^8.0.5",
44
+ "vibegame": "^0.1.1"
45
+ }
46
+ }
src/App.svelte ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import { consoleCapture } from './lib/services/console-capture';
4
+ import { registerShortcuts, shortcuts } from './lib/config/shortcuts';
5
+ import { loadingStore } from './lib/stores/loading';
6
+ import AppHeader from './lib/components/layout/AppHeader.svelte';
7
+ import SplitView from './lib/components/layout/SplitView.svelte';
8
+ import LoadingScreen from './lib/components/layout/LoadingScreen.svelte';
9
+
10
+ let unregisterShortcuts: () => void;
11
+
12
+ onMount(() => {
13
+ loadingStore.startLoading();
14
+
15
+ consoleCapture.setup();
16
+ unregisterShortcuts = registerShortcuts(shortcuts);
17
+
18
+ setTimeout(() => {
19
+ loadingStore.setProgress(60);
20
+ }, 100);
21
+
22
+ requestAnimationFrame(() => {
23
+ requestAnimationFrame(() => {
24
+ loadingStore.finishLoading();
25
+ });
26
+ });
27
+ });
28
+
29
+ onDestroy(() => {
30
+ consoleCapture.teardown();
31
+ if (unregisterShortcuts) unregisterShortcuts();
32
+ });
33
+ </script>
34
+
35
+ <LoadingScreen
36
+ loading={$loadingStore.isLoading}
37
+ />
38
+
39
+ <main>
40
+ <AppHeader />
41
+ <SplitView />
42
+ </main>
43
+
44
+ <style>
45
+ :global(body) {
46
+ margin: 0;
47
+ padding: 0;
48
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", system-ui, sans-serif;
49
+ background: linear-gradient(135deg, #0B0A09 0%, #0F0E0C 100%);
50
+ color: #ffffff;
51
+ overflow: hidden;
52
+ }
53
+
54
+ :global(*) {
55
+ box-sizing: border-box;
56
+ }
57
+
58
+ main {
59
+ width: 100vw;
60
+ height: 100vh;
61
+ overflow: hidden;
62
+ display: flex;
63
+ flex-direction: column;
64
+ }
65
+ </style>
src/app.css ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ html,
6
+ body {
7
+ margin: 0;
8
+ padding: 0;
9
+ height: 100%;
10
+ overflow: hidden;
11
+ }
12
+
13
+ #app {
14
+ height: 100vh;
15
+ width: 100vw;
16
+ }
src/context.md ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # src/
2
+
3
+ Main application source code.
4
+
5
+ ## Structure
6
+
7
+ - `main.ts` - Svelte app mount point
8
+ - `App.svelte` - Game development environment with view modes
9
+ - `app.css` - Global styles
10
+
11
+ ## Interface
12
+
13
+ - **Header**: View toggle (Code/Preview), status indicator, restart button
14
+ - **Code mode**: Split view with editor (40%) and game/console (60%)
15
+ - **Preview mode**: Full-screen game view
16
+ - **Animations**: GSAP transitions (0.2s) for smooth mode switching
17
+ - **Auto-reload**: 800ms debounce on code changes
18
+ - **Console**: Auto-scroll, message animations, hidden in preview mode
src/lib/components/Editor.svelte ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount, onDestroy, createEventDispatcher } from "svelte";
3
+ import * as monaco from "monaco-editor";
4
+ import type { editor } from "monaco-editor";
5
+
6
+ import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
7
+ import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
8
+ import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
9
+ import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
10
+ import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
11
+
12
+ export let value: string = "";
13
+ export let language: string = "html";
14
+ export let theme: string = "vs-dark";
15
+ export let readOnly: boolean = false;
16
+
17
+ const dispatch = createEventDispatcher();
18
+
19
+ let editorContainer: HTMLDivElement;
20
+ let editorInstance: editor.IStandaloneCodeEditor | null = null;
21
+ let isInternalUpdate = false;
22
+
23
+ (self as any).MonacoEnvironment = {
24
+ getWorker: function (_: any, label: string) {
25
+ switch (label) {
26
+ case "json":
27
+ return new jsonWorker();
28
+ case "css":
29
+ case "scss":
30
+ case "less":
31
+ return new cssWorker();
32
+ case "html":
33
+ case "handlebars":
34
+ case "razor":
35
+ case "xml":
36
+ return new htmlWorker();
37
+ case "typescript":
38
+ case "javascript":
39
+ return new tsWorker();
40
+ default:
41
+ return new editorWorker();
42
+ }
43
+ },
44
+ };
45
+
46
+ onMount(() => {
47
+ editorInstance = monaco.editor.create(editorContainer, {
48
+ value: value,
49
+ language: language,
50
+ theme: theme,
51
+ minimap: {
52
+ enabled: false,
53
+ },
54
+ fontSize: 13,
55
+ fontFamily: '"Monaco", "Menlo", "Ubuntu Mono", monospace',
56
+ lineHeight: 20,
57
+ wordWrap: "on",
58
+ scrollBeyondLastLine: false,
59
+ renderWhitespace: "selection",
60
+ automaticLayout: true,
61
+ tabSize: 2,
62
+ insertSpaces: true,
63
+ formatOnPaste: true,
64
+ formatOnType: true,
65
+ suggestOnTriggerCharacters: true,
66
+ quickSuggestions: {
67
+ other: true,
68
+ comments: false,
69
+ strings: true,
70
+ },
71
+ scrollbar: {
72
+ verticalScrollbarSize: 10,
73
+ horizontalScrollbarSize: 10,
74
+ },
75
+ });
76
+
77
+ editorInstance.onDidChangeModelContent(() => {
78
+ if (!isInternalUpdate) {
79
+ const newValue = editorInstance?.getValue() || "";
80
+ dispatch("change", newValue);
81
+ }
82
+ });
83
+
84
+ const resizeObserver = new ResizeObserver(() => {
85
+ editorInstance?.layout();
86
+ });
87
+ resizeObserver.observe(editorContainer);
88
+
89
+ return () => {
90
+ resizeObserver.disconnect();
91
+ };
92
+ });
93
+
94
+ onDestroy(() => {
95
+ editorInstance?.dispose();
96
+ });
97
+
98
+ $: if (editorInstance && value !== editorInstance.getValue()) {
99
+ isInternalUpdate = true;
100
+ editorInstance.setValue(value);
101
+ isInternalUpdate = false;
102
+ }
103
+
104
+ $: if (editorInstance) {
105
+ const model = editorInstance.getModel();
106
+ if (model) {
107
+ monaco.editor.setModelLanguage(model, language);
108
+ }
109
+ }
110
+
111
+ $: if (editorInstance && theme) {
112
+ monaco.editor.setTheme(theme);
113
+ }
114
+
115
+ $: if (editorInstance) {
116
+ editorInstance.updateOptions({ readOnly });
117
+ }
118
+ </script>
119
+
120
+ <div bind:this={editorContainer} class="monaco-editor-container"></div>
121
+
122
+ <style>
123
+ .monaco-editor-container {
124
+ width: 100%;
125
+ height: 100%;
126
+ min-height: 200px;
127
+ }
128
+ </style>
src/lib/components/auth/LoginButton.svelte ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { authStore } from '../../services/auth';
4
+ import gsap from 'gsap';
5
+
6
+ let authState = {
7
+ isAuthenticated: false,
8
+ user: null as any,
9
+ loading: true,
10
+ error: null as string | null
11
+ };
12
+
13
+ let loginBtn: HTMLButtonElement;
14
+
15
+ authStore.subscribe(state => {
16
+ authState = state;
17
+ });
18
+
19
+ onMount(async () => {
20
+ await authStore.init();
21
+
22
+ if (loginBtn && !authState.isAuthenticated) {
23
+ gsap.to(loginBtn, {
24
+ boxShadow: '0 0 20px rgba(255, 255, 255, 0.15)',
25
+ duration: 2,
26
+ repeat: -1,
27
+ yoyo: true,
28
+ ease: 'sine.inOut'
29
+ });
30
+ }
31
+ });
32
+
33
+ $: if (loginBtn && !authState.isAuthenticated && !authState.loading) {
34
+ gsap.to(loginBtn, {
35
+ boxShadow: '0 0 20px rgba(255, 255, 255, 0.15)',
36
+ duration: 2,
37
+ repeat: -1,
38
+ yoyo: true,
39
+ ease: 'sine.inOut'
40
+ });
41
+ }
42
+
43
+ function handleLogin() {
44
+ authStore.login();
45
+ }
46
+
47
+ function handleLogout() {
48
+ authStore.logout();
49
+ }
50
+ </script>
51
+
52
+ <div class="auth-container">
53
+ {#if authState.loading}
54
+ <div class="loading">Loading...</div>
55
+ {:else if authState.error}
56
+ <div class="error">
57
+ <span>{authState.error}</span>
58
+ <button on:click={handleLogin} class="retry-btn">Try Again</button>
59
+ </div>
60
+ {:else if authState.isAuthenticated}
61
+ <div class="user-info">
62
+ {#if authState.user?.avatarUrl}
63
+ <img src={authState.user.avatarUrl} alt={authState.user.name} class="avatar" />
64
+ {/if}
65
+ <span class="username">{authState.user?.name || 'User'}</span>
66
+ <button on:click={handleLogout} class="logout-btn">Logout</button>
67
+ </div>
68
+ {:else}
69
+ <button bind:this={loginBtn} on:click={handleLogin} class="login-btn">
70
+ Sign in
71
+ </button>
72
+ {/if}
73
+ </div>
74
+
75
+ <style>
76
+ .auth-container {
77
+ display: flex;
78
+ align-items: center;
79
+ gap: 0.5rem;
80
+ }
81
+
82
+ .loading {
83
+ color: #888;
84
+ font-size: 0.875rem;
85
+ }
86
+
87
+ .error {
88
+ display: flex;
89
+ align-items: center;
90
+ gap: 0.5rem;
91
+ color: #ff6b6b;
92
+ font-size: 0.875rem;
93
+ }
94
+
95
+ .retry-btn {
96
+ padding: 0.25rem 0.5rem;
97
+ background: #ff6b6b;
98
+ color: white;
99
+ border: none;
100
+ border-radius: 0.25rem;
101
+ cursor: pointer;
102
+ font-size: 0.75rem;
103
+ }
104
+
105
+ .retry-btn:hover {
106
+ background: #ff5252;
107
+ }
108
+
109
+ .user-info {
110
+ display: flex;
111
+ align-items: center;
112
+ gap: 0.5rem;
113
+ }
114
+
115
+ .avatar {
116
+ width: 24px;
117
+ height: 24px;
118
+ border-radius: 50%;
119
+ }
120
+
121
+ .username {
122
+ color: #ccc;
123
+ font-size: 0.875rem;
124
+ }
125
+
126
+ .logout-btn {
127
+ padding: 0.25rem 0.5rem;
128
+ background: transparent;
129
+ color: #888;
130
+ border: 1px solid #333;
131
+ border-radius: 0.25rem;
132
+ cursor: pointer;
133
+ font-size: 0.75rem;
134
+ transition: all 0.2s;
135
+ }
136
+
137
+ .logout-btn:hover {
138
+ background: #333;
139
+ color: #fff;
140
+ }
141
+
142
+ .login-btn {
143
+ padding: 0.35rem 0.85rem;
144
+ background: rgba(255, 255, 255, 0.03);
145
+ color: rgba(255, 255, 255, 0.7);
146
+ border: 1px solid rgba(255, 255, 255, 0.08);
147
+ border-radius: 0.35rem;
148
+ cursor: pointer;
149
+ font-size: 0.75rem;
150
+ font-weight: 500;
151
+ transition: all 0.3s ease;
152
+ backdrop-filter: blur(10px);
153
+ position: relative;
154
+ overflow: hidden;
155
+ }
156
+
157
+ .login-btn:hover {
158
+ background: rgba(255, 255, 255, 0.08);
159
+ color: rgba(255, 255, 255, 0.95);
160
+ border-color: rgba(255, 255, 255, 0.15);
161
+ transform: translateY(-1px);
162
+ }
163
+
164
+ .login-btn:active {
165
+ transform: translateY(0);
166
+ }
167
+ </style>
src/lib/components/auth/context.md ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Auth Components
2
+
3
+ Authentication UI for Hugging Face OAuth
4
+
5
+ ## Purpose
6
+
7
+ Handle user authentication flow and state display
8
+
9
+ ## Layout
10
+
11
+ ```
12
+ auth/
13
+ ├── context.md # This file
14
+ └── LoginButton.svelte # OAuth login button
15
+ ```
16
+
17
+ ## Components
18
+
19
+ ### LoginButton.svelte
20
+
21
+ - Subtle glassmorphic sign-in button with pulse animation
22
+ - User info display when authenticated
23
+ - Located in header top right
24
+
25
+ ## Dependencies
26
+
27
+ - authStore for authentication state
28
+ - GSAP for subtle animations
src/lib/components/chat/ChatPanel.svelte ADDED
@@ -0,0 +1,430 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount, onDestroy, afterUpdate } from "svelte";
3
+ import { agentStore, isConnected, isProcessing } from "../../stores/agent";
4
+ import { authStore } from "../../services/auth";
5
+ import gsap from "gsap";
6
+
7
+ let inputValue = "";
8
+ let messagesContainer: HTMLDivElement;
9
+ let sendButton: HTMLButtonElement;
10
+ let inputTextarea: HTMLTextAreaElement;
11
+ let authPromptBtn: HTMLButtonElement;
12
+
13
+ let hasConnected = false;
14
+
15
+ onMount(() => {
16
+ if ($authStore.isAuthenticated && !$authStore.loading) {
17
+ agentStore.connect();
18
+ hasConnected = true;
19
+ }
20
+
21
+ if (authPromptBtn) {
22
+ gsap.to(authPromptBtn, {
23
+ boxShadow: '0 0 25px rgba(255, 210, 30, 0.3)',
24
+ duration: 2.5,
25
+ repeat: -1,
26
+ yoyo: true,
27
+ ease: 'sine.inOut'
28
+ });
29
+ }
30
+ });
31
+
32
+ onDestroy(() => {
33
+ agentStore.disconnect();
34
+ });
35
+
36
+ $: if ($authStore.isAuthenticated && !$authStore.loading && !hasConnected) {
37
+ agentStore.connect();
38
+ hasConnected = true;
39
+ }
40
+
41
+ $: if (inputTextarea && $isConnected && !$isProcessing && $agentStore.messages.length === 0) {
42
+ gsap.to(inputTextarea, {
43
+ borderColor: 'rgba(65, 105, 225, 0.4)',
44
+ duration: 2,
45
+ repeat: -1,
46
+ yoyo: true,
47
+ ease: 'sine.inOut'
48
+ });
49
+ } else if (inputTextarea) {
50
+ gsap.killTweensOf(inputTextarea);
51
+ gsap.set(inputTextarea, {
52
+ borderColor: 'rgba(255, 255, 255, 0.1)'
53
+ });
54
+ }
55
+
56
+ afterUpdate(() => {
57
+ if (messagesContainer) {
58
+ messagesContainer.scrollTop = messagesContainer.scrollHeight;
59
+ }
60
+ });
61
+
62
+ function handleSubmit() {
63
+ if (inputValue.trim() && $authStore.isAuthenticated && $isConnected && !$isProcessing) {
64
+ if (sendButton) {
65
+ gsap.to(sendButton, {
66
+ scale: 0.9,
67
+ duration: 0.1,
68
+ ease: "power2.in",
69
+ onComplete: () => {
70
+ gsap.to(sendButton, {
71
+ scale: 1,
72
+ duration: 0.2,
73
+ ease: "elastic.out(1, 0.5)",
74
+ });
75
+ },
76
+ });
77
+ }
78
+
79
+ agentStore.sendMessage(inputValue.trim());
80
+ inputValue = "";
81
+ }
82
+ }
83
+
84
+ function handleKeydown(event: KeyboardEvent) {
85
+ if (event.key === "Enter" && !event.shiftKey) {
86
+ event.preventDefault();
87
+ handleSubmit();
88
+ }
89
+ }
90
+
91
+ function handleButtonMouseEnter() {
92
+ if (sendButton && !sendButton.disabled) {
93
+ gsap.to(sendButton, {
94
+ scale: 1.05,
95
+ duration: 0.2,
96
+ ease: "power2.out",
97
+ });
98
+ }
99
+ }
100
+
101
+ function handleButtonMouseLeave() {
102
+ if (sendButton) {
103
+ gsap.to(sendButton, {
104
+ scale: 1,
105
+ duration: 0.2,
106
+ ease: "power2.out",
107
+ });
108
+ }
109
+ }
110
+
111
+ function handleButtonMouseDown() {
112
+ if (sendButton && !sendButton.disabled) {
113
+ gsap.to(sendButton, {
114
+ scale: 0.95,
115
+ duration: 0.1,
116
+ ease: "power2.in",
117
+ });
118
+ }
119
+ }
120
+
121
+ function handleButtonMouseUp() {
122
+ if (sendButton && !sendButton.disabled) {
123
+ gsap.to(sendButton, {
124
+ scale: 1.05,
125
+ duration: 0.1,
126
+ ease: "power2.out",
127
+ });
128
+ }
129
+ }
130
+
131
+ $: {
132
+ if (sendButton) {
133
+ if (!$authStore.isAuthenticated || !$isConnected || $isProcessing || !inputValue.trim()) {
134
+ gsap.to(sendButton, {
135
+ opacity: 0.3,
136
+ duration: 0.2,
137
+ ease: "power2.out",
138
+ });
139
+ } else {
140
+ gsap.to(sendButton, {
141
+ opacity: 1,
142
+ duration: 0.2,
143
+ ease: "power2.out",
144
+ });
145
+ }
146
+ }
147
+ }
148
+ </script>
149
+
150
+ <div class="chat-panel">
151
+ <div class="messages" bind:this={messagesContainer}>
152
+ {#if !$authStore.isAuthenticated && !$authStore.loading}
153
+ <div class="auth-prompt">
154
+ <p>Sign in to chat.</p>
155
+ <button bind:this={authPromptBtn} on:click={() => authStore.login()} class="auth-prompt-btn">
156
+ Sign in with 🤗 Hugging Face
157
+ </button>
158
+ </div>
159
+ {:else}
160
+ {#if $agentStore.messages.length === 0 && $isConnected}
161
+ <div class="ready-message">Ready to Chat!</div>
162
+ {/if}
163
+ {#each $agentStore.messages as message}
164
+ <div class="message {message.role}">
165
+ <div class="message-content">
166
+ {message.content.trim()}
167
+ {#if message.streaming}
168
+ <span class="cursor">▊</span>
169
+ {/if}
170
+ </div>
171
+ </div>
172
+ {/each}
173
+ {#if $agentStore.error}
174
+ <div class="error-message">
175
+ Error: {$agentStore.error}
176
+ </div>
177
+ {/if}
178
+ {/if}
179
+ </div>
180
+
181
+ <div class="input-area">
182
+ <textarea
183
+ bind:this={inputTextarea}
184
+ bind:value={inputValue}
185
+ on:keydown={handleKeydown}
186
+ placeholder={!$authStore.isAuthenticated
187
+ ? "Sign in to chat..."
188
+ : $isConnected
189
+ ? $isProcessing
190
+ ? "Processing..."
191
+ : "Type a message..."
192
+ : "Connecting..."}
193
+ disabled={!$authStore.isAuthenticated || !$isConnected || $isProcessing}
194
+ rows="1"
195
+ />
196
+ <button
197
+ bind:this={sendButton}
198
+ on:click={handleSubmit}
199
+ on:mouseenter={handleButtonMouseEnter}
200
+ on:mouseleave={handleButtonMouseLeave}
201
+ on:mousedown={handleButtonMouseDown}
202
+ on:mouseup={handleButtonMouseUp}
203
+ disabled={!$authStore.isAuthenticated || !$isConnected || $isProcessing || !inputValue.trim()}
204
+ class="send-btn"
205
+ title="Send message"
206
+ >
207
+
208
+ </button>
209
+ </div>
210
+ </div>
211
+
212
+ <style>
213
+ .chat-panel {
214
+ display: flex;
215
+ flex-direction: column;
216
+ height: 100%;
217
+ width: 100%;
218
+ background: rgba(20, 20, 20, 0.5);
219
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
220
+ }
221
+
222
+ .messages {
223
+ flex: 1;
224
+ overflow-y: auto;
225
+ padding: 0.5rem;
226
+ display: flex;
227
+ flex-direction: column;
228
+ gap: 0.4rem;
229
+ min-height: 0;
230
+ }
231
+
232
+ .message {
233
+ padding: 0.4rem 0.6rem;
234
+ border-radius: 3px;
235
+ font-size: 0.75rem;
236
+ animation: fadeIn 0.2s ease-out;
237
+ }
238
+
239
+ @keyframes fadeIn {
240
+ from {
241
+ opacity: 0;
242
+ transform: translateY(5px);
243
+ }
244
+ to {
245
+ opacity: 1;
246
+ transform: translateY(0);
247
+ }
248
+ }
249
+
250
+ .message.user {
251
+ background: rgba(65, 105, 225, 0.08);
252
+ border-left: 2px solid rgba(65, 105, 225, 0.6);
253
+ margin-left: 1rem;
254
+ }
255
+
256
+ .message.assistant {
257
+ background: rgba(255, 255, 255, 0.02);
258
+ border-left: 2px solid rgba(255, 255, 255, 0.15);
259
+ margin-right: 1rem;
260
+ }
261
+
262
+ .message-content {
263
+ color: rgba(255, 255, 255, 0.9);
264
+ line-height: 1.5;
265
+ white-space: pre-line;
266
+ word-wrap: break-word;
267
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Monaco", "Menlo", monospace;
268
+ margin: 0;
269
+ display: block;
270
+ }
271
+
272
+ .cursor {
273
+ animation: blink 1s infinite;
274
+ }
275
+
276
+ @keyframes blink {
277
+ 0%,
278
+ 50% {
279
+ opacity: 1;
280
+ }
281
+ 51%,
282
+ 100% {
283
+ opacity: 0;
284
+ }
285
+ }
286
+
287
+ .error-message {
288
+ background: rgba(244, 67, 54, 0.1);
289
+ border-left: 2px solid #f44336;
290
+ border-radius: 3px;
291
+ padding: 0.4rem 0.6rem;
292
+ color: #ff9999;
293
+ font-size: 0.75rem;
294
+ animation: fadeIn 0.2s ease-out;
295
+ }
296
+
297
+ .input-area {
298
+ display: flex;
299
+ gap: 0.5rem;
300
+ padding: 0.5rem;
301
+ background: rgba(0, 0, 0, 0.2);
302
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
303
+ }
304
+
305
+ textarea {
306
+ flex: 1;
307
+ background: rgba(0, 0, 0, 0.3);
308
+ color: rgba(255, 255, 255, 0.9);
309
+ border: 1px solid rgba(255, 255, 255, 0.1);
310
+ border-radius: 4px;
311
+ padding: 0.4rem 0.6rem;
312
+ resize: none;
313
+ font-family: "Monaco", "Menlo", monospace;
314
+ font-size: 0.8rem;
315
+ line-height: 1.2;
316
+ }
317
+
318
+ textarea:focus {
319
+ outline: none;
320
+ border-color: rgba(65, 105, 225, 0.5);
321
+ background: rgba(0, 0, 0, 0.5);
322
+ }
323
+
324
+ textarea:disabled {
325
+ opacity: 0.5;
326
+ cursor: not-allowed;
327
+ }
328
+
329
+ .send-btn {
330
+ padding: 0.4rem 0.8rem;
331
+ background: rgba(65, 105, 225, 0.2);
332
+ color: #4169e1;
333
+ border: 1px solid rgba(65, 105, 225, 0.3);
334
+ border-radius: 4px;
335
+ cursor: pointer;
336
+ font-size: 1rem;
337
+ transform-origin: center;
338
+ will-change: transform, opacity;
339
+ }
340
+
341
+ .send-btn:hover:not(:disabled) {
342
+ background: rgba(65, 105, 225, 0.3);
343
+ border-color: rgba(65, 105, 225, 0.5);
344
+ }
345
+
346
+ .send-btn:disabled {
347
+ cursor: not-allowed;
348
+ }
349
+
350
+ ::-webkit-scrollbar {
351
+ width: 6px;
352
+ }
353
+
354
+ ::-webkit-scrollbar-track {
355
+ background: transparent;
356
+ }
357
+
358
+ ::-webkit-scrollbar-thumb {
359
+ background: rgba(255, 255, 255, 0.1);
360
+ border-radius: 3px;
361
+ }
362
+
363
+ ::-webkit-scrollbar-thumb:hover {
364
+ background: rgba(255, 255, 255, 0.2);
365
+ }
366
+
367
+ .auth-prompt {
368
+ display: flex;
369
+ flex-direction: column;
370
+ align-items: center;
371
+ justify-content: center;
372
+ padding: 2rem;
373
+ height: 100%;
374
+ text-align: center;
375
+ }
376
+
377
+ .auth-prompt p {
378
+ color: rgba(255, 255, 255, 0.6);
379
+ margin-bottom: 1.5rem;
380
+ font-size: 0.875rem;
381
+ }
382
+
383
+ .auth-prompt-btn {
384
+ padding: 0.6rem 1.8rem;
385
+ background: rgba(255, 210, 30, 0.08);
386
+ color: rgba(255, 210, 30, 0.9);
387
+ border: 1px solid rgba(255, 210, 30, 0.2);
388
+ border-radius: 0.5rem;
389
+ cursor: pointer;
390
+ font-size: 0.875rem;
391
+ font-weight: 600;
392
+ transition: all 0.3s ease;
393
+ backdrop-filter: blur(10px);
394
+ position: relative;
395
+ overflow: hidden;
396
+ }
397
+
398
+ .auth-prompt-btn:hover {
399
+ transform: translateY(-2px);
400
+ background: rgba(255, 210, 30, 0.12);
401
+ color: rgba(255, 210, 30, 1);
402
+ border-color: rgba(255, 210, 30, 0.3);
403
+ }
404
+
405
+ .auth-prompt-btn:active {
406
+ transform: translateY(0);
407
+ }
408
+
409
+ .ready-message {
410
+ color: rgba(255, 255, 255, 0.2);
411
+ font-size: 0.75rem;
412
+ text-align: center;
413
+ font-style: italic;
414
+ display: flex;
415
+ align-items: center;
416
+ justify-content: center;
417
+ height: 100%;
418
+ min-height: 200px;
419
+ animation: gentle-fade 3s ease-in-out infinite;
420
+ }
421
+
422
+ @keyframes gentle-fade {
423
+ 0%, 100% {
424
+ opacity: 0.7;
425
+ }
426
+ 50% {
427
+ opacity: 1;
428
+ }
429
+ }
430
+ </style>
src/lib/components/chat/context.md ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Chat Context
2
+
3
+ AI assistant interface with authentication-gated input
4
+
5
+ ## Components
6
+
7
+ - `ChatPanel.svelte` - Chat UI with auth-aware input controls
8
+
9
+ ## Features
10
+
11
+ - Authentication-required input (visible but disabled when not logged in)
12
+ - Real-time message streaming when connected
13
+ - Breathing input animation when ready
14
+ - GSAP-animated button interactions
src/lib/components/console/ConsoleMessage.svelte ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { ConsoleMessage } from '../../stores/console';
3
+ import { onMount } from 'svelte';
4
+ import gsap from 'gsap';
5
+
6
+ export let message: ConsoleMessage;
7
+
8
+ let messageElement: HTMLDivElement;
9
+
10
+ onMount(() => {
11
+ gsap.fromTo(messageElement,
12
+ { opacity: 0, y: -5 },
13
+ { opacity: 1, y: 0, duration: 0.3, ease: "power2.out" }
14
+ );
15
+ });
16
+ </script>
17
+
18
+ <div
19
+ bind:this={messageElement}
20
+ class="console-line console-{message.type}"
21
+ >
22
+ <span class="console-type">{message.type}</span>
23
+ <span class="console-msg">{message.message}</span>
24
+ </div>
25
+
26
+ <style>
27
+ .console-line {
28
+ margin-bottom: 6px;
29
+ display: flex;
30
+ gap: 10px;
31
+ align-items: flex-start;
32
+ padding: 4px 6px;
33
+ border-radius: 4px;
34
+ transition: background 0.2s;
35
+ }
36
+
37
+ .console-line:hover {
38
+ background: rgba(139, 115, 85, 0.02);
39
+ }
40
+
41
+ .console-type {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 6px;
45
+ font-size: 9px;
46
+ text-transform: uppercase;
47
+ letter-spacing: 0.3px;
48
+ opacity: 0.5;
49
+ }
50
+
51
+ .console-type::before {
52
+ content: '';
53
+ width: 6px;
54
+ height: 6px;
55
+ border-radius: 50%;
56
+ display: inline-block;
57
+ }
58
+
59
+ .console-log .console-type::before {
60
+ background: rgba(251, 248, 244, 0.5);
61
+ }
62
+
63
+ .console-warn .console-type::before {
64
+ background: #D4A574;
65
+ }
66
+
67
+ .console-error .console-type::before {
68
+ background: #B85450;
69
+ }
70
+
71
+ .console-info .console-type::before {
72
+ background: #7C9885;
73
+ }
74
+
75
+ .console-msg {
76
+ flex: 1;
77
+ word-break: break-word;
78
+ white-space: pre-wrap;
79
+ color: rgba(251, 248, 244, 0.8);
80
+ }
81
+
82
+ .console-log {
83
+ color: rgba(251, 248, 244, 0.7);
84
+ }
85
+
86
+ .console-warn {
87
+ background: rgba(212, 165, 116, 0.05);
88
+ }
89
+
90
+ .console-warn .console-msg {
91
+ color: #D4A574;
92
+ }
93
+
94
+ .console-error {
95
+ background: rgba(184, 84, 80, 0.05);
96
+ }
97
+
98
+ .console-error .console-msg {
99
+ color: #B85450;
100
+ }
101
+
102
+ .console-info {
103
+ background: rgba(124, 152, 133, 0.03);
104
+ }
105
+
106
+ .console-info .console-msg {
107
+ color: #7C9885;
108
+ }
109
+ </style>
src/lib/components/console/ConsolePanel.svelte ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { consoleStore } from '../../stores/console';
3
+ import ConsoleMessage from './ConsoleMessage.svelte';
4
+ import { afterUpdate } from 'svelte';
5
+
6
+ let consoleOutput: HTMLDivElement;
7
+ let wasAtBottom = true;
8
+
9
+ function clearConsole() {
10
+ consoleStore.clear();
11
+ }
12
+
13
+ function checkScrollPosition() {
14
+ if (consoleOutput) {
15
+ const threshold = 5;
16
+ wasAtBottom = consoleOutput.scrollHeight - consoleOutput.scrollTop - consoleOutput.clientHeight < threshold;
17
+ }
18
+ }
19
+
20
+ afterUpdate(() => {
21
+ if (wasAtBottom && consoleOutput) {
22
+ consoleOutput.scrollTop = consoleOutput.scrollHeight;
23
+ }
24
+ });
25
+ </script>
26
+
27
+ <div class="console-section">
28
+ <div class="panel-header">
29
+ <h2>Console</h2>
30
+ <button on:click={clearConsole} class="clear-button">Clear</button>
31
+ </div>
32
+ <div
33
+ bind:this={consoleOutput}
34
+ on:scroll={checkScrollPosition}
35
+ class="console-output"
36
+ >
37
+ {#each $consoleStore.messages as message (message.id)}
38
+ <ConsoleMessage {message} />
39
+ {/each}
40
+ {#if $consoleStore.messages.length === 0}
41
+ <div class="console-empty">Awaiting console output...</div>
42
+ {/if}
43
+ </div>
44
+ </div>
45
+
46
+ <style>
47
+ .console-section {
48
+ width: 100%;
49
+ height: 100%;
50
+ display: flex;
51
+ flex-direction: column;
52
+ background: rgba(8, 7, 6, 0.4);
53
+ }
54
+
55
+ .panel-header {
56
+ display: flex;
57
+ justify-content: space-between;
58
+ align-items: center;
59
+ padding: 10px 16px;
60
+ background: rgba(15, 14, 12, 0.3);
61
+ border-bottom: 1px solid rgba(139, 115, 85, 0.06);
62
+ flex-shrink: 0;
63
+ }
64
+
65
+ .panel-header h2 {
66
+ margin: 0;
67
+ font-size: 11px;
68
+ font-weight: 500;
69
+ color: rgba(251, 248, 244, 0.5);
70
+ text-transform: uppercase;
71
+ letter-spacing: 0.5px;
72
+ }
73
+
74
+ .console-output {
75
+ flex: 1;
76
+ padding: 12px 16px;
77
+ background: transparent;
78
+ overflow-y: auto;
79
+ font-family: "JetBrains Mono", "Monaco", "Menlo", monospace;
80
+ font-size: 11px;
81
+ line-height: 1.6;
82
+ }
83
+
84
+ .console-output::-webkit-scrollbar {
85
+ width: 6px;
86
+ }
87
+
88
+ .console-output::-webkit-scrollbar-track {
89
+ background: rgba(139, 115, 85, 0.02);
90
+ }
91
+
92
+ .console-output::-webkit-scrollbar-thumb {
93
+ background: rgba(139, 115, 85, 0.1);
94
+ border-radius: 3px;
95
+ }
96
+
97
+ .console-output::-webkit-scrollbar-thumb:hover {
98
+ background: rgba(139, 115, 85, 0.15);
99
+ }
100
+
101
+ .console-empty {
102
+ color: rgba(251, 248, 244, 0.3);
103
+ font-style: italic;
104
+ font-size: 11px;
105
+ padding: 4px 6px;
106
+ }
107
+
108
+ .clear-button {
109
+ padding: 4px 10px;
110
+ background: rgba(139, 115, 85, 0.03);
111
+ color: rgba(251, 248, 244, 0.4);
112
+ border: 1px solid rgba(139, 115, 85, 0.08);
113
+ border-radius: 4px;
114
+ font-size: 10px;
115
+ font-weight: 500;
116
+ text-transform: uppercase;
117
+ letter-spacing: 0.3px;
118
+ cursor: pointer;
119
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
120
+ }
121
+
122
+ .clear-button:hover {
123
+ background: rgba(139, 115, 85, 0.06);
124
+ color: rgba(251, 248, 244, 0.6);
125
+ border-color: rgba(139, 115, 85, 0.12);
126
+ }
127
+
128
+ .clear-button:active {
129
+ transform: scale(0.95);
130
+ }
131
+ </style>
src/lib/components/console/context.md ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Console Components
2
+
3
+ Console output display and management
4
+
5
+ ## Purpose
6
+
7
+ - Display console messages with formatting
8
+ - Auto-scroll and message buffering
9
+ - Clear and filter capabilities
10
+
11
+ ## Layout
12
+
13
+ ```
14
+ console/
15
+ ├── context.md # This file
16
+ ├── ConsolePanel.svelte # Main console container
17
+ └── ConsoleMessage.svelte # Individual message display
18
+ ```
19
+
20
+ ## Scope
21
+
22
+ - In-scope: Console UI, message rendering
23
+ - Out-of-scope: Console capture logic
24
+
25
+ ## Entrypoints
26
+
27
+ - `ConsolePanel.svelte` - Main component to embed console
28
+
29
+ ## Dependencies
30
+
31
+ - consoleStore for messages
32
+ - GSAP for message animations
src/lib/components/context.md ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Components
2
+
3
+ UI components organized by feature/responsibility
4
+
5
+ ## Purpose
6
+
7
+ - Declarative UI components
8
+ - Single responsibility per component
9
+ - Clean props/events interface
10
+
11
+ ## Layout
12
+
13
+ ```
14
+ components/
15
+ ├── context.md # This file
16
+ ├── auth/ # Authentication UI components
17
+ ├── chat/ # AI chat interface
18
+ ├── console/ # Console display components
19
+ ├── editor/ # Code editor wrapper
20
+ ├── game/ # Game canvas and errors
21
+ ├── layout/ # App layout components
22
+ └── Editor.svelte # Monaco editor (legacy)
23
+ ```
24
+
25
+ ## Scope
26
+
27
+ - In-scope: UI rendering, user interactions
28
+ - Out-of-scope: Business logic, direct state mutations
29
+
30
+ ## Entrypoints
31
+
32
+ - `AppHeader.svelte` - Top navigation bar with auth
33
+ - `LoginButton.svelte` - OAuth authentication button
34
+ - `ChatPanel.svelte` - AI chat interface
35
+ - `SplitView.svelte` - Main layout container
36
+ - `ConsolePanel.svelte` - Console output display
37
+ - `GameCanvas.svelte` - Game rendering area
38
+ - `CodeEditor.svelte` - Code editing interface
39
+
40
+ ## Dependencies
41
+
42
+ - Stores for reactive state
43
+ - Services for operations
44
+ - GSAP for animations
45
+ - svelte-splitpanes for layout
src/lib/components/editor/CodeEditor.svelte ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { editorStore } from '../../stores/editor';
3
+ import Editor from '../Editor.svelte';
4
+
5
+ function handleChange(event: CustomEvent<string>) {
6
+ editorStore.setContent(event.detail);
7
+ }
8
+ </script>
9
+
10
+ <div class="editor-panel">
11
+ <Editor
12
+ value={$editorStore.content}
13
+ language={$editorStore.language}
14
+ theme={$editorStore.theme}
15
+ on:change={handleChange}
16
+ />
17
+ </div>
18
+
19
+ <style>
20
+ .editor-panel {
21
+ width: 100%;
22
+ height: 100%;
23
+ display: flex;
24
+ flex-direction: column;
25
+ background: rgba(11, 10, 9, 0.4);
26
+ min-width: 0;
27
+ }
28
+ </style>
src/lib/components/editor/context.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Editor Components
2
+
3
+ Code editing interface
4
+
5
+ ## Purpose
6
+
7
+ - Wrap Monaco editor
8
+ - Connect to editor store
9
+ - Handle code changes
10
+
11
+ ## Layout
12
+
13
+ ```
14
+ editor/
15
+ ├── context.md # This file
16
+ └── CodeEditor.svelte # Monaco editor wrapper
17
+ ```
18
+
19
+ ## Scope
20
+
21
+ - In-scope: Code editing UI
22
+ - Out-of-scope: Game parsing, validation
23
+
24
+ ## Entrypoints
25
+
26
+ - `CodeEditor.svelte` - Main editor component
27
+
28
+ ## Dependencies
29
+
30
+ - editorStore for content state
31
+ - Editor.svelte (Monaco wrapper)
src/lib/components/game/GameCanvas.svelte ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from 'svelte';
3
+ import { uiStore } from '../../stores/ui';
4
+ import { gameStore } from '../../stores/game';
5
+ import { editorStore } from '../../stores/editor';
6
+ import { gameEngine } from '../../services/game-engine';
7
+ import { HTMLParser } from '../../services/html-parser';
8
+ import GameError from './GameError.svelte';
9
+
10
+ let reloadTimer: any;
11
+ let previousContent = '';
12
+ let isInitialized = false;
13
+
14
+ $: if ($editorStore.content !== previousContent && $gameStore.isAutoRunning && isInitialized) {
15
+ previousContent = $editorStore.content;
16
+ clearTimeout(reloadTimer);
17
+ reloadTimer = setTimeout(async () => {
18
+ if (!$gameStore.isStarting) {
19
+ const worldContent = HTMLParser.extractGameContent($editorStore.content);
20
+ await gameEngine.start(worldContent);
21
+ }
22
+ }, 800);
23
+ }
24
+
25
+ onMount(async () => {
26
+ previousContent = $editorStore.content;
27
+ setTimeout(async () => {
28
+ if (!$gameStore.instance && $gameStore.isAutoRunning) {
29
+ const worldContent = HTMLParser.extractGameContent($editorStore.content);
30
+ await gameEngine.start(worldContent);
31
+ }
32
+ isInitialized = true;
33
+ }, 400);
34
+ });
35
+
36
+ onDestroy(() => {
37
+ clearTimeout(reloadTimer);
38
+ gameEngine.stop();
39
+ });
40
+ </script>
41
+
42
+ <div class="game-section">
43
+ {#if $uiStore.error}
44
+ <GameError error={$uiStore.error} />
45
+ {/if}
46
+
47
+ <div id="world-container" style="display: none;"></div>
48
+
49
+ <div class="canvas-container">
50
+ <canvas id="game-canvas"></canvas>
51
+ </div>
52
+ </div>
53
+
54
+ <style>
55
+ .game-section {
56
+ width: 100%;
57
+ height: 100%;
58
+ display: flex;
59
+ flex-direction: column;
60
+ min-height: 0;
61
+ }
62
+
63
+ .canvas-container {
64
+ flex: 1;
65
+ position: relative;
66
+ background: radial-gradient(ellipse at center, rgba(124, 152, 133, 0.02) 0%, transparent 70%);
67
+ overflow: hidden;
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ }
72
+
73
+ #game-canvas {
74
+ width: 100%;
75
+ height: 100%;
76
+ display: block;
77
+ object-fit: contain;
78
+ pointer-events: auto;
79
+ user-select: none;
80
+ }
81
+ </style>
src/lib/components/game/GameError.svelte ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ export let error: string;
3
+ </script>
4
+
5
+ <div class="error-message">
6
+ ❌ {error}
7
+ </div>
8
+
9
+ <style>
10
+ .error-message {
11
+ padding: 12px 16px;
12
+ background: rgba(184, 84, 80, 0.08);
13
+ border-left: 2px solid #B85450;
14
+ color: #B85450;
15
+ font-size: 12px;
16
+ font-family: "JetBrains Mono", "Monaco", "Menlo", monospace;
17
+ animation: slideDown 0.3s ease;
18
+ }
19
+
20
+ @keyframes slideDown {
21
+ from {
22
+ opacity: 0;
23
+ transform: translateY(-10px);
24
+ }
25
+ to {
26
+ opacity: 1;
27
+ transform: translateY(0);
28
+ }
29
+ }
30
+ </style>
src/lib/components/game/context.md ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Game Components
2
+
3
+ Game rendering and error display
4
+
5
+ ## Purpose
6
+
7
+ - Render game canvas
8
+ - Display game errors
9
+ - Manage game lifecycle
10
+
11
+ ## Layout
12
+
13
+ ```
14
+ game/
15
+ ├── context.md # This file
16
+ ├── GameCanvas.svelte # Game rendering canvas
17
+ └── GameError.svelte # Error message display
18
+ ```
19
+
20
+ ## Scope
21
+
22
+ - In-scope: Game display, error UI
23
+ - Out-of-scope: Game logic, physics
24
+
25
+ ## Entrypoints
26
+
27
+ - `GameCanvas.svelte` - Main game rendering component
28
+
29
+ ## Dependencies
30
+
31
+ - gameStore for game state
32
+ - gameEngine service for lifecycle
33
+ - uiStore for error state
src/lib/components/layout/AppHeader.svelte ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { uiStore } from '../../stores/ui';
4
+ import { gameStore } from '../../stores/game';
5
+ import { gameEngine } from '../../services/game-engine';
6
+ import { editorStore } from '../../stores/editor';
7
+ import { HTMLParser } from '../../services/html-parser';
8
+ import LoginButton from '../auth/LoginButton.svelte';
9
+ import gsap from 'gsap';
10
+
11
+ async function restartGame() {
12
+ const worldContent = HTMLParser.extractGameContent($editorStore.content);
13
+ await gameEngine.start(worldContent);
14
+ }
15
+
16
+ function handleViewModeChange(mode: 'code' | 'preview') {
17
+ uiStore.setViewMode(mode);
18
+ }
19
+
20
+ onMount(() => {
21
+ gsap.fromTo(".app-header",
22
+ { opacity: 0, y: -20 },
23
+ { opacity: 1, y: 0, duration: 0.6, ease: "power3.out" }
24
+ );
25
+
26
+ const handleKeyPress = (e: KeyboardEvent) => {
27
+ if ((e.ctrlKey || e.metaKey) && e.key === 'e') {
28
+ e.preventDefault();
29
+ uiStore.toggleViewMode();
30
+ }
31
+ };
32
+ window.addEventListener('keydown', handleKeyPress);
33
+
34
+ const toggleButtons = document.querySelectorAll('.toggle-btn');
35
+ toggleButtons.forEach(btn => {
36
+ btn.addEventListener('mouseenter', () => {
37
+ if (!btn.classList.contains('active')) {
38
+ gsap.to(btn, {
39
+ scale: 1.05,
40
+ duration: 0.2,
41
+ ease: "power2.out"
42
+ });
43
+ }
44
+ });
45
+
46
+ btn.addEventListener('mouseleave', () => {
47
+ if (!btn.classList.contains('active')) {
48
+ gsap.to(btn, {
49
+ scale: 1,
50
+ duration: 0.2,
51
+ ease: "power2.out"
52
+ });
53
+ }
54
+ });
55
+ });
56
+
57
+ return () => {
58
+ window.removeEventListener('keydown', handleKeyPress);
59
+ };
60
+ });
61
+ </script>
62
+
63
+ <div class="app-header">
64
+ <div class="header-left">
65
+ <div class="app-title">
66
+ <span class="app-icon">🥕</span>
67
+ <span class="app-name">VibeGame</span>
68
+ </div>
69
+ </div>
70
+
71
+ <div class="header-center">
72
+ <div class="view-toggle">
73
+ <button
74
+ class="toggle-btn"
75
+ class:active={$uiStore.viewMode === 'code'}
76
+ on:click={() => handleViewModeChange('code')}
77
+ >
78
+ Code
79
+ </button>
80
+ <button
81
+ class="toggle-btn"
82
+ class:active={$uiStore.viewMode === 'preview'}
83
+ on:click={() => handleViewModeChange('preview')}
84
+ >
85
+ Preview
86
+ </button>
87
+ </div>
88
+ </div>
89
+
90
+ <div class="header-right">
91
+ <LoginButton />
92
+ <div class="status-indicator">
93
+ {#if $uiStore.error}
94
+ <span class="status-dot error"></span>
95
+ {:else if $gameStore.isRunning}
96
+ <span class="status-dot running"></span>
97
+ {:else}
98
+ <span class="status-dot"></span>
99
+ {/if}
100
+ </div>
101
+ <button
102
+ on:click={restartGame}
103
+ class="restart-button"
104
+ aria-label="Restart"
105
+ >
106
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor">
107
+ <path d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/>
108
+ <path d="M8 1a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h1.293L5.646 1.354a.5.5 0 1 1 .708-.708L8 2.293V1.5A.5.5 0 0 1 8 1z"/>
109
+ </svg>
110
+ <span>Restart</span>
111
+ </button>
112
+ </div>
113
+ </div>
114
+
115
+ <style>
116
+ .app-header {
117
+ height: 40px;
118
+ background: rgba(15, 14, 12, 0.6);
119
+ backdrop-filter: blur(10px);
120
+ border-bottom: 1px solid rgba(139, 115, 85, 0.06);
121
+ display: flex;
122
+ align-items: center;
123
+ justify-content: space-between;
124
+ padding: 0 16px;
125
+ flex-shrink: 0;
126
+ position: relative;
127
+ z-index: 10;
128
+ }
129
+
130
+ .header-left,
131
+ .header-center,
132
+ .header-right {
133
+ display: flex;
134
+ align-items: center;
135
+ flex: 1;
136
+ }
137
+
138
+ .header-left {
139
+ justify-content: flex-start;
140
+ }
141
+
142
+ .app-title {
143
+ display: flex;
144
+ align-items: center;
145
+ gap: 0.5rem;
146
+ user-select: none;
147
+ }
148
+
149
+ .app-icon {
150
+ font-size: 1.25rem;
151
+ line-height: 1;
152
+ }
153
+
154
+ .app-name {
155
+ font-size: 0.875rem;
156
+ font-weight: 600;
157
+ color: rgba(251, 248, 244, 0.9);
158
+ letter-spacing: 0.025em;
159
+ }
160
+
161
+ .header-center {
162
+ justify-content: center;
163
+ }
164
+
165
+ .header-right {
166
+ justify-content: flex-end;
167
+ gap: 12px;
168
+ }
169
+
170
+ .view-toggle {
171
+ display: flex;
172
+ background: rgba(139, 115, 85, 0.05);
173
+ border-radius: 6px;
174
+ padding: 2px;
175
+ border: 1px solid rgba(139, 115, 85, 0.08);
176
+ }
177
+
178
+ .toggle-btn {
179
+ padding: 6px 14px;
180
+ background: transparent;
181
+ border: none;
182
+ color: rgba(251, 248, 244, 0.5);
183
+ font-size: 11px;
184
+ font-weight: 500;
185
+ text-transform: uppercase;
186
+ letter-spacing: 0.5px;
187
+ cursor: pointer;
188
+ border-radius: 4px;
189
+ position: relative;
190
+ transform-origin: center;
191
+ transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
192
+ background 0.2s cubic-bezier(0.4, 0, 0.2, 1),
193
+ box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1);
194
+ }
195
+
196
+ .toggle-btn::before {
197
+ content: '';
198
+ position: absolute;
199
+ inset: 0;
200
+ border-radius: 4px;
201
+ background: rgba(124, 152, 133, 0.08);
202
+ opacity: 0;
203
+ transition: opacity 0.2s ease-out;
204
+ }
205
+
206
+ .toggle-btn:hover:not(.active)::before {
207
+ opacity: 1;
208
+ }
209
+
210
+ .toggle-btn:hover:not(.active) {
211
+ color: rgba(251, 248, 244, 0.7);
212
+ }
213
+
214
+ .toggle-btn.active {
215
+ background: rgba(124, 152, 133, 0.15);
216
+ color: rgba(251, 248, 244, 0.9);
217
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1),
218
+ inset 0 1px 0 rgba(124, 152, 133, 0.2);
219
+ }
220
+
221
+ .toggle-btn.active::after {
222
+ content: '';
223
+ position: absolute;
224
+ bottom: -1px;
225
+ left: 50%;
226
+ transform: translateX(-50%);
227
+ width: 20px;
228
+ height: 2px;
229
+ background: #7C9885;
230
+ border-radius: 1px;
231
+ animation: slideIn 0.2s ease-out;
232
+ }
233
+
234
+ @keyframes slideIn {
235
+ from {
236
+ width: 0;
237
+ opacity: 0;
238
+ }
239
+ to {
240
+ width: 20px;
241
+ opacity: 1;
242
+ }
243
+ }
244
+
245
+ .restart-button {
246
+ display: flex;
247
+ align-items: center;
248
+ gap: 4px;
249
+ padding: 0.25rem 0.75rem;
250
+ background: transparent;
251
+ border: 1px solid rgba(255, 255, 255, 0.1);
252
+ border-radius: 0.25rem;
253
+ color: rgba(255, 255, 255, 0.6);
254
+ font-size: 0.75rem;
255
+ font-weight: 500;
256
+ cursor: pointer;
257
+ transition: all 0.2s;
258
+ position: relative;
259
+ }
260
+
261
+ .restart-button:hover {
262
+ background: rgba(255, 255, 255, 0.05);
263
+ border-color: rgba(255, 255, 255, 0.2);
264
+ color: rgba(255, 255, 255, 0.9);
265
+ }
266
+
267
+ .restart-button span {
268
+ text-transform: none;
269
+ letter-spacing: normal;
270
+ }
271
+
272
+ .restart-button:active {
273
+ transform: scale(0.98);
274
+ }
275
+
276
+ .restart-button svg {
277
+ transition: transform 0.2s ease-out;
278
+ }
279
+
280
+ .restart-button:hover svg {
281
+ transform: rotate(180deg);
282
+ }
283
+
284
+ .status-indicator {
285
+ display: flex;
286
+ align-items: center;
287
+ }
288
+
289
+ .status-dot {
290
+ width: 8px;
291
+ height: 8px;
292
+ border-radius: 50%;
293
+ background: rgba(139, 115, 85, 0.3);
294
+ transition: all 0.3s ease;
295
+ }
296
+
297
+ .status-dot.running {
298
+ background: #7C9885;
299
+ box-shadow: 0 0 12px rgba(124, 152, 133, 0.4);
300
+ animation: breathe 2s ease-in-out infinite;
301
+ }
302
+
303
+ .status-dot.error {
304
+ background: #B85450;
305
+ box-shadow: 0 0 12px rgba(184, 84, 80, 0.4);
306
+ }
307
+
308
+ @keyframes breathe {
309
+ 0%, 100% {
310
+ opacity: 0.8;
311
+ transform: scale(1);
312
+ }
313
+ 50% {
314
+ opacity: 1;
315
+ transform: scale(1.1);
316
+ }
317
+ }
318
+ </style>
src/lib/components/layout/LoadingScreen.svelte ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { gsap } from 'gsap';
4
+
5
+ export let loading = true;
6
+
7
+ let container: HTMLDivElement;
8
+ let spinner: HTMLDivElement;
9
+ let fadeOut = false;
10
+
11
+ onMount(() => {
12
+ const tl = gsap.timeline();
13
+
14
+ tl.from('.loading-title', {
15
+ opacity: 0,
16
+ y: 10,
17
+ duration: 0.3,
18
+ ease: 'power3.out'
19
+ })
20
+ .from('.spinner', {
21
+ opacity: 0,
22
+ scale: 0.8,
23
+ duration: 0.2,
24
+ ease: 'power3.out'
25
+ }, '-=0.1');
26
+
27
+ gsap.to(spinner, {
28
+ rotation: 360,
29
+ duration: 1,
30
+ repeat: -1,
31
+ ease: 'none'
32
+ });
33
+
34
+ return () => {
35
+ tl.kill();
36
+ gsap.killTweensOf(spinner);
37
+ };
38
+ });
39
+
40
+ $: if (!loading && container && !fadeOut) {
41
+ fadeOut = true;
42
+ gsap.to(container, {
43
+ opacity: 0,
44
+ duration: 0.25,
45
+ ease: 'power2.inOut',
46
+ onComplete: () => {
47
+ container.style.display = 'none';
48
+ }
49
+ });
50
+ }
51
+ </script>
52
+
53
+ {#if loading || fadeOut}
54
+ <div bind:this={container} class="loading-screen">
55
+ <div class="loading-content">
56
+ <h1 class="loading-title">VibeGame</h1>
57
+ <div bind:this={spinner} class="spinner">
58
+ <div class="spinner-ring"></div>
59
+ <div class="spinner-ring"></div>
60
+ <div class="spinner-ring"></div>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ {/if}
65
+
66
+ <style>
67
+ .loading-screen {
68
+ position: fixed;
69
+ top: 0;
70
+ left: 0;
71
+ width: 100vw;
72
+ height: 100vh;
73
+ background: #0B0A09;
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ z-index: 10000;
78
+ }
79
+
80
+ .loading-content {
81
+ text-align: center;
82
+ display: flex;
83
+ flex-direction: column;
84
+ align-items: center;
85
+ gap: 2.5rem;
86
+ }
87
+
88
+ .loading-title {
89
+ font-size: 2.5rem;
90
+ font-weight: 200;
91
+ margin: 0;
92
+ color: #ffffff;
93
+ letter-spacing: -0.02em;
94
+ }
95
+
96
+ .spinner {
97
+ position: relative;
98
+ width: 40px;
99
+ height: 40px;
100
+ }
101
+
102
+ .spinner-ring {
103
+ position: absolute;
104
+ width: 100%;
105
+ height: 100%;
106
+ border: 2px solid transparent;
107
+ border-radius: 50%;
108
+ border-top-color: #ffffff;
109
+ opacity: 0.3;
110
+ }
111
+
112
+ .spinner-ring:nth-child(1) {
113
+ animation: spin 1.5s linear infinite;
114
+ }
115
+
116
+ .spinner-ring:nth-child(2) {
117
+ width: 80%;
118
+ height: 80%;
119
+ top: 10%;
120
+ left: 10%;
121
+ border-top-color: #ffffff;
122
+ opacity: 0.5;
123
+ animation: spin 1.2s linear infinite reverse;
124
+ }
125
+
126
+ .spinner-ring:nth-child(3) {
127
+ width: 60%;
128
+ height: 60%;
129
+ top: 20%;
130
+ left: 20%;
131
+ border-top-color: #ffffff;
132
+ opacity: 0.8;
133
+ animation: spin 0.9s linear infinite;
134
+ }
135
+
136
+ @keyframes spin {
137
+ to {
138
+ transform: rotate(360deg);
139
+ }
140
+ }
141
+ </style>
src/lib/components/layout/SplitView.svelte ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { Splitpanes, Pane } from 'svelte-splitpanes';
4
+ import { uiStore } from '../../stores/ui';
5
+ import CodeEditor from '../editor/CodeEditor.svelte';
6
+ import GameCanvas from '../game/GameCanvas.svelte';
7
+ import ConsolePanel from '../console/ConsolePanel.svelte';
8
+ import ChatPanel from '../chat/ChatPanel.svelte';
9
+ import gsap from 'gsap';
10
+
11
+ $: viewMode = $uiStore.viewMode;
12
+
13
+ let userMainPaneSizes = { editor: 0.4, preview: 0.6 };
14
+ let userEditorPaneSizes = { code: 0.7, chat: 0.3 };
15
+ let userPreviewPaneSizes = { game: 0.75, console: 0.25 };
16
+
17
+ onMount(() => {
18
+ gsap.fromTo(".editor-pane",
19
+ { opacity: 0, x: -20 },
20
+ { opacity: 1, x: 0, duration: 0.6, delay: 0.1, ease: "power3.out" }
21
+ );
22
+
23
+ gsap.fromTo(".preview-pane",
24
+ { opacity: 0, x: 20 },
25
+ { opacity: 1, x: 0, duration: 0.6, delay: 0.2, ease: "power3.out" }
26
+ );
27
+
28
+ const resetCursor = () => {
29
+ document.body.style.cursor = '';
30
+ };
31
+ document.addEventListener('mouseup', resetCursor);
32
+
33
+ return () => {
34
+ document.removeEventListener('mouseup', resetCursor);
35
+ };
36
+ });
37
+
38
+ $: if (viewMode) {
39
+ handleViewModeAnimation(viewMode);
40
+ }
41
+
42
+ function handleViewModeAnimation(mode: 'code' | 'preview') {
43
+ const mainPanes = document.querySelector('.main-splitpanes')?.querySelectorAll(':scope > .splitpanes__pane');
44
+ if (!mainPanes || mainPanes.length < 2) return;
45
+
46
+ const editorPaneEl = mainPanes[0] as HTMLElement;
47
+ const previewPaneEl = mainPanes[1] as HTMLElement;
48
+ const mainSplitter = document.querySelector('.main-splitpanes > .splitpanes__splitter') as HTMLElement;
49
+
50
+ if (!editorPaneEl || !previewPaneEl) return;
51
+
52
+ const editorSplitpanes = editorPaneEl.querySelectorAll('.splitpanes__pane');
53
+ const codePane = editorSplitpanes[0] as HTMLElement;
54
+ const chatPane = editorSplitpanes[1] as HTMLElement;
55
+
56
+ const previewSplitpanes = previewPaneEl.querySelectorAll('.splitpanes__pane');
57
+ const gamePane = previewSplitpanes[0] as HTMLElement;
58
+ const consolePane = previewSplitpanes[1] as HTMLElement;
59
+ const consoleSplitter = previewPaneEl.querySelector('.splitpanes__splitter') as HTMLElement;
60
+
61
+ if (mode === 'preview') {
62
+ const editorWidth = editorPaneEl.offsetWidth;
63
+ const previewWidth = previewPaneEl.offsetWidth;
64
+ const totalWidth = editorWidth + previewWidth;
65
+
66
+ if (totalWidth > 0) {
67
+ userMainPaneSizes.editor = editorWidth / totalWidth;
68
+ userMainPaneSizes.preview = previewWidth / totalWidth;
69
+ }
70
+
71
+ if (codePane && chatPane) {
72
+ const codeHeight = codePane.offsetHeight;
73
+ const chatHeight = chatPane.offsetHeight;
74
+ const totalEditorHeight = codeHeight + chatHeight;
75
+
76
+ if (totalEditorHeight > 0) {
77
+ userEditorPaneSizes.code = codeHeight / totalEditorHeight;
78
+ userEditorPaneSizes.chat = chatHeight / totalEditorHeight;
79
+ }
80
+ }
81
+
82
+ if (gamePane && consolePane) {
83
+ const gameHeight = gamePane.offsetHeight;
84
+ const consoleHeight = consolePane.offsetHeight;
85
+ const totalHeight = gameHeight + consoleHeight;
86
+
87
+ if (totalHeight > 0) {
88
+ userPreviewPaneSizes.game = gameHeight / totalHeight;
89
+ userPreviewPaneSizes.console = consoleHeight / totalHeight;
90
+ }
91
+ }
92
+
93
+ gsap.set(editorPaneEl, { flexGrow: userMainPaneSizes.editor, flexBasis: `${userMainPaneSizes.editor * 100}%` });
94
+ gsap.set(previewPaneEl, { flexGrow: userMainPaneSizes.preview, flexBasis: `${userMainPaneSizes.preview * 100}%` });
95
+
96
+ if (codePane && chatPane) {
97
+ gsap.set(codePane, { flexGrow: userEditorPaneSizes.code, flexBasis: `${userEditorPaneSizes.code * 100}%` });
98
+ gsap.set(chatPane, { flexGrow: userEditorPaneSizes.chat, flexBasis: `${userEditorPaneSizes.chat * 100}%` });
99
+ }
100
+
101
+ if (gamePane && consolePane) {
102
+ gsap.set(gamePane, { flexGrow: userPreviewPaneSizes.game, flexBasis: `${userPreviewPaneSizes.game * 100}%` });
103
+ gsap.set(consolePane, { flexGrow: userPreviewPaneSizes.console, flexBasis: `${userPreviewPaneSizes.console * 100}%` });
104
+ }
105
+ }
106
+
107
+ if (mode === 'preview') {
108
+ gsap.timeline({ ease: "power2.out" })
109
+ .to(editorPaneEl, {
110
+ opacity: 0,
111
+ duration: 0.15,
112
+ })
113
+ .to(consolePane, {
114
+ opacity: 0,
115
+ duration: 0.15,
116
+ }, "-=0.15")
117
+ .to(editorPaneEl, {
118
+ flexGrow: 0,
119
+ flexBasis: "0%",
120
+ duration: 0.2,
121
+ ease: "power2.inOut",
122
+ onComplete: () => {
123
+ editorPaneEl.style.display = 'none';
124
+ if (mainSplitter) mainSplitter.style.display = 'none';
125
+ }
126
+ }, "-=0.1")
127
+ .to(consolePane, {
128
+ flexGrow: 0,
129
+ flexBasis: "0%",
130
+ duration: 0.2,
131
+ ease: "power2.inOut",
132
+ onComplete: () => {
133
+ consolePane.style.display = 'none';
134
+ if (consoleSplitter) consoleSplitter.style.display = 'none';
135
+ }
136
+ }, "-=0.2")
137
+ .to(gamePane, {
138
+ flexGrow: 1,
139
+ flexBasis: "100%",
140
+ duration: 0.2,
141
+ ease: "power2.inOut",
142
+ }, "-=0.2")
143
+ .to(previewPaneEl, {
144
+ flexGrow: 1,
145
+ flexBasis: "100%",
146
+ duration: 0.2,
147
+ ease: "power2.inOut",
148
+ }, "-=0.2");
149
+ } else {
150
+ editorPaneEl.style.display = '';
151
+ if (mainSplitter) mainSplitter.style.display = '';
152
+ consolePane.style.display = '';
153
+ if (consoleSplitter) consoleSplitter.style.display = '';
154
+
155
+ gsap.timeline({ ease: "power2.out" })
156
+ .set(editorPaneEl, {
157
+ opacity: 0,
158
+ flexGrow: 0,
159
+ flexBasis: "0%"
160
+ })
161
+ .set(consolePane, {
162
+ opacity: 0,
163
+ flexGrow: 0,
164
+ flexBasis: "0%"
165
+ })
166
+ .to([editorPaneEl, previewPaneEl], {
167
+ flexGrow: (i) => i === 0 ? userMainPaneSizes.editor : userMainPaneSizes.preview,
168
+ flexBasis: (i) => i === 0 ? `${userMainPaneSizes.editor * 100}%` : `${userMainPaneSizes.preview * 100}%`,
169
+ duration: 0.2,
170
+ ease: "power2.inOut",
171
+ })
172
+ .to([codePane, chatPane], {
173
+ flexGrow: (i) => i === 0 ? userEditorPaneSizes.code : userEditorPaneSizes.chat,
174
+ flexBasis: (i) => i === 0 ? `${userEditorPaneSizes.code * 100}%` : `${userEditorPaneSizes.chat * 100}%`,
175
+ duration: 0.2,
176
+ ease: "power2.inOut",
177
+ }, "-=0.2")
178
+ .to([gamePane, consolePane], {
179
+ flexGrow: (i) => i === 0 ? userPreviewPaneSizes.game : userPreviewPaneSizes.console,
180
+ flexBasis: (i) => i === 0 ? `${userPreviewPaneSizes.game * 100}%` : `${userPreviewPaneSizes.console * 100}%`,
181
+ duration: 0.2,
182
+ ease: "power2.inOut",
183
+ }, "-=0.2")
184
+ .to(consolePane, {
185
+ opacity: 1,
186
+ duration: 0.15,
187
+ }, "-=0.15")
188
+ .to(editorPaneEl, {
189
+ opacity: 1,
190
+ duration: 0.15,
191
+ onComplete: () => {
192
+ window.dispatchEvent(new Event('resize'));
193
+ }
194
+ }, "-=0.15");
195
+ }
196
+ }
197
+ </script>
198
+
199
+ <div class="editor-layout">
200
+ <Splitpanes class="main-splitpanes" theme="modern-theme">
201
+ <Pane minSize={20} size={40} class="editor-pane">
202
+ <div class="editor-panel">
203
+ <Splitpanes horizontal class="editor-splitpanes" theme="modern-theme">
204
+ <Pane minSize={30} size={70} class="code-pane">
205
+ <CodeEditor />
206
+ </Pane>
207
+ <Pane minSize={15} size={30} class="chat-pane">
208
+ <ChatPanel />
209
+ </Pane>
210
+ </Splitpanes>
211
+ </div>
212
+ </Pane>
213
+ <Pane minSize={25} size={60} class="preview-pane">
214
+ <div class="preview-panel">
215
+ <Splitpanes horizontal class="preview-splitpanes" theme="modern-theme">
216
+ <Pane minSize={30} class="game-pane">
217
+ <GameCanvas />
218
+ </Pane>
219
+ <Pane minSize={15} size={25} class="console-pane">
220
+ <ConsolePanel />
221
+ </Pane>
222
+ </Splitpanes>
223
+ </div>
224
+ </Pane>
225
+ </Splitpanes>
226
+ </div>
227
+
228
+ <style>
229
+ .editor-layout {
230
+ flex: 1;
231
+ display: flex;
232
+ min-height: 0;
233
+ background: rgba(139, 115, 85, 0.02);
234
+ }
235
+
236
+ :global(.main-splitpanes) {
237
+ width: 100%;
238
+ height: 100%;
239
+ }
240
+
241
+ :global(.editor-splitpanes) {
242
+ width: 100%;
243
+ height: 100%;
244
+ }
245
+
246
+ :global(.preview-splitpanes) {
247
+ width: 100%;
248
+ height: 100%;
249
+ }
250
+
251
+ :global(.editor-pane) {
252
+ display: flex;
253
+ overflow: hidden;
254
+ }
255
+
256
+ :global(.preview-pane) {
257
+ display: flex;
258
+ overflow: hidden;
259
+ }
260
+
261
+ :global(.code-pane) {
262
+ display: flex;
263
+ overflow: hidden;
264
+ }
265
+
266
+ :global(.game-pane) {
267
+ display: flex;
268
+ overflow: hidden;
269
+ }
270
+
271
+ :global(.console-pane) {
272
+ display: flex;
273
+ overflow: hidden;
274
+ }
275
+
276
+ :global(.chat-pane) {
277
+ display: flex;
278
+ overflow: hidden;
279
+ }
280
+
281
+ .editor-panel {
282
+ width: 100%;
283
+ height: 100%;
284
+ display: flex;
285
+ flex-direction: column;
286
+ background: rgba(11, 10, 9, 0.3);
287
+ min-width: 0;
288
+ overflow: hidden;
289
+ }
290
+
291
+ .preview-panel {
292
+ width: 100%;
293
+ height: 100%;
294
+ display: flex;
295
+ flex-direction: column;
296
+ background: rgba(11, 10, 9, 0.3);
297
+ min-width: 0;
298
+ overflow: hidden;
299
+ }
300
+
301
+ :global(.splitpanes.modern-theme .splitpanes__splitter) {
302
+ background: rgba(139, 115, 85, 0.06);
303
+ position: relative;
304
+ transition: background 0.2s;
305
+ }
306
+
307
+ :global(.splitpanes.modern-theme .splitpanes__splitter:hover) {
308
+ background: rgba(139, 115, 85, 0.12);
309
+ }
310
+
311
+ :global(.splitpanes.modern-theme .splitpanes__splitter:before) {
312
+ content: '';
313
+ position: absolute;
314
+ z-index: 1;
315
+ transition: opacity 0.2s;
316
+ background: rgba(124, 152, 133, 0.1);
317
+ opacity: 0;
318
+ }
319
+
320
+ :global(.splitpanes.modern-theme .splitpanes__splitter:hover:before) {
321
+ opacity: 1;
322
+ }
323
+
324
+ :global(.splitpanes--vertical.modern-theme > .splitpanes__splitter) {
325
+ width: 1px;
326
+ cursor: col-resize;
327
+ }
328
+
329
+ :global(.splitpanes--vertical.modern-theme > .splitpanes__splitter:before) {
330
+ left: -3px;
331
+ right: -3px;
332
+ height: 100%;
333
+ cursor: col-resize;
334
+ }
335
+
336
+ :global(.splitpanes--horizontal.modern-theme > .splitpanes__splitter) {
337
+ height: 1px;
338
+ cursor: row-resize;
339
+ }
340
+
341
+ :global(.splitpanes--horizontal.modern-theme > .splitpanes__splitter:before) {
342
+ top: -3px;
343
+ bottom: -3px;
344
+ width: 100%;
345
+ cursor: row-resize;
346
+ }
347
+
348
+ :global(body.splitpanes--dragging) {
349
+ cursor: inherit;
350
+ }
351
+
352
+ :global(body:not(.splitpanes--dragging) .splitpanes__splitter:not(:hover)) {
353
+ cursor: default;
354
+ }
355
+ </style>
src/lib/components/layout/context.md ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Layout Components
2
+
3
+ Application layout structure
4
+
5
+ ## Purpose
6
+
7
+ - Loading state management
8
+ - Header navigation
9
+ - Two-pane layout with nested splits
10
+ - View mode transitions
11
+
12
+ ## Structure
13
+
14
+ ```
15
+ layout/
16
+ ├── context.md # This file
17
+ ├── LoadingScreen.svelte # Initial loading with spinner
18
+ ├── AppHeader.svelte # Top navigation bar
19
+ └── SplitView.svelte # Two-pane layout with nested splits
20
+ ```
21
+
22
+ ## Layout Organization
23
+
24
+ - Main split: Editor pane (left) | Preview pane (right)
25
+ - Editor pane: Code editor (top) | Chat panel (bottom)
26
+ - Preview pane: Game canvas (top) | Console (bottom)
27
+
28
+ ## Dependencies
29
+
30
+ - loadingStore for loading state
31
+ - uiStore for view mode
32
+ - svelte-splitpanes for resizable panes
33
+ - GSAP for animations
src/lib/config/animations.ts ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export const animationConfig = {
2
+ header: {
3
+ initial: { opacity: 0, y: -20 },
4
+ animate: { opacity: 1, y: 0, duration: 0.6, ease: "power3.out" },
5
+ },
6
+
7
+ editor: {
8
+ initial: { opacity: 0, x: -20 },
9
+ animate: {
10
+ opacity: 1,
11
+ x: 0,
12
+ duration: 0.6,
13
+ delay: 0.1,
14
+ ease: "power3.out",
15
+ },
16
+ },
17
+
18
+ preview: {
19
+ initial: { opacity: 0, x: 20 },
20
+ animate: {
21
+ opacity: 1,
22
+ x: 0,
23
+ duration: 0.6,
24
+ delay: 0.2,
25
+ ease: "power3.out",
26
+ },
27
+ },
28
+
29
+ consoleMessage: {
30
+ initial: { opacity: 0, y: -5 },
31
+ animate: { opacity: 1, y: 0, duration: 0.3, ease: "power2.out" },
32
+ },
33
+
34
+ error: {
35
+ initial: { opacity: 0, transform: "translateY(-10px)" },
36
+ animate: { opacity: 1, transform: "translateY(0)", duration: 0.3 },
37
+ },
38
+
39
+ viewTransition: {
40
+ duration: 0.2,
41
+ ease: "power2.inOut",
42
+ },
43
+ };
src/lib/config/context.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Configuration
2
+
3
+ Application configuration and constants
4
+
5
+ ## Purpose
6
+
7
+ - Centralize configuration values
8
+ - Define animation settings
9
+ - Keyboard shortcuts registry
10
+
11
+ ## Layout
12
+
13
+ ```
14
+ config/
15
+ ├── context.md # This file
16
+ ├── animations.ts # GSAP animation configs
17
+ └── shortcuts.ts # Keyboard shortcut definitions
18
+ ```
19
+
20
+ ## Scope
21
+
22
+ - In-scope: Static configuration, constants
23
+ - Out-of-scope: Runtime state, business logic
24
+
25
+ ## Entrypoints
26
+
27
+ - `animationConfig` - Animation presets
28
+ - `shortcuts` - Keyboard shortcut definitions
29
+ - `registerShortcuts()` - Setup keyboard handlers
30
+
31
+ ## Dependencies
32
+
33
+ - No external dependencies
34
+ - Imported by components and services
src/lib/config/shortcuts.ts ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export interface Shortcut {
2
+ key: string;
3
+ ctrl?: boolean;
4
+ meta?: boolean;
5
+ shift?: boolean;
6
+ alt?: boolean;
7
+ action: () => void;
8
+ description: string;
9
+ }
10
+
11
+ export const shortcuts: Shortcut[] = [
12
+ {
13
+ key: "e",
14
+ ctrl: true,
15
+ meta: true,
16
+ action: () => {
17
+ import("../stores/ui").then(({ uiStore }) => {
18
+ uiStore.toggleViewMode();
19
+ });
20
+ },
21
+ description: "Toggle between code and preview mode",
22
+ },
23
+ ];
24
+
25
+ export function registerShortcuts(shortcuts: Shortcut[]): () => void {
26
+ const handler = (e: KeyboardEvent) => {
27
+ for (const shortcut of shortcuts) {
28
+ const ctrlMatch = shortcut.ctrl
29
+ ? e.ctrlKey
30
+ : !shortcut.ctrl || !e.ctrlKey;
31
+ const metaMatch = shortcut.meta
32
+ ? e.metaKey
33
+ : !shortcut.meta || !e.metaKey;
34
+ const shiftMatch = shortcut.shift
35
+ ? e.shiftKey
36
+ : !shortcut.shift || !e.shiftKey;
37
+ const altMatch = shortcut.alt ? e.altKey : !shortcut.alt || !e.altKey;
38
+
39
+ if (
40
+ e.key === shortcut.key &&
41
+ (ctrlMatch || metaMatch) &&
42
+ shiftMatch &&
43
+ altMatch
44
+ ) {
45
+ e.preventDefault();
46
+ shortcut.action();
47
+ break;
48
+ }
49
+ }
50
+ };
51
+
52
+ window.addEventListener("keydown", handler);
53
+
54
+ return () => {
55
+ window.removeEventListener("keydown", handler);
56
+ };
57
+ }
src/lib/server/agent-runner.ts ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { HfInference } from "@huggingface/inference";
2
+
3
+ export interface AgentMessage {
4
+ id: string;
5
+ role: "user" | "assistant" | "system";
6
+ content: string;
7
+ timestamp: number;
8
+ }
9
+
10
+ export interface AgentConfig {
11
+ model?: string;
12
+ maxIterations?: number;
13
+ temperature?: number;
14
+ maxTokens?: number;
15
+ }
16
+
17
+ export class AgentRunner {
18
+ private client: HfInference | null = null;
19
+ private config: AgentConfig;
20
+ private messageHistory: AgentMessage[] = [];
21
+
22
+ constructor(config: AgentConfig = {}) {
23
+ this.config = {
24
+ model: "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B",
25
+ maxIterations: 10,
26
+ temperature: 0.7,
27
+ maxTokens: 1000,
28
+ ...config,
29
+ };
30
+ }
31
+
32
+ async initialize(hfToken?: string) {
33
+ if (!hfToken) {
34
+ throw new Error(
35
+ "Hugging Face authentication required. Please sign in to continue.",
36
+ );
37
+ }
38
+
39
+ this.client = new HfInference(hfToken);
40
+ }
41
+
42
+ async processMessage(
43
+ message: string,
44
+ onStream?: (chunk: string) => void,
45
+ ): Promise<string> {
46
+ if (!this.client) {
47
+ throw new Error("AgentRunner not initialized. Call initialize() first.");
48
+ }
49
+
50
+ const userMessage: AgentMessage = {
51
+ id: this.generateId(),
52
+ role: "user",
53
+ content: message,
54
+ timestamp: Date.now(),
55
+ };
56
+
57
+ this.messageHistory.push(userMessage);
58
+
59
+ try {
60
+ const systemPrompt = `You are an AI assistant helping to build games with VibeGame.
61
+ You can read and modify game code using XML syntax.
62
+ Always validate changes and ensure the game remains playable.
63
+ Use small, incremental changes rather than large rewrites.`;
64
+
65
+ const messages = [
66
+ { role: "system", content: systemPrompt },
67
+ ...this.messageHistory.map((msg) => ({
68
+ role: msg.role,
69
+ content: msg.content,
70
+ })),
71
+ ];
72
+
73
+ let fullResponse = "";
74
+
75
+ const stream = await this.client.chatCompletionStream({
76
+ model: this.config.model!,
77
+ messages: messages as Array<{ role: string; content: string }>,
78
+ temperature: this.config.temperature,
79
+ max_tokens: this.config.maxTokens,
80
+ });
81
+
82
+ for await (const chunk of stream) {
83
+ if (chunk.choices && chunk.choices.length > 0) {
84
+ const delta = chunk.choices[0].delta?.content;
85
+ if (delta) {
86
+ fullResponse += delta;
87
+ if (onStream) {
88
+ onStream(delta);
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ const assistantMessage: AgentMessage = {
95
+ id: this.generateId(),
96
+ role: "assistant",
97
+ content: fullResponse,
98
+ timestamp: Date.now(),
99
+ };
100
+
101
+ this.messageHistory.push(assistantMessage);
102
+
103
+ return fullResponse;
104
+ } catch (error) {
105
+ console.error("Error processing message:", error);
106
+
107
+ if (error instanceof Error && error.message.includes("rate limit")) {
108
+ throw new Error(
109
+ "Hugging Face API rate limit exceeded. Please provide an API token or wait before retrying.",
110
+ );
111
+ }
112
+
113
+ throw error;
114
+ }
115
+ }
116
+
117
+ getHistory(): AgentMessage[] {
118
+ return [...this.messageHistory];
119
+ }
120
+
121
+ clearHistory() {
122
+ this.messageHistory = [];
123
+ }
124
+
125
+ private generateId(): string {
126
+ return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
127
+ }
128
+ }
src/lib/server/api.ts ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import type { IncomingMessage } from "http";
2
+ import type { WebSocket } from "ws";
3
+ import type { AgentRunner } from "./agent-runner";
4
+
5
+ export interface WebSocketMessage {
6
+ type: "chat" | "error" | "status" | "stream" | "auth";
7
+ payload: {
8
+ content?: string;
9
+ role?: string;
10
+ chunk?: string;
11
+ error?: string;
12
+ processing?: boolean;
13
+ connected?: boolean;
14
+ message?: string;
15
+ token?: string;
16
+ };
17
+ timestamp: number;
18
+ }
19
+
20
+ class WebSocketManager {
21
+ private connections: Map<WebSocket, { token?: string; agent?: AgentRunner }> =
22
+ new Map();
23
+
24
+ handleConnection(ws: WebSocket, _request: IncomingMessage) {
25
+ this.connections.set(ws, {});
26
+
27
+ this.sendMessage(ws, {
28
+ type: "status",
29
+ payload: { connected: true, message: "Connected to agent server" },
30
+ timestamp: Date.now(),
31
+ });
32
+
33
+ ws.on("message", async (data) => {
34
+ try {
35
+ const message = JSON.parse(data.toString()) as WebSocketMessage;
36
+ await this.handleMessage(ws, message);
37
+ } catch (error) {
38
+ console.error("Error handling WebSocket message:", error);
39
+ this.sendError(ws, "Failed to process message");
40
+ }
41
+ });
42
+
43
+ ws.on("close", () => {
44
+ this.connections.delete(ws);
45
+ });
46
+
47
+ ws.on("error", (error) => {
48
+ console.error("WebSocket error:", error);
49
+ this.connections.delete(ws);
50
+ });
51
+ }
52
+
53
+ private async handleMessage(ws: WebSocket, message: WebSocketMessage) {
54
+ const connectionData = this.connections.get(ws);
55
+
56
+ switch (message.type) {
57
+ case "auth":
58
+ if (message.payload.token && connectionData) {
59
+ connectionData.token = message.payload.token;
60
+
61
+ try {
62
+ // Create a new agent instance for this connection
63
+ const { AgentRunner } = await import("./agent-runner");
64
+ connectionData.agent = new AgentRunner();
65
+ await connectionData.agent.initialize(message.payload.token);
66
+
67
+ this.sendMessage(ws, {
68
+ type: "status",
69
+ payload: { message: "Authenticated successfully" },
70
+ timestamp: Date.now(),
71
+ });
72
+ } catch (error) {
73
+ console.error("Authentication failed:", error);
74
+ this.sendError(
75
+ ws,
76
+ "Authentication failed. Please sign in with Hugging Face.",
77
+ );
78
+ }
79
+ } else {
80
+ this.sendError(ws, "No authentication token provided");
81
+ }
82
+ break;
83
+
84
+ case "chat":
85
+ try {
86
+ if (!connectionData?.agent) {
87
+ throw new Error(
88
+ "Authentication required. Please sign in with Hugging Face.",
89
+ );
90
+ }
91
+
92
+ const userMessage = message.payload.content;
93
+ if (!userMessage) {
94
+ throw new Error("No message content provided");
95
+ }
96
+
97
+ this.sendMessage(ws, {
98
+ type: "status",
99
+ payload: { processing: true },
100
+ timestamp: Date.now(),
101
+ });
102
+
103
+ const response = await connectionData.agent.processMessage(
104
+ userMessage,
105
+ (chunk: string) => {
106
+ this.sendMessage(ws, {
107
+ type: "stream",
108
+ payload: { chunk },
109
+ timestamp: Date.now(),
110
+ });
111
+ },
112
+ );
113
+
114
+ this.sendMessage(ws, {
115
+ type: "chat",
116
+ payload: {
117
+ role: "assistant",
118
+ content: response,
119
+ },
120
+ timestamp: Date.now(),
121
+ });
122
+
123
+ this.sendMessage(ws, {
124
+ type: "status",
125
+ payload: { processing: false },
126
+ timestamp: Date.now(),
127
+ });
128
+ } catch (error) {
129
+ console.error("Error processing chat message:", error);
130
+ this.sendError(
131
+ ws,
132
+ error instanceof Error ? error.message : "Unknown error",
133
+ );
134
+ }
135
+ break;
136
+
137
+ default:
138
+ this.sendError(ws, `Unknown message type: ${message.type}`);
139
+ }
140
+ }
141
+
142
+ private sendMessage(ws: WebSocket, message: WebSocketMessage) {
143
+ if (ws.readyState === ws.OPEN) {
144
+ ws.send(JSON.stringify(message));
145
+ }
146
+ }
147
+
148
+ private sendError(ws: WebSocket, error: string) {
149
+ this.sendMessage(ws, {
150
+ type: "error",
151
+ payload: { error },
152
+ timestamp: Date.now(),
153
+ });
154
+ }
155
+
156
+ broadcast(message: WebSocketMessage) {
157
+ for (const [ws] of this.connections) {
158
+ this.sendMessage(ws, message);
159
+ }
160
+ }
161
+ }
162
+
163
+ export const wsManager = new WebSocketManager();
164
+
165
+ export async function initializeAgent() {}
src/lib/server/context.md ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Server Context
2
+
3
+ WebSocket server for AI agent communication.
4
+
5
+ ## Components
6
+
7
+ - `agent-runner.ts` - HuggingFace inference client with streaming support
8
+ - `api.ts` - WebSocket manager with per-connection agent instances
9
+
10
+ ## Architecture
11
+
12
+ Vite plugin providing:
13
+
14
+ - WebSocket endpoint at `/ws`
15
+ - Per-connection authentication via HuggingFace tokens
16
+ - Message streaming for chat responses
17
+
18
+ ## Integration
19
+
20
+ Frontend connection via `src/lib/stores/agent.ts` store.
src/lib/services/auth.ts ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { writable, get } from "svelte/store";
2
+ import {
3
+ oauthLoginUrl,
4
+ oauthHandleRedirectIfPresent,
5
+ type UserInfo,
6
+ } from "@huggingface/hub";
7
+
8
+ export interface AuthState {
9
+ isAuthenticated: boolean;
10
+ user: UserInfo | null;
11
+ accessToken: string | null;
12
+ expiresAt: number | null;
13
+ loading: boolean;
14
+ error: string | null;
15
+ }
16
+
17
+ function createAuthStore() {
18
+ const { subscribe, set, update } = writable<AuthState>({
19
+ isAuthenticated: false,
20
+ user: null,
21
+ accessToken: null,
22
+ expiresAt: null,
23
+ loading: true,
24
+ error: null,
25
+ });
26
+
27
+ const getOAuthConfig = () => {
28
+ const isProduction = window.location.hostname.includes("hf.space");
29
+ const clientId = "87f5f1d1-6e9e-4962-98f0-e5f3831ec988";
30
+
31
+ let redirectUrl: string;
32
+ if (isProduction) {
33
+ redirectUrl = `https://${window.location.hostname}/auth/callback`;
34
+ } else {
35
+ redirectUrl = `http://localhost:7860/auth/callback`;
36
+ }
37
+
38
+ return {
39
+ clientId,
40
+ redirectUrl,
41
+ scopes: "openid profile inference-api",
42
+ };
43
+ };
44
+
45
+ return {
46
+ subscribe,
47
+
48
+ async init() {
49
+ update((state) => ({ ...state, loading: true }));
50
+
51
+ try {
52
+ const oauthResult = await oauthHandleRedirectIfPresent();
53
+
54
+ if (oauthResult) {
55
+ const { accessToken, accessTokenExpiresAt, userInfo } = oauthResult;
56
+
57
+ set({
58
+ isAuthenticated: true,
59
+ user: userInfo,
60
+ accessToken,
61
+ expiresAt: accessTokenExpiresAt
62
+ ? accessTokenExpiresAt.getTime()
63
+ : null,
64
+ loading: false,
65
+ error: null,
66
+ });
67
+
68
+ sessionStorage.setItem(
69
+ "hf_auth",
70
+ JSON.stringify({
71
+ accessToken,
72
+ expiresAt: accessTokenExpiresAt
73
+ ? accessTokenExpiresAt.getTime()
74
+ : null,
75
+ user: userInfo,
76
+ }),
77
+ );
78
+
79
+ return true;
80
+ }
81
+
82
+ const stored = sessionStorage.getItem("hf_auth");
83
+ if (stored) {
84
+ const authData = JSON.parse(stored);
85
+
86
+ if (!authData.expiresAt || authData.expiresAt > Date.now()) {
87
+ set({
88
+ isAuthenticated: true,
89
+ user: authData.user,
90
+ accessToken: authData.accessToken,
91
+ expiresAt: authData.expiresAt,
92
+ loading: false,
93
+ error: null,
94
+ });
95
+ return true;
96
+ } else {
97
+ sessionStorage.removeItem("hf_auth");
98
+ }
99
+ }
100
+
101
+ set({
102
+ isAuthenticated: false,
103
+ user: null,
104
+ accessToken: null,
105
+ expiresAt: null,
106
+ loading: false,
107
+ error: null,
108
+ });
109
+
110
+ return false;
111
+ } catch (error) {
112
+ console.error("Auth initialization error:", error);
113
+ set({
114
+ isAuthenticated: false,
115
+ user: null,
116
+ accessToken: null,
117
+ expiresAt: null,
118
+ loading: false,
119
+ error:
120
+ error instanceof Error ? error.message : "Authentication failed",
121
+ });
122
+ return false;
123
+ }
124
+ },
125
+
126
+ async login() {
127
+ const config = getOAuthConfig();
128
+
129
+ try {
130
+ const url = await oauthLoginUrl({
131
+ clientId: config.clientId,
132
+ redirectUrl: config.redirectUrl,
133
+ scopes: config.scopes,
134
+ });
135
+
136
+ window.location.href = url;
137
+ } catch (error) {
138
+ console.error("Login error:", error);
139
+ update((state) => ({
140
+ ...state,
141
+ error: error instanceof Error ? error.message : "Login failed",
142
+ }));
143
+ }
144
+ },
145
+
146
+ logout() {
147
+ sessionStorage.removeItem("hf_auth");
148
+ set({
149
+ isAuthenticated: false,
150
+ user: null,
151
+ accessToken: null,
152
+ expiresAt: null,
153
+ loading: false,
154
+ error: null,
155
+ });
156
+ },
157
+
158
+ getToken(): string | null {
159
+ const state = get({ subscribe });
160
+ return state.accessToken;
161
+ },
162
+
163
+ isTokenValid(): boolean {
164
+ const state = get({ subscribe });
165
+ if (!state.accessToken) return false;
166
+ if (!state.expiresAt) return true;
167
+ return state.expiresAt > Date.now();
168
+ },
169
+ };
170
+ }
171
+
172
+ export const authStore = createAuthStore();
src/lib/services/console-capture.ts ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { consoleStore } from "../stores/console";
2
+
3
+ type ConsoleMethod = "log" | "warn" | "error" | "info";
4
+ type ConsoleMethodFunc = (...args: unknown[]) => void;
5
+ type OriginalConsole = Record<ConsoleMethod, ConsoleMethodFunc>;
6
+
7
+ export class ConsoleCapture {
8
+ private static instance: ConsoleCapture | null = null;
9
+ private originalConsole: OriginalConsole = {} as OriginalConsole;
10
+ private isCapturing = false;
11
+
12
+ private constructor() {}
13
+
14
+ static getInstance(): ConsoleCapture {
15
+ if (!ConsoleCapture.instance) {
16
+ ConsoleCapture.instance = new ConsoleCapture();
17
+ }
18
+ return ConsoleCapture.instance;
19
+ }
20
+
21
+ setup(): void {
22
+ if (this.isCapturing) return;
23
+
24
+ this.originalConsole = {
25
+ log: console.log,
26
+ warn: console.warn,
27
+ error: console.error,
28
+ info: console.info,
29
+ };
30
+
31
+ const methods: Array<"log" | "warn" | "error" | "info"> = [
32
+ "log",
33
+ "warn",
34
+ "error",
35
+ "info",
36
+ ];
37
+
38
+ methods.forEach((method) => {
39
+ console[method] = (...args: unknown[]) => {
40
+ this.originalConsole[method]?.apply(console, args);
41
+
42
+ const firstArg = args[0];
43
+ if (typeof firstArg === "string") {
44
+ if (
45
+ firstArg.includes("[vite]") ||
46
+ firstArg.includes("[VibeGame] Console forwarding") ||
47
+ firstArg.includes("[DEBUG]")
48
+ ) {
49
+ return;
50
+ }
51
+ }
52
+
53
+ const message = args
54
+ .map((arg) => {
55
+ if (arg instanceof Error) {
56
+ return arg.message;
57
+ } else if (typeof arg === "object") {
58
+ try {
59
+ return JSON.stringify(arg, null, 2);
60
+ } catch {
61
+ return String(arg);
62
+ }
63
+ }
64
+ return String(arg);
65
+ })
66
+ .join(" ");
67
+
68
+ consoleStore.addMessage(method, message);
69
+ };
70
+ });
71
+
72
+ this.isCapturing = true;
73
+ }
74
+
75
+ teardown(): void {
76
+ if (!this.isCapturing) return;
77
+
78
+ if (this.originalConsole.log) {
79
+ console.log = this.originalConsole.log;
80
+ console.warn = this.originalConsole.warn;
81
+ console.error = this.originalConsole.error;
82
+ console.info = this.originalConsole.info;
83
+ }
84
+
85
+ this.originalConsole = {} as OriginalConsole;
86
+ this.isCapturing = false;
87
+ }
88
+ }
89
+
90
+ export const consoleCapture = ConsoleCapture.getInstance();
src/lib/services/context.md ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Services
2
+
3
+ Business logic layer with pure functions and singleton services
4
+
5
+ ## Purpose
6
+
7
+ - Encapsulate complex business logic
8
+ - Provide clean APIs for operations
9
+ - Keep components simple and declarative
10
+
11
+ ## Layout
12
+
13
+ ```
14
+ services/
15
+ ├── context.md # This file
16
+ ├── auth.ts # Hugging Face OAuth authentication
17
+ ├── game-engine.ts # Game lifecycle management
18
+ ├── console-capture.ts # Console interception
19
+ └── html-parser.ts # Game HTML parsing
20
+ ```
21
+
22
+ ## Scope
23
+
24
+ - In-scope: Business logic, side effects, API calls, authentication
25
+ - Out-of-scope: UI rendering, state storage
26
+
27
+ ## Entrypoints
28
+
29
+ - `authStore.login()` - Start OAuth flow
30
+ - `authStore.logout()` - Clear authentication
31
+ - `authStore.getToken()` - Get current token
32
+ - `authStore.isTokenValid()` - Check token validity
33
+ - `gameEngine.start()` - Start game with world content
34
+ - `gameEngine.stop()` - Clean up game instance
35
+ - `consoleCapture.setup()` - Begin console interception
36
+ - `HTMLParser.extractGameContent()` - Parse world from HTML
37
+
38
+ ## Dependencies
39
+
40
+ - @huggingface/hub for OAuth
41
+ - VibeGame for game engine
42
+ - Stores for state updates
43
+ - No UI dependencies
src/lib/services/game-engine.ts ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as GAME from "vibegame";
2
+ import { gameStore } from "../stores/game";
3
+ import { consoleStore } from "../stores/console";
4
+ import { uiStore } from "../stores/ui";
5
+
6
+ type GameInstance = Awaited<ReturnType<typeof GAME.run>>;
7
+
8
+ export class GameEngine {
9
+ private static instance: GameEngine | null = null;
10
+ private gameInstance: GameInstance | null = null;
11
+
12
+ private constructor() {}
13
+
14
+ static getInstance(): GameEngine {
15
+ if (!GameEngine.instance) {
16
+ GameEngine.instance = new GameEngine();
17
+ }
18
+ return GameEngine.instance;
19
+ }
20
+
21
+ async start(worldContent: string): Promise<void> {
22
+ gameStore.setStarting(true);
23
+ consoleStore.addMessage("info", "🎮 Starting game...");
24
+
25
+ this.stop();
26
+ uiStore.setError(null);
27
+
28
+ try {
29
+ const container = document.getElementById("world-container");
30
+ if (!container) {
31
+ throw new Error("World container not found");
32
+ }
33
+
34
+ container.innerHTML = worldContent;
35
+
36
+ this.gameInstance = await GAME.run();
37
+ gameStore.setInstance(this.gameInstance);
38
+ consoleStore.addMessage("info", "✅ Game started!");
39
+ } catch (error: unknown) {
40
+ const errorMsg = error instanceof Error ? error.message : String(error);
41
+ uiStore.setError(errorMsg);
42
+ consoleStore.addMessage("error", `❌ Error: ${errorMsg}`);
43
+ gameStore.setInstance(null);
44
+ } finally {
45
+ gameStore.setStarting(false);
46
+ }
47
+ }
48
+
49
+ stop(): void {
50
+ if (this.gameInstance) {
51
+ try {
52
+ if (typeof this.gameInstance.destroy === "function") {
53
+ this.gameInstance.destroy();
54
+ } else if (typeof this.gameInstance.stop === "function") {
55
+ this.gameInstance.stop();
56
+ }
57
+ } catch (error) {
58
+ console.error("Error stopping game:", error);
59
+ }
60
+ this.gameInstance = null;
61
+ gameStore.setInstance(null);
62
+ }
63
+
64
+ const container = document.getElementById("world-container");
65
+ if (container) {
66
+ while (container.firstChild) {
67
+ container.removeChild(container.firstChild);
68
+ }
69
+ }
70
+ }
71
+
72
+ isRunning(): boolean {
73
+ return this.gameInstance !== null;
74
+ }
75
+ }
76
+
77
+ export const gameEngine = GameEngine.getInstance();
src/lib/services/html-parser.ts ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export class HTMLParser {
2
+ static extractGameContent(html: string): string {
3
+ const worldMatch = html.match(/<world[^>]*>[\s\S]*?<\/world>/);
4
+ return worldMatch ? worldMatch[0] : '<world canvas="#game-canvas"></world>';
5
+ }
6
+
7
+ static validateGameHTML(html: string): { valid: boolean; error?: string } {
8
+ if (!html.includes("<world")) {
9
+ return { valid: false, error: "Missing <world> tag" };
10
+ }
11
+
12
+ if (!html.includes("canvas=")) {
13
+ return { valid: false, error: "Missing canvas attribute in <world> tag" };
14
+ }
15
+
16
+ return { valid: true };
17
+ }
18
+ }
src/lib/stores/agent.ts ADDED
@@ -0,0 +1,271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { writable, derived } from "svelte/store";
2
+ import { authStore } from "../services/auth";
3
+
4
+ export interface ChatMessage {
5
+ id: string;
6
+ role: "user" | "assistant" | "system";
7
+ content: string;
8
+ timestamp: number;
9
+ streaming?: boolean;
10
+ }
11
+
12
+ export interface AgentState {
13
+ connected: boolean;
14
+ processing: boolean;
15
+ messages: ChatMessage[];
16
+ error: string | null;
17
+ streamingContent: string;
18
+ }
19
+
20
+ function createAgentStore() {
21
+ const { subscribe, update } = writable<AgentState>({
22
+ connected: false,
23
+ processing: false,
24
+ messages: [],
25
+ error: null,
26
+ streamingContent: "",
27
+ });
28
+
29
+ let ws: WebSocket | null = null;
30
+ let currentStreamId: string | null = null;
31
+
32
+ function connect() {
33
+ if (ws && ws.readyState === WebSocket.OPEN) {
34
+ return;
35
+ }
36
+
37
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
38
+ const wsUrl = `${protocol}//${window.location.host}/ws`;
39
+
40
+ ws = new WebSocket(wsUrl);
41
+
42
+ ws.onopen = () => {
43
+ update((state) => ({ ...state, connected: true, error: null }));
44
+
45
+ const token = authStore.getToken();
46
+ if (token && ws) {
47
+ ws.send(
48
+ JSON.stringify({
49
+ type: "auth",
50
+ payload: { token },
51
+ timestamp: Date.now(),
52
+ }),
53
+ );
54
+ } else {
55
+ update((state) => ({
56
+ ...state,
57
+ error: "Authentication required. Please sign in with Hugging Face.",
58
+ connected: false,
59
+ }));
60
+ if (ws) {
61
+ ws.close();
62
+ }
63
+ }
64
+ };
65
+
66
+ ws.onmessage = (event) => {
67
+ try {
68
+ const message = JSON.parse(event.data);
69
+ handleWebSocketMessage(message);
70
+ } catch (error) {
71
+ console.error("Error parsing WebSocket message:", error);
72
+ }
73
+ };
74
+
75
+ ws.onerror = (error) => {
76
+ console.error("WebSocket error:", error);
77
+ update((state) => ({ ...state, error: "Connection error" }));
78
+ };
79
+
80
+ ws.onclose = () => {
81
+ update((state) => ({ ...state, connected: false }));
82
+
83
+ const token = authStore.getToken();
84
+ if (token) {
85
+ setTimeout(() => {
86
+ connect();
87
+ }, 3000);
88
+ }
89
+ };
90
+ }
91
+
92
+ function handleWebSocketMessage(message: {
93
+ type: string;
94
+ payload: {
95
+ processing?: boolean;
96
+ connected?: boolean;
97
+ chunk?: string;
98
+ role?: string;
99
+ content?: string;
100
+ error?: string;
101
+ };
102
+ }) {
103
+ switch (message.type) {
104
+ case "status":
105
+ if (message.payload.processing !== undefined) {
106
+ update((state) => ({
107
+ ...state,
108
+ processing: message.payload.processing as boolean,
109
+ }));
110
+ }
111
+ if (message.payload.connected !== undefined) {
112
+ update((state) => ({
113
+ ...state,
114
+ connected: message.payload.connected as boolean,
115
+ }));
116
+ }
117
+ break;
118
+
119
+ case "stream":
120
+ update((state) => {
121
+ const newContent =
122
+ state.streamingContent + (message.payload.chunk || "");
123
+
124
+ if (!currentStreamId) {
125
+ currentStreamId = `msg_${Date.now()}`;
126
+ const streamMessage: ChatMessage = {
127
+ id: currentStreamId,
128
+ role: "assistant",
129
+ content: newContent,
130
+ timestamp: Date.now(),
131
+ streaming: true,
132
+ };
133
+ return {
134
+ ...state,
135
+ streamingContent: newContent,
136
+ messages: [...state.messages, streamMessage],
137
+ };
138
+ } else {
139
+ const messages = state.messages.map((msg) => {
140
+ if (msg.id === currentStreamId) {
141
+ return { ...msg, content: newContent };
142
+ }
143
+ return msg;
144
+ });
145
+ return {
146
+ ...state,
147
+ streamingContent: newContent,
148
+ messages,
149
+ };
150
+ }
151
+ });
152
+ break;
153
+
154
+ case "chat":
155
+ update((state) => {
156
+ if (currentStreamId) {
157
+ const messages = state.messages.map((msg) => {
158
+ if (msg.id === currentStreamId) {
159
+ return { ...msg, streaming: false };
160
+ }
161
+ return msg;
162
+ });
163
+ currentStreamId = null;
164
+ return {
165
+ ...state,
166
+ streamingContent: "",
167
+ messages,
168
+ };
169
+ } else {
170
+ if (message.payload.role && message.payload.content) {
171
+ const newMessage: ChatMessage = {
172
+ id: `msg_${Date.now()}`,
173
+ role: message.payload.role as "user" | "assistant" | "system",
174
+ content: message.payload.content,
175
+ timestamp: Date.now(),
176
+ };
177
+ return {
178
+ ...state,
179
+ messages: [...state.messages, newMessage],
180
+ };
181
+ }
182
+ return state;
183
+ }
184
+ });
185
+ break;
186
+
187
+ case "error":
188
+ update((state) => ({
189
+ ...state,
190
+ error: message.payload.error || null,
191
+ processing: false,
192
+ }));
193
+ break;
194
+ }
195
+ }
196
+
197
+ function sendMessage(content: string) {
198
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
199
+ update((state) => ({ ...state, error: "Not connected to server" }));
200
+ return;
201
+ }
202
+
203
+ const userMessage: ChatMessage = {
204
+ id: `msg_${Date.now()}`,
205
+ role: "user",
206
+ content,
207
+ timestamp: Date.now(),
208
+ };
209
+
210
+ update((state) => ({
211
+ ...state,
212
+ messages: [...state.messages, userMessage],
213
+ error: null,
214
+ }));
215
+
216
+ ws.send(
217
+ JSON.stringify({
218
+ type: "chat",
219
+ payload: { content },
220
+ timestamp: Date.now(),
221
+ }),
222
+ );
223
+ }
224
+
225
+ function clearMessages() {
226
+ update((state) => ({
227
+ ...state,
228
+ messages: [],
229
+ streamingContent: "",
230
+ error: null,
231
+ }));
232
+ currentStreamId = null;
233
+ }
234
+
235
+ function disconnect() {
236
+ if (ws) {
237
+ ws.close();
238
+ ws = null;
239
+ }
240
+ }
241
+
242
+ function reauthenticate() {
243
+ if (ws && ws.readyState === WebSocket.OPEN) {
244
+ const token = authStore.getToken();
245
+ if (token) {
246
+ ws.send(
247
+ JSON.stringify({
248
+ type: "auth",
249
+ payload: { token },
250
+ timestamp: Date.now(),
251
+ }),
252
+ );
253
+ }
254
+ }
255
+ }
256
+
257
+ return {
258
+ subscribe,
259
+ connect,
260
+ disconnect,
261
+ sendMessage,
262
+ clearMessages,
263
+ reauthenticate,
264
+ };
265
+ }
266
+
267
+ export const agentStore = createAgentStore();
268
+
269
+ export const isProcessing = derived(agentStore, ($agent) => $agent.processing);
270
+
271
+ export const isConnected = derived(agentStore, ($agent) => $agent.connected);