How Assets End Up On Your Page
Images, sounds, and sprites appear in the editor. Where do they actually come from, and what are all the ways a user can bring them in?
§1 The counter-intuitive big idea
The primary way assets are generated is not by clicking a button. The AI writes URLs into the HTML. The browser fetching those URLs is what triggers generation.
When the user asks the AI to build a page, the AI emits literal <img src="https://images.fuzzycode.dev/fast_ai?search=..."> and <audio src="https://sounds.fuzzycode.dev/sound_effect?prompt=..."> tags into the returned HTML. Generation happens at GET-time, when the iframe loads. There is no "create image" first-class button on the main editor toolbar — the "Generate Image" and "Sound Effects" panels are iframed side tools, and even they work by swapping URLs into existing slots after the AI already wrote them.
§2 The 17 distinct paths (images · sounds · sprites)
| Kind | # | Path | Triggered by | Endpoint | Evidence |
|---|---|---|---|---|---|
| IMG | 1 | AI fast_ai — primary |
AI emits <img src=".../fast_ai?search=...&resize=WxH"> |
images.fuzzycode.dev/fast_ai |
core_ai.py:68-134 (rules) |
| 2 | AI multi_ai spritesheet grab |
AI emits <multi-asset-sheet> + <img .../multi_ai?grab=...> |
/multi_ai/prewarm + /multi_ai |
html_processing.py:382 |
|
| 3 | AI Unsplash stock | AI emits <img .../unsplash?search=..."> |
images.fuzzycode.dev/unsplash |
core_ai.py:92 |
|
| 4 | iframe panel Generate (manual) | Game Assets → Generate tab → type prompt → click Generate | .../fast_ai|better_ai|best_ai|unsplash|google |
generate_page.html:309-339 |
|
| 5 | upload New image | /pages/myassets.html drag-drop / paste into super_image_importer → Upload |
POST uploads.fuzzycode.dev/upload/ |
myassets.html:431 |
|
| 6 | reuse My Assets gallery | My Assets → Images tab → pick existing upload | GET uploads.fuzzycode.dev/list_images |
myassets.html |
|
| 7 | iframe panel Animated characters | Game Assets → Animated Characters → SpriteBuddy iframe picker | sprites.fuzzycode.dev |
game_assets.html:1183 |
|
| 8 | context Paste screenshot | super_image_importer accepts drag/drop/paste/URL; sent as AI context |
no gen; becomes screenshotImage on next /prompt_to_code |
core_ai.py:1037 |
|
| 9 | standalone User avatar | /user_avatar_generator separate page |
fast_ai?resize=256x256 with &cache_bust= |
user_avatar_generator.html:956 |
|
| SFX | 1 | AI Sound effect | AI emits <audio src=".../sound_effect?prompt=..."> |
sounds.fuzzycode.dev/sound_effect |
core_ai.py:130 |
| 2 | AI Music | AI emits <audio src=".../music?prompt=..."> |
sounds.fuzzycode.dev/music |
core_ai.py:130 |
|
| 3 | iframe panel Sound Effects (manual) | Game Assets → Sound Effects → type prompt → Create Sound/Music | .../sound_effect or .../music |
pages/sounds.html:563 |
|
| 4 | reuse List sounds | Same panel → Saved tab → pick + vote | /list_sounds, /vote |
pages/sounds.html:465 |
|
| SPR | 1 | AI Multi-asset sheet | AI declares <multi-asset-sheet> — prewarm → Gemini Vision slicing → bg-removed WebPs |
/multi_ai/prewarm |
dedicated diagram → |
| 2 | AI spritesheet_ref style extension |
AI adds second sheet referencing a prior sheet for art-style consistency via FAL flux-2/edit |
/multi_ai/prewarm with ref image |
core_ai.py:114 |
|
| 3 | iframe panel ASE animated chars | SpriteBuddy iframe delivers Aseprite .json+.png pair |
sprites.fuzzycode.dev |
game_assets.html:347 |
|
| 4 | post-process Background remover | Imported sprite → super_bg_remover popup |
sprites.fuzzycode.dev/super_bg_remover |
super_image_importer.js:490 |
§3 The six path archetypes
All 17 paths collapse into one of six archetypes. Each has a distinct UX pattern and evidence anchor.
AI-authored URL primary · 5 paths
- AI emits literal
<img>/<audio>tag - Generation = browser's GET request
- URL is the cache key
- Same prompt → same cached asset
- No seed control; retry = edit prompt
core_ai.py:68-134Iframed side panels 4 paths
- Image gen:
/generate_page - Sound gen:
/pages/sounds.html - Animated chars:
sprites.fuzzycode.deviframe - Hands a URL to parent via
postMessage - Parent does URL-swap on current HTML
/metadata_page + game_assets.htmlUpload + reuse 3 paths
- User's own images uploaded
- Listed from
/list_imagesor/list_sounds - URL-swap to insert into page
- ⚠ UploaderBuddy has no PII firewall
myassets.html:431-470Context drops 2 paths
- Screenshot / paste / drag-drop
- Not generated — attached as context
- AI reads image, writes references in HTML
- Also: bg-remover post-processing
super_image_importer.jsStandalone pages 1 path
/user_avatar_generator— profile avatars only- Uses
fast_aiwith&cache_bust=query - Does not insert into any project
user_avatar_generator.html:956Multi-asset orchestration 2 paths
- Synchronous prewarm during AI turn
- Gemini Vision slices sheet
- Per-sprite bg-removed WebPs cached
spritesheet_refkeeps art style consistent
§4 Insertion into page — three mechanisms
synchronous] IP --> B[HTML returned with
<img>/<audio> URLs inline]:::tag end subgraph PANEL["MANUAL — iframed panels"] G[Game Assets panel
Generate / Sounds / Characters]:::swap G -->|postMessage url| SW[parent runs
replaceUrlInHtmlContent]:::swap end subgraph CONTEXT["CONTEXT — drag/drop screenshot"] C[super_image_importer]:::ctx C -->|screenshotImage| CT[sent with next /prompt_to_code]:::ctx end B --> P[Project HTML
currentVersion]:::page SW --> P CT -.->|AI rewrites HTML| A P --> IF[Iframe fetches assets
generation happens at GET-time]
§5 What the user sees during generation
(blocks ALL generation this turn) else clean PF-->>E: ok E->>AI: /prompt_to_code Note over AI: AI writes HTML with
embedded asset URLs AI-->>E: { html with <img> tags } E->>IF: render HTML Note over IF: iframe fetches each <img> / <audio> par parallel asset fetches IF->>IB: GET /fast_ai?search=... IB-->>IF: WebP (200) — or slow end alt fetches are slow Note over U: ugc_asset_progress_parent.js
shows "Loading N assets"
overlay with progress bar else fast cache hit Note over U: assets appear instantly;
no overlay end opt per-asset 429 (rate limit) IB-->>IF: 429 Note over U: ⚠ broken image icon only
no UI signal end end
ugc_asset_progress overlay handles the "slow because generating" case visibly, but a rate-limit 429 during a per-asset fetch just renders as a broken image — no toast, no retry UI.
/prompt_to_code fails the entire AI turn. There is no "this image was blocked" message because image generation never started — the AI itself never ran.
§6 Caching & determinism from the user's point of view
| Concern | Behavior | Evidence |
|---|---|---|
| Same prompt twice | Same image (URL-deterministic) | fast_ai?search=... is the cache key |
| Different size requested | Different image (resize is part of cache key) | &resize=WxH |
| Want a variation | Must change the prompt text (no seed control) | no seed param in URLs |
| Force regeneration | &cache_bust=<timestamp> — exposed only in avatar generator, not main editor | user_avatar_generator.html:956 |
| Multi-asset regen | Change any of: assets, style, theme, requirements, sheet_size, model | multi-asset hash formula |
§7 Rate limit / quota visibility
/payment_required. Handled at script.js:662-753.
script.js:662-753.
<img> fetch) → broken image, no UI signal. The progress overlay cannot distinguish "slow because generating" from "failed because rate-limited."
§8 Verification pointers
- AI URL rules
FuzzyCode/quart_server/blueprints/core_ai.py:68-134 - Multi-asset prewarm
FuzzyCode/quart_server/utils/html_processing.py:382-482 - Prewarm invocation
core_ai.py:1050, 1268, 1504 - Generate-image panel
FuzzyCode/templates/generate_page.html:167-339 - Sound panel
FuzzyCode/static/pages/sounds.html:563-591 - My Assets upload
FuzzyCode/static/pages/myassets.html:431-470 - Animated characters iframe
FuzzyCode/templates/game_assets.html:1183-1193 - Game Assets tabs
game_assets.html:335-353 - URL-swap mechanism
game_assets.html:772-782(replaceUrlInHtmlContent) - Loading overlay (parent)
FuzzyCode/static/ugc_asset_progress_parent.js:100-246 - Loading overlay (child)
FuzzyCode/static/ugc_asset_progress_child.js:110-213 - Multi-asset validation toasts
FuzzyCode/static/script.js:1509-1532, 1534-1655 - PII block modal
script.js:627-644 - 402/429 handling
script.js:662-753 - Bg-remover popup
FuzzyCode/static/fuzzy-blocks/super_image_importer.js:488-521 - Avatar generator
FuzzyCode/templates/user_avatar_generator.html:956