User journey · verified · asset generation pathways

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?

Last verified 2026-04-18 against code
Slug asset-generation-paths
Image paths 9
Sound paths 4
Sprite paths 4

§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 1AI fast_ai — primary AI emits <img src=".../fast_ai?search=...&resize=WxH"> images.fuzzycode.dev/fast_ai core_ai.py:68-134 (rules)
2AI multi_ai spritesheet grab AI emits <multi-asset-sheet> + <img .../multi_ai?grab=...> /multi_ai/prewarm + /multi_ai html_processing.py:382
3AI Unsplash stock AI emits <img .../unsplash?search=..."> images.fuzzycode.dev/unsplash core_ai.py:92
4iframe panel Generate (manual) Game Assets → Generate tab → type prompt → click Generate .../fast_ai|better_ai|best_ai|unsplash|google generate_page.html:309-339
5upload New image /pages/myassets.html drag-drop / paste into super_image_importer → Upload POST uploads.fuzzycode.dev/upload/ myassets.html:431
6reuse My Assets gallery My Assets → Images tab → pick existing upload GET uploads.fuzzycode.dev/list_images myassets.html
7iframe panel Animated characters Game Assets → Animated Characters → SpriteBuddy iframe picker sprites.fuzzycode.dev game_assets.html:1183
8context 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
9standalone User avatar /user_avatar_generator separate page fast_ai?resize=256x256 with &cache_bust= user_avatar_generator.html:956
SFX 1AI Sound effect AI emits <audio src=".../sound_effect?prompt=..."> sounds.fuzzycode.dev/sound_effect core_ai.py:130
2AI Music AI emits <audio src=".../music?prompt=..."> sounds.fuzzycode.dev/music core_ai.py:130
3iframe panel Sound Effects (manual) Game Assets → Sound Effects → type prompt → Create Sound/Music .../sound_effect or .../music pages/sounds.html:563
4reuse List sounds Same panel → Saved tab → pick + vote /list_sounds, /vote pages/sounds.html:465
SPR 1AI Multi-asset sheet AI declares <multi-asset-sheet> — prewarm → Gemini Vision slicing → bg-removed WebPs /multi_ai/prewarm dedicated diagram →
2AI 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
3iframe panel ASE animated chars SpriteBuddy iframe delivers Aseprite .json+.png pair sprites.fuzzycode.dev game_assets.html:347
4post-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

trigger: AI response
  • 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
rules: core_ai.py:68-134

Iframed side panels 4 paths

trigger: toolbar → puzzle icon → Game Assets tab
  • Image gen: /generate_page
  • Sound gen: /pages/sounds.html
  • Animated chars: sprites.fuzzycode.dev iframe
  • Hands a URL to parent via postMessage
  • Parent does URL-swap on current HTML
entry: /metadata_page + game_assets.html

Upload + reuse 3 paths

trigger: My Assets
  • User's own images uploaded
  • Listed from /list_images or /list_sounds
  • URL-swap to insert into page
  • ⚠ UploaderBuddy has no PII firewall
myassets.html:431-470

Context drops 2 paths

trigger: super_image_importer modal
  • Screenshot / paste / drag-drop
  • Not generated — attached as context
  • AI reads image, writes references in HTML
  • Also: bg-remover post-processing
super_image_importer.js

Standalone pages 1 path

trigger: direct URL
  • /user_avatar_generator — profile avatars only
  • Uses fast_ai with &cache_bust= query
  • Does not insert into any project
user_avatar_generator.html:956

Multi-asset orchestration 2 paths

trigger: AI emits <multi-asset-sheet>
  • Synchronous prewarm during AI turn
  • Gemini Vision slices sheet
  • Per-sprite bg-removed WebPs cached
  • spritesheet_ref keeps art style consistent

§4 Insertion into page — three mechanisms

flowchart LR classDef tag fill:#fff460,stroke:#683c06,color:#111 classDef swap fill:#eaf3ff,stroke:#1d58b1,color:#111 classDef ctx fill:#fdf6ea,stroke:#683c06,color:#111 classDef page fill:#edd9c0,stroke:#683c06,color:#111 subgraph AI["AI-AUTHORED — the majority of assets"] R1[User prompt] --> A[AI generates HTML]:::tag A --> IP[prewarm multi-asset-sheet URLs
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

sequenceDiagram autonumber participant U as 👤 User participant E as Editor participant AI as AI participant PF as PII firewall participant IF as Iframe participant IB as ImageBuddy U->>E: types prompt with "pixel art game" E->>PF: scan prompt alt PII detected PF-->>E: 400 pii_detected E-->>U: modal "Personal Info Detected"
(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
Per-asset 429s are silent. The 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.
Moderation is prompt-level, not asset-level. A PII block at /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

ConcernBehaviorEvidence
Same prompt twiceSame image (URL-deterministic)fast_ai?search=... is the cache key
Different size requestedDifferent image (resize is part of cache key)&resize=WxH
Want a variationMust change the prompt text (no seed control)no seed param in URLs
Force regeneration&cache_bust=<timestamp> — exposed only in avatar generator, not main editoruser_avatar_generator.html:956
Multi-asset regenChange any of: assets, style, theme, requirements, sheet_size, modelmulti-asset hash formula

§7 Rate limit / quota visibility

402 Payment Required on the main AI call → redirects to /payment_required. Handled at script.js:662-753.
429 Too Many Requests on the main AI call → toast "We are getting a lot of requests right now. Please try again in N seconds." Also at script.js:662-753.
Per-asset 429 (ImageBuddy rate-limit during <img> fetch) → broken image, no UI signal. The progress overlay cannot distinguish "slow because generating" from "failed because rate-limited."
No quota meter. User has no visibility into their remaining quota until they hit a limit.

§8 Verification pointers