From bd61b037ab931aead92e1abdf82f078d88a68e5a Mon Sep 17 00:00:00 2001 From: abose Date: Sun, 11 Oct 2026 21:53:01 +0530 Subject: [PATCH 1/3] docs(release): update 5.5 highlights and Pro pin Refine the in-app release highlights around Layers, visual AI workflows, existing CLI agents, usage graphs, setup, demos, and image selection. Sync the Node lockfile version with 5.5.6-0 and pin the Pro release audit. Follow-up before publication: - Update the images for AI replies in chat. - Fix the AI usage graph. - Review and update all release images. --- src-node/package-lock.json | 4 +- .../en/Newly_added_features.md | 70 +++++++++++++++---- tracking-repos.json | 2 +- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src-node/package-lock.json b/src-node/package-lock.json index 2832561ed2..71533e2c4b 100644 --- a/src-node/package-lock.json +++ b/src-node/package-lock.json @@ -1,12 +1,12 @@ { "name": "@phcode/node-core", - "version": "5.5.5-0", + "version": "5.5.6-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@phcode/node-core", - "version": "5.5.5-0", + "version": "5.5.6-0", "hasInstallScript": true, "license": "GNU-AGPL3.0", "dependencies": { diff --git a/src/assets/default-project/en/Newly_added_features.md b/src/assets/default-project/en/Newly_added_features.md index 53d9378ad1..0665929975 100644 --- a/src/assets/default-project/en/Newly_added_features.md +++ b/src/assets/default-project/en/Newly_added_features.md @@ -4,60 +4,102 @@ We are continuously adding features every week. [Check out our release page to s Here's a list of top features recently added to Phoenix Code: -## [Layers Panel: Your Page as a Tree](https://docs.phcode.dev/app-links/layers-panel) +## [Explore and Edit Your Page with Layers](https://docs.phcode.dev/app-links/layers-panel) `Added in October 2026` -The new **Layers** tab in the sidebar shows your page as a tree. Click a row to select the element, then edit its tag, classes, attributes, and styles right in the sidebar. Drag rows to move things around, and insert, duplicate, or delete elements without touching the code. +See and edit your page’s HTML structure in the new **Layers** sidebar. Add, rearrange, and duplicate elements, edit their properties, and fine-tune CSS, with changes synced to your code and Live Preview. -The Styles section lists every rule that applies to the element, shows which values are overridden and by what, and lets you edit them in place. +See which styles affect an element and edit them in one place. Pick colors, adjust sizes and spacing, and watch the result in Live Preview. + +> The Layers panel is a Phoenix Pro feature. ![Image](https://docs-images.phcode.dev/in-app/pro-layersPanel.jpg) -## [A New AI Panel with Built-in Claude Code](https://docs.phcode.dev/app-links/ai-chat) +## [Visual Questions in Live Preview](https://docs.phcode.dev/app-links/ai-ask) `Added in October 2026` -Claude Code now comes built in. Sign in and start chatting, with nothing to install. The new chat shows you what the AI is doing as it works, and every change it makes can be undone with one click. You decide how much it can do on its own. +Select part of your page and use **Ask AI** to explore an idea. Phoenix AI can create interactive questions with design options you can try on the page—layouts, colors, and styles you can see before choosing what goes into your code. -New to AI? Click **Surprise Me** on the start screen to watch a demo first. Free accounts get a daily and monthly chat limit. Phoenix Pro removes the limits. +Hover to preview an option, click to keep it, then press **Send** to confirm. You can also use **Ask AI** with selected code or Markdown text. > This feature is available only in desktop apps. -![Image](https://docs-images.phcode.dev/in-app/pro-aiPanel.jpg) +![Image](https://docs-images.phcode.dev/in-app/pro-aiAsk.jpg) + +## [Interactive Replies in Chat](https://docs.phcode.dev/app-links/ai-chat) + +`Added in October 2026` + +Phoenix AI can create interactive mockups, comparisons, and explanations in the chat. Click through options and adjust controls to explore an idea, instead of piecing it together from a text description. You can use these visuals even without a page open in Live Preview. + +> This feature is available only in desktop apps. -## [Claude Code CLI and Codex CLI Inside the Editor](https://docs.phcode.dev/app-links/ai-cli) +## [Bring Your Existing CLI Agents into Phoenix Code](https://docs.phcode.dev/app-links/ai-cli) `Added in October 2026` -Already use **Claude Code** or **Codex**? Run them inside the AI panel. They see the file you are editing, your unsaved changes, and the Live Preview, and they can take screenshots and open files. +Bring your existing agents into Phoenix Code and give them a visual way to work with you. **ChatGPT Codex** and **Claude Code CLI** gain tools to prototype designs in Live Preview, show interactive choices, and ask questions on your page—so you can see, try, and refine ideas instead of just reading descriptions. + +Keep multiple sessions running and switch between them as you work. You can also transfer an **Ask AI** draft and its attachments to a connected session, then review and submit it there. > Running the CLIs inside the panel is a Phoenix Pro feature, available only in desktop apps. ![Image](https://docs-images.phcode.dev/in-app/pro-aiCli.jpg) -## [Ask AI About What You See](https://docs.phcode.dev/app-links/ai-ask) +## [AI Usage Graphs](https://docs.phcode.dev/app-links/ai-chat) `Added in October 2026` -Select an element in Live Preview and click **Ask AI**. A screenshot of the element and its place in the code go with your question, so you don't have to describe where it is. The same button appears on selected code in the editor and on selected text in the Markdown preview. +See your AI usage across Phoenix AI, ChatGPT Codex, and Claude Code CLI sessions in Phoenix. Track tokens, estimated costs, and model breakdowns, with daily activity graphs and monthly history. + +Costs are estimates at API list prices; your provider bill may differ. You can delete usage history while keeping your chats. + +> These features are available only in desktop apps. + +## [Simpler AI Setup](https://docs.phcode.dev/app-links/ai-chat) -The AI can ask you back the same way, with a card inside the Live Preview and options you can preview on the page. +`Added in October 2026` + +Get from signing in to creating with AI more easily, with guided setup in Phoenix Code. The start screen brings Phoenix AI, ChatGPT Codex, and Claude Code CLI together and shows your running sessions. > This feature is available only in desktop apps. -![Image](https://docs-images.phcode.dev/in-app/pro-aiAsk.jpg) +![Image](https://docs-images.phcode.dev/in-app/pro-aiPanel.jpg) + +## [AI Demos](https://docs.phcode.dev/app-links/ai-chat) + +`Added in October 2026` + +See what you can create with Phoenix AI before signing in or using any AI credits. Watch a page take shape, explore the result, and reveal the prompt behind it. Click **Surprise Me** to try it. + +> This feature is available only in desktop apps. + +## [AI Thinking Effort](https://docs.phcode.dev/app-links/ai-chat) + +`Added in October 2026` + +Adjust how deeply supported AI models reason, from quick everyday tasks to more involved problems. Choose **Thinking effort** for the selected model, or leave it at Default. + +> This feature is available only in desktop apps. ## [Find Photos with AI](https://docs.phcode.dev/app-links/ai-images) `Added in October 2026` -Ask the AI for a picture and it searches Unsplash. Pick one and it goes on your page, linked from Unsplash or downloaded into your project. +Find the right photos for your page together with AI. Browse and compare options in an interactive gallery, refine the search, and choose what fits your design. Ask AI to use your choices on the page or download them into your project. > This feature is available only in desktop apps. ![Image](https://docs-images.phcode.dev/in-app/pro-aiImages.jpg) +## [Larger Image Previews in Markdown](https://docs.phcode.dev/app-links/markdown-editor) + +`Added in October 2026` + +Open an image in a larger lightbox without leaving your document. Click an unlinked image in reader mode, or use its expand button or double-click while editing. Press Escape to return to your Markdown. + ## [Style Your Page Visually with the Styles Bar](https://docs.phcode.dev/app-links/styles-bar) `Added in August 2026` diff --git a/tracking-repos.json b/tracking-repos.json index dbff03ee51..6a08e7bc03 100644 --- a/tracking-repos.json +++ b/tracking-repos.json @@ -1,5 +1,5 @@ { "phoenixPro": { - "commitID": "25ea705112c785794c401dcfc413aefde122b2e3" + "commitID": "8c8ac5021f1ed6bd5f2425f53ce97ab3e36a76bc" } } From 845aa1b8615d405f9165576642803bccb6c0e85e Mon Sep 17 00:00:00 2001 From: abose Date: Wed, 14 Oct 2026 11:54:27 -0700 Subject: [PATCH 2/3] fix(ai): preserve bundled demo in release assets Move the recording into core assets and update the Pro ai pin. Include the pending API documentation and package updates. --- docs/API-Reference/features/TaskManager.md | 1 + docs/API-Reference/utils/DragAndDrop.md | 3 +- package-lock.json | 4 +- src-node/package-lock.json | 75 +++++++++++++++++++ src-node/package.json | 1 + .../aiDemos/0000-dave-jungle-temple.json | 1 + tracking-repos.json | 2 +- 7 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 src/assets/aiDemos/0000-dave-jungle-temple.json diff --git a/docs/API-Reference/features/TaskManager.md b/docs/API-Reference/features/TaskManager.md index d07490a63a..9d13cf300d 100644 --- a/docs/API-Reference/features/TaskManager.md +++ b/docs/API-Reference/features/TaskManager.md @@ -39,6 +39,7 @@ like `showStopIcon`, `hideStopIcon`, etc. | [options.onRetryClick] | function | | Callback function triggered when the retry button is clicked. | | [options.onSelect] | function | | Callback function triggered when the task is selected from the dropdown. | | [options.progressPercent] | number | | Initial progress percentage of the task. | +| [options.hideProgressBar] | boolean | | Hide progress for tasks waiting on a user action. | | [options.noSpinnerNotification] | boolean | | If set to true, will not show the task spinners for this task. This can be used for silent background tasks where user attention is not needed. | **Example** diff --git a/docs/API-Reference/utils/DragAndDrop.md b/docs/API-Reference/utils/DragAndDrop.md index 5800006e76..b1caeda9b8 100644 --- a/docs/API-Reference/utils/DragAndDrop.md +++ b/docs/API-Reference/utils/DragAndDrop.md @@ -18,7 +18,8 @@ Returns true if the drag and drop items contains valid drop objects. ## openDroppedFiles(paths) ⇒ Promise -Open dropped files +Open dropped files in order so the last file becomes active, regardless of load times. +Continue processing the remaining paths if an earlier file cannot be opened. **Kind**: global function **Returns**: Promise - Promise that is resolved if all files are opened, or rejected diff --git a/package-lock.json b/package-lock.json index b4e819d156..b785839fa6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "phoenix", - "version": "5.5.3-0", + "version": "5.5.6-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "phoenix", - "version": "5.5.3-0", + "version": "5.5.6-0", "hasInstallScript": true, "dependencies": { "@bugsnag/js": "^7.18.0", diff --git a/src-node/package-lock.json b/src-node/package-lock.json index 71533e2c4b..5c98351674 100644 --- a/src-node/package-lock.json +++ b/src-node/package-lock.json @@ -21,6 +21,7 @@ "node-pty": "^1.1.0", "npm": "11.8.0", "open": "^10.1.0", + "phoenix": "file:..", "vscode-langservers-extracted": "4.10.0", "which": "^2.0.1", "ws": "^8.17.1", @@ -30,6 +31,76 @@ "node": "24" } }, + "..": { + "version": "5.5.6-0", + "hasInstallScript": true, + "dependencies": { + "@bugsnag/js": "^7.18.0", + "@floating-ui/dom": "^0.5.4", + "@fortawesome/fontawesome-free": "^6.1.2", + "@highlightjs/cdn-assets": "^11.5.1", + "@phcode/fs": "^4.0.2", + "@phcode/language-support": "^1.1.0", + "@pixelbrackets/gfm-stylesheet": "^1.1.0", + "@prettier/plugin-php": "^0.22.2", + "@uiw/file-icons": "^1.3.2", + "@xterm/addon-fit": "0.12.0-beta.301", + "@xterm/addon-search": "0.17.0-beta.301", + "@xterm/addon-web-links": "0.13.0-beta.301", + "@xterm/addon-webgl": "0.20.0-beta.300", + "@xterm/xterm": "6.1.0-beta.304", + "bootstrap": "^5.1.3", + "browser-mime": "^1.0.1", + "codemirror": "^5.65.16", + "cross-env": "^7.0.3", + "devicon": "^2.15.1", + "emmet": "^2.4.11", + "file-saver": "^2.0.5", + "idb-keyval": "^6.2.1", + "jshint": "^2.13.5", + "jszip": "^3.8.0", + "less": "^4.1.3", + "lodash": "^4.18.1", + "lru-cache": "^10.2.0", + "marked": "^4.0.18", + "mime-db": "^1.52.0", + "mustache": "^4.2.0", + "prettier": "^3.2.5", + "requirejs": "^2.3.7", + "tern": "^0.24.3", + "tinycolor2": "^1.4.2", + "underscore": "^1.13.4" + }, + "devDependencies": { + "@commitlint/cli": "^16.0.2", + "@commitlint/config-conventional": "^16.0.0", + "@playwright/test": "^1.38.1", + "del": "^6.0.0", + "eslint": "^8.18.0", + "glob": "^8.1.0", + "gulp": "^4.0.2", + "gulp-concat": "^2.6.1", + "gulp-cssnano": "^2.1.3", + "gulp-flatten": "^0.4.0", + "gulp-if": "^3.0.0", + "gulp-minify": "^3.1.0", + "gulp-rename": "^2.0.0", + "gulp-sourcemaps": "^3.0.0", + "gulp-uglify": "^3.0.2", + "gulp-useref": "^5.0.0", + "gulp-webserver": "^0.9.1", + "gulp-zip": "^5.1.0", + "http-proxy": "^1.18.1", + "http-server": "14.1.0", + "husky": "^7.0.4", + "jasmine-core": "^4.2.0", + "jasmine-reporters": "^2.5.0", + "jsdoc-to-markdown": "^9.1.1", + "lmdb": "^3.5.1", + "readable-stream": "^3.6.0", + "through2": "^4.0.2" + } + }, "node_modules/@anthropic-ai/claude-agent-sdk": { "version": "0.3.280", "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.280.tgz", @@ -3748,6 +3819,10 @@ "url": "https://opencollective.com/express" } }, + "node_modules/phoenix": { + "resolved": "..", + "link": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", diff --git a/src-node/package.json b/src-node/package.json index 62b0f24b0e..7d8f88a340 100644 --- a/src-node/package.json +++ b/src-node/package.json @@ -31,6 +31,7 @@ "node-pty": "^1.1.0", "npm": "11.8.0", "open": "^10.1.0", + "phoenix": "file:..", "vscode-langservers-extracted": "4.10.0", "which": "^2.0.1", "ws": "^8.17.1", diff --git a/src/assets/aiDemos/0000-dave-jungle-temple.json b/src/assets/aiDemos/0000-dave-jungle-temple.json new file mode 100644 index 0000000000..6b14cef45a --- /dev/null +++ b/src/assets/aiDemos/0000-dave-jungle-temple.json @@ -0,0 +1 @@ +{"format":"phoenix-ai-panel-recording","version":1,"recordedAt":"2026-09-21T13:43:53.372Z","appVersion":"5.5.3-0","durationMs":1798755,"preferredSpeed":8,"builtWith":"Claude Fable 5","userMessage":"Surprise me!","prompt":"Surprise me — build a small playable game (specifically: dave (Dangerous Dave-style platformer)) in vanilla HTML/CSS/JS that I can preview right now. Aesthetic: a tropical jungle palette (deep green, papaya, ivory). Make it visually impressive, modern, and polished. The specific pick and the aesthetic are FIXED for your decisions — don't substitute a different game / widget / piece if you think it's safer, and don't drift to a different palette on your own initiative mid-build. How you design and structure the build is fully up to you. If I ask for a different category, aesthetic, theme, or palette in a follow-up, my follow-up wins. Avoid the word \"aurora\" anywhere in the page or filenames — pick fresh names.\n\nThis one has to run smoothly on low-end student laptops and still look great, so:\n- World-building first: a side-scrolling jungle-temple level a few screens wide with parallax background layers, animated water, torches and vines, collectible gems and a key, a few patrolling enemies, hazards, and an exit door that needs the key. Pixel-art style, with every sprite and tile drawn in code — no external assets, fonts or libraries.\n- Render on a small fixed internal canvas (about 320x180) scaled up with CSS image-rendering: pixelated. 2D canvas only — no WebGL or 3D. Pre-render tiles and sprites to offscreen canvases once. No shadowBlur, no getImageData or per-pixel work, no large particle counts. Step the game with delta time, cap the step, and pause when the tab is hidden.\n- Attract mode: until the player presses a key or taps, the game plays itself (a simple scripted player runs the level on a loop) so the preview is alive with nobody touching it. Show a small 'Press any key to play' prompt; any input hands control to the player.\n- Controls: arrow keys / WASD and Space to jump, plus on-screen touch buttons for trackpad and touch users. HUD with gems, key and lives. Win and game-over screens with restart.\n- Sound off by default (tiny WebAudio bleeps behind a mute toggle are fine).\n- When you test with execJsInLivePreview keep every check short and cheap: read state, no long synchronous loops, no simulating long stretches of gameplay in one call, no canvas readbacks, no synthetic input storms. A few quick checks and screenshots are enough.\n\nCRITICAL: Always create a BRAND NEW HTML file for this build. Do NOT Read, Edit, or Write into any file that already existed before this task started — whatever file the user has open is irrelevant, do not touch it. Call getEditorState ONCE up front if you need to learn the project root path (so your Write call uses a correct absolute path), but ignore the active file it reports — that's not your target. Pick a fresh filename that matches the pick (e.g. `.html`) and use the Write tool to create it from scratch in the project root. After that file is created, you SHOULD use Edit on it freely for the incremental build steps below — the rule is only about not touching pre-existing files.\n\nBuild it INCREMENTALLY so I see it come together like a person is hand-building it — never write the whole thing in one Write call:\n1. Start by building a task list with TaskCreate (one call per step: scaffold, sections/features, styling, animations, polish). Use TaskUpdate to mark each step in_progress when you start it and completed when you finish, so progress is always visible.\n2. Write a minimal scaffold HTML file first (a NEW file via the Write tool — not an Edit of any existing file) — basic structure and placeholder content, just enough that something appears in the live preview within a few seconds.\n3. Enhance progressively in coherent chunks — one section, one feature, or one cohesive style/animation block at a time. Each Edit should produce a visible change in the preview but stay focused enough to render quickly. Don't write the whole page in one giant rewrite, and don't fragment into atomic single-property edits — aim for meaningful steps the user can watch land.\n4. Take screenshots only at logical milestones (e.g. after the scaffold lands, after a major section is complete, at the end) — not after every small edit.\n5. At the end, test and inspect the page using execJsInLivePreview — verify there are no console errors and that the controls respond. Keep it to a few cheap checks. Fix anything broken before declaring done.\n\nUse a cohesive design, smooth animations, and a fully responsive layout. Save to a single NEW HTML file (created via Write, not by editing an existing file). Build it in the user's locale (en-US).","events":[{"t":5,"name":"aiProgress","data":{"message":"Analyzing...","phase":"start"}},{"t":3502,"name":"aiProgress","data":{"toolName":"ToolSearch","toolId":1,"phase":"tool_use"}},{"t":3503,"name":"aiToolStream","data":{"toolId":1,"toolName":"ToolSearch","append":"{\"query\": \"select:Task"}},{"t":3779,"name":"aiToolStream","data":{"toolId":1,"toolName":"ToolSearch","append":"Create,TaskUpdate\", \"max_results\": 5}"}},{"t":3786,"name":"aiToolInfo","data":{"toolName":"ToolSearch","toolId":1,"toolInput":{"query":"select:TaskCreate,TaskUpdate","max_results":5}}},{"t":3796,"name":"aiProgress","data":{"toolName":"mcp__phoenix-editor__getEditorState","toolId":2,"phase":"tool_use"}},{"t":3804,"name":"aiToolResult","data":{"toolId":1,"isError":false,"preview":""}},{"t":3888,"name":"aiToolInfo","data":{"toolName":"mcp__phoenix-editor__getEditorState","toolId":2,"toolInput":{}}},{"t":3901,"name":"aiToolResult","data":{"toolId":2,"isError":false,"preview":""}},{"t":862142,"name":"aiProgress","data":{"toolName":"TaskCreate","toolId":3,"phase":"tool_use"}},{"t":862775,"name":"aiToolStream","data":{"toolId":3,"toolName":"TaskCreate","append":"{\"subject\": \"Scaffold page + canvas shell\", \"description\": \"New dave-jungle.html with layout, 320x180 pixelated canvas, game loop w/ delta time"}},{"t":863438,"name":"aiToolStream","data":{"toolId":3,"toolName":"TaskCreate","append":" + visibility pause\", \"activeForm\": \"Scaffolding page\"}"}},{"t":863585,"name":"aiToolInfo","data":{"toolName":"TaskCreate","toolId":3,"toolInput":{"subject":"Scaffold page + canvas shell","description":"New dave-jungle.html with layout, 320x180 pixelated canvas, game loop w/ delta time + visibility pause","activeForm":"Scaffolding page"}}},{"t":863604,"name":"aiProgress","data":{"toolName":"TaskCreate","toolId":4,"phase":"tool_use"}},{"t":863611,"name":"aiToolResult","data":{"toolId":3,"isError":false,"preview":"Task #1 created successfully: Scaffold page + canvas shell"}},{"t":864066,"name":"aiToolStream","data":{"toolId":4,"toolName":"TaskCreate","append":"{\"subject\": \"Tiles, level map & parallax world\", \"description\": \"Pre-rendered tiles, level layout, parallax layers, water"}},{"t":864323,"name":"aiToolStream","data":{"toolId":4,"toolName":"TaskCreate","append":", torches, vines"}},{"t":864702,"name":"aiToolStream","data":{"toolId":4,"toolName":"TaskCreate","append":"\", \"activeForm\": \"Building the world\"}"}},{"t":864817,"name":"aiToolInfo","data":{"toolName":"TaskCreate","toolId":4,"toolInput":{"subject":"Tiles, level map & parallax world","description":"Pre-rendered tiles, level layout, parallax layers, water, torches, vines","activeForm":"Building the world"}}},{"t":864818,"name":"aiProgress","data":{"toolName":"TaskCreate","toolId":5,"phase":"tool_use"}},{"t":864823,"name":"aiToolResult","data":{"toolId":4,"isError":false,"preview":"Task #2 created successfully: Tiles, level map & parallax world"}},{"t":864945,"name":"aiToolStream","data":{"toolId":5,"toolName":"TaskCreate","append":"{\"subject\": \"Player, physics & sprites"}},{"t":865359,"name":"aiToolStream","data":{"toolId":5,"toolName":"TaskCreate","append":"\", \"description\": \"Pixel sprites, platformer physics, camera, keyboard + touch controls"}},{"t":865810,"name":"aiToolStream","data":{"toolId":5,"toolName":"TaskCreate","append":"\", \"activeForm\": \"Adding the player\"}"}},{"t":865994,"name":"aiToolInfo","data":{"toolName":"TaskCreate","toolId":5,"toolInput":{"subject":"Player, physics & sprites","description":"Pixel sprites, platformer physics, camera, keyboard + touch controls","activeForm":"Adding the player"}}},{"t":865994,"name":"aiProgress","data":{"toolName":"TaskCreate","toolId":6,"phase":"tool_use"}},{"t":865999,"name":"aiToolResult","data":{"toolId":5,"isError":false,"preview":"Task #3 created successfully: Player, physics & sprites"}},{"t":866121,"name":"aiToolStream","data":{"toolId":6,"toolName":"TaskCreate","append":"{\"subject\": \"Gems, key, door, enemies, hazards"}},{"t":866372,"name":"aiToolStream","data":{"toolId":6,"toolName":"TaskCreate","append":"\", \"description\": \"Collectibles, patrolling enemies, spikes/water hazards, loc"}},{"t":866682,"name":"aiToolStream","data":{"toolId":6,"toolName":"TaskCreate","append":"ked exit door, lives"}},{"t":866948,"name":"aiToolStream","data":{"toolId":6,"toolName":"TaskCreate","append":"\", \"activeForm\": \"Adding gameplay entities"}},{"t":867345,"name":"aiToolStream","data":{"toolId":6,"toolName":"TaskCreate","append":"\"}"}},{"t":867348,"name":"aiToolInfo","data":{"toolName":"TaskCreate","toolId":6,"toolInput":{"subject":"Gems, key, door, enemies, hazards","description":"Collectibles, patrolling enemies, spikes/water hazards, locked exit door, lives","activeForm":"Adding gameplay entities"}}},{"t":867348,"name":"aiProgress","data":{"toolName":"TaskCreate","toolId":7,"phase":"tool_use"}},{"t":867352,"name":"aiToolResult","data":{"toolId":6,"isError":false,"preview":"Task #4 created successfully: Gems, key, door, enemies, hazards"}},{"t":867527,"name":"aiToolStream","data":{"toolId":7,"toolName":"TaskCreate","append":"{\"subject\": \"Attract mode, HUD, screens, sound\", \"description\": \"Self-playing dem"}},{"t":867824,"name":"aiToolStream","data":{"toolId":7,"toolName":"TaskCreate","append":"o bot, HUD, win/game-over overlays, muted-"}},{"t":868123,"name":"aiToolStream","data":{"toolId":7,"toolName":"TaskCreate","append":"by-default WebAudio bleeps\", \"activeForm\": \"Adding attract"}},{"t":868392,"name":"aiToolStream","data":{"toolId":7,"toolName":"TaskCreate","append":" mode & HUD"}},{"t":868657,"name":"aiToolStream","data":{"toolId":7,"toolName":"TaskCreate","append":"\"}"}},{"t":868659,"name":"aiToolInfo","data":{"toolName":"TaskCreate","toolId":7,"toolInput":{"subject":"Attract mode, HUD, screens, sound","description":"Self-playing demo bot, HUD, win/game-over overlays, muted-by-default WebAudio bleeps","activeForm":"Adding attract mode & HUD"}}},{"t":868659,"name":"aiProgress","data":{"toolName":"TaskCreate","toolId":8,"phase":"tool_use"}},{"t":868667,"name":"aiToolResult","data":{"toolId":7,"isError":false,"preview":"Task #5 created successfully: Attract mode, HUD, screens, sound"}},{"t":868775,"name":"aiToolStream","data":{"toolId":8,"toolName":"TaskCreate","append":"{\"subject\": \"Polish & test\", \"description\": \"Particles"}},{"t":869066,"name":"aiToolStream","data":{"toolId":8,"toolName":"TaskCreate","append":", responsive tuning, cheap live-preview checks, fix bugs"}},{"t":869489,"name":"aiToolStream","data":{"toolId":8,"toolName":"TaskCreate","append":"\", \"activeForm\": \"Polishing & testing\"}"}},{"t":869676,"name":"aiToolInfo","data":{"toolName":"TaskCreate","toolId":8,"toolInput":{"subject":"Polish & test","description":"Particles, responsive tuning, cheap live-preview checks, fix bugs","activeForm":"Polishing & testing"}}},{"t":869680,"name":"aiToolResult","data":{"toolId":8,"isError":false,"preview":"Task #6 created successfully: Polish & test"}},{"t":871362,"name":"aiProgress","data":{"toolName":"TaskUpdate","toolId":9,"phase":"tool_use"}},{"t":871740,"name":"aiToolStream","data":{"toolId":9,"toolName":"TaskUpdate","append":"{\"taskId\": \"1\", \"status\": \"in_progress\"}"}},{"t":871799,"name":"aiToolInfo","data":{"toolName":"TaskUpdate","toolId":9,"toolInput":{"taskId":"1","status":"in_progress"}}},{"t":871806,"name":"aiToolResult","data":{"toolId":9,"isError":false,"preview":"Updated task #1 status"}},{"t":885318,"name":"aiProgress","data":{"toolName":"Write","toolId":10,"phase":"tool_use"}},{"t":885443,"name":"aiToolStream","data":{"toolId":10,"toolName":"Write","append":"{\"file_path\": \"{{PROJECT}}/dave-jungle-temple.html"}},{"t":885884,"name":"aiToolStream","data":{"toolId":10,"toolName":"Write","append":"\", \"content\": \"\\n\\n\\n\\n\\nD"}},{"t":886512,"name":"aiToolStream","data":{"toolId":10,"toolName":"Write","append":"ave & the Papaya Temple\\n\\n\\n\\n
\\n
\\n "}},{"t":892447,"name":"aiToolStream","data":{"toolId":10,"toolName":"Write","append":"

Dave & the Papaya Temple

\\n
\\n \\n \\n "}},{"t":893199,"name":"aiToolStream","data":{"toolId":10,"toolName":"Write","append":"\\n
\\n\\n\\n\\n\\n"}},{"t":898996,"name":"aiToolStream","data":{"toolId":10,"toolName":"Write","append":"\"}"}},{"t":899011,"name":"aiToolInfo","data":{"toolName":"Write","toolId":10,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","content":"\n\n\n\n\nDave & the Papaya Temple\n\n\n\n
\n
\n

Dave & the Papaya Temple

\n
\n
\n \n
\n
\n\n\n\n\n"}}},{"t":899120,"name":"aiToolEdit","data":{"toolId":10,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":null,"newText":"\n\n\n\n\nDave & the Papaya Temple\n\n\n\n
\n
\n

Dave & the Papaya Temple

\n
\n
\n \n
\n
\n\n\n\n\n","isLivePreviewRelated":false}}},{"t":899120,"name":"aiToolResult","data":{"toolId":10,"isError":false,"preview":"File created successfully at: {{PROJECT}}/dave-jungle-temple.ht"}},{"t":900704,"name":"aiProgress","data":{"toolName":"mcp__phoenix-editor__controlEditor","toolId":11,"phase":"tool_use"}},{"t":901323,"name":"aiToolStream","data":{"toolId":11,"toolName":"mcp__phoenix-editor__controlEditor","append":"{\"operations\": [{\"operation\":\"open\",\"filePath\":\"{{PROJECT}}/dave-jungle-temple.html\"},{\"operation\":\"toggleLivePreview\",\"showPreview\":true}]"}},{"t":901596,"name":"aiToolStream","data":{"toolId":11,"toolName":"mcp__phoenix-editor__controlEditor","append":"}"}},{"t":901599,"name":"aiToolInfo","data":{"toolName":"mcp__phoenix-editor__controlEditor","toolId":11,"toolInput":{"operations":[{"operation":"open","filePath":"{{PROJECT}}/dave-jungle-temple.html"},{"operation":"toggleLivePreview","showPreview":true}]}}},{"t":901634,"name":"aiToolResult","data":{"toolId":11,"isError":false,"preview":"[{\"success\":true},{\"success\":true,\"alreadyInState\":true}]"}},{"t":902795,"name":"aiProgress","data":{"toolName":"TaskUpdate","toolId":12,"phase":"tool_use"}},{"t":903400,"name":"aiToolStream","data":{"toolId":12,"toolName":"TaskUpdate","append":"{\"taskId\": \"1\", \"status\": \"completed\"}"}},{"t":903403,"name":"aiToolInfo","data":{"toolName":"TaskUpdate","toolId":12,"toolInput":{"taskId":"1","status":"completed"}}},{"t":903403,"name":"aiProgress","data":{"toolName":"TaskUpdate","toolId":13,"phase":"tool_use"}},{"t":903408,"name":"aiToolResult","data":{"toolId":12,"isError":false,"preview":"Updated task #1 status"}},{"t":903474,"name":"aiToolStream","data":{"toolId":13,"toolName":"TaskUpdate","append":"{\"taskId\": \"2\", \"status\": \"in_"}},{"t":903773,"name":"aiToolStream","data":{"toolId":13,"toolName":"TaskUpdate","append":"progress\"}"}},{"t":903775,"name":"aiToolInfo","data":{"toolName":"TaskUpdate","toolId":13,"toolInput":{"taskId":"2","status":"in_progress"}}},{"t":903780,"name":"aiToolResult","data":{"toolId":13,"isError":false,"preview":"Updated task #2 status"}},{"t":1118711,"name":"aiTextStream","data":{"text":"Building the world next"}},{"t":1118734,"name":"aiTextStream","data":{"text":": tiles, level map, and parallax layers, in a few focused edits."}},{"t":1118736,"name":"aiProgress","data":{"toolName":"Edit","toolId":14,"phase":"tool_use"}},{"t":1118777,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"{\"file_path\": \"{{PROJECT}}/dave-jungle-temple."}},{"t":1119088,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"html\", \"old_string\": \"/* ==HELPERS"}},{"t":1119340,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"== */\\n\", \"new_string\": \"/* ==HELP"}},{"t":1119596,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"ERS== */\\nfunction mk(w,h){ const c=document.createElement('canvas'); c.width=w; c.height=h;"}},{"t":1119904,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":" const g=c.getContext('2d'); g.imageSmoothingEnabled=false; return [c,g]; }\\nlet _"}},{"t":1120213,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"seed = 20260921;\\nfunction rnd(){ _seed = (_seed*"}},{"t":1120463,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"1664525 + 1013904223)>>>0; return _seed/4294967296; }"}},{"t":1120715,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"\\nfunction ri(a,b){ return a + Math.floor(rnd()*(b-a+1)); }\\nfunction px(g,c"}},{"t":1121026,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",x,y,w,h){ g.fillStyle=c; g.fillRect(x|0,y"}},{"t":1121278,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"|0,w||1,h||1); }\\nfunction disc(g,c,cx,cy,r){"}},{"t":1121529,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":" g.fillStyle=c; for(let y=-r;y<=r;y++){ const s=Math.floor("}},{"t":1121843,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"Math.sqrt(r*r-y*y)); g.fillRect(cx-s,cy+y"}},{"t":1122094,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",s*2+1,1); } }\\nfunction sprite(rows,pal){ const [c,g]=mk("}},{"t":1122404,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"rows[0].length,rows.length);\\n rows.forEach((r,y)=>{ for(let x=0;xvb?b:v;\\n\\nconst C = {\\n ink:'#07110c', le"}},{"t":1124097,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"af9:'#06150f', leaf8:'#0b2318', leaf7:'#103424',"}},{"t":1124347,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":" leaf6:'#17482f', leaf5:'#1f6b45', leaf4:'#2f8a57', leaf"}},{"t":1124653,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"3:'#58b57c', leaf2:'#9ad9a0',\\n pap:'#ff"}},{"t":1124903,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"8a3d', papD:'#e2612a', papDD:'#a83f1c', papL:'#"}},{"t":1125155,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"ffc08a',\\n ivo:'#fbf3df', ivoD:'#d9cfb"}},{"t":1125405,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"2', ivoDD:'#a59c80',\\n stone:'#8f9a7e', stone"}},{"t":1125721,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"D:'#66735a', stoneDD:'#3b4638', stoneL:'#b"}},{"t":1125982,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"cc5a4',\\n dirt:'#4a3323', dirtD:'#2"}},{"t":1126244,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"f2016', dirtL:'#6b4a30',\\n water:'#1c7a72', waterD:'#0f4f50"}},{"t":1126548,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"', waterL:'#7fe0c6',\\n wood:'#9a6a35"}},{"t":1126841,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"', woodD:'#5a3520'\\n};\\n\\n/* ==TILES== */\\nconst TILE = {};"}},{"t":1127091,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"\\n(function makeTiles(){\\n // temple stone brick,"}},{"t":1127343,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":" 3 variants\\n TILE.brick = [0,1,2].map(v=>{ const [c,"}},{"t":1127594,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"g]=mk(T,T); px(g,C.stone,0,0,T,T);\\n for(let r=0;r<2;"}},{"t":1127904,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"r++){ const y=r*8;\\n px(g,C.stoneL,0,y"}},{"t":1128154,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",T,1); px(g,C.stoneD,0,y+6,T,1); px(g,C."}},{"t":1128410,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"stoneDD,0,y+7,T,1);\\n const vx=(r*8+v*5+3"}},{"t":1128720,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":")%16; px(g,C.stoneDD,vx,y,1,7); px(g,C.stoneL,("}},{"t":1129033,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"vx+1)%16,y+1,1,5); }\\n for(let i=0;i<7;i++) px(g,"}},{"t":1129343,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":" rnd()<.5?C.stoneD:C.stoneL, ri(1,14), ri("}},{"t":1129600,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"1,14));\\n if(v===2){ for(let i=0;i<5;i++) px(g,"}},{"t":1129905,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"C.leaf5,ri(0,13),ri(2,13),ri(1,"}},{"t":1130217,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"3),1); }\\n return c; });\\n // moss cap drawn over exposed br"}},{"t":1130467,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"ick tops\\n TILE.moss = [0,1].map(()=>{ const [c,g]=m"}},{"t":1130721,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"k(T,T); px(g,C.leaf5,0,0,T,2); px(g,C.leaf3,0,0,"}},{"t":1131029,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"T,1);\\n for(let x=0;x{ const [c,g]=mk(T,T); px"}},{"t":1132472,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"(g,C.dirt,0,0,T,T);\\n for(let i=0;i<10;i++) px(g,"}},{"t":1132780,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":" rnd()<.6?C.dirtD:C.dirtL, ri(0,14"}},{"t":1133030,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"), ri(0,15), ri(1,2), 1);\\n px(g,C."}},{"t":1133282,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"ivoDD,ri(2,12),ri(5,12),2"}},{"t":1133533,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",1); return c; });\\n TILE.grass = [0,1].map(()=>{ const [c,g]=mk(T,"}},{"t":1133855,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"T); px(g,C.leaf4,0,0,T,3); px(g,C.leaf3,0,0,T,1);"}},{"t":1134157,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"\\n for(let x=0;x{ const [c,g]=mk(T,"}},{"t":1135531,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"T); px(g,C.leaf8,0,0,T,T);\\n for(let r="}},{"t":1135781,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"0;r<2;r++){ const y=r*8; px(g,C.leaf7,0,y,"}},{"t":1136044,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"T,1); px(g,C.ink,0,y+7,T,1); px(g,C.ink,(r*8+v*6"}},{"t":1136345,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"+2)%16,y,1,7); }\\n if(v===1) px(g,C.le"}},{"t":1136595,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"af6,ri(2,10),ri(2,12),3"}},{"t":1136845,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",1); if(v===2){ px(g,C.leaf7,ri(2,10),ri(9,"}},{"t":1137156,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"13),4,2); }\\n return c; });\\n {"}},{"t":1137408,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":" const [c,g]=mk(T,T); px(g,C.leaf7,2,0,12"}},{"t":1137734,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",T); px(g,C.leaf6,4,0,3,T); px(g,C.leaf5,5"}},{"t":1138033,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",0,1,T); px(g,C."}},{"t":1138376,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"ink,2,0,1,T); px(g,C.ink,13,0,1,T); px(g,C.leaf8,10,0,2,T); TILE.column"}},{"t":1138658,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"=c; }\\n { const [c,g]=mk(T,T); px(g,"}},{"t":1138908,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"C.leaf6,0,4,T,8); px(g,C"}},{"t":1139159,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":".leaf5,0,4,T,1); px(g,C.ink,0,12,T,1); px(g"}},{"t":1139479,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",C.leaf7,1,6,14,4); TILE.capital=c; }\\n /"}},{"t":1139786,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"/ bamboo bridge (one-way)\\n { const [c,g]=mk(T,T); px(g,C.wood"}},{"t":1140096,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",0,0,T,5); px(g,C.papL,0,0,T,1); px(g,C.woodD,0,4"}},{"t":1140418,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",T,2);\\n for(let x=3;x{ const [c,g]=mk(T,T); px(g,C.water,0,4"}},{"t":1143536,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",T,12); px(g,C.waterD,0,11,T,5);\\n for(let x="}},{"t":1143850,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"0;x{ const [c,g]=mk(T,T); px(g,C.waterD,"}},{"t":1145848,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"0,0,T,T); px(g,C.water,(3+f*5)%14"}},{"t":1146158,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":",4,3,1); px(g,C.water,(10"}},{"t":1146413,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"+f*3)%14,11,2,1); px(g,'#0a3a3c"}},{"t":1146722,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"',0,12,T,4); return c; });\\n})();\\n"}},{"t":1146996,"name":"aiToolStream","data":{"toolId":14,"toolName":"Edit","append":"\"}"}},{"t":1147016,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":14,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"/* ==HELPERS== */\n","new_string":"/* ==HELPERS== */\nfunction mk(w,h){ const c=document.createElement('canvas'); c.width=w; c.height=h; const g=c.getContext('2d'); g.imageSmoothingEnabled=false; return [c,g]; }\nlet _seed = 20260921;\nfunction rnd(){ _seed = (_seed*1664525 + 1013904223)>>>0; return _seed/4294967296; }\nfunction ri(a,b){ return a + Math.floor(rnd()*(b-a+1)); }\nfunction px(g,c,x,y,w,h){ g.fillStyle=c; g.fillRect(x|0,y|0,w||1,h||1); }\nfunction disc(g,c,cx,cy,r){ g.fillStyle=c; for(let y=-r;y<=r;y++){ const s=Math.floor(Math.sqrt(r*r-y*y)); g.fillRect(cx-s,cy+y,s*2+1,1); } }\nfunction sprite(rows,pal){ const [c,g]=mk(rows[0].length,rows.length);\n rows.forEach((r,y)=>{ for(let x=0;xvb?b:v;\n\nconst C = {\n ink:'#07110c', leaf9:'#06150f', leaf8:'#0b2318', leaf7:'#103424', leaf6:'#17482f', leaf5:'#1f6b45', leaf4:'#2f8a57', leaf3:'#58b57c', leaf2:'#9ad9a0',\n pap:'#ff8a3d', papD:'#e2612a', papDD:'#a83f1c', papL:'#ffc08a',\n ivo:'#fbf3df', ivoD:'#d9cfb2', ivoDD:'#a59c80',\n stone:'#8f9a7e', stoneD:'#66735a', stoneDD:'#3b4638', stoneL:'#bcc5a4',\n dirt:'#4a3323', dirtD:'#2f2016', dirtL:'#6b4a30',\n water:'#1c7a72', waterD:'#0f4f50', waterL:'#7fe0c6',\n wood:'#9a6a35', woodD:'#5a3520'\n};\n\n/* ==TILES== */\nconst TILE = {};\n(function makeTiles(){\n // temple stone brick, 3 variants\n TILE.brick = [0,1,2].map(v=>{ const [c,g]=mk(T,T); px(g,C.stone,0,0,T,T);\n for(let r=0;r<2;r++){ const y=r*8;\n px(g,C.stoneL,0,y,T,1); px(g,C.stoneD,0,y+6,T,1); px(g,C.stoneDD,0,y+7,T,1);\n const vx=(r*8+v*5+3)%16; px(g,C.stoneDD,vx,y,1,7); px(g,C.stoneL,(vx+1)%16,y+1,1,5); }\n for(let i=0;i<7;i++) px(g, rnd()<.5?C.stoneD:C.stoneL, ri(1,14), ri(1,14));\n if(v===2){ for(let i=0;i<5;i++) px(g,C.leaf5,ri(0,13),ri(2,13),ri(1,3),1); }\n return c; });\n // moss cap drawn over exposed brick tops\n TILE.moss = [0,1].map(()=>{ const [c,g]=mk(T,T); px(g,C.leaf5,0,0,T,2); px(g,C.leaf3,0,0,T,1);\n for(let x=0;x{ const [c,g]=mk(T,T); px(g,C.dirt,0,0,T,T);\n for(let i=0;i<10;i++) px(g, rnd()<.6?C.dirtD:C.dirtL, ri(0,14), ri(0,15), ri(1,2), 1);\n px(g,C.ivoDD,ri(2,12),ri(5,12),2,1); return c; });\n TILE.grass = [0,1].map(()=>{ const [c,g]=mk(T,T); px(g,C.leaf4,0,0,T,3); px(g,C.leaf3,0,0,T,1);\n for(let x=0;x{ const [c,g]=mk(T,T); px(g,C.leaf8,0,0,T,T);\n for(let r=0;r<2;r++){ const y=r*8; px(g,C.leaf7,0,y,T,1); px(g,C.ink,0,y+7,T,1); px(g,C.ink,(r*8+v*6+2)%16,y,1,7); }\n if(v===1) px(g,C.leaf6,ri(2,10),ri(2,12),3,1); if(v===2){ px(g,C.leaf7,ri(2,10),ri(9,13),4,2); }\n return c; });\n { const [c,g]=mk(T,T); px(g,C.leaf7,2,0,12,T); px(g,C.leaf6,4,0,3,T); px(g,C.leaf5,5,0,1,T); px(g,C.ink,2,0,1,T); px(g,C.ink,13,0,1,T); px(g,C.leaf8,10,0,2,T); TILE.column=c; }\n { const [c,g]=mk(T,T); px(g,C.leaf6,0,4,T,8); px(g,C.leaf5,0,4,T,1); px(g,C.ink,0,12,T,1); px(g,C.leaf7,1,6,14,4); TILE.capital=c; }\n // bamboo bridge (one-way)\n { const [c,g]=mk(T,T); px(g,C.wood,0,0,T,5); px(g,C.papL,0,0,T,1); px(g,C.woodD,0,4,T,2);\n for(let x=3;x{ const [c,g]=mk(T,T); px(g,C.water,0,4,T,12); px(g,C.waterD,0,11,T,5);\n for(let x=0;x{ const [c,g]=mk(T,T); px(g,C.waterD,0,0,T,T); px(g,C.water,(3+f*5)%14,4,3,1); px(g,C.water,(10+f*3)%14,11,2,1); px(g,'#0a3a3c',0,12,T,4); return c; });\n})();\n"}}},{"t":1147090,"name":"aiToolEdit","data":{"toolId":14,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"/* ==HELPERS== */\n","newText":"/* ==HELPERS== */\nfunction mk(w,h){ const c=document.createElement('canvas'); c.width=w; c.height=h; const g=c.getContext('2d'); g.imageSmoothingEnabled=false; return [c,g]; }\nlet _seed = 20260921;\nfunction rnd(){ _seed = (_seed*1664525 + 1013904223)>>>0; return _seed/4294967296; }\nfunction ri(a,b){ return a + Math.floor(rnd()*(b-a+1)); }\nfunction px(g,c,x,y,w,h){ g.fillStyle=c; g.fillRect(x|0,y|0,w||1,h||1); }\nfunction disc(g,c,cx,cy,r){ g.fillStyle=c; for(let y=-r;y<=r;y++){ const s=Math.floor(Math.sqrt(r*r-y*y)); g.fillRect(cx-s,cy+y,s*2+1,1); } }\nfunction sprite(rows,pal){ const [c,g]=mk(rows[0].length,rows.length);\n rows.forEach((r,y)=>{ for(let x=0;xvb?b:v;\n\nconst C = {\n ink:'#07110c', leaf9:'#06150f', leaf8:'#0b2318', leaf7:'#103424', leaf6:'#17482f', leaf5:'#1f6b45', leaf4:'#2f8a57', leaf3:'#58b57c', leaf2:'#9ad9a0',\n pap:'#ff8a3d', papD:'#e2612a', papDD:'#a83f1c', papL:'#ffc08a',\n ivo:'#fbf3df', ivoD:'#d9cfb2', ivoDD:'#a59c80',\n stone:'#8f9a7e', stoneD:'#66735a', stoneDD:'#3b4638', stoneL:'#bcc5a4',\n dirt:'#4a3323', dirtD:'#2f2016', dirtL:'#6b4a30',\n water:'#1c7a72', waterD:'#0f4f50', waterL:'#7fe0c6',\n wood:'#9a6a35', woodD:'#5a3520'\n};\n\n/* ==TILES== */\nconst TILE = {};\n(function makeTiles(){\n // temple stone brick, 3 variants\n TILE.brick = [0,1,2].map(v=>{ const [c,g]=mk(T,T); px(g,C.stone,0,0,T,T);\n for(let r=0;r<2;r++){ const y=r*8;\n px(g,C.stoneL,0,y,T,1); px(g,C.stoneD,0,y+6,T,1); px(g,C.stoneDD,0,y+7,T,1);\n const vx=(r*8+v*5+3)%16; px(g,C.stoneDD,vx,y,1,7); px(g,C.stoneL,(vx+1)%16,y+1,1,5); }\n for(let i=0;i<7;i++) px(g, rnd()<.5?C.stoneD:C.stoneL, ri(1,14), ri(1,14));\n if(v===2){ for(let i=0;i<5;i++) px(g,C.leaf5,ri(0,13),ri(2,13),ri(1,3),1); }\n return c; });\n // moss cap drawn over exposed brick tops\n TILE.moss = [0,1].map(()=>{ const [c,g]=mk(T,T); px(g,C.leaf5,0,0,T,2); px(g,C.leaf3,0,0,T,1);\n for(let x=0;x{ const [c,g]=mk(T,T); px(g,C.dirt,0,0,T,T);\n for(let i=0;i<10;i++) px(g, rnd()<.6?C.dirtD:C.dirtL, ri(0,14), ri(0,15), ri(1,2), 1);\n px(g,C.ivoDD,ri(2,12),ri(5,12),2,1); return c; });\n TILE.grass = [0,1].map(()=>{ const [c,g]=mk(T,T); px(g,C.leaf4,0,0,T,3); px(g,C.leaf3,0,0,T,1);\n for(let x=0;x{ const [c,g]=mk(T,T); px(g,C.leaf8,0,0,T,T);\n for(let r=0;r<2;r++){ const y=r*8; px(g,C.leaf7,0,y,T,1); px(g,C.ink,0,y+7,T,1); px(g,C.ink,(r*8+v*6+2)%16,y,1,7); }\n if(v===1) px(g,C.leaf6,ri(2,10),ri(2,12),3,1); if(v===2){ px(g,C.leaf7,ri(2,10),ri(9,13),4,2); }\n return c; });\n { const [c,g]=mk(T,T); px(g,C.leaf7,2,0,12,T); px(g,C.leaf6,4,0,3,T); px(g,C.leaf5,5,0,1,T); px(g,C.ink,2,0,1,T); px(g,C.ink,13,0,1,T); px(g,C.leaf8,10,0,2,T); TILE.column=c; }\n { const [c,g]=mk(T,T); px(g,C.leaf6,0,4,T,8); px(g,C.leaf5,0,4,T,1); px(g,C.ink,0,12,T,1); px(g,C.leaf7,1,6,14,4); TILE.capital=c; }\n // bamboo bridge (one-way)\n { const [c,g]=mk(T,T); px(g,C.wood,0,0,T,5); px(g,C.papL,0,0,T,1); px(g,C.woodD,0,4,T,2);\n for(let x=3;x{ const [c,g]=mk(T,T); px(g,C.water,0,4,T,12); px(g,C.waterD,0,11,T,5);\n for(let x=0;x{ const [c,g]=mk(T,T); px(g,C.waterD,0,0,T,T); px(g,C.water,(3+f*5)%14,4,3,1); px(g,C.water,(10+f*3)%14,11,2,1); px(g,'#0a3a3c',0,12,T,4); return c; });\n})();\n","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1147092,"name":"aiToolResult","data":{"toolId":14,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1150339,"name":"aiProgress","data":{"toolName":"Edit","toolId":15,"phase":"tool_use"}},{"t":1150340,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"{\"file_path\": \"{{PROJECT}}/dave-jungle-temple.html\", \"old_string\": \"/* ==L"}},{"t":1150961,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"EVEL== */\\n\", \"new_string\": \"/* ==LEVEL== */\\nconst LW = 96, LH = 12, WORLD_W = LW*T, WORLD_H = LH*T;\\nconst map = [], back"}},{"t":1151601,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":" = [];\\nfor(let y=0;ySPAWN.gems.push({x:x*T+4,y:y*T+4"}},{"t":1158764,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":",k:k||0});\\n [5,6,7].forEach(x=>gem(x,9)); g"}},{"t":1159018,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"em(10,7,1); gem(11,7,1);\\n gem(22"}},{"t":1159321,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":",7); gem(23,7); g"}},{"t":1159572,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"em(15,9); gem(18,9);\\n [35,36].forEach(x=>g"}},{"t":1159883,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"em(x,7)); [37,38,39].forEach(x=>gem(x,5,1"}},{"t":1160136,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":")); [42,43,44,45].forEach(x=>gem(x,3,1));\\n gem("}},{"t":1160386,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"48,9); gem(50,9); gem(52,9); gem(51,6,1);\\n gem(62,7"}},{"t":1160698,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"); gem(63,7); gem(66,9); gem(69,9);\\n [83"}},{"t":1160957,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":",84,85,86].for"}},{"t":1162348,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"Each(x=>gem(x,7)); gem(85,4,1); gem(90,9,1);\\n SPAWN.key = {x:58*T+2, y:8*T+5};\\n SPAWN.door = {x:92*T, y:8*T};\\n SPAWN.enemies.push({t:'snake',x:14*T,y:10*T,x0:13*T,x1:20*T});\\n SPAWN.enemies.push({t:'snake',x:67*T,y:10*T,x0:65*T,x1:71*T});"}},{"t":1162635,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"\\n SPAWN.enemies.push({t:'bat',x:50*T,y:6*T"}},{"t":1162885,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":",x0:47*T,x1:53*T});\\n SPAWN.enemies.push({t:'b"}},{"t":1163202,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"at',x:84*T,y:4*T+8,x0:82*T,x1:88*T});\\n [["}},{"t":1163509,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"30,6],[38,3],[44,7],[50,4"}},{"t":1163821,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"],[58,5],[64,4],[70,6]].forEach(p"}},{"t":1164081,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"=>SPAWN.torches.push({x:p[0]*T+8,y:p[1]*T+4"}},{"t":1164386,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"}));\\n [[4,0,4],[8,0,3],[16,0,5],[20"}},{"t":1164696,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":",0,3],[32,2,3],[36,2,2],[43,2,1],[48,2,"}},{"t":1164946,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"4],[55,2,3],[60,2,4"}},{"t":1165202,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"],[67,2,3],[71,2,2],[75,0,4],[79,0,3],"}},{"t":1165509,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"[85,0,2],[90,0,5]]\\n .forEach(v"}},{"t":1165761,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"=>SPAWN.vines.push({x:v[0]*T+8,y:v[1]*T,len:v[2]"}},{"t":1166095,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"*T+ri(0,8),ph:rnd()*6}));"}},{"t":1166388,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"\\n})();\\nconst tileAt=(tx,ty)=> (tx<0||tx"}},{"t":1166702,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":">=LW) ? '#' : (ty<0||ty>=LH) ? ' ' : map[ty][tx];"}},{"t":1167008,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"\\nconst isSolid=ch=> ch==='#'||ch==='G';"}},{"t":1167270,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"\\n\\n// Pre-render the entire static level once\\nconst [levelCv"}},{"t":1167579,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":", lg] = mk(WORLD_W, WORLD_H);\\n(function paintLevel(){\\n "}},{"t":1167887,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"for(let y=0;y0 && x>0 && x1) lg.drawImage"}},{"t":1174354,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"(TILE.moss[x%2],X,Y);\\n if(y<=1 && !"}},{"t":1174636,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"isSolid(tileAt(x,y+1))"}},{"t":1175043,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":") { px(lg,C.stoneDD,X,Y+13,T,3); px(lg,C.ink,X,Y+15,T,1); } }\\n else if(ch==='G'){ lg.drawImage"}},{"t":1175321,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"(TILE.earth[(x+y)%2],X,Y); if(!isSolid(up))"}},{"t":1175571,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":" lg.drawImage(TILE.grass[x%2],X,Y); }\\n else if(ch"}},{"t":1175821,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"==='-') lg.drawImage(TILE.bridge,X,Y);\\n else if(ch"}},{"t":1176071,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":"==='^') lg.drawImage(TILE.spikes,X,Y"}},{"t":1176323,"name":"aiToolStream","data":{"toolId":15,"toolName":"Edit","append":");\\n }\\n // little plants + papaya flowers on grass\\n for(let x=0;xSPAWN.gems.push({x:x*T+4,y:y*T+4,k:k||0});\n [5,6,7].forEach(x=>gem(x,9)); gem(10,7,1); gem(11,7,1);\n gem(22,7); gem(23,7); gem(15,9); gem(18,9);\n [35,36].forEach(x=>gem(x,7)); [37,38,39].forEach(x=>gem(x,5,1)); [42,43,44,45].forEach(x=>gem(x,3,1));\n gem(48,9); gem(50,9); gem(52,9); gem(51,6,1);\n gem(62,7); gem(63,7); gem(66,9); gem(69,9);\n [83,84,85,86].forEach(x=>gem(x,7)); gem(85,4,1); gem(90,9,1);\n SPAWN.key = {x:58*T+2, y:8*T+5};\n SPAWN.door = {x:92*T, y:8*T};\n SPAWN.enemies.push({t:'snake',x:14*T,y:10*T,x0:13*T,x1:20*T});\n SPAWN.enemies.push({t:'snake',x:67*T,y:10*T,x0:65*T,x1:71*T});\n SPAWN.enemies.push({t:'bat',x:50*T,y:6*T,x0:47*T,x1:53*T});\n SPAWN.enemies.push({t:'bat',x:84*T,y:4*T+8,x0:82*T,x1:88*T});\n [[30,6],[38,3],[44,7],[50,4],[58,5],[64,4],[70,6]].forEach(p=>SPAWN.torches.push({x:p[0]*T+8,y:p[1]*T+4}));\n [[4,0,4],[8,0,3],[16,0,5],[20,0,3],[32,2,3],[36,2,2],[43,2,1],[48,2,4],[55,2,3],[60,2,4],[67,2,3],[71,2,2],[75,0,4],[79,0,3],[85,0,2],[90,0,5]]\n .forEach(v=>SPAWN.vines.push({x:v[0]*T+8,y:v[1]*T,len:v[2]*T+ri(0,8),ph:rnd()*6}));\n})();\nconst tileAt=(tx,ty)=> (tx<0||tx>=LW) ? '#' : (ty<0||ty>=LH) ? ' ' : map[ty][tx];\nconst isSolid=ch=> ch==='#'||ch==='G';\n\n// Pre-render the entire static level once\nconst [levelCv, lg] = mk(WORLD_W, WORLD_H);\n(function paintLevel(){\n for(let y=0;y0 && x>0 && x1) lg.drawImage(TILE.moss[x%2],X,Y);\n if(y<=1 && !isSolid(tileAt(x,y+1))) { px(lg,C.stoneDD,X,Y+13,T,3); px(lg,C.ink,X,Y+15,T,1); } }\n else if(ch==='G'){ lg.drawImage(TILE.earth[(x+y)%2],X,Y); if(!isSolid(up)) lg.drawImage(TILE.grass[x%2],X,Y); }\n else if(ch==='-') lg.drawImage(TILE.bridge,X,Y);\n else if(ch==='^') lg.drawImage(TILE.spikes,X,Y);\n }\n // little plants + papaya flowers on grass\n for(let x=0;xSPAWN.gems.push({x:x*T+4,y:y*T+4,k:k||0});\n [5,6,7].forEach(x=>gem(x,9)); gem(10,7,1); gem(11,7,1);\n gem(22,7); gem(23,7); gem(15,9); gem(18,9);\n [35,36].forEach(x=>gem(x,7)); [37,38,39].forEach(x=>gem(x,5,1)); [42,43,44,45].forEach(x=>gem(x,3,1));\n gem(48,9); gem(50,9); gem(52,9); gem(51,6,1);\n gem(62,7); gem(63,7); gem(66,9); gem(69,9);\n [83,84,85,86].forEach(x=>gem(x,7)); gem(85,4,1); gem(90,9,1);\n SPAWN.key = {x:58*T+2, y:8*T+5};\n SPAWN.door = {x:92*T, y:8*T};\n SPAWN.enemies.push({t:'snake',x:14*T,y:10*T,x0:13*T,x1:20*T});\n SPAWN.enemies.push({t:'snake',x:67*T,y:10*T,x0:65*T,x1:71*T});\n SPAWN.enemies.push({t:'bat',x:50*T,y:6*T,x0:47*T,x1:53*T});\n SPAWN.enemies.push({t:'bat',x:84*T,y:4*T+8,x0:82*T,x1:88*T});\n [[30,6],[38,3],[44,7],[50,4],[58,5],[64,4],[70,6]].forEach(p=>SPAWN.torches.push({x:p[0]*T+8,y:p[1]*T+4}));\n [[4,0,4],[8,0,3],[16,0,5],[20,0,3],[32,2,3],[36,2,2],[43,2,1],[48,2,4],[55,2,3],[60,2,4],[67,2,3],[71,2,2],[75,0,4],[79,0,3],[85,0,2],[90,0,5]]\n .forEach(v=>SPAWN.vines.push({x:v[0]*T+8,y:v[1]*T,len:v[2]*T+ri(0,8),ph:rnd()*6}));\n})();\nconst tileAt=(tx,ty)=> (tx<0||tx>=LW) ? '#' : (ty<0||ty>=LH) ? ' ' : map[ty][tx];\nconst isSolid=ch=> ch==='#'||ch==='G';\n\n// Pre-render the entire static level once\nconst [levelCv, lg] = mk(WORLD_W, WORLD_H);\n(function paintLevel(){\n for(let y=0;y0 && x>0 && x1) lg.drawImage(TILE.moss[x%2],X,Y);\n if(y<=1 && !isSolid(tileAt(x,y+1))) { px(lg,C.stoneDD,X,Y+13,T,3); px(lg,C.ink,X,Y+15,T,1); } }\n else if(ch==='G'){ lg.drawImage(TILE.earth[(x+y)%2],X,Y); if(!isSolid(up)) lg.drawImage(TILE.grass[x%2],X,Y); }\n else if(ch==='-') lg.drawImage(TILE.bridge,X,Y);\n else if(ch==='^') lg.drawImage(TILE.spikes,X,Y);\n }\n // little plants + papaya flowers on grass\n for(let x=0;x{ px(g,b[0],0,y,W,b[1]); if(i){ for(let x=0;xtop;y--){ if(y%9===0) tx+=(pxm%2?1:-1); px(g,col,tx,y,3,1); }\\n for(let f=0;f<7"}},{"t":1204092,"name":"aiToolStream","data":{"toolId":16,"toolName":"Edit","append":";f++){ const a=-2.9+f*.45+rnd()*.1; for(let t=0;t<17;t++){ const fx=tx+1+Math.cos(a)*t, fy=top+"}},{"t":1204842,"name":"aiToolStream","data":{"toolId":16,"toolName":"Edit","append":"Math.sin(a)*t*.7+t*t*.035; px(g,col,fx,fy,2,2); if(t>4) px(g,col,fx,fy+2,1,2);} }\\n disc(g,'"}},{"t":1205593,"name":"aiToolStream","data":{"toolId":16,"toolName":"Edit","append":"#c9642f',tx+2,top+3,2); }\\n BG.mid={c,w,f:.3}; }\\n // near: dark trunks, leaves, undergrowth\\n { const w=512,[c,g"}},{"t":1206345,"name":"aiToolStream","data":{"toolId":16,"toolName":"Edit","append":"]=mk(w,H), col='#0c2a1d', hi='#123a28';\\n for(const t of [[30,12],[150,9],[235"}},{"t":1207093,"name":"aiToolStream","data":{"toolId":16,"toolName":"Edit","append":",14],[350,10],[440,12]]){ px(g,col,t[0],0,t[1],H); px(g,hi,t[0]+2,0,2,H); for(let y=10;y0)x-=w; for(;x{ px(g,b[0],0,y,W,b[1]); if(i){ for(let x=0;xtop;y--){ if(y%9===0) tx+=(pxm%2?1:-1); px(g,col,tx,y,3,1); }\n for(let f=0;f<7;f++){ const a=-2.9+f*.45+rnd()*.1; for(let t=0;t<17;t++){ const fx=tx+1+Math.cos(a)*t, fy=top+Math.sin(a)*t*.7+t*t*.035; px(g,col,fx,fy,2,2); if(t>4) px(g,col,fx,fy+2,1,2);} }\n disc(g,'#c9642f',tx+2,top+3,2); }\n BG.mid={c,w,f:.3}; }\n // near: dark trunks, leaves, undergrowth\n { const w=512,[c,g]=mk(w,H), col='#0c2a1d', hi='#123a28';\n for(const t of [[30,12],[150,9],[235,14],[350,10],[440,12]]){ px(g,col,t[0],0,t[1],H); px(g,hi,t[0]+2,0,2,H); for(let y=10;y0)x-=w; for(;x{ px(g,b[0],0,y,W,b[1]); if(i){ for(let x=0;xtop;y--){ if(y%9===0) tx+=(pxm%2?1:-1); px(g,col,tx,y,3,1); }\n for(let f=0;f<7;f++){ const a=-2.9+f*.45+rnd()*.1; for(let t=0;t<17;t++){ const fx=tx+1+Math.cos(a)*t, fy=top+Math.sin(a)*t*.7+t*t*.035; px(g,col,fx,fy,2,2); if(t>4) px(g,col,fx,fy+2,1,2);} }\n disc(g,'#c9642f',tx+2,top+3,2); }\n BG.mid={c,w,f:.3}; }\n // near: dark trunks, leaves, undergrowth\n { const w=512,[c,g]=mk(w,H), col='#0c2a1d', hi='#123a28';\n for(const t of [[30,12],[150,9],[235,14],[350,10],[440,12]]){ px(g,col,t[0],0,t[1],H); px(g,hi,t[0]+2,0,2,H); for(let y=10;y0)x-=w; for(;xW+40)"}},{"t":1220185,"name":"aiToolStream","data":{"toolId":17,"toolName":"Edit","append":" continue; const sy=o.y-cy;\\n const f=((t*9"}},{"t":1220487,"name":"aiToolStream","data":{"toolId":17,"toolName":"Edit","append":" + o.x)"}},{"t":1220739,"name":"aiToolStream","data":{"toolId":17,"toolName":"Edit","append":"|0)%4; ctx.drawImage(SP.glow[f&"}},{"t":1221076,"name":"aiToolStream","data":{"toolId":17,"toolName":"Edit","append":"1], (sx-24)|0, (sy-26)|0);"}},{"t":1221359,"name":"aiToolStream","data":{"toolId":17,"toolName":"Edit","append":" ctx.drawImage(SP.torch, (sx-3)|0, s"}},{"t":1221611,"name":"aiToolStream","data":{"toolId":17,"toolName":"Edit","append":"y|0); ctx.drawImage(SP.flame[f], (sx-4)|0, (s"}},{"t":1221868,"name":"aiToolStream","data":{"toolId":17,"toolName":"Edit","append":"y-11)|0); }\\n // vines: swaying segment chains\\n for(const v of S"}},{"t":1222177,"name":"aiToolStream","data":{"toolId":17,"toolName":"Edit","append":"PAWN.vines){ const sx=v.x-cx; if(sx<-30||sx>W+30)"}},{"t":1222488,"name":"aiToolStream","data":{"toolId":17,"toolName":"Edit","append":" continue; const n=(v.len/4)|0;\\n for(let i=0;iW+40) continue; const sy=o.y-cy;\n const f=((t*9 + o.x)|0)%4; ctx.drawImage(SP.glow[f&1], (sx-24)|0, (sy-26)|0); ctx.drawImage(SP.torch, (sx-3)|0, sy|0); ctx.drawImage(SP.flame[f], (sx-4)|0, (sy-11)|0); }\n // vines: swaying segment chains\n for(const v of SPAWN.vines){ const sx=v.x-cx; if(sx<-30||sx>W+30) continue; const n=(v.len/4)|0;\n for(let i=0;iW+40) continue; const sy=o.y-cy;\n const f=((t*9 + o.x)|0)%4; ctx.drawImage(SP.glow[f&1], (sx-24)|0, (sy-26)|0); ctx.drawImage(SP.torch, (sx-3)|0, sy|0); ctx.drawImage(SP.flame[f], (sx-4)|0, (sy-11)|0); }\n // vines: swaying segment chains\n for(const v of SPAWN.vines){ const sx=v.x-cx; if(sx<-30||sx>W+30) continue; const n=(v.len/4)|0;\n for(let i=0;i{ const [c,g]=mk(8,12); const lean=[0,1,0"}},{"t":1234286,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":",-1][f], h=[10,11,9,11"}},{"t":1234618,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"][f];\\n for(let y=0;y1) px(g,C.pap,x+1,11-"}},{"t":1236008,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"y,wv*2-2,1); if(wv>2&&y{ const ["}},{"t":1237129,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"c,g]=mk(48,48); g.globalAlpha=.07; disc(g,C"}},{"t":1237380,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":".pap,24,24,23-f); disc(g,C.pap,24,24,17-"}},{"t":1237630,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"f); g.globalAlpha=.09; disc(g,C.papL,24,24,11"}},{"t":1237881,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"-f); disc(g,C.ivo,24,24,6); return c; });\\n SP"}},{"t":1238131,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":".vine = [0,1,2,3].map(v=>{ const [c,g]=mk(8,"}},{"t":1238384,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"4); px(g,C.leaf5,3,0,2,4); px(g,C.leaf"}},{"t":1238708,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"3,3,0,1,4);\\n if(v===1){ px(g,C.leaf4,5,1"}},{"t":1239006,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":",3,2); px(g,C.leaf2,6,1,1,1);} if("}},{"t":1239267,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"v===3){ px(g,C.leaf4,0,1,3,2); px(g,C.lea"}},{"t":1239518,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"f2,1,1,1,1);} if(v===2) px(g,C.leaf6"}},{"t":1239819,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":",4,2,1,2); return c; });\\n})();\\n"}},{"t":1240259,"name":"aiToolStream","data":{"toolId":18,"toolName":"Edit","append":"\"}"}},{"t":1240272,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":18,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"/* ==SPRITES== */\n","new_string":"/* ==SPRITES== */\nconst SP = {};\n(function makeDecorSprites(){\n { const [c,g]=mk(6,12); px(g,C.woodD,2,2,2,10); px(g,C.wood,2,2,1,9); px(g,C.stoneDD,0,0,6,3); px(g,C.stoneL,0,0,6,1); SP.torch=c; }\n SP.flame = [0,1,2,3].map(f=>{ const [c,g]=mk(8,12); const lean=[0,1,0,-1][f], h=[10,11,9,11][f];\n for(let y=0;y1) px(g,C.pap,x+1,11-y,wv*2-2,1); if(wv>2&&y{ const [c,g]=mk(48,48); g.globalAlpha=.07; disc(g,C.pap,24,24,23-f); disc(g,C.pap,24,24,17-f); g.globalAlpha=.09; disc(g,C.papL,24,24,11-f); disc(g,C.ivo,24,24,6); return c; });\n SP.vine = [0,1,2,3].map(v=>{ const [c,g]=mk(8,4); px(g,C.leaf5,3,0,2,4); px(g,C.leaf3,3,0,1,4);\n if(v===1){ px(g,C.leaf4,5,1,3,2); px(g,C.leaf2,6,1,1,1);} if(v===3){ px(g,C.leaf4,0,1,3,2); px(g,C.leaf2,1,1,1,1);} if(v===2) px(g,C.leaf6,4,2,1,2); return c; });\n})();\n"}}},{"t":1240274,"name":"aiProgress","data":{"toolName":"Edit","toolId":19,"phase":"tool_use"}},{"t":1240319,"name":"aiToolEdit","data":{"toolId":18,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"/* ==SPRITES== */\n","newText":"/* ==SPRITES== */\nconst SP = {};\n(function makeDecorSprites(){\n { const [c,g]=mk(6,12); px(g,C.woodD,2,2,2,10); px(g,C.wood,2,2,1,9); px(g,C.stoneDD,0,0,6,3); px(g,C.stoneL,0,0,6,1); SP.torch=c; }\n SP.flame = [0,1,2,3].map(f=>{ const [c,g]=mk(8,12); const lean=[0,1,0,-1][f], h=[10,11,9,11][f];\n for(let y=0;y1) px(g,C.pap,x+1,11-y,wv*2-2,1); if(wv>2&&y{ const [c,g]=mk(48,48); g.globalAlpha=.07; disc(g,C.pap,24,24,23-f); disc(g,C.pap,24,24,17-f); g.globalAlpha=.09; disc(g,C.papL,24,24,11-f); disc(g,C.ivo,24,24,6); return c; });\n SP.vine = [0,1,2,3].map(v=>{ const [c,g]=mk(8,4); px(g,C.leaf5,3,0,2,4); px(g,C.leaf3,3,0,1,4);\n if(v===1){ px(g,C.leaf4,5,1,3,2); px(g,C.leaf2,6,1,1,1);} if(v===3){ px(g,C.leaf4,0,1,3,2); px(g,C.leaf2,1,1,1,1);} if(v===2) px(g,C.leaf6,4,2,1,2); return c; });\n})();\n","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1240321,"name":"aiToolResult","data":{"toolId":18,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1240388,"name":"aiToolStream","data":{"toolId":19,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1240697,"name":"aiToolStream","data":{"toolId":19,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-temple.html"}},{"t":1241009,"name":"aiToolStream","data":{"toolId":19,"toolName":"Edit","append":"\", \"old_string\": \"function update(dt){\\n G.time += dt;\\n}"}},{"t":1241320,"name":"aiToolStream","data":{"toolId":19,"toolName":"Edit","append":"\", \"new_string\": \"function update(dt){\\n G.time += dt;\\n if(typeof stepGame==='function')"}},{"t":1241589,"name":"aiToolStream","data":{"toolId":19,"toolName":"Edit","append":" stepGame(dt);\\n else G.camX = (Math.sin(G.time*.25-1.57)+1)"}},{"t":1241883,"name":"aiToolStream","data":{"toolId":19,"toolName":"Edit","append":"/2*(WORLD_W-W); // scenic pan until the player ex"}},{"t":1242133,"name":"aiToolStream","data":{"toolId":19,"toolName":"Edit","append":"ists\\n}\"}"}},{"t":1242255,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":19,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"function update(dt){\n G.time += dt;\n}","new_string":"function update(dt){\n G.time += dt;\n if(typeof stepGame==='function') stepGame(dt);\n else G.camX = (Math.sin(G.time*.25-1.57)+1)/2*(WORLD_W-W); // scenic pan until the player exists\n}"}}},{"t":1242300,"name":"aiToolEdit","data":{"toolId":19,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"function update(dt){\n G.time += dt;\n}","newText":"function update(dt){\n G.time += dt;\n if(typeof stepGame==='function') stepGame(dt);\n else G.camX = (Math.sin(G.time*.25-1.57)+1)/2*(WORLD_W-W); // scenic pan until the player exists\n}","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1242304,"name":"aiToolResult","data":{"toolId":19,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1243568,"name":"aiProgress","data":{"toolName":"mcp__phoenix-editor__takeScreenshot","toolId":20,"phase":"tool_use"}},{"t":1244071,"name":"aiToolStream","data":{"toolId":20,"toolName":"mcp__phoenix-editor__takeScreenshot","append":"{\"selector\": \"#panel-live-preview-frame\", \"purePreview\": true}"}},{"t":1244116,"name":"aiToolInfo","data":{"toolName":"mcp__phoenix-editor__takeScreenshot","toolId":20,"toolInput":{"selector":"#panel-live-preview-frame","purePreview":true}}},{"t":1244356,"name":"aiToolResult","data":{"toolId":20,"isError":false,"preview":""}},{"t":1247427,"name":"aiTextStream","data":{"text":"\n\nThe preview is still showing the scaffold"}},{"t":1247468,"name":"aiTextStream","data":{"text":" — reloading to see the world layers."}},{"t":1247471,"name":"aiProgress","data":{"toolName":"mcp__phoenix-editor__takeScreenshot","toolId":21,"phase":"tool_use"}},{"t":1247471,"name":"aiToolStream","data":{"toolId":21,"toolName":"mcp__phoenix-editor__takeScreenshot","append":"{\"selector\": \"#panel-live-preview-frame"}},{"t":1247745,"name":"aiToolStream","data":{"toolId":21,"toolName":"mcp__phoenix-editor__takeScreenshot","append":"\", \"purePreview\": true, \"reload\": true}"}},{"t":1247753,"name":"aiToolInfo","data":{"toolName":"mcp__phoenix-editor__takeScreenshot","toolId":21,"toolInput":{"selector":"#panel-live-preview-frame","purePreview":true,"reload":true}}},{"t":1248583,"name":"aiToolResult","data":{"toolId":21,"isError":false,"preview":""}},{"t":1251806,"name":"aiProgress","data":{"toolName":"TaskUpdate","toolId":22,"phase":"tool_use"}},{"t":1251808,"name":"aiToolStream","data":{"toolId":22,"toolName":"TaskUpdate","append":"{\"taskId\": \"2"}},{"t":1252095,"name":"aiToolStream","data":{"toolId":22,"toolName":"TaskUpdate","append":"\", \"status\": \"completed\"}"}},{"t":1252098,"name":"aiToolInfo","data":{"toolName":"TaskUpdate","toolId":22,"toolInput":{"taskId":"2","status":"completed"}}},{"t":1252098,"name":"aiProgress","data":{"toolName":"TaskUpdate","toolId":23,"phase":"tool_use"}},{"t":1252102,"name":"aiToolResult","data":{"toolId":22,"isError":false,"preview":"Updated task #2 status"}},{"t":1252227,"name":"aiToolStream","data":{"toolId":23,"toolName":"TaskUpdate","append":"{\"taskId\": \"3\", \"status\": \"in_progress"}},{"t":1252520,"name":"aiToolStream","data":{"toolId":23,"toolName":"TaskUpdate","append":"\"}"}},{"t":1252524,"name":"aiToolInfo","data":{"toolName":"TaskUpdate","toolId":23,"toolInput":{"taskId":"3","status":"in_progress"}}},{"t":1252528,"name":"aiToolResult","data":{"toolId":23,"isError":false,"preview":"Updated task #3 status"}},{"t":1311951,"name":"aiProgress","data":{"toolName":"Edit","toolId":24,"phase":"tool_use"}},{"t":1312310,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"{\"file_path\": \"{{PROJECT}}"}},{"t":1312568,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"/dave-jungle-temple.html"}},{"t":1312831,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"\", \"old_string\": \"/* ==TILES== */\", \"new_string\": \""}},{"t":1313145,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"/* ==ACTOR SPRITES== */\\nfunction outlined(c){ const [s,sg]=mk(c.width,c"}},{"t":1313436,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":".height); sg.drawImage(c,0,0); sg.globalCompositeOperation='source-in'; sg.fill"}},{"t":1313732,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"Style=C.ink; sg.fillRect(0,0,c.width,c.height);\\n const"}},{"t":1313985,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":" [o,og]=mk(c.width+2,c.height+2); [[0,1],[2,1],"}},{"t":1314246,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"[1,0],[1,2]].forEach(d=>og.drawImage(s,d[0],d"}},{"t":1314526,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"[1])); og.drawImage(c,1,1); return o; }\\n(function makeActorSprites(){\\n const pal={p"}},{"t":1314829,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":":C.pap,P:C.papD,s:'#f2c79a',S:'#c98f5f"}},{"t":1315079,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"',i:C.ivo,I:C.ivoD,g:C.leaf4,G:C.leaf6"}},{"t":1315381,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":",b:C.woodD,k:C.ink,h:'#5a3520',v"}},{"t":1315678,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":":C.ivo,d:C.papDD};\\n const body=[\\\"....pppp"}},{"t":1315930,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"....\\\",\\\"...pppppp...\\\",\\\"..PPPPPPppp.\\\",\\\"...hsssks...\\\",\\\"...hsssss"}},{"t":1316207,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"...\\\",\\\"....sSSs....\\\",\\\"...iiiiiI...\\\",\\\"..siiiiiIs..\\\",\\\"..siii"}},{"t":1316458,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"iiIs..\\\",\\\"..s.iiiI.s..\\\",\\\"...PPPPPP...\\\",\\\"...ggggGG...\\\"];\\n const bod"}},{"t":1316763,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"yJ=[\\\"....pppp....\\\",\\\"...pppppp...\\\",\\\"..PPPPPPppp.\\\",\\\"...hsssks...\\\",\\\".."}},{"t":1317054,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"shsssss.s.\\\",\\\"..s.sSSs.s..\\\",\\\"..si"}},{"t":1317342,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"iiiiIs..\\\",\\\"...iiiiiI...\\\",\\\"...iiiiiI...\\\",\\\"....iiiI....\\\",\\\"...P"}},{"t":1317649,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"PPPPP...\\\",\\\"...ggggGG...\\\"];\\n const legs={idle:[\\\"...gg..GG...\\\",\\\"...gg..GG"}},{"t":1317956,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"...\\\",\\\"...bb..bb...\\\",\\\"...bbb.bbb..\\\"],\\n r"}},{"t":1318243,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"1:[\\\"..ggg..GG...\\\",\\\".ggg....GG..\\\",\\\".bb.....bb..\\\",\\\".bb.....b"}},{"t":1318556,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"bb.\\\"], r2:[\\\"....ggGG....\\\",\\\"....ggGG....\\\",\\\"....bb"}},{"t":1318845,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"G.....\\\",\\\"....bbbb....\\\"],\\n r3:[\\\"...GG..gg...\\\",\\\".."}},{"t":1319139,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"GG....gg..\\\",\\\"..bb....bb..\\\",\\\"..bbb..."}},{"t":1319394,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"bbb.\\\"], j:[\\\"..ggg..GGG..\\\",\\\"..gg....GG..\\\",\\\"..bb....bb..\\\",\\\"............\\\"]};"}},{"t":1319717,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"\\n const mkp=(b,l)=>{ const r=outlined(spr"}},{"t":1320020,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"ite(b.concat(l),pal)); return [flipH(r),r];"}},{"t":1320276,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":" }; // [left,right]\\n SP.dave={ idle:mkp(body"}},{"t":1320583,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":",legs.idle), run:[mkp(body,legs.r1),mkp(body,legs.r2),mkp(body,"}},{"t":1320871,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"legs.r3),mkp(body,legs.r2)], jump:mkp(bodyJ,"}},{"t":1321123,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"legs.j) };\\n SP.snake=[0,1].map(f=>{ const [c,g]"}},{"t":1321431,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"=mk(16,10);\\n for(let x=0;x<11;x++){ const y=6+Math.round(Math.sin"}},{"t":1321711,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"(x*.95+f*Math.PI)*1.5); px(g,C.pap"}},{"t":1321962,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"D,x,y,1,"}},{"t":1322453,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"3); px(g,C.pap,x,y,1,1); if(x%3===0) px(g,C.ivo,x,y+1,1,1); }\\n px(g,C.papD,9,4,2,5); px(g,C.papD,10,1,5,5); px(g"}},{"t":1322768,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":",C.pap,10,1,5,2); px(g,C.ivo,13,2,1,2"}},{"t":1323436,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"); px(g,C.ink,13,3,1,1); px(g,C.ivo,15,5,"}},{"t":1323729,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"1,1);\\n const r=outlined(c); return [flipH(r),r]; });\\n const batPal={p:C.papD,P:C.papDD,i:C.ivo,k:C.papDD,v:C.ivo};\\n SP."}},{"t":1324063,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"bat=[[\\\"p..............p\\\",\\\"pp............pp\\\",\\\"ppp...k..k...ppp\\\",\\\".pppp.PPP"}},{"t":1324322,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"P.pppp.\\\",\\\"..ppppPiPiPppp..\\\",\\\"...pppPPPPppp...\\\","}},{"t":1324586,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"\\\".....pPPPPp.....\\\",\\\"......PvvP......\\\"],\\n "}},{"t":1324837,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"[\\\"................\\\",\\\"......k..k......\\\",\\\"......PPPP......\\\",\\\"..ppppPiP"}},{"t":1325456,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"iPppp..\\\",\\\".pppppPPPPppppp.\\\",\\\"ppp.ppPPPPpp.ppp\\\",\\\"pp....PvvP....pp\\\",\\\"p..............p\\\"]].map(r=>outlined(sprite(r,batPal)));\\n const gemRows=[\\\"..hhhh..\\\","}},{"t":1325795,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"\\\".hllllm.\\\",\\\"hllllmmd\\\",\\\"hlllmmmd\\\",\\\".mmmmdd.\\\",\\\"..mmdd..\\\",\\\"...d"}},{"t":1326065,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"d...\\\"];\\n SP.gem=[ outlined(sprite(gemRows,{h:"}},{"t":1326401,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"C.ivo,l:C.papL,m:C.pap,d:C.papD})), outlined("}},{"t":1327039,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"sprite(gemRows,{h:'#ffffff',l:C.ivo,m:C.ivoD,d:C.ivoDD})) ];\\n SP.spark=sprite([\\\"..i..\\\",\\\"..i..\\\",\\\"iiiii\\\",\\\""}},{"t":1327336,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"..i..\\\",\\\"..i..\\\"],{i:C.ivo});\\n SP.key=outlined(spr"}},{"t":1327590,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"ite([\\\".hhh........\\\",\\\"p"}},{"t":1328290,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"p.pp.......\\\",\\\"p...pppppppp\\\",\\\"pp.pp..."}},{"t":1328558,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"p.p.\\\",\\\".ddd....d.d.\\\"],{h:C.ivo,p:C.papL,d:C.pap}));\\n SP.heart=outlined(sprite([\\\".pp.pp.\\\",\\\"phpp"}},{"t":1328933,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"ppp\\\",\\\"ppppppp\\\",\\\".ppppp.\\\",\\\"..ppp..\\\",\\\"...p.."}},{"t":1329341,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":".\\\"],{p"}},{"t":1329793,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":":C.pap,h:C.ivo}));\\n SP.door=[0,1].map(open=>{ const [c,g]=mk(16,32); px(g,C.stoneD,0,2,16,30); px(g,C.st"}},{"t":1330136,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"oneD,2,0,12,2); px(g,C.stoneL,2,0,12,1); px(g,C.stoneL,0,2,2,1); px(g,C"}},{"t":1330514,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":".stoneL,14,2,2,1); px(g,C.stoneDD,0,31,16,1);\\n for(let"}},{"t":1330891,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":" y=6;y<32;y+=6){ px(g,C.st"}},{"t":1331242,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"oneDD,0,y,2,1); px(g,C.stoneDD,14,y,2,1); }\\n if(!open){ px(g,C.wood,2,4,12"}},{"t":1331599,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":",28); px(g,C.wood,4,2,8,2); for"}},{"t":1331992,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"(let x=5;x<14;x+=3) px(g,C.woodD,x,3,1,29"}},{"t":1332371,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"); px(g,C.woodD,2,12,12,1); px(g,C.woodD,2,24,12,1); px(g,C"}},{"t":1332733,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":".papL,2,4,12,1);\\n px(g,C.pap,9,16,4,5"}},{"t":1333110,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"); px(g,C.ink,10,17,2,2); px(g,C.ink,10,19,1,1"}},{"t":1333487,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"); }\\n else { px(g,C.ink,2,4,12,28); px(g,C.ink,4,2,8,2); px(g,C.papD"}},{"t":1333776,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":",4,6,8,26); px(g,C.pap,5"}},{"t":1334032,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":",8,6,24); px(g,C.papL,6,11,4,21"}},{"t":1334322,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":"); px(g,C.ivo,7,15,2,17); }\\n return c; });\\n})();\\n\\n/* ==TILES=="}},{"t":1334620,"name":"aiToolStream","data":{"toolId":24,"toolName":"Edit","append":" */\"}"}},{"t":1334761,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":24,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"/* ==TILES== */","new_string":"/* ==ACTOR SPRITES== */\nfunction outlined(c){ const [s,sg]=mk(c.width,c.height); sg.drawImage(c,0,0); sg.globalCompositeOperation='source-in'; sg.fillStyle=C.ink; sg.fillRect(0,0,c.width,c.height);\n const [o,og]=mk(c.width+2,c.height+2); [[0,1],[2,1],[1,0],[1,2]].forEach(d=>og.drawImage(s,d[0],d[1])); og.drawImage(c,1,1); return o; }\n(function makeActorSprites(){\n const pal={p:C.pap,P:C.papD,s:'#f2c79a',S:'#c98f5f',i:C.ivo,I:C.ivoD,g:C.leaf4,G:C.leaf6,b:C.woodD,k:C.ink,h:'#5a3520',v:C.ivo,d:C.papDD};\n const body=[\"....pppp....\",\"...pppppp...\",\"..PPPPPPppp.\",\"...hsssks...\",\"...hsssss...\",\"....sSSs....\",\"...iiiiiI...\",\"..siiiiiIs..\",\"..siiiiiIs..\",\"..s.iiiI.s..\",\"...PPPPPP...\",\"...ggggGG...\"];\n const bodyJ=[\"....pppp....\",\"...pppppp...\",\"..PPPPPPppp.\",\"...hsssks...\",\"..shsssss.s.\",\"..s.sSSs.s..\",\"..siiiiiIs..\",\"...iiiiiI...\",\"...iiiiiI...\",\"....iiiI....\",\"...PPPPPP...\",\"...ggggGG...\"];\n const legs={idle:[\"...gg..GG...\",\"...gg..GG...\",\"...bb..bb...\",\"...bbb.bbb..\"],\n r1:[\"..ggg..GG...\",\".ggg....GG..\",\".bb.....bb..\",\".bb.....bbb.\"], r2:[\"....ggGG....\",\"....ggGG....\",\"....bbG.....\",\"....bbbb....\"],\n r3:[\"...GG..gg...\",\"..GG....gg..\",\"..bb....bb..\",\"..bbb...bbb.\"], j:[\"..ggg..GGG..\",\"..gg....GG..\",\"..bb....bb..\",\"............\"]};\n const mkp=(b,l)=>{ const r=outlined(sprite(b.concat(l),pal)); return [flipH(r),r]; }; // [left,right]\n SP.dave={ idle:mkp(body,legs.idle), run:[mkp(body,legs.r1),mkp(body,legs.r2),mkp(body,legs.r3),mkp(body,legs.r2)], jump:mkp(bodyJ,legs.j) };\n SP.snake=[0,1].map(f=>{ const [c,g]=mk(16,10);\n for(let x=0;x<11;x++){ const y=6+Math.round(Math.sin(x*.95+f*Math.PI)*1.5); px(g,C.papD,x,y,1,3); px(g,C.pap,x,y,1,1); if(x%3===0) px(g,C.ivo,x,y+1,1,1); }\n px(g,C.papD,9,4,2,5); px(g,C.papD,10,1,5,5); px(g,C.pap,10,1,5,2); px(g,C.ivo,13,2,1,2); px(g,C.ink,13,3,1,1); px(g,C.ivo,15,5,1,1);\n const r=outlined(c); return [flipH(r),r]; });\n const batPal={p:C.papD,P:C.papDD,i:C.ivo,k:C.papDD,v:C.ivo};\n SP.bat=[[\"p..............p\",\"pp............pp\",\"ppp...k..k...ppp\",\".pppp.PPPP.pppp.\",\"..ppppPiPiPppp..\",\"...pppPPPPppp...\",\".....pPPPPp.....\",\"......PvvP......\"],\n [\"................\",\"......k..k......\",\"......PPPP......\",\"..ppppPiPiPppp..\",\".pppppPPPPppppp.\",\"ppp.ppPPPPpp.ppp\",\"pp....PvvP....pp\",\"p..............p\"]].map(r=>outlined(sprite(r,batPal)));\n const gemRows=[\"..hhhh..\",\".hllllm.\",\"hllllmmd\",\"hlllmmmd\",\".mmmmdd.\",\"..mmdd..\",\"...dd...\"];\n SP.gem=[ outlined(sprite(gemRows,{h:C.ivo,l:C.papL,m:C.pap,d:C.papD})), outlined(sprite(gemRows,{h:'#ffffff',l:C.ivo,m:C.ivoD,d:C.ivoDD})) ];\n SP.spark=sprite([\"..i..\",\"..i..\",\"iiiii\",\"..i..\",\"..i..\"],{i:C.ivo});\n SP.key=outlined(sprite([\".hhh........\",\"pp.pp.......\",\"p...pppppppp\",\"pp.pp...p.p.\",\".ddd....d.d.\"],{h:C.ivo,p:C.papL,d:C.pap}));\n SP.heart=outlined(sprite([\".pp.pp.\",\"phppppp\",\"ppppppp\",\".ppppp.\",\"..ppp..\",\"...p...\"],{p:C.pap,h:C.ivo}));\n SP.door=[0,1].map(open=>{ const [c,g]=mk(16,32); px(g,C.stoneD,0,2,16,30); px(g,C.stoneD,2,0,12,2); px(g,C.stoneL,2,0,12,1); px(g,C.stoneL,0,2,2,1); px(g,C.stoneL,14,2,2,1); px(g,C.stoneDD,0,31,16,1);\n for(let y=6;y<32;y+=6){ px(g,C.stoneDD,0,y,2,1); px(g,C.stoneDD,14,y,2,1); }\n if(!open){ px(g,C.wood,2,4,12,28); px(g,C.wood,4,2,8,2); for(let x=5;x<14;x+=3) px(g,C.woodD,x,3,1,29); px(g,C.woodD,2,12,12,1); px(g,C.woodD,2,24,12,1); px(g,C.papL,2,4,12,1);\n px(g,C.pap,9,16,4,5); px(g,C.ink,10,17,2,2); px(g,C.ink,10,19,1,1); }\n else { px(g,C.ink,2,4,12,28); px(g,C.ink,4,2,8,2); px(g,C.papD,4,6,8,26); px(g,C.pap,5,8,6,24); px(g,C.papL,6,11,4,21); px(g,C.ivo,7,15,2,17); }\n return c; });\n})();\n\n/* ==TILES== */"}}},{"t":1334814,"name":"aiToolEdit","data":{"toolId":24,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"/* ==TILES== */","newText":"/* ==ACTOR SPRITES== */\nfunction outlined(c){ const [s,sg]=mk(c.width,c.height); sg.drawImage(c,0,0); sg.globalCompositeOperation='source-in'; sg.fillStyle=C.ink; sg.fillRect(0,0,c.width,c.height);\n const [o,og]=mk(c.width+2,c.height+2); [[0,1],[2,1],[1,0],[1,2]].forEach(d=>og.drawImage(s,d[0],d[1])); og.drawImage(c,1,1); return o; }\n(function makeActorSprites(){\n const pal={p:C.pap,P:C.papD,s:'#f2c79a',S:'#c98f5f',i:C.ivo,I:C.ivoD,g:C.leaf4,G:C.leaf6,b:C.woodD,k:C.ink,h:'#5a3520',v:C.ivo,d:C.papDD};\n const body=[\"....pppp....\",\"...pppppp...\",\"..PPPPPPppp.\",\"...hsssks...\",\"...hsssss...\",\"....sSSs....\",\"...iiiiiI...\",\"..siiiiiIs..\",\"..siiiiiIs..\",\"..s.iiiI.s..\",\"...PPPPPP...\",\"...ggggGG...\"];\n const bodyJ=[\"....pppp....\",\"...pppppp...\",\"..PPPPPPppp.\",\"...hsssks...\",\"..shsssss.s.\",\"..s.sSSs.s..\",\"..siiiiiIs..\",\"...iiiiiI...\",\"...iiiiiI...\",\"....iiiI....\",\"...PPPPPP...\",\"...ggggGG...\"];\n const legs={idle:[\"...gg..GG...\",\"...gg..GG...\",\"...bb..bb...\",\"...bbb.bbb..\"],\n r1:[\"..ggg..GG...\",\".ggg....GG..\",\".bb.....bb..\",\".bb.....bbb.\"], r2:[\"....ggGG....\",\"....ggGG....\",\"....bbG.....\",\"....bbbb....\"],\n r3:[\"...GG..gg...\",\"..GG....gg..\",\"..bb....bb..\",\"..bbb...bbb.\"], j:[\"..ggg..GGG..\",\"..gg....GG..\",\"..bb....bb..\",\"............\"]};\n const mkp=(b,l)=>{ const r=outlined(sprite(b.concat(l),pal)); return [flipH(r),r]; }; // [left,right]\n SP.dave={ idle:mkp(body,legs.idle), run:[mkp(body,legs.r1),mkp(body,legs.r2),mkp(body,legs.r3),mkp(body,legs.r2)], jump:mkp(bodyJ,legs.j) };\n SP.snake=[0,1].map(f=>{ const [c,g]=mk(16,10);\n for(let x=0;x<11;x++){ const y=6+Math.round(Math.sin(x*.95+f*Math.PI)*1.5); px(g,C.papD,x,y,1,3); px(g,C.pap,x,y,1,1); if(x%3===0) px(g,C.ivo,x,y+1,1,1); }\n px(g,C.papD,9,4,2,5); px(g,C.papD,10,1,5,5); px(g,C.pap,10,1,5,2); px(g,C.ivo,13,2,1,2); px(g,C.ink,13,3,1,1); px(g,C.ivo,15,5,1,1);\n const r=outlined(c); return [flipH(r),r]; });\n const batPal={p:C.papD,P:C.papDD,i:C.ivo,k:C.papDD,v:C.ivo};\n SP.bat=[[\"p..............p\",\"pp............pp\",\"ppp...k..k...ppp\",\".pppp.PPPP.pppp.\",\"..ppppPiPiPppp..\",\"...pppPPPPppp...\",\".....pPPPPp.....\",\"......PvvP......\"],\n [\"................\",\"......k..k......\",\"......PPPP......\",\"..ppppPiPiPppp..\",\".pppppPPPPppppp.\",\"ppp.ppPPPPpp.ppp\",\"pp....PvvP....pp\",\"p..............p\"]].map(r=>outlined(sprite(r,batPal)));\n const gemRows=[\"..hhhh..\",\".hllllm.\",\"hllllmmd\",\"hlllmmmd\",\".mmmmdd.\",\"..mmdd..\",\"...dd...\"];\n SP.gem=[ outlined(sprite(gemRows,{h:C.ivo,l:C.papL,m:C.pap,d:C.papD})), outlined(sprite(gemRows,{h:'#ffffff',l:C.ivo,m:C.ivoD,d:C.ivoDD})) ];\n SP.spark=sprite([\"..i..\",\"..i..\",\"iiiii\",\"..i..\",\"..i..\"],{i:C.ivo});\n SP.key=outlined(sprite([\".hhh........\",\"pp.pp.......\",\"p...pppppppp\",\"pp.pp...p.p.\",\".ddd....d.d.\"],{h:C.ivo,p:C.papL,d:C.pap}));\n SP.heart=outlined(sprite([\".pp.pp.\",\"phppppp\",\"ppppppp\",\".ppppp.\",\"..ppp..\",\"...p...\"],{p:C.pap,h:C.ivo}));\n SP.door=[0,1].map(open=>{ const [c,g]=mk(16,32); px(g,C.stoneD,0,2,16,30); px(g,C.stoneD,2,0,12,2); px(g,C.stoneL,2,0,12,1); px(g,C.stoneL,0,2,2,1); px(g,C.stoneL,14,2,2,1); px(g,C.stoneDD,0,31,16,1);\n for(let y=6;y<32;y+=6){ px(g,C.stoneDD,0,y,2,1); px(g,C.stoneDD,14,y,2,1); }\n if(!open){ px(g,C.wood,2,4,12,28); px(g,C.wood,4,2,8,2); for(let x=5;x<14;x+=3) px(g,C.woodD,x,3,1,29); px(g,C.woodD,2,12,12,1); px(g,C.woodD,2,24,12,1); px(g,C.papL,2,4,12,1);\n px(g,C.pap,9,16,4,5); px(g,C.ink,10,17,2,2); px(g,C.ink,10,19,1,1); }\n else { px(g,C.ink,2,4,12,28); px(g,C.ink,4,2,8,2); px(g,C.papD,4,6,8,26); px(g,C.pap,5,8,6,24); px(g,C.papL,6,11,4,21); px(g,C.ivo,7,15,2,17); }\n return c; });\n})();\n\n/* ==TILES== */","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1334815,"name":"aiToolResult","data":{"toolId":24,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1339582,"name":"aiProgress","data":{"toolName":"Edit","toolId":25,"phase":"tool_use"}},{"t":1339722,"name":"aiToolStream","data":{"toolId":25,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1340247,"name":"aiToolStream","data":{"toolId":25,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-temple.html\", \"old_string\": \"/* ==SP"}},{"t":1340544,"name":"aiToolStream","data":{"toolId":25,"toolName":"Edit","append":"RITES== */\\nconst SP = {};\\n(function makeDecorSprites(){\", \"new_string\": \"/* ==SPRITES"}},{"t":1340853,"name":"aiToolStream","data":{"toolId":25,"toolName":"Edit","append":"== */\\n(function makeDecorSprites(){"}},{"t":1341579,"name":"aiToolStream","data":{"toolId":25,"toolName":"Edit","append":"\"}"}},{"t":1341592,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":25,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"/* ==SPRITES== */\nconst SP = {};\n(function makeDecorSprites(){","new_string":"/* ==SPRITES== */\n(function makeDecorSprites(){"}}},{"t":1341594,"name":"aiProgress","data":{"toolName":"Edit","toolId":26,"phase":"tool_use"}},{"t":1341594,"name":"aiToolStream","data":{"toolId":26,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1341641,"name":"aiToolEdit","data":{"toolId":25,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"/* ==SPRITES== */\nconst SP = {};\n(function makeDecorSprites(){","newText":"/* ==SPRITES== */\n(function makeDecorSprites(){","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1341643,"name":"aiToolResult","data":{"toolId":25,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1341812,"name":"aiToolStream","data":{"toolId":26,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-temple.html\", \"old_string\": \"/* ==AC"}},{"t":1342162,"name":"aiToolStream","data":{"toolId":26,"toolName":"Edit","append":"TOR SPRITES== */\\nfunction outlined(c"}},{"t":1342551,"name":"aiToolStream","data":{"toolId":26,"toolName":"Edit","append":"){\", \"new_string\": \""}},{"t":1343043,"name":"aiToolStream","data":{"toolId":26,"toolName":"Edit","append":"/* ==ACTOR SPRITES== */\\nconst SP = {};\\nfunction outlined(c){\"}"}},{"t":1343059,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":26,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"/* ==ACTOR SPRITES== */\nfunction outlined(c){","new_string":"/* ==ACTOR SPRITES== */\nconst SP = {};\nfunction outlined(c){"}}},{"t":1343114,"name":"aiToolEdit","data":{"toolId":26,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"/* ==ACTOR SPRITES== */\nfunction outlined(c){","newText":"/* ==ACTOR SPRITES== */\nconst SP = {};\nfunction outlined(c){","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1343116,"name":"aiToolResult","data":{"toolId":26,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1345626,"name":"aiProgress","data":{"toolName":"Edit","toolId":27,"phase":"tool_use"}},{"t":1345627,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"{\"file_path\": \"{{PROJECT}}/dave-jungle-"}},{"t":1346273,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"temple.html\", \"old_string\": \"/* ==INPUT== */\\n\", \"new_string\": \"/* ==INPUT== *"}},{"t":1346928,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"/\\nconst keys = {left:false,right:false,jump:false};\\nconst KEYMAP = {ArrowLeft:'left',KeyA:'left',ArrowRight:'right',KeyD:'right',Ar"}},{"t":1347272,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"rowUp:'jump',KeyW:'jump',Space:'jump'};\\nfunction onAnyInput(){ if"}},{"t":1347534,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"(typeof takeControl==='function') takeControl(); }\\naddEventListener('keydown',e=>{ if(e.ctrlKey||e."}},{"t":1347809,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"metaKey||e.altKey) return; const k=KEYMAP[e.code];"}},{"t":1348113,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"\\n if(k){ keys[k]=true; e.preventDefault(); }"}},{"t":1348366,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"\\n if(e.code==='KeyM' && typeof to"}},{"t":1348621,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"ggleMute==='function'){ toggleMute(); return; }\\n if((e.code==='Enter'||e.code==='K"}},{"t":1348929,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"eyR') && typeof restartIfEnded==='function' && restartIfEnded"}},{"t":1349241,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"()) return;\\n if(e.key!=='Tab' && e.key!=='Sh"}},{"t":1349512,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"ift')"}},{"t":1350174,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":" onAnyInput(); });\\naddEventListener('keyup',e=>{ const k=KEYMAP[e.code]; if(k){ keys[k]=false; e.preventDefault(); } });\\naddEventListener('blur',()=>{ keys.left=keys.right=keys.jump=false; });\\n\\n/* "}},{"t":1350435,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"==PLAYER== */\\nconst RUN=95, ACC=900, GRAV=950, JUM"}},{"t":1350686,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"P=310, MAXFALL=330;\\nconst P = {x:0,y:0,w:8,h:"}},{"t":1350939,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"14,vx:0,vy:0,dir:1,ground:false,coyote:0,jbuf:0,prevJump:"}},{"t":1351250,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"false,anim:0,dead:0,inv:0};\\nfunction placePlayer(x,y"}},{"t":1351560,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"){ P.x=x; P.y=y; P.vx=P.vy=0; P.dir"}},{"t":1351814,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"=1; P.dead=0; P.ground=false; P.prevJump=false; P.jbuf=0;"}},{"t":1352119,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":" }\\nfunction movePlayer(dt,inp){\\n const want=(inp.right?1:0)-(inp.left"}},{"t":1352423,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"?1:0);\\n if(want){ P.vx+=want*ACC*dt; P.dir="}},{"t":1352689,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"want; } else { const d=Math.sign(P.vx); P.vx-=d*Math.min(Math.abs(P."}},{"t":1353003,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"vx),ACC*dt); }\\n P.vx=clamp(P.vx,-RUN,RUN);\\n P."}},{"t":1353305,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"coyote = P.ground ? .09 : P.coyote-dt;\\n if(inp.jump"}},{"t":1353555,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":" && !P.prevJump) P.jbuf=.12; P.prevJump=inp.jump;"}},{"t":1353984,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":" P.jbuf-="}},{"t":1354518,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"dt;\\n if(P.jbuf>0 && P.coyote>0){ P.vy=-JUMP; P.jbuf=0; P."}},{"t":1354770,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"coyote=0; P.ground=false; if(typeof onJump==='function') onJump(); }\\n if(!inp.jump && P.vy<-110) P.vy=-110; // release early = short h"}},{"t":1355062,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"op\\n P.vy=Math.min(P.vy+GRAV*dt,MAXFALL);\\n // horizontal"}},{"t":1355316,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"\\n P.x+=P"}},{"t":1355850,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":".vx*dt;"}},{"t":1356350,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"\\n { const top=Math.floor(P.y/T), bot=Math.floor((P.y+P.h-.01)/T);\\n if(P.vx>0){ const tx=Math.floor((P.x+P.w)/T); for(let ty=top;ty<=bot;ty++) if(isSolid(tileAt(tx,ty))){ P.x=tx*T-P.w-.001; P.v"}},{"t":1356695,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"x=0; break; } }\\n else if(P.vx<0){ const tx=Math.floor(P.x/T); for(let ty=top;ty<=bot;ty++)"}},{"t":1357075,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":" if(isSolid(tileAt(tx,ty))){ P.x=(tx+1)*T; P.vx=0; break; } } }\\n // vertical ("}},{"t":1357442,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"bridges are one-way)\\n const prevBottom=P.y+P.h, wasGround=P.ground; P.y+=P.vy*dt;"}},{"t":1357818,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":" P.ground=false;\\n { const l=Math.floor(P.x/T), r=Math.floor((P.x+P.w"}},{"t":1358072,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"-.01)/T);\\n if(P.vy>=0){ const ty=Math.floor((P.y+P.h)/T"}},{"t":1358389,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":");\\n for(let tx=l;tx<=r;tx++){ const ch=tileAt(tx"}},{"t":1358687,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":",ty); if(isSolid(ch)||(ch==='-'&&prevBottom<="}},{"t":1358938,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"ty*T+.5)){ P.y=ty*T-P.h; if"}},{"t":1359191,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"(!wasGround&&P.vy>150&&typeof onLand"}},{"t":1359446,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"==='function') onLand(); P.vy=0;"}},{"t":1360072,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":" P.ground=true; break; } } }\\n else { const ty=Math.floor(P.y/T); for(let tx=l;tx<=r;tx++) if(isSolid(tileAt(tx,ty))){ P.y=(ty+1)*T; P.vy=0; break; } } }"}},{"t":1360383,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"\\n P.anim += Math.abs(P.vx)*dt*.11;\\n}\\nfunction follow"}},{"t":1360642,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"Camera(dt,snap){\\n const tx=clamp(P.x+P.w/2-W/2+P.d"}},{"t":1360938,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"ir*18,0,WORLD_W-W), ty=clamp(P.y-92"}},{"t":1361245,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":",0,WORLD_H-H), k=snap?1:Math.min(1,dt*4"}},{"t":1361558,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":".5);\\n G.camX+=(tx-G.camX)*k; G.camY+=(ty"}},{"t":1361820,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"-G.camY)*Math.min(1,k*.7+"}},{"t":1362135,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":" (snap?1:0));\\n}\\nfunction drawPl"}},{"t":1362726,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"ayer(cx,cy,t){\\n if(P.inv>0 && ((t*16)|0)%2) return;\\n const d=P.dir>0?1:0; let s;\\n if(!"}},{"t":1363076,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"P.ground) s=SP.dave.jump[d]; else if(Math.abs(P.vx)>12) s=SP.dave.run[(P.anim|0)%"}},{"t":1363379,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"4][d]; else s=SP.dave.idle[d];\\n const bob="}},{"t":1363633,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"(P.ground&&Math.abs(P.vx)<=12&"}},{"t":1363941,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"&((t*2.2)|0)%"}},{"t":1364226,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"2)"}},{"t":1364720,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"?1:0;\\n ctx.drawImage(s,Math.round(P.x-c"}},{"t":1365006,"name":"aiToolStream","data":{"toolId":27,"toolName":"Edit","append":"x)-3,Math.round(P.y-cy)-3+bob);\\n}\\n\"}"}},{"t":1365018,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":27,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"/* ==INPUT== */\n","new_string":"/* ==INPUT== */\nconst keys = {left:false,right:false,jump:false};\nconst KEYMAP = {ArrowLeft:'left',KeyA:'left',ArrowRight:'right',KeyD:'right',ArrowUp:'jump',KeyW:'jump',Space:'jump'};\nfunction onAnyInput(){ if(typeof takeControl==='function') takeControl(); }\naddEventListener('keydown',e=>{ if(e.ctrlKey||e.metaKey||e.altKey) return; const k=KEYMAP[e.code];\n if(k){ keys[k]=true; e.preventDefault(); }\n if(e.code==='KeyM' && typeof toggleMute==='function'){ toggleMute(); return; }\n if((e.code==='Enter'||e.code==='KeyR') && typeof restartIfEnded==='function' && restartIfEnded()) return;\n if(e.key!=='Tab' && e.key!=='Shift') onAnyInput(); });\naddEventListener('keyup',e=>{ const k=KEYMAP[e.code]; if(k){ keys[k]=false; e.preventDefault(); } });\naddEventListener('blur',()=>{ keys.left=keys.right=keys.jump=false; });\n\n/* ==PLAYER== */\nconst RUN=95, ACC=900, GRAV=950, JUMP=310, MAXFALL=330;\nconst P = {x:0,y:0,w:8,h:14,vx:0,vy:0,dir:1,ground:false,coyote:0,jbuf:0,prevJump:false,anim:0,dead:0,inv:0};\nfunction placePlayer(x,y){ P.x=x; P.y=y; P.vx=P.vy=0; P.dir=1; P.dead=0; P.ground=false; P.prevJump=false; P.jbuf=0; }\nfunction movePlayer(dt,inp){\n const want=(inp.right?1:0)-(inp.left?1:0);\n if(want){ P.vx+=want*ACC*dt; P.dir=want; } else { const d=Math.sign(P.vx); P.vx-=d*Math.min(Math.abs(P.vx),ACC*dt); }\n P.vx=clamp(P.vx,-RUN,RUN);\n P.coyote = P.ground ? .09 : P.coyote-dt;\n if(inp.jump && !P.prevJump) P.jbuf=.12; P.prevJump=inp.jump; P.jbuf-=dt;\n if(P.jbuf>0 && P.coyote>0){ P.vy=-JUMP; P.jbuf=0; P.coyote=0; P.ground=false; if(typeof onJump==='function') onJump(); }\n if(!inp.jump && P.vy<-110) P.vy=-110; // release early = short hop\n P.vy=Math.min(P.vy+GRAV*dt,MAXFALL);\n // horizontal\n P.x+=P.vx*dt;\n { const top=Math.floor(P.y/T), bot=Math.floor((P.y+P.h-.01)/T);\n if(P.vx>0){ const tx=Math.floor((P.x+P.w)/T); for(let ty=top;ty<=bot;ty++) if(isSolid(tileAt(tx,ty))){ P.x=tx*T-P.w-.001; P.vx=0; break; } }\n else if(P.vx<0){ const tx=Math.floor(P.x/T); for(let ty=top;ty<=bot;ty++) if(isSolid(tileAt(tx,ty))){ P.x=(tx+1)*T; P.vx=0; break; } } }\n // vertical (bridges are one-way)\n const prevBottom=P.y+P.h, wasGround=P.ground; P.y+=P.vy*dt; P.ground=false;\n { const l=Math.floor(P.x/T), r=Math.floor((P.x+P.w-.01)/T);\n if(P.vy>=0){ const ty=Math.floor((P.y+P.h)/T);\n for(let tx=l;tx<=r;tx++){ const ch=tileAt(tx,ty); if(isSolid(ch)||(ch==='-'&&prevBottom<=ty*T+.5)){ P.y=ty*T-P.h; if(!wasGround&&P.vy>150&&typeof onLand==='function') onLand(); P.vy=0; P.ground=true; break; } } }\n else { const ty=Math.floor(P.y/T); for(let tx=l;tx<=r;tx++) if(isSolid(tileAt(tx,ty))){ P.y=(ty+1)*T; P.vy=0; break; } } }\n P.anim += Math.abs(P.vx)*dt*.11;\n}\nfunction followCamera(dt,snap){\n const tx=clamp(P.x+P.w/2-W/2+P.dir*18,0,WORLD_W-W), ty=clamp(P.y-92,0,WORLD_H-H), k=snap?1:Math.min(1,dt*4.5);\n G.camX+=(tx-G.camX)*k; G.camY+=(ty-G.camY)*Math.min(1,k*.7+ (snap?1:0));\n}\nfunction drawPlayer(cx,cy,t){\n if(P.inv>0 && ((t*16)|0)%2) return;\n const d=P.dir>0?1:0; let s;\n if(!P.ground) s=SP.dave.jump[d]; else if(Math.abs(P.vx)>12) s=SP.dave.run[(P.anim|0)%4][d]; else s=SP.dave.idle[d];\n const bob=(P.ground&&Math.abs(P.vx)<=12&&((t*2.2)|0)%2)?1:0;\n ctx.drawImage(s,Math.round(P.x-cx)-3,Math.round(P.y-cy)-3+bob);\n}\n"}}},{"t":1365070,"name":"aiToolEdit","data":{"toolId":27,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"/* ==INPUT== */\n","newText":"/* ==INPUT== */\nconst keys = {left:false,right:false,jump:false};\nconst KEYMAP = {ArrowLeft:'left',KeyA:'left',ArrowRight:'right',KeyD:'right',ArrowUp:'jump',KeyW:'jump',Space:'jump'};\nfunction onAnyInput(){ if(typeof takeControl==='function') takeControl(); }\naddEventListener('keydown',e=>{ if(e.ctrlKey||e.metaKey||e.altKey) return; const k=KEYMAP[e.code];\n if(k){ keys[k]=true; e.preventDefault(); }\n if(e.code==='KeyM' && typeof toggleMute==='function'){ toggleMute(); return; }\n if((e.code==='Enter'||e.code==='KeyR') && typeof restartIfEnded==='function' && restartIfEnded()) return;\n if(e.key!=='Tab' && e.key!=='Shift') onAnyInput(); });\naddEventListener('keyup',e=>{ const k=KEYMAP[e.code]; if(k){ keys[k]=false; e.preventDefault(); } });\naddEventListener('blur',()=>{ keys.left=keys.right=keys.jump=false; });\n\n/* ==PLAYER== */\nconst RUN=95, ACC=900, GRAV=950, JUMP=310, MAXFALL=330;\nconst P = {x:0,y:0,w:8,h:14,vx:0,vy:0,dir:1,ground:false,coyote:0,jbuf:0,prevJump:false,anim:0,dead:0,inv:0};\nfunction placePlayer(x,y){ P.x=x; P.y=y; P.vx=P.vy=0; P.dir=1; P.dead=0; P.ground=false; P.prevJump=false; P.jbuf=0; }\nfunction movePlayer(dt,inp){\n const want=(inp.right?1:0)-(inp.left?1:0);\n if(want){ P.vx+=want*ACC*dt; P.dir=want; } else { const d=Math.sign(P.vx); P.vx-=d*Math.min(Math.abs(P.vx),ACC*dt); }\n P.vx=clamp(P.vx,-RUN,RUN);\n P.coyote = P.ground ? .09 : P.coyote-dt;\n if(inp.jump && !P.prevJump) P.jbuf=.12; P.prevJump=inp.jump; P.jbuf-=dt;\n if(P.jbuf>0 && P.coyote>0){ P.vy=-JUMP; P.jbuf=0; P.coyote=0; P.ground=false; if(typeof onJump==='function') onJump(); }\n if(!inp.jump && P.vy<-110) P.vy=-110; // release early = short hop\n P.vy=Math.min(P.vy+GRAV*dt,MAXFALL);\n // horizontal\n P.x+=P.vx*dt;\n { const top=Math.floor(P.y/T), bot=Math.floor((P.y+P.h-.01)/T);\n if(P.vx>0){ const tx=Math.floor((P.x+P.w)/T); for(let ty=top;ty<=bot;ty++) if(isSolid(tileAt(tx,ty))){ P.x=tx*T-P.w-.001; P.vx=0; break; } }\n else if(P.vx<0){ const tx=Math.floor(P.x/T); for(let ty=top;ty<=bot;ty++) if(isSolid(tileAt(tx,ty))){ P.x=(tx+1)*T; P.vx=0; break; } } }\n // vertical (bridges are one-way)\n const prevBottom=P.y+P.h, wasGround=P.ground; P.y+=P.vy*dt; P.ground=false;\n { const l=Math.floor(P.x/T), r=Math.floor((P.x+P.w-.01)/T);\n if(P.vy>=0){ const ty=Math.floor((P.y+P.h)/T);\n for(let tx=l;tx<=r;tx++){ const ch=tileAt(tx,ty); if(isSolid(ch)||(ch==='-'&&prevBottom<=ty*T+.5)){ P.y=ty*T-P.h; if(!wasGround&&P.vy>150&&typeof onLand==='function') onLand(); P.vy=0; P.ground=true; break; } } }\n else { const ty=Math.floor(P.y/T); for(let tx=l;tx<=r;tx++) if(isSolid(tileAt(tx,ty))){ P.y=(ty+1)*T; P.vy=0; break; } } }\n P.anim += Math.abs(P.vx)*dt*.11;\n}\nfunction followCamera(dt,snap){\n const tx=clamp(P.x+P.w/2-W/2+P.dir*18,0,WORLD_W-W), ty=clamp(P.y-92,0,WORLD_H-H), k=snap?1:Math.min(1,dt*4.5);\n G.camX+=(tx-G.camX)*k; G.camY+=(ty-G.camY)*Math.min(1,k*.7+ (snap?1:0));\n}\nfunction drawPlayer(cx,cy,t){\n if(P.inv>0 && ((t*16)|0)%2) return;\n const d=P.dir>0?1:0; let s;\n if(!P.ground) s=SP.dave.jump[d]; else if(Math.abs(P.vx)>12) s=SP.dave.run[(P.anim|0)%4][d]; else s=SP.dave.idle[d];\n const bob=(P.ground&&Math.abs(P.vx)<=12&&((t*2.2)|0)%2)?1:0;\n ctx.drawImage(s,Math.round(P.x-cx)-3,Math.round(P.y-cy)-3+bob);\n}\n","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1365071,"name":"aiToolResult","data":{"toolId":27,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1398731,"name":"aiProgress","data":{"toolName":"Edit","toolId":28,"phase":"tool_use"}},{"t":1398839,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1399107,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-"}},{"t":1399404,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"temple.html\", \"old_string\": \"/* ==ENTITIES== *"}},{"t":1399849,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"/\", \"new_string\": \"/* ==ENTITIES== */\\nlet gems=[], enemies=[], keyItem=null"}},{"t":1400154,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":", door=null;\\nlet playSfx=function(){}, showToast=function(){}, syncHud=function(){"}},{"t":1400468,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"}, endGame=function(kind){ G.mode=kind; };\\nconst CHECKPOINTS"}},{"t":1400777,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"=[26,47,74];\\n// tiny particle pool (hard cap ke"}},{"t":1401031,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"eps it cheap)\\nconst fx=[]; const FX_MAX=48;\\nfunction pu"}},{"t":1401338,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"ff(x,y,n,col,spd,up){ for(let"}},{"t":1401651,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" i=0;i=0;i--){ const p=fx[i]; p.life-=dt; if(p.life<=0){ fx[i]=f"}},{"t":1403532,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"x[fx.length-1]; fx.pop(); continue; } p.vy+=p.g*dt; p.x+=p"}},{"t":1403846,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".vx*dt; p.y+=p.vy*dt; } }\\nfunction drawFx(cx,"}},{"t":1404096,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"cy){ for(const p of fx){ ctx.fillStyle=p.c; const s=p.life>.25"}},{"t":1404420,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"?2:1; ctx.fillRect((p.x-cx)|0,(p.y-cy)|0,s,s); }"}},{"t":1404723,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" }\\nfunction onJump(){ puff(P.x+4,P.y+P.h,4,C.ivoD,30"}},{"t":1405031,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":",10); playSfx('jump'); }\\nfunction onLand(){ puff(P."}},{"t":1405281,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"x+4,P.y+P.h,5,C.ivoD,36,14"}},{"t":1405532,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"); }\\n\\nfunction resetLevel(){\\n gems=SPAWN.gems.map(g=>({x"}},{"t":1405783,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":":g.x,y:g.y,k:g.k,got:false,ph:Math.random()*6}));\\n enemies=S"}},{"t":1406093,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"PAWN.enemies.map(e=>({t:e.t,x:e.x,y:e.t==='snake'?e."}},{"t":1406408,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"y-8:e.y,y0:e.y,x0:e.x0,x1:e.x1,d"}},{"t":1406659,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"ir:1,dead:0,ph:Math.random()*6,w:e."}},{"t":1407107,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"t==='snake'?14:12,h:e.t==='snake'?8:7}));\\n keyItem={x:SPAWN.key.x,y:SPAWN.key.y,got:false}; door={x:SPAWN"}},{"t":1407406,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".door.x,y:SPAWN.door.y,open:false};\\n G.gems=0; G."}},{"t":1407665,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"total=gems.length; G.hasKey=false; G.lives=3; G.winT=0; G.check"}},{"t":1407967,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"=-1; G.doorHint=0;\\n placeP"}},{"t":1408217,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"layer(SPAWN.start.x,SPAWN.start.y); P.inv=0; f"}},{"t":1408469,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"x.length=0; followCamera(0,true); syncHud();\\n}\\nconst hit=("}},{"t":1408727,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"ax,ay,aw,ah,bx,by,bw,bh)=>axbx&&ayby;\\nfunction killPlayer(spl"}},{"t":1409282,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"ash){\\n if(P.dead>0||P.inv>0||G.winT>0)"}},{"t":1409534,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" return;\\n P.dead=1.2; P.vy=splash?-90"}},{"t":1409843,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":":-250; P.vx=0; playSfx('hurt');\\n puff(P.x+4"}},{"t":1410156,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":",P.y+8,10,splash?C.waterL:C.pap,70"}},{"t":1410408,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":",40);\\n if(G.mode==='play'){ G.lives--;"}},{"t":1410661,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" syncHud(); }\\n}\\nfunction afterDeath(){\\n if(G.mode==='play' && G.lives<=0){"}},{"t":1410970,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" endGame('over'); return; }\\n const c=G.check; placePlayer(c"}},{"t":1411224,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"<0?SPAWN.start.x:CHECKPOINTS[c]*T, 9*T+"}},{"t":1411483,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"2); P.inv=1.6;\\n}\\nfunction updateEnemies(dt,alive){\\n for(const"}},{"t":1411784,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" e of enemies){\\n if(e.dead>0){ e.dead-=dt; if(e.dead<=0) e."}},{"t":1412096,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"gone=true; continue; } if(e.gone) continue;\\n const sp="}},{"t":1412348,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"e.t==='snake'?26:42; e.x+=e.dir*sp*dt; if(e.x"}},{"t":1412907,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"e.x1){ e.x=e.x1-e.w; e.dir=-1; }\\n if(e.t==='bat')"}},{"t":1413219,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" e.y=e.y0+Math.sin(G.time*2.3+e.ph)*11"}},{"t":1413469,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":";\\n if(alive && hit(P.x,P.y,P.w,P.h,e.x"}},{"t":1413728,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"+1,e.y+1,e.w-2,e.h-1)){\\n if(P."}},{"t":1414033,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"vy>40 && P.y+P.h-e.y<9){ e.dead="}},{"t":1414283,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".35; P.vy=-230; P.in"}},{"t":1414581,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"v=Math.max(P.inv,.15); puff(e.x+e"}},{"t":1414851,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".w/2,e.y+4,9,C.papL"}},{"t":1415164,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":",60,20); playSfx('stomp'); }\\n else killPlayer(false);"}},{"t":1415470,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"\\n }\\n }\\n}\\nfunction checkWorld(){\\n // hazards\\n const l=Math.floor((P.x"}},{"t":1417048,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"+1)/T), r=Math.floor((P.x+P.w-1)/T), by=P.y+P.h, ty=Math.floor((by-1)/T);\\n for(let tx=l;tx<=r;tx++){ const ch=tileAt(tx,ty); if(ch==='^'&&by>ty*T+7){ killPlayer(false); return; } if(ch==='~'&&by>ty*T+10){ killPlayer(true); return; } }\\n if(P.y>WORLD_H+24"}},{"t":1417345,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"){ killPlayer(true); return; }\\n // checkpoints\\n if"}},{"t":1417596,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"(P.ground) for(let i=CHECKPOINTS.length-1;i"}},{"t":1417860,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":">G.check;i--) if(P.x>CHECKPOINTS[i]*T){ G.check=i; break; }"}},{"t":1418159,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"\\n // pickups\\n for(const g of gems){ if(!g.got && hit(P"}},{"t":1418410,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".x,P.y,P.w,P.h,g.x-1,g.y"}},{"t":1418661,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"-1,10,10)){ g.got=true; G.gems++; puff(g.x+4,g.y+4,6,g."}},{"t":1418920,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"k?C.ivo:C.papL,55,10); playSfx('gem'); syncHud(); } }\\n if("}},{"t":1419219,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"!keyItem.got && hit(P.x,P.y,P.w,P.h,keyItem."}},{"t":1419469,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"x,keyItem.y-2,12,9)){ keyItem."}},{"t":1419734,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"got=true; G.hasKey=true; puff(keyItem.x+6,keyItem.y+2,12"}},{"t":1420033,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":",C.ivo,70,10); playSfx('key'); showToast('Key found"}},{"t":1420284,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" — the exit is unlocked!'); syncHud(); }\\n /"}},{"t":1420597,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"/ exit door\\n G.doorHint-=1/60;\\n if(hit(P.x,P.y,P.w,"}},{"t":1420909,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"P.h,door.x+4,door.y+8,8,24)){\\n if(G."}},{"t":1421161,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"hasKey){ if(!door.open){ door.open=true; G.win"}},{"t":1421414,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"T=.9; P.vx=0; puff(door.x+8,door.y+16,14,C.papL,60"}},{"t":1421719,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":",20); playSfx('win'); } }\\n else if(G.doorHint<=0){ G"}},{"t":1421974,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".doorHint=3; showToast('Locked! Find the temple key first.'); playSfx('"}},{"t":1422282,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"locked'); }\\n }\\n}\\nfunction stepGame(dt){\\n if(G"}},{"t":1422539,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".mode==='win'||G.mode==='over'){ updateEnemies(dt,false); update"}},{"t":1423033,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"Fx(dt); return; }\\n const inp=(G.mode==='attract'&&typeof botInput==='function')?botInput(dt):keys;\\n if(G.winT>0){ G"}},{"t":1423290,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".winT-=dt; if(G.winT<=0) endGame('win'); }\\n else if(P.dead>0){ P"}},{"t":1423598,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".vy+=GRAV*dt; P.y+=P.vy*dt; P.dead-=dt; if(P"}},{"t":1423907,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".dead<=0) afterDeath(); }\\n else { movePlayer(dt,inp); chec"}},{"t":1424176,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"kWorld(); }\\n updateEnemies(dt, P.dead<=0 "}},{"t":1424722,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"&& G.winT<=0); updateFx(dt); followCamera(dt);\\n if(P.inv>0) P.inv-=dt;\\n}\\nfunction drawActors(cx,"}},{"t":1424972,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"cy,t){\\n ctx.drawImage(SP.door[door.open?1:0],door.x"}},{"t":1425290,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"-cx,door.y-cy);\\n for(const g of gems){ if(g.got) continue; const sx=g.x-c"}},{"t":1425546,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"x; if(sx<-12||sx>W+4) continue; const by=Math.round(Math.sin(t"}},{"t":1425845,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"*3+g.ph)*1.5);\\n ctx.drawImage(SP"}},{"t":1426099,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":".gem[g.k],(sx-1)|0,(g.y-cy-1+by)|0);"}},{"t":1426349,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" if(((t*1.3+g.ph)%2.2"}},{"t":1426666,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":")<.18) ctx.drawImage(SP.spark,(sx+3"}},{"t":1426977,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":")|0,(g.y-cy-3+by)|0); }\\n if(!keyItem.got){ const by="}},{"t":1427286,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"Math.round(Math.sin(t*2.6)*2); ctx.drawImage(SP.key,("}},{"t":1427596,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"keyItem.x-cx-1)|0,(keyItem.y-cy-1+by)|0"}},{"t":1427850,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"); if((t%1.6)<.2) ctx.drawIm"}},{"t":1428160,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"age(SP.spark,(keyItem.x-cx+8)|0,(keyItem.y-cy-4+by)|"}},{"t":1428475,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"0); }\\n for(const e of enemies){ if(e.gone) continue; const sx=e.x"}},{"t":1428725,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"-cx; if(sx<-24||sx>W+8) continue;\\n if(e.dead>0 "}},{"t":1429033,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"&& ((t*20)|0)%2) continue;\\n if(e."}},{"t":1429290,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"t==='snake') ctx.drawImage(SP.snake[(t*6|0)%2][e.dir>0?"}},{"t":1429597,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"1:0],(sx-2)|0,(e.y-cy-3+(e.dead>0?"}},{"t":1429910,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"3:0))|0);\\n else ctx.drawImage(SP.bat[(t*9"}},{"t":1430221,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"|0)%2],(sx-3)|0,(e.y-cy-2)|0); }\\n if(G.winT<=0"}},{"t":1430534,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":" || G.winT>.55) drawPlayer(cx,cy,t);"}},{"t":1430792,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":"\\n}\\nG.mode='play'; resetLevel();\"}"}},{"t":1431044,"name":"aiToolStream","data":{"toolId":28,"toolName":"Edit","append":""}},{"t":1431046,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":28,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"/* ==ENTITIES== */","new_string":"/* ==ENTITIES== */\nlet gems=[], enemies=[], keyItem=null, door=null;\nlet playSfx=function(){}, showToast=function(){}, syncHud=function(){}, endGame=function(kind){ G.mode=kind; };\nconst CHECKPOINTS=[26,47,74];\n// tiny particle pool (hard cap keeps it cheap)\nconst fx=[]; const FX_MAX=48;\nfunction puff(x,y,n,col,spd,up){ for(let i=0;i=0;i--){ const p=fx[i]; p.life-=dt; if(p.life<=0){ fx[i]=fx[fx.length-1]; fx.pop(); continue; } p.vy+=p.g*dt; p.x+=p.vx*dt; p.y+=p.vy*dt; } }\nfunction drawFx(cx,cy){ for(const p of fx){ ctx.fillStyle=p.c; const s=p.life>.25?2:1; ctx.fillRect((p.x-cx)|0,(p.y-cy)|0,s,s); } }\nfunction onJump(){ puff(P.x+4,P.y+P.h,4,C.ivoD,30,10); playSfx('jump'); }\nfunction onLand(){ puff(P.x+4,P.y+P.h,5,C.ivoD,36,14); }\n\nfunction resetLevel(){\n gems=SPAWN.gems.map(g=>({x:g.x,y:g.y,k:g.k,got:false,ph:Math.random()*6}));\n enemies=SPAWN.enemies.map(e=>({t:e.t,x:e.x,y:e.t==='snake'?e.y-8:e.y,y0:e.y,x0:e.x0,x1:e.x1,dir:1,dead:0,ph:Math.random()*6,w:e.t==='snake'?14:12,h:e.t==='snake'?8:7}));\n keyItem={x:SPAWN.key.x,y:SPAWN.key.y,got:false}; door={x:SPAWN.door.x,y:SPAWN.door.y,open:false};\n G.gems=0; G.total=gems.length; G.hasKey=false; G.lives=3; G.winT=0; G.check=-1; G.doorHint=0;\n placePlayer(SPAWN.start.x,SPAWN.start.y); P.inv=0; fx.length=0; followCamera(0,true); syncHud();\n}\nconst hit=(ax,ay,aw,ah,bx,by,bw,bh)=>axbx&&ayby;\nfunction killPlayer(splash){\n if(P.dead>0||P.inv>0||G.winT>0) return;\n P.dead=1.2; P.vy=splash?-90:-250; P.vx=0; playSfx('hurt');\n puff(P.x+4,P.y+8,10,splash?C.waterL:C.pap,70,40);\n if(G.mode==='play'){ G.lives--; syncHud(); }\n}\nfunction afterDeath(){\n if(G.mode==='play' && G.lives<=0){ endGame('over'); return; }\n const c=G.check; placePlayer(c<0?SPAWN.start.x:CHECKPOINTS[c]*T, 9*T+2); P.inv=1.6;\n}\nfunction updateEnemies(dt,alive){\n for(const e of enemies){\n if(e.dead>0){ e.dead-=dt; if(e.dead<=0) e.gone=true; continue; } if(e.gone) continue;\n const sp=e.t==='snake'?26:42; e.x+=e.dir*sp*dt; if(e.xe.x1){ e.x=e.x1-e.w; e.dir=-1; }\n if(e.t==='bat') e.y=e.y0+Math.sin(G.time*2.3+e.ph)*11;\n if(alive && hit(P.x,P.y,P.w,P.h,e.x+1,e.y+1,e.w-2,e.h-1)){\n if(P.vy>40 && P.y+P.h-e.y<9){ e.dead=.35; P.vy=-230; P.inv=Math.max(P.inv,.15); puff(e.x+e.w/2,e.y+4,9,C.papL,60,20); playSfx('stomp'); }\n else killPlayer(false);\n }\n }\n}\nfunction checkWorld(){\n // hazards\n const l=Math.floor((P.x+1)/T), r=Math.floor((P.x+P.w-1)/T), by=P.y+P.h, ty=Math.floor((by-1)/T);\n for(let tx=l;tx<=r;tx++){ const ch=tileAt(tx,ty); if(ch==='^'&&by>ty*T+7){ killPlayer(false); return; } if(ch==='~'&&by>ty*T+10){ killPlayer(true); return; } }\n if(P.y>WORLD_H+24){ killPlayer(true); return; }\n // checkpoints\n if(P.ground) for(let i=CHECKPOINTS.length-1;i>G.check;i--) if(P.x>CHECKPOINTS[i]*T){ G.check=i; break; }\n // pickups\n for(const g of gems){ if(!g.got && hit(P.x,P.y,P.w,P.h,g.x-1,g.y-1,10,10)){ g.got=true; G.gems++; puff(g.x+4,g.y+4,6,g.k?C.ivo:C.papL,55,10); playSfx('gem'); syncHud(); } }\n if(!keyItem.got && hit(P.x,P.y,P.w,P.h,keyItem.x,keyItem.y-2,12,9)){ keyItem.got=true; G.hasKey=true; puff(keyItem.x+6,keyItem.y+2,12,C.ivo,70,10); playSfx('key'); showToast('Key found — the exit is unlocked!'); syncHud(); }\n // exit door\n G.doorHint-=1/60;\n if(hit(P.x,P.y,P.w,P.h,door.x+4,door.y+8,8,24)){\n if(G.hasKey){ if(!door.open){ door.open=true; G.winT=.9; P.vx=0; puff(door.x+8,door.y+16,14,C.papL,60,20); playSfx('win'); } }\n else if(G.doorHint<=0){ G.doorHint=3; showToast('Locked! Find the temple key first.'); playSfx('locked'); }\n }\n}\nfunction stepGame(dt){\n if(G.mode==='win'||G.mode==='over'){ updateEnemies(dt,false); updateFx(dt); return; }\n const inp=(G.mode==='attract'&&typeof botInput==='function')?botInput(dt):keys;\n if(G.winT>0){ G.winT-=dt; if(G.winT<=0) endGame('win'); }\n else if(P.dead>0){ P.vy+=GRAV*dt; P.y+=P.vy*dt; P.dead-=dt; if(P.dead<=0) afterDeath(); }\n else { movePlayer(dt,inp); checkWorld(); }\n updateEnemies(dt, P.dead<=0 && G.winT<=0); updateFx(dt); followCamera(dt);\n if(P.inv>0) P.inv-=dt;\n}\nfunction drawActors(cx,cy,t){\n ctx.drawImage(SP.door[door.open?1:0],door.x-cx,door.y-cy);\n for(const g of gems){ if(g.got) continue; const sx=g.x-cx; if(sx<-12||sx>W+4) continue; const by=Math.round(Math.sin(t*3+g.ph)*1.5);\n ctx.drawImage(SP.gem[g.k],(sx-1)|0,(g.y-cy-1+by)|0); if(((t*1.3+g.ph)%2.2)<.18) ctx.drawImage(SP.spark,(sx+3)|0,(g.y-cy-3+by)|0); }\n if(!keyItem.got){ const by=Math.round(Math.sin(t*2.6)*2); ctx.drawImage(SP.key,(keyItem.x-cx-1)|0,(keyItem.y-cy-1+by)|0); if((t%1.6)<.2) ctx.drawImage(SP.spark,(keyItem.x-cx+8)|0,(keyItem.y-cy-4+by)|0); }\n for(const e of enemies){ if(e.gone) continue; const sx=e.x-cx; if(sx<-24||sx>W+8) continue;\n if(e.dead>0 && ((t*20)|0)%2) continue;\n if(e.t==='snake') ctx.drawImage(SP.snake[(t*6|0)%2][e.dir>0?1:0],(sx-2)|0,(e.y-cy-3+(e.dead>0?3:0))|0);\n else ctx.drawImage(SP.bat[(t*9|0)%2],(sx-3)|0,(e.y-cy-2)|0); }\n if(G.winT<=0 || G.winT>.55) drawPlayer(cx,cy,t);\n}\nG.mode='play'; resetLevel();"}}},{"t":1431125,"name":"aiToolEdit","data":{"toolId":28,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"/* ==ENTITIES== */","newText":"/* ==ENTITIES== */\nlet gems=[], enemies=[], keyItem=null, door=null;\nlet playSfx=function(){}, showToast=function(){}, syncHud=function(){}, endGame=function(kind){ G.mode=kind; };\nconst CHECKPOINTS=[26,47,74];\n// tiny particle pool (hard cap keeps it cheap)\nconst fx=[]; const FX_MAX=48;\nfunction puff(x,y,n,col,spd,up){ for(let i=0;i=0;i--){ const p=fx[i]; p.life-=dt; if(p.life<=0){ fx[i]=fx[fx.length-1]; fx.pop(); continue; } p.vy+=p.g*dt; p.x+=p.vx*dt; p.y+=p.vy*dt; } }\nfunction drawFx(cx,cy){ for(const p of fx){ ctx.fillStyle=p.c; const s=p.life>.25?2:1; ctx.fillRect((p.x-cx)|0,(p.y-cy)|0,s,s); } }\nfunction onJump(){ puff(P.x+4,P.y+P.h,4,C.ivoD,30,10); playSfx('jump'); }\nfunction onLand(){ puff(P.x+4,P.y+P.h,5,C.ivoD,36,14); }\n\nfunction resetLevel(){\n gems=SPAWN.gems.map(g=>({x:g.x,y:g.y,k:g.k,got:false,ph:Math.random()*6}));\n enemies=SPAWN.enemies.map(e=>({t:e.t,x:e.x,y:e.t==='snake'?e.y-8:e.y,y0:e.y,x0:e.x0,x1:e.x1,dir:1,dead:0,ph:Math.random()*6,w:e.t==='snake'?14:12,h:e.t==='snake'?8:7}));\n keyItem={x:SPAWN.key.x,y:SPAWN.key.y,got:false}; door={x:SPAWN.door.x,y:SPAWN.door.y,open:false};\n G.gems=0; G.total=gems.length; G.hasKey=false; G.lives=3; G.winT=0; G.check=-1; G.doorHint=0;\n placePlayer(SPAWN.start.x,SPAWN.start.y); P.inv=0; fx.length=0; followCamera(0,true); syncHud();\n}\nconst hit=(ax,ay,aw,ah,bx,by,bw,bh)=>axbx&&ayby;\nfunction killPlayer(splash){\n if(P.dead>0||P.inv>0||G.winT>0) return;\n P.dead=1.2; P.vy=splash?-90:-250; P.vx=0; playSfx('hurt');\n puff(P.x+4,P.y+8,10,splash?C.waterL:C.pap,70,40);\n if(G.mode==='play'){ G.lives--; syncHud(); }\n}\nfunction afterDeath(){\n if(G.mode==='play' && G.lives<=0){ endGame('over'); return; }\n const c=G.check; placePlayer(c<0?SPAWN.start.x:CHECKPOINTS[c]*T, 9*T+2); P.inv=1.6;\n}\nfunction updateEnemies(dt,alive){\n for(const e of enemies){\n if(e.dead>0){ e.dead-=dt; if(e.dead<=0) e.gone=true; continue; } if(e.gone) continue;\n const sp=e.t==='snake'?26:42; e.x+=e.dir*sp*dt; if(e.xe.x1){ e.x=e.x1-e.w; e.dir=-1; }\n if(e.t==='bat') e.y=e.y0+Math.sin(G.time*2.3+e.ph)*11;\n if(alive && hit(P.x,P.y,P.w,P.h,e.x+1,e.y+1,e.w-2,e.h-1)){\n if(P.vy>40 && P.y+P.h-e.y<9){ e.dead=.35; P.vy=-230; P.inv=Math.max(P.inv,.15); puff(e.x+e.w/2,e.y+4,9,C.papL,60,20); playSfx('stomp'); }\n else killPlayer(false);\n }\n }\n}\nfunction checkWorld(){\n // hazards\n const l=Math.floor((P.x+1)/T), r=Math.floor((P.x+P.w-1)/T), by=P.y+P.h, ty=Math.floor((by-1)/T);\n for(let tx=l;tx<=r;tx++){ const ch=tileAt(tx,ty); if(ch==='^'&&by>ty*T+7){ killPlayer(false); return; } if(ch==='~'&&by>ty*T+10){ killPlayer(true); return; } }\n if(P.y>WORLD_H+24){ killPlayer(true); return; }\n // checkpoints\n if(P.ground) for(let i=CHECKPOINTS.length-1;i>G.check;i--) if(P.x>CHECKPOINTS[i]*T){ G.check=i; break; }\n // pickups\n for(const g of gems){ if(!g.got && hit(P.x,P.y,P.w,P.h,g.x-1,g.y-1,10,10)){ g.got=true; G.gems++; puff(g.x+4,g.y+4,6,g.k?C.ivo:C.papL,55,10); playSfx('gem'); syncHud(); } }\n if(!keyItem.got && hit(P.x,P.y,P.w,P.h,keyItem.x,keyItem.y-2,12,9)){ keyItem.got=true; G.hasKey=true; puff(keyItem.x+6,keyItem.y+2,12,C.ivo,70,10); playSfx('key'); showToast('Key found — the exit is unlocked!'); syncHud(); }\n // exit door\n G.doorHint-=1/60;\n if(hit(P.x,P.y,P.w,P.h,door.x+4,door.y+8,8,24)){\n if(G.hasKey){ if(!door.open){ door.open=true; G.winT=.9; P.vx=0; puff(door.x+8,door.y+16,14,C.papL,60,20); playSfx('win'); } }\n else if(G.doorHint<=0){ G.doorHint=3; showToast('Locked! Find the temple key first.'); playSfx('locked'); }\n }\n}\nfunction stepGame(dt){\n if(G.mode==='win'||G.mode==='over'){ updateEnemies(dt,false); updateFx(dt); return; }\n const inp=(G.mode==='attract'&&typeof botInput==='function')?botInput(dt):keys;\n if(G.winT>0){ G.winT-=dt; if(G.winT<=0) endGame('win'); }\n else if(P.dead>0){ P.vy+=GRAV*dt; P.y+=P.vy*dt; P.dead-=dt; if(P.dead<=0) afterDeath(); }\n else { movePlayer(dt,inp); checkWorld(); }\n updateEnemies(dt, P.dead<=0 && G.winT<=0); updateFx(dt); followCamera(dt);\n if(P.inv>0) P.inv-=dt;\n}\nfunction drawActors(cx,cy,t){\n ctx.drawImage(SP.door[door.open?1:0],door.x-cx,door.y-cy);\n for(const g of gems){ if(g.got) continue; const sx=g.x-cx; if(sx<-12||sx>W+4) continue; const by=Math.round(Math.sin(t*3+g.ph)*1.5);\n ctx.drawImage(SP.gem[g.k],(sx-1)|0,(g.y-cy-1+by)|0); if(((t*1.3+g.ph)%2.2)<.18) ctx.drawImage(SP.spark,(sx+3)|0,(g.y-cy-3+by)|0); }\n if(!keyItem.got){ const by=Math.round(Math.sin(t*2.6)*2); ctx.drawImage(SP.key,(keyItem.x-cx-1)|0,(keyItem.y-cy-1+by)|0); if((t%1.6)<.2) ctx.drawImage(SP.spark,(keyItem.x-cx+8)|0,(keyItem.y-cy-4+by)|0); }\n for(const e of enemies){ if(e.gone) continue; const sx=e.x-cx; if(sx<-24||sx>W+8) continue;\n if(e.dead>0 && ((t*20)|0)%2) continue;\n if(e.t==='snake') ctx.drawImage(SP.snake[(t*6|0)%2][e.dir>0?1:0],(sx-2)|0,(e.y-cy-3+(e.dead>0?3:0))|0);\n else ctx.drawImage(SP.bat[(t*9|0)%2],(sx-3)|0,(e.y-cy-2)|0); }\n if(G.winT<=0 || G.winT>.55) drawPlayer(cx,cy,t);\n}\nG.mode='play'; resetLevel();","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1431129,"name":"aiToolResult","data":{"toolId":28,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1434615,"name":"aiTextStream","data":{"text":"\n\nW"}},{"t":1434615,"name":"aiTextStream","data":{"text":"iring the player and entities together now — fixing initialization order, then a milestone screenshot."}},{"t":1434618,"name":"aiProgress","data":{"toolName":"Edit","toolId":29,"phase":"tool_use"}},{"t":1434737,"name":"aiToolStream","data":{"toolId":29,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1435214,"name":"aiToolStream","data":{"toolId":29,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-temple.html\", \"old_string\": \" if(G.win"}},{"t":1435483,"name":"aiToolStream","data":{"toolId":29,"toolName":"Edit","append":"T<=0 || G.winT>.55) drawPlayer(cx,cy,t);\\n}"}},{"t":1435867,"name":"aiToolStream","data":{"toolId":29,"toolName":"Edit","append":"\\nG.mode='play'; resetLevel();\", \"new_string\": \" if(G.winT<=0 || G.winT>.55)"}},{"t":1436176,"name":"aiToolStream","data":{"toolId":29,"toolName":"Edit","append":" drawPlayer(cx,cy,t);\\n}"}},{"t":1436512,"name":"aiToolStream","data":{"toolId":29,"toolName":"Edit","append":"\"}"}},{"t":1436525,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":29,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":" if(G.winT<=0 || G.winT>.55) drawPlayer(cx,cy,t);\n}\nG.mode='play'; resetLevel();","new_string":" if(G.winT<=0 || G.winT>.55) drawPlayer(cx,cy,t);\n}"}}},{"t":1436527,"name":"aiProgress","data":{"toolName":"Edit","toolId":30,"phase":"tool_use"}},{"t":1436580,"name":"aiToolEdit","data":{"toolId":29,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":" if(G.winT<=0 || G.winT>.55) drawPlayer(cx,cy,t);\n}\nG.mode='play'; resetLevel();","newText":" if(G.winT<=0 || G.winT>.55) drawPlayer(cx,cy,t);\n}","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1436580,"name":"aiToolResult","data":{"toolId":29,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1436617,"name":"aiToolStream","data":{"toolId":30,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1436869,"name":"aiToolStream","data":{"toolId":30,"toolName":"Edit","append":"{{PROJECT}}"}},{"t":1437173,"name":"aiToolStream","data":{"toolId":30,"toolName":"Edit","append":"/dave-jungle-temple.html"}},{"t":1437430,"name":"aiToolStream","data":{"toolId":30,"toolName":"Edit","append":"\", \"old_string\": \"document.addEventListener('visibilitychange', () => document.hidden ? stop() : start());\\nstart();"}},{"t":1437863,"name":"aiToolStream","data":{"toolId":30,"toolName":"Edit","append":"\", \"new_string\": \"document.addEventListener('visibilitychange', () => document.hidden ? stop()"}},{"t":1438120,"name":"aiToolStream","data":{"toolId":30,"toolName":"Edit","append":" : start());\\n/* ==BOOT== */\\nG.mode='play'; resetLevel();\\nstart();"}},{"t":1438552,"name":"aiToolStream","data":{"toolId":30,"toolName":"Edit","append":"\"}"}},{"t":1438563,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":30,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"document.addEventListener('visibilitychange', () => document.hidden ? stop() : start());\nstart();","new_string":"document.addEventListener('visibilitychange', () => document.hidden ? stop() : start());\n/* ==BOOT== */\nG.mode='play'; resetLevel();\nstart();"}}},{"t":1438565,"name":"aiProgress","data":{"toolName":"Edit","toolId":31,"phase":"tool_use"}},{"t":1438614,"name":"aiToolEdit","data":{"toolId":30,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"document.addEventListener('visibilitychange', () => document.hidden ? stop() : start());\nstart();","newText":"document.addEventListener('visibilitychange', () => document.hidden ? stop() : start());\n/* ==BOOT== */\nG.mode='play'; resetLevel();\nstart();","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1438615,"name":"aiToolResult","data":{"toolId":30,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1438679,"name":"aiToolStream","data":{"toolId":31,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1438988,"name":"aiToolStream","data":{"toolId":31,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-"}},{"t":1439251,"name":"aiToolStream","data":{"toolId":31,"toolName":"Edit","append":"temple.html\", \"old_string\": \"const y=6+Math.round(Math.s"}},{"t":1439554,"name":"aiToolStream","data":{"toolId":31,"toolName":"Edit","append":"in(x*.95+f*Math.PI)*1.5); px(g,C.papD,x,y,1,3);"}},{"t":1439989,"name":"aiToolStream","data":{"toolId":31,"toolName":"Edit","append":"\", \"new_string\": \"const y=5+Math.round(Math.sin(x*.95+f*Math.PI)"}},{"t":1440240,"name":"aiToolStream","data":{"toolId":31,"toolName":"Edit","append":"*1.5); px(g,C.papD,x,y,1,3);"}},{"t":1440616,"name":"aiToolStream","data":{"toolId":31,"toolName":"Edit","append":"\"}"}},{"t":1440628,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":31,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"const y=6+Math.round(Math.sin(x*.95+f*Math.PI)*1.5); px(g,C.papD,x,y,1,3);","new_string":"const y=5+Math.round(Math.sin(x*.95+f*Math.PI)*1.5); px(g,C.papD,x,y,1,3);"}}},{"t":1440631,"name":"aiProgress","data":{"toolName":"Edit","toolId":32,"phase":"tool_use"}},{"t":1440683,"name":"aiToolEdit","data":{"toolId":31,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"const y=6+Math.round(Math.sin(x*.95+f*Math.PI)*1.5); px(g,C.papD,x,y,1,3);","newText":"const y=5+Math.round(Math.sin(x*.95+f*Math.PI)*1.5); px(g,C.papD,x,y,1,3);","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1440684,"name":"aiToolResult","data":{"toolId":31,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1440740,"name":"aiToolStream","data":{"toolId":32,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1441075,"name":"aiToolStream","data":{"toolId":32,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-"}},{"t":1441345,"name":"aiToolStream","data":{"toolId":32,"toolName":"Edit","append":"temple.html\", \"old_string\": \" const bob=(P.ground&&Math"}},{"t":1441616,"name":"aiToolStream","data":{"toolId":32,"toolName":"Edit","append":".abs(P.vx)<=12&&((t*2.2)|0)%2)?1:0;\\n ctx.draw"}},{"t":1441928,"name":"aiToolStream","data":{"toolId":32,"toolName":"Edit","append":"Image(s,Math.round(P.x-cx)-3,Math.round(P.y-cy)-3+bob);"}},{"t":1442601,"name":"aiToolStream","data":{"toolId":32,"toolName":"Edit","append":"\", \"new_string\": \" ctx.drawImage(s,Math.round(P.x-cx)-3,Math.round(P.y-cy)-3);\"}"}},{"t":1442857,"name":"aiToolStream","data":{"toolId":32,"toolName":"Edit","append":""}},{"t":1442858,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":32,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":" const bob=(P.ground&&Math.abs(P.vx)<=12&&((t*2.2)|0)%2)?1:0;\n ctx.drawImage(s,Math.round(P.x-cx)-3,Math.round(P.y-cy)-3+bob);","new_string":" ctx.drawImage(s,Math.round(P.x-cx)-3,Math.round(P.y-cy)-3);"}}},{"t":1442905,"name":"aiToolEdit","data":{"toolId":32,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":" const bob=(P.ground&&Math.abs(P.vx)<=12&&((t*2.2)|0)%2)?1:0;\n ctx.drawImage(s,Math.round(P.x-cx)-3,Math.round(P.y-cy)-3+bob);","newText":" ctx.drawImage(s,Math.round(P.x-cx)-3,Math.round(P.y-cy)-3);","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1442907,"name":"aiToolResult","data":{"toolId":32,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1444103,"name":"aiProgress","data":{"toolName":"TaskUpdate","toolId":33,"phase":"tool_use"}},{"t":1444702,"name":"aiToolStream","data":{"toolId":33,"toolName":"TaskUpdate","append":"{\"taskId\": \"3\", \"status\": \"completed\"}"}},{"t":1444704,"name":"aiToolInfo","data":{"toolName":"TaskUpdate","toolId":33,"toolInput":{"taskId":"3","status":"completed"}}},{"t":1444704,"name":"aiProgress","data":{"toolName":"TaskUpdate","toolId":34,"phase":"tool_use"}},{"t":1444708,"name":"aiToolResult","data":{"toolId":33,"isError":false,"preview":"Updated task #3 status"}},{"t":1444781,"name":"aiToolStream","data":{"toolId":34,"toolName":"TaskUpdate","append":"{\"taskId\": \"4"}},{"t":1445348,"name":"aiToolStream","data":{"toolId":34,"toolName":"TaskUpdate","append":"\", \"status\": \"in_progress\"}"}},{"t":1445351,"name":"aiToolInfo","data":{"toolName":"TaskUpdate","toolId":34,"toolInput":{"taskId":"4","status":"in_progress"}}},{"t":1445354,"name":"aiProgress","data":{"toolName":"mcp__phoenix-editor__takeScreenshot","toolId":35,"phase":"tool_use"}},{"t":1445355,"name":"aiToolResult","data":{"toolId":34,"isError":false,"preview":"Updated task #4 status"}},{"t":1445407,"name":"aiToolStream","data":{"toolId":35,"toolName":"mcp__phoenix-editor__takeScreenshot","append":"{\"selector\": \"#panel-live-preview-frame"}},{"t":1445720,"name":"aiToolStream","data":{"toolId":35,"toolName":"mcp__phoenix-editor__takeScreenshot","append":"\", \"purePreview\": true, \"reload\": true"}},{"t":1446002,"name":"aiToolStream","data":{"toolId":35,"toolName":"mcp__phoenix-editor__takeScreenshot","append":"}"}},{"t":1446004,"name":"aiToolInfo","data":{"toolName":"mcp__phoenix-editor__takeScreenshot","toolId":35,"toolInput":{"selector":"#panel-live-preview-frame","purePreview":true,"reload":true}}},{"t":1446842,"name":"aiToolResult","data":{"toolId":35,"isError":false,"preview":""}},{"t":1528650,"name":"aiProgress","data":{"toolName":"TaskUpdate","toolId":36,"phase":"tool_use"}},{"t":1528752,"name":"aiToolStream","data":{"toolId":36,"toolName":"TaskUpdate","append":"{\"taskId\": \"4\", \"status\": \"completed"}},{"t":1529186,"name":"aiToolStream","data":{"toolId":36,"toolName":"TaskUpdate","append":"\"}"}},{"t":1529191,"name":"aiToolInfo","data":{"toolName":"TaskUpdate","toolId":36,"toolInput":{"taskId":"4","status":"completed"}}},{"t":1529195,"name":"aiProgress","data":{"toolName":"TaskUpdate","toolId":37,"phase":"tool_use"}},{"t":1529197,"name":"aiToolResult","data":{"toolId":36,"isError":false,"preview":"Updated task #4 status"}},{"t":1529315,"name":"aiToolStream","data":{"toolId":37,"toolName":"TaskUpdate","append":"{\"taskId\": \"5\", \"status\": \"in_progress"}},{"t":1529629,"name":"aiToolStream","data":{"toolId":37,"toolName":"TaskUpdate","append":"\"}"}},{"t":1529631,"name":"aiToolInfo","data":{"toolName":"TaskUpdate","toolId":37,"toolInput":{"taskId":"5","status":"in_progress"}}},{"t":1529635,"name":"aiToolResult","data":{"toolId":37,"isError":false,"preview":"Updated task #5 status"}},{"t":1531219,"name":"aiProgress","data":{"toolName":"Edit","toolId":38,"phase":"tool_use"}},{"t":1531835,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1532468,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-temple.html\", \"old_string\": \"/* ==UPDATE== */\", \"new_string\": \"/* ==ATTRACT MODE BOT== */\\n// A tiny scripted runner: always heads right, h"}},{"t":1533088,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"ops walls, gaps, spikes, water and snakes.\\nconst bot={jumpT:0,air:false,stuck:0,lastX:0,restart:0};\\nfunction botInput(dt){"}},{"t":1533393,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"\\n const inp={left:false,right:true,jump:"}},{"t":1533713,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"false};\\n if(bot.restart>0){ bot.restart-=dt; inp.right=false; if(bot.restart<=0) startAttract(); return inp"}},{"t":1534008,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"; }\\n if(P.dead>0) return inp;\\n bot.jumpT-=dt;"}},{"t":1534373,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"\\n const front=P.x+P.w, feet=P.y+P.h;\\n if(P.ground){\\n if(bot.j"}},{"t":1534633,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"umpT>0&&bot.air) bot.jumpT=0; bot.air=false;\\n const col=Math.floor(("}},{"t":1534893,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"front+6)/T), row=Math.floor((feet-2)/T), t0=tileAt(col,row); let need=false;"}},{"t":1535198,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"\\n if(isSolid(t0)||t0==='^') need=true;\\n else { let safe=false"}},{"t":1535474,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"; for(let r=row+1;r<=row+3;r++){ const ch=tileAt(col,r); if(ch==='"}},{"t":1535760,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":" ') continue; safe=isSolid(ch)||ch==='-'; break; } need"}},{"t":1536021,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"=!safe; }\\n for(const e of enemies){ if(e.gone||e.dead>0)"}},{"t":1536337,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":" continue; const dx=e.x-front; if(dx>-6&&dx<("}},{"t":1536590,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"e.dir<0?34:20)&&Math.abs(e.y+e.h-feet)<14) need"}},{"t":1536899,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"=true; }\\n if(need&&bot.jumpT<=0&&!P.prevJump) bot.jumpT=."}},{"t":1537212,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"4;\\n } else bot.air=true;\\n inp.jump=bot.jumpT>0;\\n // failsafe: if"}},{"t":1537465,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":" wedged somewhere, hop;"}},{"t":1537718,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":" if hopeless, restart the demo\\n if(Math.abs(P.x-b"}},{"t":1538003,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"ot.lastX)>3){ bot.lastX=P.x; bot.stuck=0;"}},{"t":1538275,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":" } else { bot.stuck+=dt; if(bot.stuck>1.2&&P.ground"}},{"t":1538568,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"&&!P.prevJump) inp.jump=true; if(bot.stu"}},{"t":1539283,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"ck>6) startAttract"}},{"t":1539564,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"(); }\\n return inp;\\n}\\nfunction startAttract(){ G.mode='attract'; bot.jumpT=0; bot.stuck=0; bot.restart=0; bot.air=false; resetLevel(); if"}},{"t":1539924,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"(typeof syncUi==='function') syncUi(); }\\nfunction takeControl(){ if(G.mode!=='attract') return; G.mode='play'; resetLevel(); if(typeof syncUi==='function') sync"}},{"t":1540202,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"Ui(); }\\nfunction restartIfEnded(){ if(G.mode!=='win'&&G.mode!=='over') return false; G.mode='play'; resetLevel(); if(type"}},{"t":1540455,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"of syncUi==='function') syncUi(); return true; }\\nendGame=function(kind){\\n if"}},{"t":1540767,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"(G.mode==='attract'){ bot.restart=1.6; G.winT=0; return; } // demo just"}},{"t":1541029,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":" loops\\n G.mode=kind; playSfx(kind==='win'?'f"}},{"t":1541328,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"anfare':'over'); if(typeof syncUi==='function') syncUi();\\n};"}},{"t":1541581,"name":"aiToolStream","data":{"toolId":38,"toolName":"Edit","append":"\\n\\n/* ==UPDATE== */\"}"}},{"t":1541769,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":38,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"/* ==UPDATE== */","new_string":"/* ==ATTRACT MODE BOT== */\n// A tiny scripted runner: always heads right, hops walls, gaps, spikes, water and snakes.\nconst bot={jumpT:0,air:false,stuck:0,lastX:0,restart:0};\nfunction botInput(dt){\n const inp={left:false,right:true,jump:false};\n if(bot.restart>0){ bot.restart-=dt; inp.right=false; if(bot.restart<=0) startAttract(); return inp; }\n if(P.dead>0) return inp;\n bot.jumpT-=dt;\n const front=P.x+P.w, feet=P.y+P.h;\n if(P.ground){\n if(bot.jumpT>0&&bot.air) bot.jumpT=0; bot.air=false;\n const col=Math.floor((front+6)/T), row=Math.floor((feet-2)/T), t0=tileAt(col,row); let need=false;\n if(isSolid(t0)||t0==='^') need=true;\n else { let safe=false; for(let r=row+1;r<=row+3;r++){ const ch=tileAt(col,r); if(ch===' ') continue; safe=isSolid(ch)||ch==='-'; break; } need=!safe; }\n for(const e of enemies){ if(e.gone||e.dead>0) continue; const dx=e.x-front; if(dx>-6&&dx<(e.dir<0?34:20)&&Math.abs(e.y+e.h-feet)<14) need=true; }\n if(need&&bot.jumpT<=0&&!P.prevJump) bot.jumpT=.4;\n } else bot.air=true;\n inp.jump=bot.jumpT>0;\n // failsafe: if wedged somewhere, hop; if hopeless, restart the demo\n if(Math.abs(P.x-bot.lastX)>3){ bot.lastX=P.x; bot.stuck=0; } else { bot.stuck+=dt; if(bot.stuck>1.2&&P.ground&&!P.prevJump) inp.jump=true; if(bot.stuck>6) startAttract(); }\n return inp;\n}\nfunction startAttract(){ G.mode='attract'; bot.jumpT=0; bot.stuck=0; bot.restart=0; bot.air=false; resetLevel(); if(typeof syncUi==='function') syncUi(); }\nfunction takeControl(){ if(G.mode!=='attract') return; G.mode='play'; resetLevel(); if(typeof syncUi==='function') syncUi(); }\nfunction restartIfEnded(){ if(G.mode!=='win'&&G.mode!=='over') return false; G.mode='play'; resetLevel(); if(typeof syncUi==='function') syncUi(); return true; }\nendGame=function(kind){\n if(G.mode==='attract'){ bot.restart=1.6; G.winT=0; return; } // demo just loops\n G.mode=kind; playSfx(kind==='win'?'fanfare':'over'); if(typeof syncUi==='function') syncUi();\n};\n\n/* ==UPDATE== */"}}},{"t":1541831,"name":"aiToolEdit","data":{"toolId":38,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"/* ==UPDATE== */","newText":"/* ==ATTRACT MODE BOT== */\n// A tiny scripted runner: always heads right, hops walls, gaps, spikes, water and snakes.\nconst bot={jumpT:0,air:false,stuck:0,lastX:0,restart:0};\nfunction botInput(dt){\n const inp={left:false,right:true,jump:false};\n if(bot.restart>0){ bot.restart-=dt; inp.right=false; if(bot.restart<=0) startAttract(); return inp; }\n if(P.dead>0) return inp;\n bot.jumpT-=dt;\n const front=P.x+P.w, feet=P.y+P.h;\n if(P.ground){\n if(bot.jumpT>0&&bot.air) bot.jumpT=0; bot.air=false;\n const col=Math.floor((front+6)/T), row=Math.floor((feet-2)/T), t0=tileAt(col,row); let need=false;\n if(isSolid(t0)||t0==='^') need=true;\n else { let safe=false; for(let r=row+1;r<=row+3;r++){ const ch=tileAt(col,r); if(ch===' ') continue; safe=isSolid(ch)||ch==='-'; break; } need=!safe; }\n for(const e of enemies){ if(e.gone||e.dead>0) continue; const dx=e.x-front; if(dx>-6&&dx<(e.dir<0?34:20)&&Math.abs(e.y+e.h-feet)<14) need=true; }\n if(need&&bot.jumpT<=0&&!P.prevJump) bot.jumpT=.4;\n } else bot.air=true;\n inp.jump=bot.jumpT>0;\n // failsafe: if wedged somewhere, hop; if hopeless, restart the demo\n if(Math.abs(P.x-bot.lastX)>3){ bot.lastX=P.x; bot.stuck=0; } else { bot.stuck+=dt; if(bot.stuck>1.2&&P.ground&&!P.prevJump) inp.jump=true; if(bot.stuck>6) startAttract(); }\n return inp;\n}\nfunction startAttract(){ G.mode='attract'; bot.jumpT=0; bot.stuck=0; bot.restart=0; bot.air=false; resetLevel(); if(typeof syncUi==='function') syncUi(); }\nfunction takeControl(){ if(G.mode!=='attract') return; G.mode='play'; resetLevel(); if(typeof syncUi==='function') syncUi(); }\nfunction restartIfEnded(){ if(G.mode!=='win'&&G.mode!=='over') return false; G.mode='play'; resetLevel(); if(typeof syncUi==='function') syncUi(); return true; }\nendGame=function(kind){\n if(G.mode==='attract'){ bot.restart=1.6; G.winT=0; return; } // demo just loops\n G.mode=kind; playSfx(kind==='win'?'fanfare':'over'); if(typeof syncUi==='function') syncUi();\n};\n\n/* ==UPDATE== */","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1541834,"name":"aiToolResult","data":{"toolId":38,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1548832,"name":"aiProgress","data":{"toolName":"Edit","toolId":39,"phase":"tool_use"}},{"t":1548957,"name":"aiToolStream","data":{"toolId":39,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1549208,"name":"aiToolStream","data":{"toolId":39,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-temple.html"}},{"t":1549704,"name":"aiToolStream","data":{"toolId":39,"toolName":"Edit","append":"\", \"old_string\": \" if(G.winT>0){ G.winT-=dt; if(G.winT<=0) endGame('win'); }"}},{"t":1550023,"name":"aiToolStream","data":{"toolId":39,"toolName":"Edit","append":"\", \"new_string\": \" if(G.winT>0){ G.winT-=dt; if(G.winT"}},{"t":1550274,"name":"aiToolStream","data":{"toolId":39,"toolName":"Edit","append":"<=0){ G.inDoor=true; endGame('win'); } }"}},{"t":1550652,"name":"aiToolStream","data":{"toolId":39,"toolName":"Edit","append":"\"}"}},{"t":1550665,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":39,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":" if(G.winT>0){ G.winT-=dt; if(G.winT<=0) endGame('win'); }","new_string":" if(G.winT>0){ G.winT-=dt; if(G.winT<=0){ G.inDoor=true; endGame('win'); } }"}}},{"t":1550668,"name":"aiProgress","data":{"toolName":"Edit","toolId":40,"phase":"tool_use"}},{"t":1550718,"name":"aiToolEdit","data":{"toolId":39,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":" if(G.winT>0){ G.winT-=dt; if(G.winT<=0) endGame('win'); }","newText":" if(G.winT>0){ G.winT-=dt; if(G.winT<=0){ G.inDoor=true; endGame('win'); } }","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1550721,"name":"aiToolResult","data":{"toolId":39,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1550779,"name":"aiToolStream","data":{"toolId":40,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1551087,"name":"aiToolStream","data":{"toolId":40,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-temple.html"}},{"t":1551402,"name":"aiToolStream","data":{"toolId":40,"toolName":"Edit","append":"\", \"old_string\": \" if(G.winT<=0 || G.winT>.55) drawPlayer(cx,"}},{"t":1551652,"name":"aiToolStream","data":{"toolId":40,"toolName":"Edit","append":"cy,t);\", \"new_string\": \" if(!G"}},{"t":1551903,"name":"aiToolStream","data":{"toolId":40,"toolName":"Edit","append":".inDoor && (G.winT<=0 || G.winT>.55)) drawPlayer("}},{"t":1552155,"name":"aiToolStream","data":{"toolId":40,"toolName":"Edit","append":"cx,cy,t);"}},{"t":1552407,"name":"aiToolStream","data":{"toolId":40,"toolName":"Edit","append":"\"}"}},{"t":1552420,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":40,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":" if(G.winT<=0 || G.winT>.55) drawPlayer(cx,cy,t);","new_string":" if(!G.inDoor && (G.winT<=0 || G.winT>.55)) drawPlayer(cx,cy,t);"}}},{"t":1552423,"name":"aiProgress","data":{"toolName":"Edit","toolId":41,"phase":"tool_use"}},{"t":1552474,"name":"aiToolEdit","data":{"toolId":40,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":" if(G.winT<=0 || G.winT>.55) drawPlayer(cx,cy,t);","newText":" if(!G.inDoor && (G.winT<=0 || G.winT>.55)) drawPlayer(cx,cy,t);","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1552475,"name":"aiToolResult","data":{"toolId":40,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1552532,"name":"aiToolStream","data":{"toolId":41,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1552784,"name":"aiToolStream","data":{"toolId":41,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-temple.html"}},{"t":1553158,"name":"aiToolStream","data":{"toolId":41,"toolName":"Edit","append":"\", \"old_string\": \" G.gems=0; G.total=gems.length; G.hasKey=false; G.lives=3; G.win"}},{"t":1553469,"name":"aiToolStream","data":{"toolId":41,"toolName":"Edit","append":"T=0; G.check=-1; G.doorHint=0;"}},{"t":1553795,"name":"aiToolStream","data":{"toolId":41,"toolName":"Edit","append":"\", \"new_string\": \" G.gems=0; G.total=gems.length; G.hasKey=false; G.lives=3; G.winT="}},{"t":1554109,"name":"aiToolStream","data":{"toolId":41,"toolName":"Edit","append":"0; G.check=-1; G.doorHint=0; G.inDoor"}},{"t":1554494,"name":"aiToolStream","data":{"toolId":41,"toolName":"Edit","append":"=false;\"}"}},{"t":1554624,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":41,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":" G.gems=0; G.total=gems.length; G.hasKey=false; G.lives=3; G.winT=0; G.check=-1; G.doorHint=0;","new_string":" G.gems=0; G.total=gems.length; G.hasKey=false; G.lives=3; G.winT=0; G.check=-1; G.doorHint=0; G.inDoor=false;"}}},{"t":1554625,"name":"aiProgress","data":{"toolName":"Edit","toolId":42,"phase":"tool_use"}},{"t":1554670,"name":"aiToolEdit","data":{"toolId":41,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":" G.gems=0; G.total=gems.length; G.hasKey=false; G.lives=3; G.winT=0; G.check=-1; G.doorHint=0;","newText":" G.gems=0; G.total=gems.length; G.hasKey=false; G.lives=3; G.winT=0; G.check=-1; G.doorHint=0; G.inDoor=false;","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1554670,"name":"aiToolResult","data":{"toolId":41,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1554688,"name":"aiToolStream","data":{"toolId":42,"toolName":"Edit","append":"{\"file_path\": \"{{PROJECT}}"}},{"t":1554991,"name":"aiToolStream","data":{"toolId":42,"toolName":"Edit","append":"/dave-jungle-temple.html\", \"old_string\": \" SPAWN"}},{"t":1555289,"name":"aiToolStream","data":{"toolId":42,"toolName":"Edit","append":".enemies.push({t:'snake',x:67*T,y:10*T,x0:65*T,x1:71*T"}},{"t":1555605,"name":"aiToolStream","data":{"toolId":42,"toolName":"Edit","append":"});\\n SPAWN.enemies.push({t:'bat',x:50*T,y:6*T,x0:47*T,"}},{"t":1555925,"name":"aiToolStream","data":{"toolId":42,"toolName":"Edit","append":"x1:53*T});\", \"new_string\": \" SPAWN.enemies."}},{"t":1556223,"name":"aiToolStream","data":{"toolId":42,"toolName":"Edit","append":"push({t:'snake',x:69*T,y:10*T,x0:67*T,x1:72*"}},{"t":1556478,"name":"aiToolStream","data":{"toolId":42,"toolName":"Edit","append":"T});\\n SPAWN.enemies.push({t:'bat',x:50*T,y:6*T,x0:49*T"}},{"t":1556787,"name":"aiToolStream","data":{"toolId":42,"toolName":"Edit","append":",x1:53*T});"}},{"t":1557041,"name":"aiToolStream","data":{"toolId":42,"toolName":"Edit","append":"\"}"}},{"t":1557053,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":42,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":" SPAWN.enemies.push({t:'snake',x:67*T,y:10*T,x0:65*T,x1:71*T});\n SPAWN.enemies.push({t:'bat',x:50*T,y:6*T,x0:47*T,x1:53*T});","new_string":" SPAWN.enemies.push({t:'snake',x:69*T,y:10*T,x0:67*T,x1:72*T});\n SPAWN.enemies.push({t:'bat',x:50*T,y:6*T,x0:49*T,x1:53*T});"}}},{"t":1557056,"name":"aiProgress","data":{"toolName":"Edit","toolId":43,"phase":"tool_use"}},{"t":1557118,"name":"aiToolEdit","data":{"toolId":42,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":" SPAWN.enemies.push({t:'snake',x:67*T,y:10*T,x0:65*T,x1:71*T});\n SPAWN.enemies.push({t:'bat',x:50*T,y:6*T,x0:47*T,x1:53*T});","newText":" SPAWN.enemies.push({t:'snake',x:69*T,y:10*T,x0:67*T,x1:72*T});\n SPAWN.enemies.push({t:'bat',x:50*T,y:6*T,x0:49*T,x1:53*T});","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1557119,"name":"aiToolResult","data":{"toolId":42,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1557163,"name":"aiToolStream","data":{"toolId":43,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1557473,"name":"aiToolStream","data":{"toolId":43,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-"}},{"t":1557723,"name":"aiToolStream","data":{"toolId":43,"toolName":"Edit","append":"temple.html\", \"old_string\": \"G.mode='play"}},{"t":1557979,"name":"aiToolStream","data":{"toolId":43,"toolName":"Edit","append":"'; resetLevel();\\nstart();"}},{"t":1558254,"name":"aiToolStream","data":{"toolId":43,"toolName":"Edit","append":"\", \"new_string\": \"startAttract();\\nstart();\"}"}},{"t":1558406,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":43,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"G.mode='play'; resetLevel();\nstart();","new_string":"startAttract();\nstart();"}}},{"t":1558457,"name":"aiToolEdit","data":{"toolId":43,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"G.mode='play'; resetLevel();\nstart();","newText":"startAttract();\nstart();","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1558460,"name":"aiToolResult","data":{"toolId":43,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1560719,"name":"aiTextStream","data":{"text":"\n\nNow the HU"}},{"t":1560720,"name":"aiTextStream","data":{"text":"D, prompt, overlays and touch controls markup."}},{"t":1560723,"name":"aiProgress","data":{"toolName":"Edit","toolId":44,"phase":"tool_use"}},{"t":1560724,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"{\"file_path\": \"{{PROJECT}}/dave-jungle"}},{"t":1561349,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"-temple.html\", \"old_string\": \"
\\n

Dave & the Papaya Temple

\\n
\\n
\\n \\n
\", \"new_string\": \"
\\n
\\n \\n

Dave "}},{"t":1562639,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"& the Papaya Temple

\\n
\\n "}},{"t":1563758,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"\\n
\\n\\n
\\n \\n
\\n
0"}},{"t":1564596,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"/0
\\n
No key
\\n "}},{"t":1565158,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"
\\n \\n
Demo
\\n "}},{"t":1565722,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"
Press any key to play
\\n "}},{"t":1565973,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"
\\n "}},{"t":1567721,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"\\n
\\n\\n
\\n
\\n \\n
\\n

←"}},{"t":1569219,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":" → / A D move · "}},{"t":1569470,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"Space jump · M sound

\\n \\n \\n
\\n
"}},{"t":1570284,"name":"aiToolStream","data":{"toolId":44,"toolName":"Edit","append":"\"}"}},{"t":1570296,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":44,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"
\n

Dave & the Papaya Temple

\n
\n
\n \n
","new_string":"
\n
\n \n

Dave & the Papaya Temple

\n
\n \n
\n\n
\n \n
\n
0/0
\n
No key
\n
\n
\n
Demo
\n
Press any key to play
\n
\n \n
\n\n
\n
\n \n \n
\n

← → / A D move · Space jump · M sound

\n
\n \n
\n
"}}},{"t":1570361,"name":"aiToolEdit","data":{"toolId":44,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"
\n

Dave & the Papaya Temple

\n
\n
\n \n
","newText":"
\n
\n \n

Dave & the Papaya Temple

\n
\n \n
\n\n
\n \n
\n
0/0
\n
No key
\n
\n
\n
Demo
\n
Press any key to play
\n
\n \n
\n\n
\n
\n \n \n
\n

← → / A D move · Space jump · M sound

\n
\n \n
\n
","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1570364,"name":"aiToolResult","data":{"toolId":44,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1571618,"name":"aiProgress","data":{"toolName":"Edit","toolId":45,"phase":"tool_use"}},{"t":1572247,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"{\"file_path\": \""}},{"t":1572865,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"{{PROJECT}}/dave-jungle-temple.html\", \"old_string\": \" canvas#game{\\n width:100%; height:100%; display:block;\\n image-rendering:pixelated; image-rendering:crisp-edges;\\n }\", \"new_string\": \" canvas#game{\\n width:"}},{"t":1573115,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"100%; height:100%;"}},{"t":1573881,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":" display:block;\\n image-"}},{"t":1574380,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"rendering:crisp-edges; image-rendering:pixelated;\\n }\\n body{\\n background:\\n radial-gradient(120% 80% at 50% 0%, #12382a 0%, transparent 60%),"}},{"t":1574764,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"\\n radial-gradient(90% 60% at 50% 110%, rgba(226,97,42,.16) 0%, transparent 60%),\\n var(--leaf-900);\\n }\\n .shell{max-width:1500px}\\n .top, .pad{width:min(96vw, calc((100vh - 170px)"}},{"t":1575145,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":" * 16 / 9)); display:flex; align-items:center; justify-content:space-between; gap:12px}\\n .brand{display:flex"}},{"t":1575531,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"; align-items:center; gap:10px; min-width:0}\\n .leaf{width:14px; height:14px; flex:"}},{"t":1575918,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"none; background:var(--papaya); border-radius:0 70% 0 70"}},{"t":1576627,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"%; box-shadow:"}},{"t":1577119,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"inset -3px -3px 0 var(--papaya-deep)}\\n h1{font-size:clamp(14px,2.2vw,22px); letter-spacing:.06em; text-transform:uppercase; font-weight:800; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}\\n "}},{"t":1577390,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"h1 em{font-style:normal; color:var(--papaya)}\\n .pill{\\n font:inherit; font-size:12"}},{"t":1577665,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"px; letter-spacing:.08em; text-transform:u"}},{"t":1577980,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ppercase; color:var(--ivory);\\n background:rgba(251,243,223,.06); border:1px solid r"}},{"t":1578269,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"gba(251,243,223"}},{"t":1578923,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":",.22); border-radius:999px;\\n padding"}},{"t":1579235,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":":7px 12px; display:inline-flex; align-items"}},{"t":1579884,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":":center; gap:8px; cursor:pointer; flex:none;\\n transition:background .2s, border-color .2s, transform .15s;\\n }\\n .pill:hover{background:rgba(251,243,223,.12); border-color:var(--papaya-soft)}\\n .pill:active{transform:scale(.96)}\\n .pill .dot{width:8px; height:8px; border-radius:50%; background:var(--ivory-dim); transition:background .2"}},{"t":1580261,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"s, box-shadow .2s}\\n .pill[aria-pressed=\\\"true\\\"] .dot{background:var(--papaya); box-shadow:0 0 0 3"}},{"t":1581221,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"px rgba(255,138,61,.25)}\\n .stage{\\n box-shadow:0 0 0 2px #"}},{"t":1581606,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"1b4a33, 0 0 0 5px var(--leaf-800), 0 24px 60px -18px rgba(0,0,0,.8);\\n touch-action:none"}},{"t":1581980,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"; user-select:none; -webkit-user-select:none;\\n }\\n .stage::after{ /* soft vignette,"}},{"t":1582343,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":" one static layer */\\n content:\\\"\\\"; position:absolute; inset:0; pointer-events:none;\\n background:radial-gradient("}},{"t":1582719,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ellipse at center, transparent 58%, rgba(3,12"}},{"t":1583102,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":",8,.5) 100%);\\n }\\n .hud{position:absolute; z-index:2; top"}},{"t":1583486,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":":2.2%; left:1.6%; right:1.6%; display:flex; g"}},{"t":1583742,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ap:1.2%; align-items:center; pointer-events:none}\\n .ch"}},{"t":1584077,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ip{\\n display:flex; align-items:center; gap:.5em; pad"}},{"t":1584864,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ding:.35em .7"}},{"t":1585332,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"em; font-size:clamp(10px,1.5vw,16px); font-weight:700;"}},{"t":1585611,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":" letter-spacing:.05em;\\n background:rgba(6,21,15,.72); border:1px solid rgba(251,243,223,.18); border-radius:8px; color:var(--ivory);\\n }\\n .chip canvas{height:1.1em; width:auto; image"}},{"t":1585995,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"-rendering:pixel"}},{"t":1586612,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ated}\\n .chip.lives{margin-left:auto; gap:.3em}\\n .chip.lives canvas{transition:opacity .25s, transform .25s}\\n .chip.lives canvas.lost{opacity:.18; transform:scale(.8)}\\n #keyChip{color:var(--ivory-dim)} #keyChip canvas{opacity:.35"}},{"t":1587499,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"; transition:opacity .3s}\\n #keyChip.has{color:var(--papaya-soft); border-color"}},{"t":1587883,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":":var(--papaya)} #keyChip.has canvas{opacity:1}\\n .bump{animation:bump .25s ease-out}\\n @keyframes bump{0%{transform:scale(1)}40%{transform:scale(1.14)}100%{transform:scale(1)}}"}},{"t":1588297,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"\\n .demo-tag{\\n position:absolute; z-index:2; left:50%; top:2.6"}},{"t":1588733,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"%; transform:translateX(-50%); font-size:clamp(9px,1.2vw,13px); letter-spacing:.3"}},{"t":1589168,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"em; text-transform:uppercase;\\n color:var(--leaf-900); background:var(--papaya); padding:.25em .7em ."}},{"t":1589420,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"25em "}},{"t":1589764,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"1em; border-radius:"}},{"t":1590413,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"4px; font-weight:800;\\n }\\n .prompt{position:absolute; z-index:2; left:0; right:0; bottom:9%; text-align:center; pointer-events:none}\\n .prompt span{\\n display:inline-block; font-size:clamp(11px,1.9vw,20px); font-weight:800; letter-spacing:.16em; text-transform"}},{"t":1590772,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":":uppercase;\\n color:var(--ivory); background:rgba(6,21,15,.78); border:1px solid var(--papaya); border-radius:8px; padding:.55"}},{"t":1591156,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"em 1.1em;\\n animation:blink 1.4s steps(2,jump-none"}},{"t":1591967,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":") infinite;\\n }\\n @keyframes blink{0%{opacity:1}100%{opacity:.45}}\\n .toast{\\n position:absolute; z-index:2; left:50%; bottom:6%; transform:translate(-50%,12px); opacity:0; pointer"}},{"t":1592311,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"-events:none; white-space:nowrap;\\n "}},{"t":1592928,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"font-size:clamp(10px,1.4vw,15px); font-weight:700; color:var(--leaf-900); background:var(--ivory); border-radius:8px; padding:.5em .9em;\\n box-shadow:0 3px 0 var(--papaya-deep); transition:opacity .25s, transform .25s;\\n "}},{"t":1593257,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"}\\n .toast.show{opacity:1; transform:translate(-50%,0)}\\n .overlay{position:absolute"}},{"t":1593521,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"; z-index:3; inset:0; display:fl"}},{"t":1593781,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ex; align-items:center; justify-content:center; background:rgba(4,14"}},{"t":1594031,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":",10,.72); animation:fade .35s ease-out}\\n .overlay[hidden]{"}},{"t":1594296,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"display:none}\\n .card{\\n text-align:center; pad"}},{"t":1594546,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ding:clamp(14px,3vw,30px) clamp(18px,4vw,44px); border-radius:14"}},{"t":1594845,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"px; max-width:86%;\\n background:linear-gradient(180deg"}},{"t":1595602,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":","}},{"t":1595881,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"#123a29,#0b2318); border:2px solid var(--papaya); box-shadow:0 6px 0 var(--papaya-deep), 0 22px 40px -12px #000;\\n animation:pop .4"}},{"t":1596590,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"s cubic-bezier(.2,1"}},{"t":1596886,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":".4,.4,1);\\n }\\n .eyebrow{font-size:clamp(9"}},{"t":1597269,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"px,1.2vw,13px); letter-spacing:.3em; text-transform:uppercase; color:var(--papaya-soft)}\\n .card h2{font-size:clamp(18px,3.6vw,40px); margin:.2em 0 .25em; letter-spacing:.04"}},{"t":1597650,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"em; color:var(--ivory)}\\n .card p{font-size:clamp(10px,1.5vw,16px); color:var(--ivory-dim)}\\n .card .hint{margin-top:.9"}},{"t":1597919,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"em; font-size:clamp(9px,1.1"}},{"t":1598183,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"vw,12px); opacity:.7}\\n .cta{\\n margin-top:1em; font:inherit; font-weight:800; font"}},{"t":1598618,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"-size:clamp(11px,1.6vw,17px); letter-spacing:.12em; text-transform:u"}},{"t":1598999,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ppercase; cursor:pointer;\\n color:var(--leaf-900); background:var(--papaya); border:0; border-radius:10px; padding:.7em "}},{"t":1599383,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"1.5em; box-shadow:0 4px 0 var(--papaya-deep"}},{"t":1600204,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":");\\n transition:transform .12s, box-shadow .12s, background .2s;\\n }\\n .cta:hover{background:var(--papaya-soft)} .cta:active{transform:translateY(3px); box-shadow:0 1px 0 var(--papaya-deep)}\\n @keyfram"}},{"t":1600535,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"es fade{from{opacity:0}to{opacity:1}}\\n @keyframes pop{from{transform:scale(."}},{"t":1601292,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"85) translateY(10px); opacity:0}to{transform:none; opacity:1}}\\n .pad{user-select:none; -webkit-user-select:none}\\n .pad-group{display:flex; gap:10px}\\n .pbtn{\\n width:clamp("}},{"t":1601678,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"52px,9vw,72px); height:clamp(44px,7vw,56px); border-radius:12px; cursor:pointer; touch"}},{"t":1602067,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"-action:none;\\n font:inherit; font-weight:800; font-size:12px; letter-spacing:.12em; text-"}},{"t":1602914,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"transform:uppercase;"}},{"t":1603273,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":" color:var(--ivory);\\n background:linear-gradient(180deg,#1b4a33,#103424); border:1px solid rgba(251,243,223,.2); box-shadow:0 4px 0 #"}},{"t":1603653,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"051009;\\n display:flex; align-items:center; justify-content:center; transition:transform .08s, box-shadow .08s, background"}},{"t":1604014,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":" .15s;\\n }\\n .pbtn.jump{width:clamp(84px,14vw,120px); background:linear-gradient(180deg,var(--papaya),var(--papaya-deep)); color:var(--leaf-900); border-color:var"}},{"t":1604403,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"(--papaya-soft"}},{"t":1605180,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"); box-shadow:0 4px 0 #7a2f12"}},{"t":1605459,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"}\\n .pbtn.on, .pbtn:active{transform:translateY(3px); box-shadow:0 1px 0 #051009}\\n .tri{width:0; height:0; border:9px solid transparent}\\n .tri.l{border-right-color:var(--ivory); marg"}},{"t":1605842,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"in-left:-9px} .tri.r{border-left-color:var(--ivory); margin-right:-9px}\\n .keys{font-size:11px; color:var(--ivory-dim); letter-spacing:.04em; text-align:center;"}},{"t":1606226,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":" line-height:1.5}\\n .keys b{color:var(--ivory); font-weight:700}\\n button:focus-visible{outline:2px solid var"}},{"t":1606613,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"(--papaya-soft); outline-offset:3px}\\n @media (max-width:620px){ .keys{display:none} .stage{border-radius:6"}},{"t":1606997,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"px} .pill span#muteTxt{display:none} .pill{padding:9px}"}},{"t":1607377,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":" }\\n @media (max-height:520px) and (orientation:landscape){\\n .top{display:none} .sh"}},{"t":1607761,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"ell{padding:4px; gap:0}\\n .stage{width:min(100"}},{"t":1609157,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"vw, calc("}},{"t":1610504,"name":"aiToolStream","data":{"toolId":45,"toolName":"Edit","append":"100vh * 16 / 9)); border-radius:0}\\n .pad{position:fixed; left:0; right:0; bottom:8px; width:auto; padding:0 12px; z-index:5; pointer-events:none}\\n .pad .pbtn{pointer-events:auto; opacity:.8} .keys{display:none}\\n }\\n @media (prefers-reduced-motion:reduce){ .prompt span,.card,.overlay,.bump{animation:none} }\"}"}},{"t":1610518,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":45,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":" canvas#game{\n width:100%; height:100%; display:block;\n image-rendering:pixelated; image-rendering:crisp-edges;\n }","new_string":" canvas#game{\n width:100%; height:100%; display:block;\n image-rendering:crisp-edges; image-rendering:pixelated;\n }\n body{\n background:\n radial-gradient(120% 80% at 50% 0%, #12382a 0%, transparent 60%),\n radial-gradient(90% 60% at 50% 110%, rgba(226,97,42,.16) 0%, transparent 60%),\n var(--leaf-900);\n }\n .shell{max-width:1500px}\n .top, .pad{width:min(96vw, calc((100vh - 170px) * 16 / 9)); display:flex; align-items:center; justify-content:space-between; gap:12px}\n .brand{display:flex; align-items:center; gap:10px; min-width:0}\n .leaf{width:14px; height:14px; flex:none; background:var(--papaya); border-radius:0 70% 0 70%; box-shadow:inset -3px -3px 0 var(--papaya-deep)}\n h1{font-size:clamp(14px,2.2vw,22px); letter-spacing:.06em; text-transform:uppercase; font-weight:800; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}\n h1 em{font-style:normal; color:var(--papaya)}\n .pill{\n font:inherit; font-size:12px; letter-spacing:.08em; text-transform:uppercase; color:var(--ivory);\n background:rgba(251,243,223,.06); border:1px solid rgba(251,243,223,.22); border-radius:999px;\n padding:7px 12px; display:inline-flex; align-items:center; gap:8px; cursor:pointer; flex:none;\n transition:background .2s, border-color .2s, transform .15s;\n }\n .pill:hover{background:rgba(251,243,223,.12); border-color:var(--papaya-soft)}\n .pill:active{transform:scale(.96)}\n .pill .dot{width:8px; height:8px; border-radius:50%; background:var(--ivory-dim); transition:background .2s, box-shadow .2s}\n .pill[aria-pressed=\"true\"] .dot{background:var(--papaya); box-shadow:0 0 0 3px rgba(255,138,61,.25)}\n .stage{\n box-shadow:0 0 0 2px #1b4a33, 0 0 0 5px var(--leaf-800), 0 24px 60px -18px rgba(0,0,0,.8);\n touch-action:none; user-select:none; -webkit-user-select:none;\n }\n .stage::after{ /* soft vignette, one static layer */\n content:\"\"; position:absolute; inset:0; pointer-events:none;\n background:radial-gradient(ellipse at center, transparent 58%, rgba(3,12,8,.5) 100%);\n }\n .hud{position:absolute; z-index:2; top:2.2%; left:1.6%; right:1.6%; display:flex; gap:1.2%; align-items:center; pointer-events:none}\n .chip{\n display:flex; align-items:center; gap:.5em; padding:.35em .7em; font-size:clamp(10px,1.5vw,16px); font-weight:700; letter-spacing:.05em;\n background:rgba(6,21,15,.72); border:1px solid rgba(251,243,223,.18); border-radius:8px; color:var(--ivory);\n }\n .chip canvas{height:1.1em; width:auto; image-rendering:pixelated}\n .chip.lives{margin-left:auto; gap:.3em}\n .chip.lives canvas{transition:opacity .25s, transform .25s}\n .chip.lives canvas.lost{opacity:.18; transform:scale(.8)}\n #keyChip{color:var(--ivory-dim)} #keyChip canvas{opacity:.35; transition:opacity .3s}\n #keyChip.has{color:var(--papaya-soft); border-color:var(--papaya)} #keyChip.has canvas{opacity:1}\n .bump{animation:bump .25s ease-out}\n @keyframes bump{0%{transform:scale(1)}40%{transform:scale(1.14)}100%{transform:scale(1)}}\n .demo-tag{\n position:absolute; z-index:2; left:50%; top:2.6%; transform:translateX(-50%); font-size:clamp(9px,1.2vw,13px); letter-spacing:.3em; text-transform:uppercase;\n color:var(--leaf-900); background:var(--papaya); padding:.25em .7em .25em 1em; border-radius:4px; font-weight:800;\n }\n .prompt{position:absolute; z-index:2; left:0; right:0; bottom:9%; text-align:center; pointer-events:none}\n .prompt span{\n display:inline-block; font-size:clamp(11px,1.9vw,20px); font-weight:800; letter-spacing:.16em; text-transform:uppercase;\n color:var(--ivory); background:rgba(6,21,15,.78); border:1px solid var(--papaya); border-radius:8px; padding:.55em 1.1em;\n animation:blink 1.4s steps(2,jump-none) infinite;\n }\n @keyframes blink{0%{opacity:1}100%{opacity:.45}}\n .toast{\n position:absolute; z-index:2; left:50%; bottom:6%; transform:translate(-50%,12px); opacity:0; pointer-events:none; white-space:nowrap;\n font-size:clamp(10px,1.4vw,15px); font-weight:700; color:var(--leaf-900); background:var(--ivory); border-radius:8px; padding:.5em .9em;\n box-shadow:0 3px 0 var(--papaya-deep); transition:opacity .25s, transform .25s;\n }\n .toast.show{opacity:1; transform:translate(-50%,0)}\n .overlay{position:absolute; z-index:3; inset:0; display:flex; align-items:center; justify-content:center; background:rgba(4,14,10,.72); animation:fade .35s ease-out}\n .overlay[hidden]{display:none}\n .card{\n text-align:center; padding:clamp(14px,3vw,30px) clamp(18px,4vw,44px); border-radius:14px; max-width:86%;\n background:linear-gradient(180deg,#123a29,#0b2318); border:2px solid var(--papaya); box-shadow:0 6px 0 var(--papaya-deep), 0 22px 40px -12px #000;\n animation:pop .4s cubic-bezier(.2,1.4,.4,1);\n }\n .eyebrow{font-size:clamp(9px,1.2vw,13px); letter-spacing:.3em; text-transform:uppercase; color:var(--papaya-soft)}\n .card h2{font-size:clamp(18px,3.6vw,40px); margin:.2em 0 .25em; letter-spacing:.04em; color:var(--ivory)}\n .card p{font-size:clamp(10px,1.5vw,16px); color:var(--ivory-dim)}\n .card .hint{margin-top:.9em; font-size:clamp(9px,1.1vw,12px); opacity:.7}\n .cta{\n margin-top:1em; font:inherit; font-weight:800; font-size:clamp(11px,1.6vw,17px); letter-spacing:.12em; text-transform:uppercase; cursor:pointer;\n color:var(--leaf-900); background:var(--papaya); border:0; border-radius:10px; padding:.7em 1.5em; box-shadow:0 4px 0 var(--papaya-deep);\n transition:transform .12s, box-shadow .12s, background .2s;\n }\n .cta:hover{background:var(--papaya-soft)} .cta:active{transform:translateY(3px); box-shadow:0 1px 0 var(--papaya-deep)}\n @keyframes fade{from{opacity:0}to{opacity:1}}\n @keyframes pop{from{transform:scale(.85) translateY(10px); opacity:0}to{transform:none; opacity:1}}\n .pad{user-select:none; -webkit-user-select:none}\n .pad-group{display:flex; gap:10px}\n .pbtn{\n width:clamp(52px,9vw,72px); height:clamp(44px,7vw,56px); border-radius:12px; cursor:pointer; touch-action:none;\n font:inherit; font-weight:800; font-size:12px; letter-spacing:.12em; text-transform:uppercase; color:var(--ivory);\n background:linear-gradient(180deg,#1b4a33,#103424); border:1px solid rgba(251,243,223,.2); box-shadow:0 4px 0 #051009;\n display:flex; align-items:center; justify-content:center; transition:transform .08s, box-shadow .08s, background .15s;\n }\n .pbtn.jump{width:clamp(84px,14vw,120px); background:linear-gradient(180deg,var(--papaya),var(--papaya-deep)); color:var(--leaf-900); border-color:var(--papaya-soft); box-shadow:0 4px 0 #7a2f12}\n .pbtn.on, .pbtn:active{transform:translateY(3px); box-shadow:0 1px 0 #051009}\n .tri{width:0; height:0; border:9px solid transparent}\n .tri.l{border-right-color:var(--ivory); margin-left:-9px} .tri.r{border-left-color:var(--ivory); margin-right:-9px}\n .keys{font-size:11px; color:var(--ivory-dim); letter-spacing:.04em; text-align:center; line-height:1.5}\n .keys b{color:var(--ivory); font-weight:700}\n button:focus-visible{outline:2px solid var(--papaya-soft); outline-offset:3px}\n @media (max-width:620px){ .keys{display:none} .stage{border-radius:6px} .pill span#muteTxt{display:none} .pill{padding:9px} }\n @media (max-height:520px) and (orientation:landscape){\n .top{display:none} .shell{padding:4px; gap:0}\n .stage{width:min(100vw, calc(100vh * 16 / 9)); border-radius:0}\n .pad{position:fixed; left:0; right:0; bottom:8px; width:auto; padding:0 12px; z-index:5; pointer-events:none}\n .pad .pbtn{pointer-events:auto; opacity:.8} .keys{display:none}\n }\n @media (prefers-reduced-motion:reduce){ .prompt span,.card,.overlay,.bump{animation:none} }"}}},{"t":1610602,"name":"aiToolEdit","data":{"toolId":45,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":" canvas#game{\n width:100%; height:100%; display:block;\n image-rendering:pixelated; image-rendering:crisp-edges;\n }","newText":" canvas#game{\n width:100%; height:100%; display:block;\n image-rendering:crisp-edges; image-rendering:pixelated;\n }\n body{\n background:\n radial-gradient(120% 80% at 50% 0%, #12382a 0%, transparent 60%),\n radial-gradient(90% 60% at 50% 110%, rgba(226,97,42,.16) 0%, transparent 60%),\n var(--leaf-900);\n }\n .shell{max-width:1500px}\n .top, .pad{width:min(96vw, calc((100vh - 170px) * 16 / 9)); display:flex; align-items:center; justify-content:space-between; gap:12px}\n .brand{display:flex; align-items:center; gap:10px; min-width:0}\n .leaf{width:14px; height:14px; flex:none; background:var(--papaya); border-radius:0 70% 0 70%; box-shadow:inset -3px -3px 0 var(--papaya-deep)}\n h1{font-size:clamp(14px,2.2vw,22px); letter-spacing:.06em; text-transform:uppercase; font-weight:800; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}\n h1 em{font-style:normal; color:var(--papaya)}\n .pill{\n font:inherit; font-size:12px; letter-spacing:.08em; text-transform:uppercase; color:var(--ivory);\n background:rgba(251,243,223,.06); border:1px solid rgba(251,243,223,.22); border-radius:999px;\n padding:7px 12px; display:inline-flex; align-items:center; gap:8px; cursor:pointer; flex:none;\n transition:background .2s, border-color .2s, transform .15s;\n }\n .pill:hover{background:rgba(251,243,223,.12); border-color:var(--papaya-soft)}\n .pill:active{transform:scale(.96)}\n .pill .dot{width:8px; height:8px; border-radius:50%; background:var(--ivory-dim); transition:background .2s, box-shadow .2s}\n .pill[aria-pressed=\"true\"] .dot{background:var(--papaya); box-shadow:0 0 0 3px rgba(255,138,61,.25)}\n .stage{\n box-shadow:0 0 0 2px #1b4a33, 0 0 0 5px var(--leaf-800), 0 24px 60px -18px rgba(0,0,0,.8);\n touch-action:none; user-select:none; -webkit-user-select:none;\n }\n .stage::after{ /* soft vignette, one static layer */\n content:\"\"; position:absolute; inset:0; pointer-events:none;\n background:radial-gradient(ellipse at center, transparent 58%, rgba(3,12,8,.5) 100%);\n }\n .hud{position:absolute; z-index:2; top:2.2%; left:1.6%; right:1.6%; display:flex; gap:1.2%; align-items:center; pointer-events:none}\n .chip{\n display:flex; align-items:center; gap:.5em; padding:.35em .7em; font-size:clamp(10px,1.5vw,16px); font-weight:700; letter-spacing:.05em;\n background:rgba(6,21,15,.72); border:1px solid rgba(251,243,223,.18); border-radius:8px; color:var(--ivory);\n }\n .chip canvas{height:1.1em; width:auto; image-rendering:pixelated}\n .chip.lives{margin-left:auto; gap:.3em}\n .chip.lives canvas{transition:opacity .25s, transform .25s}\n .chip.lives canvas.lost{opacity:.18; transform:scale(.8)}\n #keyChip{color:var(--ivory-dim)} #keyChip canvas{opacity:.35; transition:opacity .3s}\n #keyChip.has{color:var(--papaya-soft); border-color:var(--papaya)} #keyChip.has canvas{opacity:1}\n .bump{animation:bump .25s ease-out}\n @keyframes bump{0%{transform:scale(1)}40%{transform:scale(1.14)}100%{transform:scale(1)}}\n .demo-tag{\n position:absolute; z-index:2; left:50%; top:2.6%; transform:translateX(-50%); font-size:clamp(9px,1.2vw,13px); letter-spacing:.3em; text-transform:uppercase;\n color:var(--leaf-900); background:var(--papaya); padding:.25em .7em .25em 1em; border-radius:4px; font-weight:800;\n }\n .prompt{position:absolute; z-index:2; left:0; right:0; bottom:9%; text-align:center; pointer-events:none}\n .prompt span{\n display:inline-block; font-size:clamp(11px,1.9vw,20px); font-weight:800; letter-spacing:.16em; text-transform:uppercase;\n color:var(--ivory); background:rgba(6,21,15,.78); border:1px solid var(--papaya); border-radius:8px; padding:.55em 1.1em;\n animation:blink 1.4s steps(2,jump-none) infinite;\n }\n @keyframes blink{0%{opacity:1}100%{opacity:.45}}\n .toast{\n position:absolute; z-index:2; left:50%; bottom:6%; transform:translate(-50%,12px); opacity:0; pointer-events:none; white-space:nowrap;\n font-size:clamp(10px,1.4vw,15px); font-weight:700; color:var(--leaf-900); background:var(--ivory); border-radius:8px; padding:.5em .9em;\n box-shadow:0 3px 0 var(--papaya-deep); transition:opacity .25s, transform .25s;\n }\n .toast.show{opacity:1; transform:translate(-50%,0)}\n .overlay{position:absolute; z-index:3; inset:0; display:flex; align-items:center; justify-content:center; background:rgba(4,14,10,.72); animation:fade .35s ease-out}\n .overlay[hidden]{display:none}\n .card{\n text-align:center; padding:clamp(14px,3vw,30px) clamp(18px,4vw,44px); border-radius:14px; max-width:86%;\n background:linear-gradient(180deg,#123a29,#0b2318); border:2px solid var(--papaya); box-shadow:0 6px 0 var(--papaya-deep), 0 22px 40px -12px #000;\n animation:pop .4s cubic-bezier(.2,1.4,.4,1);\n }\n .eyebrow{font-size:clamp(9px,1.2vw,13px); letter-spacing:.3em; text-transform:uppercase; color:var(--papaya-soft)}\n .card h2{font-size:clamp(18px,3.6vw,40px); margin:.2em 0 .25em; letter-spacing:.04em; color:var(--ivory)}\n .card p{font-size:clamp(10px,1.5vw,16px); color:var(--ivory-dim)}\n .card .hint{margin-top:.9em; font-size:clamp(9px,1.1vw,12px); opacity:.7}\n .cta{\n margin-top:1em; font:inherit; font-weight:800; font-size:clamp(11px,1.6vw,17px); letter-spacing:.12em; text-transform:uppercase; cursor:pointer;\n color:var(--leaf-900); background:var(--papaya); border:0; border-radius:10px; padding:.7em 1.5em; box-shadow:0 4px 0 var(--papaya-deep);\n transition:transform .12s, box-shadow .12s, background .2s;\n }\n .cta:hover{background:var(--papaya-soft)} .cta:active{transform:translateY(3px); box-shadow:0 1px 0 var(--papaya-deep)}\n @keyframes fade{from{opacity:0}to{opacity:1}}\n @keyframes pop{from{transform:scale(.85) translateY(10px); opacity:0}to{transform:none; opacity:1}}\n .pad{user-select:none; -webkit-user-select:none}\n .pad-group{display:flex; gap:10px}\n .pbtn{\n width:clamp(52px,9vw,72px); height:clamp(44px,7vw,56px); border-radius:12px; cursor:pointer; touch-action:none;\n font:inherit; font-weight:800; font-size:12px; letter-spacing:.12em; text-transform:uppercase; color:var(--ivory);\n background:linear-gradient(180deg,#1b4a33,#103424); border:1px solid rgba(251,243,223,.2); box-shadow:0 4px 0 #051009;\n display:flex; align-items:center; justify-content:center; transition:transform .08s, box-shadow .08s, background .15s;\n }\n .pbtn.jump{width:clamp(84px,14vw,120px); background:linear-gradient(180deg,var(--papaya),var(--papaya-deep)); color:var(--leaf-900); border-color:var(--papaya-soft); box-shadow:0 4px 0 #7a2f12}\n .pbtn.on, .pbtn:active{transform:translateY(3px); box-shadow:0 1px 0 #051009}\n .tri{width:0; height:0; border:9px solid transparent}\n .tri.l{border-right-color:var(--ivory); margin-left:-9px} .tri.r{border-left-color:var(--ivory); margin-right:-9px}\n .keys{font-size:11px; color:var(--ivory-dim); letter-spacing:.04em; text-align:center; line-height:1.5}\n .keys b{color:var(--ivory); font-weight:700}\n button:focus-visible{outline:2px solid var(--papaya-soft); outline-offset:3px}\n @media (max-width:620px){ .keys{display:none} .stage{border-radius:6px} .pill span#muteTxt{display:none} .pill{padding:9px} }\n @media (max-height:520px) and (orientation:landscape){\n .top{display:none} .shell{padding:4px; gap:0}\n .stage{width:min(100vw, calc(100vh * 16 / 9)); border-radius:0}\n .pad{position:fixed; left:0; right:0; bottom:8px; width:auto; padding:0 12px; z-index:5; pointer-events:none}\n .pad .pbtn{pointer-events:auto; opacity:.8} .keys{display:none}\n }\n @media (prefers-reduced-motion:reduce){ .prompt span,.card,.overlay,.bump{animation:none} }","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1610604,"name":"aiToolResult","data":{"toolId":45,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1612886,"name":"aiProgress","data":{"toolName":"Edit","toolId":46,"phase":"tool_use"}},{"t":1612886,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"{\"file_path\": \"{{PROJECT}}/dave-jungle-temple.html"}},{"t":1613524,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"\", \"old_string\": \"/* ==BOOT== */\", \"new_string\": \"/* ==UI: HUD, overlays, touch== */\\nconst $=id=>document.getElementById"}},{"t":1614201,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"(id);\\nconst ui={gem:$('gemTxt'),keyChip:$('keyChip'),keyTxt:$('keyTxt'),lives:$('lives'),prompt:$('prompt'),demo:$('dem"}},{"t":1614455,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"oTag'),toast:$('toast'),"}},{"t":1614855,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ov:$('overlay'),ovE:$('ovEyebrow'),ovT:$('ovTitle'),ovP:$('ovText'),ovB:$('ovBtn'),mute:$('mu"}},{"t":1615157,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"teBtn'),muteTxt:$('muteT"}},{"t":1615521,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"xt')};\\n$('icoGem').getContext('2d').drawImage(SP.gem[0],0,0);\\n$('icoKey').getContext('2d').drawImage("}},{"t":1615771,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"SP.key,0,0);\\nconst hearts=[0,1,2].map(()=>{ const c=document.createElement('canv"}},{"t":1616150,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"as'); c.width=9; c.height=8; c.getContext('2d').drawImage(SP.heart,0,0); "}},{"t":1616456,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ui.lives.appendChild(c); return c; });\\nlet lastGems=-1;\\nsy"}},{"t":1616710,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ncHud=function(){\\n ui.gem.textContent=G.gems+'/'+G.total;\\n if(G.gems"}},{"t":1617017,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"!==lastGems && G.gems>0){ const ch=ui.gem.parentN"}},{"t":1617267,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ode; ch.classList.remove('bump'); void ch.offsetWidth; ch."}},{"t":1617522,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"classList.add('bump'); } lastGems=G.gems;\\n ui.keyChip.classList.to"}},{"t":1617833,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ggle('has',!!G.hasKey); ui.keyTxt.textContent=G.h"}},{"t":1618084,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"asKey?'Key':'No key';\\n hearts.forEach((h,i)=>h.classList.toggle('lost',"}},{"t":1618394,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"i>=G.lives));\\n};\\nlet toastTimer=0;\\nshowToast=function(ms"}},{"t":1618644,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"g){ if(G.mode==='attract') return; ui.toast.textContent=msg; ui."}},{"t":1618895,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"toast.classList.add('show'); clearTimeout(toastTimer); toastTimer=setT"}},{"t":1619150,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"imeout(()=>ui.toast.classList.remove('show'),2200); };\\nfunction syncUi(){\\n const dem"}},{"t":1619455,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"o=G.mode==='attract', ended=G.mode==='win'||G.mode"}},{"t":1619717,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"==='over';\\n ui.prompt.style.display=demo?'':'none'; ui.demo.style.display=demo"}},{"t":1620018,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"?'':'none';\\n if(ended){\\n const win"}},{"t":1620270,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"=G.mode==='win';\\n ui.ovE.textContent=win?'Temple cleared':'Out"}},{"t":1620580,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":" of lives';\\n ui.ovT.textContent=win?'You escaped!':'Game over';"}},{"t":1620834,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"\\n ui.ovP.textContent=win?('Gems collected: '+G.gems"}},{"t":1621084,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"+' of '+G.total+(G.gems===G.total?' — a perfect run!':'')"}},{"t":1621336,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"):('The jungle keeps its tre"}},{"t":1621592,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"asure… '+G.gems+' of '+G.total+' gems found.');\\n ui.ovB.textContent"}},{"t":1621893,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"=win?'Play again':'Try again';\\n }\\n ui.ov.hidden=!ended; if"}},{"t":1622203,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"(ended) ui.ovB.focus({preventScroll:true});\\n ui.toast."}},{"t":1622454,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"classList.remove('show'); syncHud();\\n}\\nui.ovB.addEventListener('click',"}},{"t":1622704,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"e=>{ e.stopPropagation(); restartIfEnded(); });\\n$('st"}},{"t":1622962,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"age').addEventListener('pointerdown',e=>{ if(G.mode==='attract'){ tak"}},{"t":1623267,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"eControl(); e.preventDefault(); } });\\ndocument.querySelector"}},{"t":1623542,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"All('.pbtn').forEach(b=>{ const k=b.dataset.k;\\n const set=(v,e)=>{ ke"}},{"t":1623858,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ys[k]=v; b.classList.toggle('on',v); if(v){ onAnyInput(); try"}},{"t":1624144,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"{ b.setPointerCapture(e.pointerId); }catch(_){} } e"}},{"t":1624419,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":".preventDefault(); };\\n b.addEventListener('pointerdown',e=>set(true,e)); "}},{"t":1624713,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"['pointerup','pointercancel','lostpointercapture'].forEach(n=>b.addEventListener(n,e="}},{"t":1625019,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":">set(false,e)));\\n b.addEventListener('contextmenu',e=>e.preventD"}},{"t":1625270,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"efault()); });\\n\\n/* ==AUDIO: tiny bleeps, off until"}},{"t":1625587,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":" the toggle is pressed== */\\nconst AU={on:false,ac:"}},{"t":1625838,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"null};\\nfunction tone(f0,f1,d"}},{"t":1626104,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ur,type,vol,delay){ const ac=AU.ac, t=ac.currentT"}},{"t":1626393,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ime+(delay||0), o=ac.createOscillator(), g=ac.createGain();\\n o.type=type||'square'"}},{"t":1626708,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"; o.frequency.setValueAtTime(f0,t); o.frequency.exponentialRampToValueAt"}},{"t":1627016,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"Time(Math.max(30,f1),t+dur);\\n g.gain."}},{"t":1627267,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"setValueAtTime(vol||.05,t); g.gain.exponentialRampToVal"}},{"t":1627520,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ueAtTime(.0008,t+dur); o.connect(g); g.connect(ac."}},{"t":1627833,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"destination); o.start(t); o.stop(t+dur+.02); }\\nconst SFX={"}},{"t":1628508,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":" jump:()=>tone(300,560,.1), gem:()=>{ tone(880,1320,.07,'triangle',.07); tone(1320"}},{"t":1628771,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":",1760,.08,'triangle',.05,.06); }, key"}},{"t":1629084,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":":()=>[660,880,1175].forEach((f,i)=>tone(f,f,.1"}},{"t":1629390,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":",'square',.05,i*.08)),\\n stomp:()=>tone(220,"}},{"t":1629640,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"70,.12), hurt:()=>tone(320,60"}},{"t":1629952,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":",.3,'sawtooth',.06), locked:()="}},{"t":1630209,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":">tone(130,110,.14), win:()=>tone(440,880"}},{"t":1630515,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":",.2,'triangle',.06),\\n fanfare:"}},{"t":1630767,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"()=>[523,659,784,1047].forEach((f,i)=>tone(f,f,.16,'square"}},{"t":1631082,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"',.05,i*.12)), over:()=>[392,330,262,196].forEach((f"}},{"t":1631393,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":",i)=>tone(f,f*.97,.2"}},{"t":1631644,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":",'triangle',.06,i*.16)) };\\nplaySfx=function(n){ if(!AU"}},{"t":1631895,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":".on||!AU.ac||G.mode==='attract'||!SFX[n]) return; try{ SF"}},{"t":1632206,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"X[n](); }catch(_){} };\\nfunction toggleMute(){ AU.on=!AU.on;"}},{"t":1632516,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"\\n if(AU.on && !AU.ac){ const A"}},{"t":1632802,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"=window.AudioContext||window.webkitAudioContext; if(A) AU.ac=new A(); else AU.on="}},{"t":1633085,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"false; }\\n if(AU.on && AU.ac.state==='suspended') AU.ac.resume();\\n ui.m"}},{"t":1633390,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"ute.setAttribute('aria-pressed',AU.on?'true':'false'); ui.mute"}},{"t":1633643,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"Txt.textContent=AU.on?'Sound on':'Sound off'; if(AU.on){"}},{"t":1633952,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":" try{ tone(660,990,.08,'triangle',.06); }catch(_"}},{"t":1634267,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"){} } }\\nui.mute.addEventListener('click',e=>{ e.st"}},{"t":1634526,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"opPropagation(); toggleMute(); ui.mute.blur(); });\\n\\n/* ==BOOT== *"}},{"t":1634894,"name":"aiToolStream","data":{"toolId":46,"toolName":"Edit","append":"/\"}"}},{"t":1634906,"name":"aiToolInfo","data":{"toolName":"Edit","toolId":46,"toolInput":{"file_path":"{{PROJECT}}/dave-jungle-temple.html","old_string":"/* ==BOOT== */","new_string":"/* ==UI: HUD, overlays, touch== */\nconst $=id=>document.getElementById(id);\nconst ui={gem:$('gemTxt'),keyChip:$('keyChip'),keyTxt:$('keyTxt'),lives:$('lives'),prompt:$('prompt'),demo:$('demoTag'),toast:$('toast'),ov:$('overlay'),ovE:$('ovEyebrow'),ovT:$('ovTitle'),ovP:$('ovText'),ovB:$('ovBtn'),mute:$('muteBtn'),muteTxt:$('muteTxt')};\n$('icoGem').getContext('2d').drawImage(SP.gem[0],0,0);\n$('icoKey').getContext('2d').drawImage(SP.key,0,0);\nconst hearts=[0,1,2].map(()=>{ const c=document.createElement('canvas'); c.width=9; c.height=8; c.getContext('2d').drawImage(SP.heart,0,0); ui.lives.appendChild(c); return c; });\nlet lastGems=-1;\nsyncHud=function(){\n ui.gem.textContent=G.gems+'/'+G.total;\n if(G.gems!==lastGems && G.gems>0){ const ch=ui.gem.parentNode; ch.classList.remove('bump'); void ch.offsetWidth; ch.classList.add('bump'); } lastGems=G.gems;\n ui.keyChip.classList.toggle('has',!!G.hasKey); ui.keyTxt.textContent=G.hasKey?'Key':'No key';\n hearts.forEach((h,i)=>h.classList.toggle('lost',i>=G.lives));\n};\nlet toastTimer=0;\nshowToast=function(msg){ if(G.mode==='attract') return; ui.toast.textContent=msg; ui.toast.classList.add('show'); clearTimeout(toastTimer); toastTimer=setTimeout(()=>ui.toast.classList.remove('show'),2200); };\nfunction syncUi(){\n const demo=G.mode==='attract', ended=G.mode==='win'||G.mode==='over';\n ui.prompt.style.display=demo?'':'none'; ui.demo.style.display=demo?'':'none';\n if(ended){\n const win=G.mode==='win';\n ui.ovE.textContent=win?'Temple cleared':'Out of lives';\n ui.ovT.textContent=win?'You escaped!':'Game over';\n ui.ovP.textContent=win?('Gems collected: '+G.gems+' of '+G.total+(G.gems===G.total?' — a perfect run!':'')):('The jungle keeps its treasure… '+G.gems+' of '+G.total+' gems found.');\n ui.ovB.textContent=win?'Play again':'Try again';\n }\n ui.ov.hidden=!ended; if(ended) ui.ovB.focus({preventScroll:true});\n ui.toast.classList.remove('show'); syncHud();\n}\nui.ovB.addEventListener('click',e=>{ e.stopPropagation(); restartIfEnded(); });\n$('stage').addEventListener('pointerdown',e=>{ if(G.mode==='attract'){ takeControl(); e.preventDefault(); } });\ndocument.querySelectorAll('.pbtn').forEach(b=>{ const k=b.dataset.k;\n const set=(v,e)=>{ keys[k]=v; b.classList.toggle('on',v); if(v){ onAnyInput(); try{ b.setPointerCapture(e.pointerId); }catch(_){} } e.preventDefault(); };\n b.addEventListener('pointerdown',e=>set(true,e)); ['pointerup','pointercancel','lostpointercapture'].forEach(n=>b.addEventListener(n,e=>set(false,e)));\n b.addEventListener('contextmenu',e=>e.preventDefault()); });\n\n/* ==AUDIO: tiny bleeps, off until the toggle is pressed== */\nconst AU={on:false,ac:null};\nfunction tone(f0,f1,dur,type,vol,delay){ const ac=AU.ac, t=ac.currentTime+(delay||0), o=ac.createOscillator(), g=ac.createGain();\n o.type=type||'square'; o.frequency.setValueAtTime(f0,t); o.frequency.exponentialRampToValueAtTime(Math.max(30,f1),t+dur);\n g.gain.setValueAtTime(vol||.05,t); g.gain.exponentialRampToValueAtTime(.0008,t+dur); o.connect(g); g.connect(ac.destination); o.start(t); o.stop(t+dur+.02); }\nconst SFX={ jump:()=>tone(300,560,.1), gem:()=>{ tone(880,1320,.07,'triangle',.07); tone(1320,1760,.08,'triangle',.05,.06); }, key:()=>[660,880,1175].forEach((f,i)=>tone(f,f,.1,'square',.05,i*.08)),\n stomp:()=>tone(220,70,.12), hurt:()=>tone(320,60,.3,'sawtooth',.06), locked:()=>tone(130,110,.14), win:()=>tone(440,880,.2,'triangle',.06),\n fanfare:()=>[523,659,784,1047].forEach((f,i)=>tone(f,f,.16,'square',.05,i*.12)), over:()=>[392,330,262,196].forEach((f,i)=>tone(f,f*.97,.2,'triangle',.06,i*.16)) };\nplaySfx=function(n){ if(!AU.on||!AU.ac||G.mode==='attract'||!SFX[n]) return; try{ SFX[n](); }catch(_){} };\nfunction toggleMute(){ AU.on=!AU.on;\n if(AU.on && !AU.ac){ const A=window.AudioContext||window.webkitAudioContext; if(A) AU.ac=new A(); else AU.on=false; }\n if(AU.on && AU.ac.state==='suspended') AU.ac.resume();\n ui.mute.setAttribute('aria-pressed',AU.on?'true':'false'); ui.muteTxt.textContent=AU.on?'Sound on':'Sound off'; if(AU.on){ try{ tone(660,990,.08,'triangle',.06); }catch(_){} } }\nui.mute.addEventListener('click',e=>{ e.stopPropagation(); toggleMute(); ui.mute.blur(); });\n\n/* ==BOOT== */"}}},{"t":1634982,"name":"aiToolEdit","data":{"toolId":46,"edit":{"file":"{{PROJECT}}/dave-jungle-temple.html","oldText":"/* ==BOOT== */","newText":"/* ==UI: HUD, overlays, touch== */\nconst $=id=>document.getElementById(id);\nconst ui={gem:$('gemTxt'),keyChip:$('keyChip'),keyTxt:$('keyTxt'),lives:$('lives'),prompt:$('prompt'),demo:$('demoTag'),toast:$('toast'),ov:$('overlay'),ovE:$('ovEyebrow'),ovT:$('ovTitle'),ovP:$('ovText'),ovB:$('ovBtn'),mute:$('muteBtn'),muteTxt:$('muteTxt')};\n$('icoGem').getContext('2d').drawImage(SP.gem[0],0,0);\n$('icoKey').getContext('2d').drawImage(SP.key,0,0);\nconst hearts=[0,1,2].map(()=>{ const c=document.createElement('canvas'); c.width=9; c.height=8; c.getContext('2d').drawImage(SP.heart,0,0); ui.lives.appendChild(c); return c; });\nlet lastGems=-1;\nsyncHud=function(){\n ui.gem.textContent=G.gems+'/'+G.total;\n if(G.gems!==lastGems && G.gems>0){ const ch=ui.gem.parentNode; ch.classList.remove('bump'); void ch.offsetWidth; ch.classList.add('bump'); } lastGems=G.gems;\n ui.keyChip.classList.toggle('has',!!G.hasKey); ui.keyTxt.textContent=G.hasKey?'Key':'No key';\n hearts.forEach((h,i)=>h.classList.toggle('lost',i>=G.lives));\n};\nlet toastTimer=0;\nshowToast=function(msg){ if(G.mode==='attract') return; ui.toast.textContent=msg; ui.toast.classList.add('show'); clearTimeout(toastTimer); toastTimer=setTimeout(()=>ui.toast.classList.remove('show'),2200); };\nfunction syncUi(){\n const demo=G.mode==='attract', ended=G.mode==='win'||G.mode==='over';\n ui.prompt.style.display=demo?'':'none'; ui.demo.style.display=demo?'':'none';\n if(ended){\n const win=G.mode==='win';\n ui.ovE.textContent=win?'Temple cleared':'Out of lives';\n ui.ovT.textContent=win?'You escaped!':'Game over';\n ui.ovP.textContent=win?('Gems collected: '+G.gems+' of '+G.total+(G.gems===G.total?' — a perfect run!':'')):('The jungle keeps its treasure… '+G.gems+' of '+G.total+' gems found.');\n ui.ovB.textContent=win?'Play again':'Try again';\n }\n ui.ov.hidden=!ended; if(ended) ui.ovB.focus({preventScroll:true});\n ui.toast.classList.remove('show'); syncHud();\n}\nui.ovB.addEventListener('click',e=>{ e.stopPropagation(); restartIfEnded(); });\n$('stage').addEventListener('pointerdown',e=>{ if(G.mode==='attract'){ takeControl(); e.preventDefault(); } });\ndocument.querySelectorAll('.pbtn').forEach(b=>{ const k=b.dataset.k;\n const set=(v,e)=>{ keys[k]=v; b.classList.toggle('on',v); if(v){ onAnyInput(); try{ b.setPointerCapture(e.pointerId); }catch(_){} } e.preventDefault(); };\n b.addEventListener('pointerdown',e=>set(true,e)); ['pointerup','pointercancel','lostpointercapture'].forEach(n=>b.addEventListener(n,e=>set(false,e)));\n b.addEventListener('contextmenu',e=>e.preventDefault()); });\n\n/* ==AUDIO: tiny bleeps, off until the toggle is pressed== */\nconst AU={on:false,ac:null};\nfunction tone(f0,f1,dur,type,vol,delay){ const ac=AU.ac, t=ac.currentTime+(delay||0), o=ac.createOscillator(), g=ac.createGain();\n o.type=type||'square'; o.frequency.setValueAtTime(f0,t); o.frequency.exponentialRampToValueAtTime(Math.max(30,f1),t+dur);\n g.gain.setValueAtTime(vol||.05,t); g.gain.exponentialRampToValueAtTime(.0008,t+dur); o.connect(g); g.connect(ac.destination); o.start(t); o.stop(t+dur+.02); }\nconst SFX={ jump:()=>tone(300,560,.1), gem:()=>{ tone(880,1320,.07,'triangle',.07); tone(1320,1760,.08,'triangle',.05,.06); }, key:()=>[660,880,1175].forEach((f,i)=>tone(f,f,.1,'square',.05,i*.08)),\n stomp:()=>tone(220,70,.12), hurt:()=>tone(320,60,.3,'sawtooth',.06), locked:()=>tone(130,110,.14), win:()=>tone(440,880,.2,'triangle',.06),\n fanfare:()=>[523,659,784,1047].forEach((f,i)=>tone(f,f,.16,'square',.05,i*.12)), over:()=>[392,330,262,196].forEach((f,i)=>tone(f,f*.97,.2,'triangle',.06,i*.16)) };\nplaySfx=function(n){ if(!AU.on||!AU.ac||G.mode==='attract'||!SFX[n]) return; try{ SFX[n](); }catch(_){} };\nfunction toggleMute(){ AU.on=!AU.on;\n if(AU.on && !AU.ac){ const A=window.AudioContext||window.webkitAudioContext; if(A) AU.ac=new A(); else AU.on=false; }\n if(AU.on && AU.ac.state==='suspended') AU.ac.resume();\n ui.mute.setAttribute('aria-pressed',AU.on?'true':'false'); ui.muteTxt.textContent=AU.on?'Sound on':'Sound off'; if(AU.on){ try{ tone(660,990,.08,'triangle',.06); }catch(_){} } }\nui.mute.addEventListener('click',e=>{ e.stopPropagation(); toggleMute(); ui.mute.blur(); });\n\n/* ==BOOT== */","replaceAll":false,"isLivePreviewRelated":true}}},{"t":1634984,"name":"aiToolResult","data":{"toolId":46,"isError":false,"preview":"The file {{PROJECT}}/dave-jungle-temple.html has been updated s"}},{"t":1640167,"name":"aiProgress","data":{"toolName":"Bash","toolId":47,"phase":"tool_use"}},{"t":1640168,"name":"aiToolStream","data":{"toolId":47,"toolName":"Bash","append":"{\"command\": \"which node &&"}},{"t":1640502,"name":"aiToolStream","data":{"toolId":47,"toolName":"Bash","append":" node --version\", \"description\": \"Check whether Node is available\"}"}},{"t":1640522,"name":"aiToolInfo","data":{"toolName":"Bash","toolId":47,"toolInput":{"command":"which node && node --version","description":"Check whether Node is available"}}},{"t":1640631,"name":"aiToolResult","data":{"toolId":47,"isError":false,"preview":""}},{"t":1660672,"name":"aiProgress","data":{"toolName":"Write","toolId":49,"phase":"tool_use"}},{"t":1660673,"name":"aiToolStream","data":{"toolId":49,"toolName":"Write","append":"{\"file_path\": \"/tmp/davesim/sim.js\", \"content\": \"const fs=require('fs');\\nconst html=fs.readFileSync('"}},{"t":1661307,"name":"aiToolStream","data":{"toolId":49,"toolName":"Write","append":"{{PROJECT}}/dave-jungle-temple.html','utf8');\\nlet src=html.match(/