The Creative Loop
A user has an idea. How do they turn it into a published page — and what are all the ways they can mess with it in between?
§1 The editor surface
The whole editor is a single page. Three tabs on the left drive everything on the right.
Left: three tabs. Right: toolbar + live preview iframe. Evidence: FuzzyCode/templates/index.html:207-535.
§2 Creation entry points — one real, seven loads
Despite appearances, there is only one in-editor "create" affordance: the "Fuzzy Code It!" button. Everything else loads existing HTML from somewhere.
Create tab button
POST /prompt_to_code]:::real L1[Paste clipboard
HTML or URL]:::load L2[URL params
?fromURL= / ?create_prompt=
/ ?action_prompt=]:::load L3[Load from Pages
/api/pages/import/<hash>]:::load L4[Local History
from IndexedDB
/local_recent_history]:::load L5[Tab-state restore
on refresh]:::auto L6[Level Editor
postMessage apply
existing project only]:::auto S1[Sample dropdown
fills textarea, doesn't submit]:::load R --> V[(projectVersionHistory
currentProjectId)]:::target L1 --> V L2 --> V L3 --> V L4 --> V L5 --> V L6 --> V S1 -.-> R V --> I[#responseIframe
live preview]:::target
confirmActionMode(..., "CREATE") dialog because typing a create-style prompt in an existing project is detected as an intent mismatch (script.js:1874-1876).
§3 Once a project exists — 20 ways to update
The #responseIframe is a reflection of projectVersionHistory[projectId][currentVersion]. You can't edit it directly. Every change flows through saveVersion(), which creates a new version entry.
5 Swipe button directions
center— make change (default)up— fast changedown— super fast changeleft— custom actionTyperight— major / meticulous (SweetAlert confirm on large projects)
3 AI Suggest engine
Fixestab — automated problem detectionImprovetab — quality suggestionsFeaturestab — new-feature suggestions- Cards are pre-cached per category; clicking one fires
/suggest_actions→/apply_action
5 Fix-error swipe (auto-show on iframe error)
fast,hard,custom,investigate,defaultvariants- Separate error container with prev/next error nav
- Fires
/apply_action[_fast]with error context
1 Touchpad Fast Change
- Tools Island button
#touchpadFastChangeBtn - Server-supplied prompt + agent
BIG_FAST_REASONER - Bypasses the large-project confirm dialog
1 Direct HTML edit
#editorButton→ popup code editor- PII cleanliness check via
/api/html/verify-cleanlinessbefore save - Can fail silently if the caller doesn't handle the error
1 Level Editor
- Gamepad icon opens
/level_editorin popup postMessage applyLevelChangescreates version with lastActionlevel_editor_apply
1 Metadata editor
- Puzzle icon
#openMetadataBtn→/metadata_page - Saves as
update_metadataversion - SweetAlert2 "save/discard" on unsaved close
1 Paste over current
- Tools Island
#pasteCodeBtn - No AI — saves clipboard as new version directly
- If no project yet:
paste_as_new_project
3 Navigation (no new version)
- Prev / Next — swap currentVersion
- Version dropdown — jump to any
- Refresh iframe / Diff / Fullscreen
- ⚠ editing an older version → silent branch (see §6)
1 Screenshot attach (next-request context)
- Tools Island camera / Save tab screenshot
- Opens modal with
#sendWithNextRequestcheckbox - Sent only on the NEXT AI request if checked
4 Project / context settings
- Project name +
#refreshProjectNameBtn - Visibility toggle (legacy + publishVisibilitySelect)
- AI model dropdown (60+ entries for admins)
- Ask modal (admin-only streaming SSE)
§4 The swipe button — up/down/left/right/center
Five distinct actions behind one UI element. Hidden affordance — new users rarely discover all five.
auto-fast if large
§5 The typical creative loop
(script.js) participant AI as Quart
core_ai.py participant IF as Iframe
preview participant T as Redis
/temp_page participant P as Pages
service Note over U,E: CREATE U->>E: types prompt, clicks "Fuzzy Code It!" E->>AI: POST /prompt_to_code AI-->>E: { html, description } E->>E: saveVersion('send', html) E->>IF: render v1 E->>T: POST /temp_page (preview URL) IF-->>U: sees rendered page Note over U,E: ITERATE (20 ways, mostly swipe button) loop several iterations U->>E: swipe center / left / right / tap a suggestion E->>AI: POST /apply_action[_fast] AI-->>E: { html, description } E->>E: saveVersion('apply_action_*', html) E->>IF: render vN+1 end Note over U,E: FIX ERRORS (if child iframe reports) opt on iframe error IF-->>E: ugc_asset_progress_child.js error event E->>U: show error-swipe button U->>E: Fix Error swipe E->>AI: POST /apply_action with error context AI-->>E: { html } E->>E: saveVersion('error_fix', html) end Note over U,E: PUBLISH U->>E: set name, visibility, press Publish E->>E: ensureHtmlCleanBeforeVersionSave (PII) E->>E: POST /api/pages/attest-publish (HMAC) E->>P: POST fuzzycode.dev/@pages/submit P-->>E: 200 { url } · or 202 pending · or 409 duplicate warning E-->>U: showPublishOutcomeModal
§6 Version history is a tree, UI is a dropdown
The version dropdown looks like a linear list. It is not — it's a flat rendering of a branching tree. Jumping to an older version and making a new change creates a new version whose referenceVersion points back to the older one. This is the undo/redo/branch mechanism, and it happens silently.
v1, v2, v3, v4, v5, v6. It doesn't visualize that v5 branched off v2 instead of continuing from v4. Users who "go back to try something different" create a divergent history without realizing it — and if they navigate back to v4, v5/v6 are still there but disconnected from their current line.
§7 Publish outcomes
One click, three distinct outcome dialogs. Worth knowing because two of them look like failure when they're not.
✓ Success · Private
HTTP 200URL returned · optional share URL · published_timestamp stamped. User is handed a link to share.
⏳ Pending parent approval
HTTP 202User selected Public. Row is stored as private with link_status=false and an approval request is opened. "Public" in the UI means "request approval" — stays private until a parent acts.
⚠ Duplicate hash warning
HTTP 409Response has matching_pages[] instead of url. Modal shows the user their matches and lets them choose update vs duplicate. Silent failure if the modal is dismissed.
§8 What persists — a quick survival note
Full persistence map in its own diagram. Short version:
| Event | projectVersionHistory (memory) | sessionStorage | IndexedDB | Server (/temp_page, @pages) |
|---|---|---|---|---|
| Tab refresh | lost | restored | survives | survives |
| Browser close + reopen | lost | lost | survives | survives |
| Clear site data | lost | lost | lost | /temp_page 30d · pages forever |
| Different device | n/a | n/a | n/a | /user_projects (Redis) 30d |
| Parent → Child context switch | cleared per-child | cleared | per-child key space | per-child |
§9 Gotchas the UX hides
index.html:46-72). No offline support; Cloudflare is the only cache.lastAction=update_metadata.§10 Verification pointers
- Editor UI
FuzzyCode/templates/index.html:207-535 - Create handler
FuzzyCode/static/script.js:1879-1910 - Swipe dispatch
FuzzyCode/static/script.js:5451-5490 - Suggestions
script.js:2295-2373 applyActioncorescript.js:2580-2720saveVersionscript.js:3227-3375- Publish flow
script.js:3891-3989 - PII gate before save
script.js:1947-2011· serverapi.py:1789 - Attestation endpoint
api.py:1655-1763 - AI server routes
core_ai.py:/prompt_to_codeL962 ·/apply_action_fastL1081 ·/apply_actionL1307 ·/suggest_actionsL1542 - Preview server
temp_pages.py:181-521 - Persistence
window_tab_state_restorer.js:255-319· IndexedDBscript.js:261-420 - Admin Ask streaming
admin/ask_experimental.js:100-180 - ServiceWorker unregister
index.html:46-72