Loading Minecraft Architect…

Ctrl+Enter to generate

Auto-tunes size & quality and tells the AI to keep the material list realistic for that play session.

Max structure size: 256 × 256 × 256 (mega sections up to 512) · Description up to 50,000 characters — very long specs are auto-split into chunks and condensed by AI so nothing gets cut

Build queue (0/20)

Queue the description currently typed above. Each job remembers which preset (whose quota) runs it — jobs run one at a time, and a failed job keeps its real error text for retry.

Scheduled builds (0/10)

Schedules the description currently typed above. No server: due builds are offered when you next open the app — consenting queues them (spends nothing); the queue's Run button spends quota. Daily schedules re-arm for the next 6:00 AM.

Work sessions — save & resume (0/10)

Park the build you're working on with its undo trail (last 10 steps) and typed description, then resume it exactly — even days later, even mid-edit. The Workshop stores finished voxel snapshots; sessions store editable work. Honest limits: 10 sessions per project (nothing silently evicted — the 11th save asks you to delete or overwrite), undo trail capped at 10 steps, and sessions live in this browser's storage like everything else.

Prompt Studio — A/B comparison (0/15 kept)

Runs the description typed above on both arms, sequentially, through the normal generate pipeline — two real generations, two real bills, each arm billing the key or preset you pick. Blocks placed and raw size are shown as facts, never scored — bigger is not better; the beauty number is a render-free heuristic, not taste.

vs
Principled micro-structures (0 tokens — deterministic)

A 1,000-block road should not be a 1,000-block file. Pick a kind: the app builds one full-quality 16-block module (a real .mcstructure) and prints its principle sheet — what recurs every N blocks and why, how junctions and endings work, what to do when the ground rises or water crosses. Honest division of labor: the app built the module; you extend the distance.

Real Build mode recreate real-world OR fictional architecture

Pick Real world for actual landmarks, or Fantasy / fiction for structures from movies, games, books and legend (Hogwarts, Minas Tirith…). Type the structure's name below, then (optionally) use the description box above for YOUR changes — scale tweaks, material swaps, "add an interior", "night-lit version"… The AI preserves the canonical silhouette, proportions and signature features, translating materials faithfully into Minecraft blocks.

Deep = block-accurate · same 1 call · cached separately

Tip: bigger size settings capture more detail — landmarks shine at Large/Huge with quality 4-5. Use Image to Build (Build tab) to recreate from a photo instead. Tick Mega build next to the Size selector to recreate a whole real-world site across multiple sections.

The Structured prompt builder now lives in its own — 19 architectural sections that compose into this description box.

Structured prompt builder 19 architectural sections — compose like a spec sheet

Split your prompt into professional sections instead of one blob: fill only what you care about — vision, exterior, structure, interiors, rooms, roofs, towers, bridges, landscaping, terrain, underground, lighting, palette, redstone, story, DNA, design rules and things to avoid. Compose assembles them into a labeled specification, drops it into the Build tab's description box and jumps there ready to generate. Sections are saved automatically between sessions.

Architectural Ruleset your personal building code — enforced on every build

Write your own building code, one rule per line (lines starting with # are ignored, max 30 rules). Every rule is injected into every generation as a mandatory requirement — like hiring an architect who knows your standards by heart. Saved automatically; applies across Build, Mega, Real Build, Director and Base Designer.

Build with what you have design around YOUR inventory

List the blocks in your chests and how many you have — the AI designs a build that uses ONLY those blocks and stays within your quantities. After generating, the material list is checked against your inventory and anything over budget is flagged.

Blueprint Editor review & edit BEFORE generating

Drafts a compact blueprint from your description (type, size, floors, roof, materials, features). Edit any field, then generate — the AI obeys your edited blueprint exactly. No more wasted generation time on wrong sizes.

World Context world-aware generation

Teach the AI about builds that already exist in your world. Every generation then inherits their palette, roof language and detail density — so a new wizard tower matches your existing castle and kingdom instead of clashing with it.

Import a .mcarch world-context file (from a compatible seed-analyzer app or hand-written JSON). It carries the world's terrain DNA, biome profile, suggested palette and ranked build-site candidates with coordinates — every generation then designs for that exact spot. Terrain data is honestly labeled: analyzer estimates say so; only files sampled from an actual world file claim real terrain.

Seed only — no file? Type what you know

Honesty first: a seed number alone tells this app nothing about your terrain — it can't simulate world generation. What it CAN do: record the seed plus whatever you tell it about the world, and feed exactly that to every generation. Estimated terrain never gets invented from it.

Build Workshop save · share · remix · rate · organize

Your personal build library with 3D thumbnails, tags, notes and search. Saves an exact snapshot of whatever is in the preview — generated, imported, merged or hand-edited — so it loads back byte-perfect. Rate builds, remix them into new variations, merge saved pieces into the current build to assemble villages, download any entry as .mcstructure, and share via compact codes — no account needed. Organize builds into world folders: create a world, select it, and every save lands in it — each Minecraft world gets its own build collection.

Import a structure (.mcstructure / Java .schem)

Preview any Bedrock .mcstructure in 3D and get its block list — or import a Java Edition .schem (WorldEdit / Litematica) and it's converted to Bedrock blocks automatically (Java → Bedrock). Export back with “Download .schem” for the reverse trip.

Import from a world (.mcworld) read-only

Open a Bedrock world export and cut any region out of it as a structure — your own base, a village, anything you built in survival. The world file is read entirely in your browser and never modified or uploaded. (Export a world from Minecraft: Settings → world → Export World.)

Director Mode prompt an experience, not a building

Describe what players should FEEL when they arrive — the AI directs structure type, scale, materials, layout, lighting, landmarks, interiors and approach, then writes the full build brief for you. Every emotion gets a matching color story (dread → blackstone + soul-fire blue, comfort → warm spruce + lantern amber, wonder → amethyst violet + light shafts…) so the palette carries the feeling. Uses World Context if enabled. Review the brief, then generate it with one click.

Map art & wall art

Turn any image — or an AI-drawn description — into a block mosaic. Lay it flat for Minecraft maps, or build it as a vertical wall mural. Staircase mode triples the color depth of flat map art by stepping block heights.

Sizes above 2×2 auto-split into one .mcstructure per map tile (named _mx_y) — works for flat, staircase and wall murals. Rotation makes art read correctly on maps hung sideways in item frames.

Image / Video to Build

Upload a photo — or a short video walkaround — of any structure and a vision AI recreates it in 3D. Video frames are extracted in your browser (nothing uploads until analysis). Scale is honored: the AI estimates the subject's real-world size (1 block = 1 metre) and builds to match — a large base comes out base-sized, not cottage-sized. You can also drag & drop a file onto this card or paste an image (Ctrl+V) while on this tab. Needs a vision-capable model (free Gemini flash works).

Super Mega Ultimate-Build

Builds sites spanning 512 to over 2000 blocks — far beyond one structure file. A master planner AI designs the whole site outline first; then each section is built one at a time (with an optional cooldown between sections to dodge rate limits) and exported as its own .mcstructure that you place side by side in-game. Add multiple API keys in AI Settings → Key Pool — if one hits a 429 rate limit, the next takes over automatically. This is meant to take a while; you can leave it running.

Note: sections larger than 256 can exceed what one in-game Structure Block load shows in its preview, but the .mcstructure files themselves load fine. Very large sections need strong AI models and take longer per section.

Functional Base Designer

Designs a complete survival HQ tuned to how YOU actually play — every zone placed with real game knowledge: mob-proof lighting grids, villager workstation/bed mechanics, portal coordinate math, raid-defense choke points and chunk-friendly farm layouts.

Zones picked and prioritized for your playstyle: storage, smelting, enchanting, farms, portal room, defenses, XP farm, villager hall and more — plus circulation logic (3-wide lit corridors, no dead ends), a material palette tuned to your style & biome, and your personal wishes woven into the design. Functionality level set automatically. Uses World Context and your inventory constraint if enabled.

Prompt Library expert-written briefs, ready to generate

Drops a full professional design brief into the description box — edit anything, then Generate. Great for learning how to write prompts that get architect-quality results.

3D Preview

All layers

Generate a structure to see the 3D preview

Drag to rotate · Scroll to zoom · Right-drag to pan

Try one of these to get started — each loads a full example prompt you can edit:

Honest note: the preview shows exactly the blocks that will be exported — no beauty filters, no staged renders. What you see here is what lands in your world.

Feature tutorials — every feature explained

Restores that report the real outcome

Restoring a full backup used to toast "Backup restored" no matter what actually happened — storage filling mid-restore or a blocked snapshot store failed silently, and you learned about the loss only when builds were missing later. Update 91: the result line states exact per-category counts — "Restored 41 of 43 entries + 5 of 6 exact snapshots — 3 FAILED (storage full or blocked)" — failures get 3.5 seconds of reading time before the reload, and the deliberately-skipped API-key entries are counted out loud so the arithmetic always adds up.

A restore confirm that stops lying

The old confirm claimed the backup "will REPLACE what is on this device" — false. The operation is a merge-overwrite: entries in the backup overwrite their current values; anything on this device that is not in the backup is left exactly as-is. The confirm now states the true semantics, so you know what you're agreeing to. Bonus honesty: a backup file with no timestamp used to display January 1970 (the computer epoch — an invented date); it now says "an unknown date (file carries no timestamp)".

Exports that admit what they're missing

If the exact-snapshot store couldn't be read, the full backup was silently written with zero snapshots and still said "Keep it safe" — a plan-only backup you'd discover at restore time, possibly after the originals were gone. The export now announces the degradation immediately: "this backup contains settings/library only, NO snapshots — your builds' plans are included; byte-exact copies are not." And the success toast counts the API-key entries excluded by design, so you can see the exclusion working rather than trusting a note field.

Storage limits that speak before they act

Browser storage is finite, and when it fills, the Workshop must evict oldest builds to fit a save. What changed in Update 90: the eviction is never silent. Every evicted build is named in the warning ("evicted the 2 oldest builds: “castle”, “farm”"), the message points at the library export, and the evicted builds' exact snapshots are actually freed — before this they vanished namelessly and their snapshot bytes leaked in the browser forever. A measured near-quota warning in the storage meter fires at 80% of the typical 5MB limit (computed from real stored bytes, never estimated), so you can export a safe copy before anything has to be evicted.

Imports that refuse instead of destroying

A real bug died in Update 90: importing a share code sliced the library to 30 builds even though the save cap is 60 — on a large library, one import silently destroyed every build past #30. Imports keep the adds-only promise now: at the true 60-build cap the import refuses honestly ("nothing was imported, nothing was evicted") and cleans up after itself. Duplicating at the cap got the same treatment — the one build the cap must evict is named in a toast and its snapshot bytes are freed, instead of being dropped wordlessly.

Filters that name themselves — and clear in one click

"Showing 3 of 20 builds (filtered)" used to make you hunt through three separate controls — search, tag chips, world selector — to find the one hiding your builds. The count line now names the active filters: "filtered by search “castle” + tag #medieval". And when filters match nothing, the empty state is no longer a dead end: a one-click Clear search & filters button resets all three at once and shows the whole library again.

Rename or delete a tag everywhere at once

Click a tag chip in the Workshop to filter by it, and rename / delete buttons appear beside the bar. Rename changes that tag on every build carrying it in one step — renaming onto an existing tag merges them (no build ends up with a duplicate pair). Delete removes the tag everywhere after a confirm that states what's destroyed and what isn't: the builds, ratings, notes and snapshots are never touched. The toast reports the real count — "renamed on 4 builds", not a guess.

Tag chips that tell you what matters

Every tag chip now shows how many builds carry it — the bar previously gave no sense of which tags were load-bearing and which were one-offs. The active filter is marked with aria-pressed so assistive tech tracks it too. And the 8-tag cap announces itself: adding a 9th tag names exactly which ones were dropped instead of silently discarding them.

Restores and loads that say what they did

Loading a build from history resets the undo timeline (it belongs to the previous build) — the status line now says so, because before it vanished silently and Ctrl+Z gave you nothing with no explanation. The crash-recovery restore also states how old the autosave is ("auto-saved 2h ago"): an hours-old session deserves a different level of trust than one from 30 seconds ago, and you should know which you got.

Rename a build without losing anything

Every Workshop card now has a rename button (pen icon). The name changes in place — the rating, tags, notes, version history, exact snapshot and branch-family links are all kept, because families link on internal ids, not names. Before this, fixing a typo meant delete + regenerate + resave, destroying all of that.

Names that refuse to lie

Renaming refuses empty names, refuses names over 80 characters instead of silently cutting them (a truncated name is a name you never typed), and refuses duplicates case-insensitively — "Castle" and "CASTLE" would be indistinguishable everywhere. The same doctrine now numbers duplicate copies — (copy), (copy 2)… — and announces branch-name trims with a toast.

Heard, not just seen

The Workshop status line (save/delete/import results) is now a live region screen readers announce automatically, the three big text boxes (build description, edit box, mod idea) carry real accessible names instead of vanishing placeholders, and the command-palette search input is named too. Accessibility floor keeps rising, batch over batch.

Rate builds without touching the mouse

The Workshop stars are now a real keyboard control: Tab lands on a card's star group once (not five separate stops), then arrow keys step the rating, digits 1–5 set it directly, and Delete / Backspace / 0 clear it — Home and End jump straight to 1★ or 5★. Screen readers announce the group as a slider with the current value ("Rating for Castle: 4 of 5 stars"). Keyboard and click share one code path, so behavior can never drift apart — and after a keyboard change, focus returns to the same card's stars instead of getting lost.

Escape closes the Undo timeline — and the cheat sheet tells the truth

The Undo timeline overlay was the only newer overlay that ignored Escape — every other one already closed; now it does too. Its step rows also show the exact timestamp on hover (the rounded "2h ago" stays for glanceability, precision is one hover away — the same contract the history panel keeps). And the ? cheat sheet finally lists Ctrl+Enter to generate, a shortcut that has existed for dozens of updates without ever being documented there.

Buttons that say what they count

Two Workshop card buttons showed a bare number — version history ("3") and branch family ("4") — which a screen reader read as just a digit with no noun. Both now carry real labels: "Version history for Castle: 3 earlier saves" and "Branch family of Castle: 4 related variants". The sort dropdown is named too ("Sort Workshop builds") — it previously had no label of any kind. Small words, but they're the difference between a UI you can hear and one you can only see.

Download names that never break

Name a build "Fort: Alpha/Beta?" and every export of it — .mcstructure, .mcpack, .schem, guides, PNGs, WebM — downloads with a clean name (Fort_Alpha_Beta): illegal characters become underscores, Windows-reserved device names like CON are guarded, names cap at 120 chars with the extension always kept, and an empty name falls back to "download". One sanitizer at the download choke point covers every export path at once.

One generation at a time — enforced honestly

Pressing Generate while a run is active (via Ctrl+Enter, the command palette, or a fast double-tap — all of which could race in before the button disabled) now refuses with a plain sentence: "A generation is already running — cancel it or let it finish first." Two concurrent runs used to be able to fight over the result and the status line. Also: the settings export now carries a date in its filename, so exporting twice never silently overwrites — and old undated files still import fine.

Named for screen readers, described for the web

The Workshop, tutorial and release-notes search boxes had only placeholders — which vanish the moment you type and which several screen readers skip entirely, leaving the boxes unnamed. All three now carry proper aria-labels. The page also gains a real meta description (search engines and link previews were inventing their own summary from stray page text) and an honest noscript message: with JavaScript off you used to get a blank dark page; now the app says plainly that nothing works without it.

Drafts: your typed prompt survives anything

The build description and mod idea boxes autosave a draft as you type (half-second debounce). Close the tab, crash the browser, lose battery — your text is back on the next visit. The honesty rule: a draft restores only into an empty box, so it can never overwrite something you're currently writing, and deliberately emptying a box deletes its draft. If storage is full, drafts silently step aside — typing is never blocked.

Mid-generation protection, online and off

Closing the tab during a generation now triggers the leave-page warning even if you've never generated before (the old guard only protected a finished build; Settings → confirm-leave opt-out still respected). And pressing Generate while offline is refused immediately with a plain sentence — no more waiting minutes for a cryptic network error. Local AI with a loaded model is exempt: generating offline on your own GPU is a feature.

A ✓ in the tab title when your build finishes

Started a long build and switched tabs? When it finishes in a hidden tab, the tab title gains a leading ✓ — visible in the tab strip and taskbar without any notification permission. It disappears the moment you return. This stacks with the opt-in completion chime and system notification (Settings) rather than replacing them. Also new: Ctrl+Enter in the mod idea box generates, matching the description box.

Palette search that matches every word

Press Ctrl+K and type multiple words — every word must match somewhere in a tool's name or hint. "jump size" finds Jump: build size; "mod recipe" finds Recipe Studio. Word order doesn't matter. Results stay in their fixed definition order — no hidden relevance scoring — and the live count under the input tells you exactly how many of the full tool list match (zero hits says so honestly).

Your recent tools float to the top

Open the palette with an empty query and your six most recently run tools appear first, each with a visible recent badge — that badge is the promise that this is the only reordering the palette ever does. A tool becomes "recent" only when you actually run it (Enter or click), never by just highlighting it. If browser storage is full or blocked, recents silently step aside and the palette works exactly as before.

Escape works the same everywhere now

One app-wide convention: in any search box, Escape clears the filter first — Workshop, Settings, prompt library, and (new in Update 84) the tutorial search, the release-notes search, and the command palette itself. In the palette it's two-stage: first Escape clears your query and shows the full list, second Escape closes. The footer inside the palette (↑↓ · Enter · Esc) documents the shortcuts right where they apply.

Generate a build

Build Generator tab → describe anything (up to 50,000 characters — very long specs are auto-chunked and condensed by AI so nothing is lost) → pick a size preset — or 📏 Custom for exact W×H×D dimensions (1-256 each) → Generate. The 3D preview builds live; orbit with mouse/touch, scroll to zoom. Load a professional brief from the Prompt Library card for inspiration.

Quality, interior & functionality

Quality 1-7 controls detail passes: 4-5 add an AI decoration pass, 6 ✨ Ultra and 7 💎 Extreme run three AI passes with build-team-grade directives (micro-detailing, layered roofing, color theory). Interior 0-3 fills rooms with furniture. Functionality 0-3 adds working essentials → full base (enchanting, forge) → automated redstone (sorters, smelters). "Auto" lets the AI decide from your description.

Architectural styles

The Style dropdown forces a design language (medieval, nordic, japanese, gothic, elven…). "Auto" reads the style from your description. Styles control palette family, roof shapes and detailing rhythm.

Real Build tab

Recreates REAL architecture (Eiffel Tower, Taj Mahal, Big Ben…) with true proportions, signature features and honest material translation. Open the Real Build tab, type the landmark's name in its own box, and put YOUR changes (scale, materials, interior…) in the description box — they're applied on top of the faithful recreation. For giant real sites, use Mega Build with the "Real Build mega" checkbox instead.

Mega Build (multi-section sites)

Mega tab → choose grid (2×2 … 4×4) and section size (128 up to 512 per tile, or Custom) → Step 1 designs a master outline with elevation contracts → Step 2 builds each section as its own .mcstructure. Place sections at offsets of the section size. Use the Key Pool for rate-limit rotation, then run the Final continuity review to auto-fix seams.

Mega: visualize & continuity review

Visualize all together stitches every section into one combined 3D preview (downsampled for big grids). Final continuity review compares every seam (floor heights, palettes, border occupancy) and offers one-click AI seam fixes that edit only the border strips.

Map Art & Wall Murals

Map & Wall Art tab → upload any image (or describe one for AI pixel art). Choose the canvas: Flat on ground makes classic map art (place a locked map over it); Vertical wall builds the same image as an upright mural you look at directly — perfect for spawn walls and shop signs. Up to 4×4 sizes, auto-split into tiles.

Sideways & staircase map art

Rotate (90°/180°/270°) pre-turns the art so it reads correctly on maps hung sideways in item frames; add Mirror for glass panes viewed from behind. Staircase shading exploits real map lighting — blocks placed higher than their northern neighbor render brighter, lower renders darker — tripling the color count of flat map art. Fine-tune with the brightness / contrast / saturation sliders, restrict the palette (wool-only, concrete-only, terracotta, natural), and toggle dithering.

Image to Build

Open the Image / Video tab: upload a photo (or drag & drop it onto the card, or just Ctrl+V paste) — a vision AI analyzes massing, materials, colors, features and real-world scale, then rebuilds it in 3D at a matching size. Full design-path controls: scale, fidelity, scope, detail, style override and notes. Needs a vision-capable model (free Gemini flash works).

Blueprint Workspace (2D CAD)

The Blueprint tab is a real top-down CAD editor: draw walls (drag, axis-snapped, live length readout), place doors, windows and stairs, drag out labeled rooms, and manage multiple floors (the floor below shows as a ghost). Every object has stable properties — click with Select to edit window sill height, room label/floor material or stair direction. Compile → 3D converts the drawing deterministically (instant, free, no AI): foundation, framed walls, floor slabs, door/window cuts, real stair blocks and a gable/hip/flat roof in your chosen palette. Then use AI furnish to have the AI decorate the labeled rooms without touching your architecture. Auto-saves, undo/redo, export/import as JSON.

Blueprint Editor

Expand Blueprint Editor → "Draft blueprint" makes the AI propose type/size/floors/roof/features as editable fields → adjust them → "Generate from blueprint" locks your choices as hard constraints. "Instant procedural build" skips AI entirely.

Build DNA & World Context

Every result gets a DNA (palette, style, proportions). "Build another like this" reuses it. World Context stores DNA of multiple builds so new generations match your existing settlement — add the current build or scan an imported .mcstructure.

Workshop (variations, remixing & your library)

Workshop tab: generate variations, mutate a build boldly, or crossbreed two parents into a child that inherits both. The library now saves a 3D thumbnail with every build and supports tags, notes, search and sorting (newest / rating / name / size) — up to 60 builds, with a storage meter. Export/import the whole library as JSON, or share single builds as compact share codes.

Time Budget mode

Pick how long you actually want to spend building in survival — 30 minutes to a 100-day project. Size and quality auto-tune, and the AI is told to keep the material list realistic for that session: a 30-minute build uses only cobble/wood/glass; a weekend build can use bulk copper and terracotta; only a 100-day project gets rare blocks freely.

Prompt Library

Build tab, its own card: pick a category (Castles, Cities, Fantasy, Sci-fi, Survival) and a brief — Use drops a full professionally-written design brief into the description box. Edit anything, then Generate. Reading these briefs is also the fastest way to learn how to write prompts that get architect-quality results.

Theme re-skin (instant, no AI)

Builder utilities → Theme re-skin: swaps every block family in the whole build (walls, roofs, wood, stairs, slabs, doors…) to a new material theme in one click — Desert sandstone, Deepslate gothic, Ocean prismarine, Cherry blossom, End city and more. Shape and stair orientations stay identical. Try the same castle in 10 themes in 10 seconds.

Weathering — age any build

Builder utilities → Weathering: deterministically ages the structure by 10 / 50 / 200 / 1000 years. Moss creeps up from the ground, bricks crack, vines and moss carpets take over, and at 200+ years the upper walls start crumbling into a genuine ruin silhouette. Instant, free, and works on imported structures too.

Director Mode

Open the Director tab → describe the EXPERIENCE you want players to feel ("awe when they round the cliff") — the AI translates emotion into architecture and writes a full build brief; one click sends it to the Build tab ready to generate.

AI Team mode

Quality 5 + team toggle runs an 8-9 stage specialist pipeline: architect → engineer → artist → interior → redstone → terrain → landscape → director merge. Slower but dramatically richer. Watch each stage report in the status line.

Functional Base Designer

The Base tab designs a survival HQ tuned to YOU: pick a playstyle (Hardcore, Redstone engineer, Explorer, Farmer, PvP/SMP, Creative) and a game stage (early/mid/end) — zones, defenses and functionality level adjust automatically. A Hardcore base gets panic rooms and zero dark spots; an Explorer base gets a portal room and elytra launch tower.

Build with what you have

Build or Real Build tab → expand Build with what you have → list the blocks in your chests and how many (e.g. oak_planks × 320) → tick Constrain. The AI designs using ONLY those blocks within those quantities, and after generating, the material list is audited against your inventory — anything over budget is flagged in the warnings box. Copy from last build seeds your inventory from the current build's materials.

Quality Gates (auto-fix pass)

Every generation now runs three deterministic gates before you see it: Gate 1 lifts buried/floating crafting tables, chests, beds and doors onto real walkable floor; Gate 2 validates the entrance — clears obstructions and carves a doorway if the AI forgot one; Gate 3 audits interior furnishing and warns when rooms are emptier than the setting asked for. Free, instant, no AI calls.

Cancel & live pipeline

The loading overlay now shows the real pipeline stage (prompt → AI design → receive → validate → build 3D) and a Cancel build button that actually aborts the network request — no more waiting out a generation you regret. Works for normal and AI-team builds.

Settings tab

The Settings tab controls the app itself: forced single-column layout, viewer height (compact/standard/tall/auto — or drag the handle under the 3D viewer), horizontal panel split (drag the vertical grip between controls and viewer; double-click it or use Settings → Reset to restore), default start tab, autosave & crash recovery (restores your last build after a crash, within 24h), toast notifications, and 3D performance (battery saver → max quality render resolution).

Custom time budget

The Time Budget dropdown now has Custom: type any duration in plain words — "45 minutes", "2 hours", "5 days", "3 weeks" — and the app converts it to play-minutes, auto-tunes size & quality, and writes a matching material-realism instruction for the AI.

Voxel Editor — hand-edit any build

Click the hammer in the 3D preview toolbar. Left-click uses the tool, right-drag rotates the camera. Tools (hotkeys 1-4): Place (green outline shows where the block lands — on the clicked face, or on the ground plane), Remove (red), Paint (blue — swap type in place), Pick (eyedropper — grabs a block from the model as your active block). Full undo/redo (Ctrl+Z / Ctrl+Y, 200 steps). Press Done (or Esc) — materials, block count and the AI-editable plan resync, and every export includes your manual edits.

Region tools — select, copy, mirror, rotate

In the Voxel Editor, pick the Select tool (hotkey 5) and click two corners — a blue box highlights the region. Then: Copy / Cut / Paste (Ctrl+C/X/V — paste lands where you point, and the selection jumps onto the pasted region so you can chain operations), Delete (Del), Fill with the active block, Mirror X/Z and Rotate 90° in place — stairs, doors and facing blocks re-orient correctly. Every operation is ONE undo step. Duplicate a tower to all four castle corners in seconds.

Merge structures

Builder utilities → Merge structures: pastes a second .mcstructure into the current build at an X/Y/Z offset — the canvas grows automatically (negative offsets shift the base). Choose whether the pasted or existing build wins where they overlap. Join a house + garden, dock a bridge to a castle, or assemble a whole village, then export as ONE file.

Workshop exact snapshots

The Workshop now saves an exact byte-perfect snapshot of whatever is in the preview — including hand edits, merges, weathering and imported files (no AI plan needed). Cards with a green cube badge load back exactly as saved. Each card also has Merge (paste that saved build into the current one at an offset — assemble a village from your library) and Download (.mcstructure straight from the card). Share codes (MCB2) and library export/import carry the snapshots too.

Import from a world (.mcworld)

Build tab → Import from a world: open any Bedrock world export (Settings → Export World) and cut a region out of it — your survival base, a village, anything. The world's ZIP + LevelDB database is parsed entirely in your browser (nothing uploaded, world never modified). Enter the corner coordinates and size (same coords as in-game), extract into the 3D preview, then edit it, save it to the Workshop, or export as .mcstructure / .mcpack. Ground level is usually around Y 60–70.

Terrain fit — builds that sit on the land

Merge structures → tick Terrain fit: instead of pasting at a fixed height, the app scans the ground under the build's footprint (ignoring grass, flowers, trees and snow), sets the floor at the median ground level, chops trees and terraces hilltops that stick up into the build, and grows foundation pillars down into dips — each pillar using that column's own surface block so it looks natural. Perfect combo: extract terrain from your .mcworld, then terrain-fit a generated build onto it. Workshop merge supports it too — add t after the offset.

Java ↔ Bedrock converter

Two-way conversion. Java → Bedrock: Import card → open a .schem (WorldEdit/Litematica schematic) — blocks, stairs orientation, doors and slabs are translated to Bedrock automatically; then Download .mcstructure. Bedrock → Java: generate or import anything, then Download .schem with a Java version picker. Any Java-only blocks fall back to the closest Bedrock equivalent and get listed in the import report.

Workshop worlds

Group builds by the Minecraft world they belong to. Workshop tab → New world → name it (e.g. "Survival SMP"). While a world is selected, every save lands in it; the dropdown filters the library per world. Move existing builds with the button on any card. Deleting a world keeps its builds (they become unfiled). World assignments survive library export/import.

Director color psychology

Director mode now maps every emotion to a color story: dread → blackstone + soul-fire blue, comfort → warm spruce + lantern amber, wonder → amethyst violet + light shafts, hope → fresh moss greens + gold dawn accents… The brief commits the whole palette to the feeling, and the result panel shows the "Color story" row explaining which hues carry the emotion and which blocks deliver them.

Base Designer — your wishes

The Base tab now takes your personal input: pick architecture style (medieval, nordic, japanese, modern…) and the biome it sits in (mountainside terraces, swamp stilts, desert courtyards…), then type free-text wishes — "rooftop greenhouse", "no ladders", "40 double chests" — and they're treated as hard requirements. Combine with World Context and the inventory constraint for a base that fits your world and your chests.

Whole-build transforms & undo/redo

Builder utilities → Whole-build transforms: rotate the entire structure 90°, mirror it east↔west or north↔south (stairs, doors, torches and every directional block re-orient automatically), or Hollow out to strip all fully-enclosed interior blocks — a huge material saver on solid builds. Every AI edit, re-skin, weathering pass and variation now supports Ctrl+Z undo and Ctrl+Y redo, 30 steps deep.

Building Code inspection

Result panel → Building Code inspection: an instant, free survival-safety audit — finds sand/gravel that will fall when placed, flammable blocks touching lava or campfires (before your build burns down), mob-spawnable dark interior floors, doors with no ground beneath, deep unsupported overhangs, and survival-unobtainable blocks like bedrock. Get a PASS / VIOLATIONS grade with exact coordinates for every issue.

Layer-by-layer build guide

Result panel → Export layer-by-layer build guide: generates a printable HTML document with one page per layer — a colored top-down grid with a letter symbol per block type, a legend, and per-layer material counts. Print it (or keep it on a second screen) and build any structure by hand in survival, bottom layer up.

Build DNA v2 — the full genome

Every build gets a 12-gene design genome: style, palette, walls/roof materials, traits, plus new v2 genes — roof silhouette (flat/pitched/domed/stepped), era, mood, color usage, detail density and verticality. Click "full genome" next to Build DNA in the result panel to see all of it, and Copy genome as AI style prompt to reuse any build's exact design language in future generations. World Context and "Build another like this" automatically use the richer genome too.

Appearance & themes

Settings → Appearance: pick an accent color (emerald, sky, violet, amber, rose, slate), switch to compact density to fit more on screen, change text size, go square corners for a blocky Minecraft feel, reduce animations for accessibility, and set how long toast notifications stay. Everything applies instantly and is saved in your browser.

3D viewer customization

Settings → 3D viewer customization: drag the field-of-view slider (low = flat architectural look, high = wide-angle drama), pick a lighting preset (studio, noon, golden hour, moody night, flat), hide the ground grid for clean screenshots, switch to flat colors for faster rendering and clean color-checking, and tune camera orbit/zoom speed.

Generation preferences — your taste, every build

Settings → Generation preferences: set your preferred roof style, symmetry, palette bias, window style, foundation type and roof overhang once — every AI generation on every tab silently follows them (your description always wins if it contradicts). Also: default size/quality on open, and a blocks-to-never-use list (e.g. "no copper, no calcite"). Leave anything on Auto for zero influence.

Inspection checks are configurable

Settings → Inspection checks: turn off the survival legality check if you build in creative, and turn off overhang advice if your balconies and floating designs are intentional (overhangs are now style advice only — never counted as a violation). Gravity, fire, mob-lighting and door checks always run because those are real in-game physics.

Workflow & alerts — never babysit a generation again

Settings → Workflow & alerts: a completion chime and/or browser notification fires when a long build finishes (even with the tab in the background), auto-download saves the .mcstructure or .mcpack the moment it's ready, a live generation timer shows elapsed time on the loading screen and in the result status, confirm-before-huge guards against accidental Gianormous/World Wonder jobs, and auto-summary copies a paste-ready build summary (name, size, blocks, top materials) to your clipboard after every generation.

Prompt starters — 24 professional templates

Click Starters above the description box: 24 professionally-written build prompts in 6 categories (Medieval, Fantasy, Modern, Industrial & Redstone, Nature & Cozy, Epic & Mega). Each one demonstrates what a great prompt looks like — specific architecture vocabulary, materials, interior callouts and character details. Load one, tweak it to taste, generate. Great for learning how to write prompts that produce professional results.

Build Card — one-click shareable PNG

Result panel → Build Card: renders your current 3D view into a framed 1200×900 share card — screenshot up top, then the build's name, dimensions, block count, beauty score, a swatch strip of its top 12 materials and the description. Perfect for Discord servers, Reddit posts or a build portfolio. Position the camera the way you like first — the card uses exactly what you see.

Settings search — find any option instantly

The Settings tab now has a search box at the top: type "sound", "camera", "theme", "architect", "backup"… and only matching cards stay visible (collapsed groups auto-open when they contain a hit). With 60+ settings across 10 cards, this is the fastest way to find the one you want. Also reachable from the Ctrl+K command palette ("Search settings").

AI Prompt Architect — write "castle", get a specification

Settings → AI Prompt Architect: pick an expansion level (1 Light → 4 Master Architect) and every generation first passes your prompt through an intelligent expansion stage that turns vague ideas into professional architectural briefs — Minecraft techniques (slab layering, buttresses, hidden lighting), build-type systems (castles get gatehouses and curtain walls, villages get districts and roads), automatic World Context + Build DNA + Ruleset integration. It NEVER changes what you asked for — a small cozy cabin stays small and cozy, just fully specified. A comparison panel shows original vs. expanded (AI additions in green) with edit/copy/save/regenerate controls. Add learning notes so it obeys your standing corrections. Level 0 = off (default).

Structured prompt builder — 19 sections

Prompt Builder tab (its own tab since Update 30): split your idea into professional sections — Overall vision, World context, Exterior architecture, Structural engineering, Interior layout, Individual rooms, Roofs, Towers, Bridges, Landscaping, Terrain, Underground, Lighting, Palette, Redstone, Storytelling, Build DNA, AI design rules and Things to avoid. Fill only what you care about, press Compose and a labeled specification lands in the description box. Sections persist between sessions.

Fantasy mode in Real Build

Real Build tab now has two modes: Real world (Eiffel Tower, Taj Mahal…) and Fantasy / fiction — recreate structures from movies, games, books and legend (Hogwarts, Minas Tirith, Howl's Moving Castle…). Fantasy mode recalls the canonical depiction, spends its best effort on the recognizable signature features, translates fictional materials faithfully (white fantasy stone → quartz/calcite, magical glow → sea lanterns/end rods) and keeps impossible geometry where canon has it. Works in Mega Build too.

Architectural Rulesets — your personal building code

Build tab → Architectural Ruleset: write rules one per line ("every roof gets a 1-block eave overhang", "all balconies need visible supports", "a light every 8 blocks indoors") and every AI generation on every tab treats them as mandatory requirements — like an architect who knows your standards by heart. Toggle the whole set on/off without deleting it, load an example set to start, lines beginning with # are comments. Up to 30 rules, saved automatically.

Workspace Profiles — one-click layouts

Settings → Workspace profile: instantly reshape the whole interface. Beginner hides everything but describe-and-generate; Builder keeps practical tools; Architect shows analysis and inspection in compact density; AI Playground surfaces Director, mutation and DNA tools; Creator is for Map Art and image-to-build; Performance minimizes UI and speeds up rendering; Everything shows it all. A profile just sets the visibility checkboxes — fine-tune anything afterwards.

Command palette & shortcuts

Press Ctrl+K (or the search button in the header) to open the command palette: type a few letters and jump to any tab, tool, download or viewer action — ~30 actions searchable, arrow keys + Enter to run. Press ? anywhere for the keyboard-shortcut cheat sheet.

Prompt history & favorites

The History button above the description box keeps your last 25 generation prompts. Click one to load it back instantly, or press the ⭐ to favorite it forever (favorites never rotate out). Perfect for iterating on a prompt across sessions.

Smart auto mode for overhang advice

Settings → Inspection checks → overhang advice now defaults to Auto: it detects when floating/overhanging design is clearly intentional (a floating island, a sky base) and stays quiet, but still gives support advice on mostly-grounded builds where an overhang is probably a mistake. Set it to Always or Off to override.

Continuity guard — AI edits can't nuke your build

AI edits (Edit with AI, Build Doctor's enact-suggestions, Report a problem, auto-balance) are now double-protected: the server strips any air-carving operation big enough to delete a large part of the structure, and the app dry-runs every edit before applying it — if an edit would remove close to half your blocks without you asking for a demolition, you get a confirmation with exact numbers and can discard it untouched. Undo (↺) still works after every applied edit.

Settings backup & sync

Settings → Settings backup: export ALL your settings, generation preferences and visibility choices to a JSON file, import it on another device or after clearing your browser, or reset everything to defaults with one click. AI keys are never included in the export for safety.

Clean up your interface

Settings → Menu & feature visibility: untick any tab (Map Art, Mega Build, Director…), Build-tab tool (World Context, inventory, imports, Prompt Library, Blueprint Editor, time budget, Create mode, lore) or result-panel tool (Build Doctor, Code inspection, Mutation engine, Expansion planner, DNA tools, Report a problem, Builder utilities) you don't use and it disappears — tick to bring it back anytime. Also in Settings: 6 viewer sizes from Mini to fill-the-window, viewer background colors, an auto-rotating turntable for showcasing builds, and the complete AI configuration (keys, models, per-task keys, key pool, diagnostics) now lives here too.

Key Pool → per-task fill

In AI Settings → Per-task keys, each row now has a pool button that fills that task from your Key Pool (click again to cycle to the next key), and the Key Pool section has Distribute pool across per-task keys — one click round-robins all pool keys across Generate/Enhance/Lore/Analyze so every task gets its own quota.

Edit & Report a problem

After generating: Edit with AI applies text requests ("add a balcony on the south side"). Report a problem describes what's broken ("door leads into a wall") and the AI diagnoses + fixes it directly.

Build Doctor

Click Build Doctor in the result panel. A free structural scan verifies real issues (floating blocks, flat monotone walls, pancake roofs, missing lighting), then an AI critique scores 9 design categories. Works on imported .mcstructure files too. One click enacts all fixes via an AI edit pass.

Presentation: flythrough & stats

In the 3D preview toolbar: the clapperboard runs a 24s cinematic flythrough (establishing orbit → hero swoop → spiral reveal); the record dot saves it as a WebM video clip for showcasing. In the result panel, Build statistics gives instant free numbers: density, interior volume, light count, survival build-time estimate and shulker boxes needed.

Video to Build

In the Image / Video tab, choose Upload video clip: a walkaround/drone clip is sampled into 4-10 frames (your choice) in your browser, and the vision AI merges all angles — including sides a single photo can't show — into one 3D structure at faithful scale. Longer orbit clips benefit from 8-10 frames.

Scale-faithful vision builds

The #1 fix in Update 29: image and video builds no longer come out miniaturized. The default Match source scale mode makes the AI estimate the subject's real-world size from visual cues (door ≈ 2 m, storey ≈ 3 m, humans, vehicles) and translate at 1 block = 1 metre — a large military base, castle or cathedral uses the full footprint budget (up to 240 blocks). You can also force any tier from Small to World Wonder, or reuse the Build tab's size selector including exact custom W×H×D.

Design brief — analyze, review, approve

With Review design brief ticked (default), vision builds run in two steps: a cheap analysis first returns a design brief — what the AI sees, its real-scale estimate with confidence level, a proposed W×H×D, the material → block palette mapping, key features and how hidden sides will be extrapolated. Adjust the size boxes or edit the brief text, then Approve → build: the approved size is enforced exactly (it becomes a custom-size instruction). Untick the box for the old one-shot behavior.

Vision → Mega Builder bridge

When the analysis decides a subject's faithful scale exceeds a single structure file (footprint beyond ~240 blocks, or a multi-structure compound), the brief shows a Send to Mega Builder button: the full brief — subject, scale, massing, palette, features — is written into the description box and you land in the Super Mega Ultimate-Build planner to build it as a sectioned multi-file site. Honest note: the mega planner works from the brief text; the images themselves aren't re-sent to it.

Mega build checkbox — in every generator

Build and Real Build tabs now have a Mega build checkbox right next to the Size selector. Tick it and the full Super Mega Ultimate-Build menu (grid, section size, cooldown, master outline planner) appears inline — no tab hopping. Your description and settings stay where they are; press Step 1: Design master outline in the menu to plan the multi-section site, then Step 2 builds every section. The normal Generate button still makes a single structure, so you can compare both paths. The state of the checkbox is remembered.

Real Build deep research pass

Real Build tab → Deep research pass (on by default): before building, a dedicated AI research call produces a factual dossier — real dimensions in meters, proportion ratios, storey/tier counts, EXACT counts of signature features (4 minarets, 3 platforms…), facade window rhythm, material-to-block translations and the mistakes builders usually make. The dossier is injected into the build prompt as mandatory facts, shown in an editable panel (your edits are used on the next Generate) and cached per landmark so repeat builds cost nothing extra. Works for fantasy mode too, using canon depictions. It also feeds Real Build mega plans.

Prompt Builder — now its own tab

The 19-section Structured prompt builder moved out of the Build tab's collapsed panel into its own Prompt Builder tab with full-page room. Fill only the sections you care about (vision, exterior, interiors, roofs, lighting, palette, things to avoid…) and press Compose into description — the labeled specification lands in the Build tab's description box and you jump straight there ready to generate. Sections persist between sessions; hide the tab in Settings → Visibility if you don't use it.

Smart 429 wait — rate limits stop killing runs

Free AI tiers allow only a few requests per minute; hitting the limit returns error 429. Previously that failed your generation — now a smart wait kicks in: a live countdown (75s, then 120s on a second hit — matching the 1-2 minute free-tier reset window) and an automatic retry. The Stop/Cancel button works during the wait, including Mega Build's per-section stop. Applies to normal generation, Real Build, research passes and the mega planner/section loop — on top of the existing Key Pool rotation, which is still tried first. Toggle via command palette: “Smart 429 wait”.

Biome Designer — your own terrain

Mod Creator → Biome Designer (also in Ctrl+K): design a custom biome visually — temperature 0-2 (below 0.15 it snows automatically) and downfall set the climate bucket the biome generates in, a 4-layer surface stack (top / under / deep / sea floor) accepts vanilla names or your own custom block ids, and sky, water, grass and foliage colors tint the world with live swatch previews. A vegetation profile (plains, forest, dense forest, desert, barren, snowy) inherits matching decorations. Honest limits, stated up front: custom biomes require the Custom Biomes experiment toggle in world settings, only generate in newly explored chunks, and biome-specific fog uses the standard plains fog for now — the health check and export reminder both repeat this so nobody is surprised in-game.

World Gen Studio — ores & scatter

Mod Creator → World Gen Studio: make the world generate your content. Ore veins: pick the block (your custom ore or any vanilla one), the host rock it carves into (stone, deepslate, netherrack, end stone, sandstone), vein size 1-16, attempts per chunk 1-20 and a Y height band — the form suggests vanilla analogues (diamond: 8 per vein, Y -64..16; iron: 9, Y -24..56) so your ore feels balanced. Surface scatter: sprinkle plants, crystals or markers on grass/sand/stone with 1-in-N chunk rarity. Every feature can be restricted to biome tags (including your custom biomes) or left everywhere. The compiler emits real Bedrock feature + feature-rule JSON pairs; features apply to newly generated chunks.

Spawn your builds in world generation

The killer integration: generate any build in the Build tab, then in World Gen Studio pick type Structure and press “Use current build as the structure” — the exact 3D model is packed as a .mcstructure inside the behavior pack and wired to a structure-template feature that generates it naturally in new chunks: grounded on the surface, randomly rotated, with a 1-in-N chunk rarity you control and optional biome filtering. Scatter your custom shrines across a custom biome, drop ruined towers through the overworld, or seed a village of your own AI-generated houses. Fair warning from Bedrock itself: worldgen structures place as-is — terrain isn't smoothed around them, so compact builds (≤48³) work best.

AI worldgen + health & Auto-fix

The AI mod designer speaks worldgen now: “a crimson biome with glowing crimsonite ore deep underground and scattered blood crystals” yields a themed biome plus matching ore and scatter entries, with sensible heights and rarities — the server sanitizer clamps every number, fixes flipped Y bands and rejects invalid host rocks. The AI never invents structure features (those are yours to attach), and it restricts themed features to the biome it designed. The health check byte-verifies each biome ships both server + client JSON, every feature has its feature-rule partner, structure features carry their .mcstructure payload, and the experiment requirement is surfaced as an info line. Auto-fix repairs flipped Y bands, drops features with dangling structure refs and clamps out-of-range climate values — then re-checks.

Quests — objectives, progress & rewards

Mod Creator → Gameplay Studio (also in Ctrl+K): give your mod real progression with up to 6 quests. Pick an objective — kill (any mob id), mine (any block, including your custom ores) or collect (hold N of an item) — a target count up to 500, and an item reward with count. In-game, every step flashes live actionbar progress (“[Zombie Slayer] 7 / 10”) and completion pays the reward once, remembered per player by the world via dynamic properties. Kill and mine quests track instantly through Script API events; collect quests scan the inventory every 5 seconds. Custom items work both as targets and rewards — “collect 5 rubies, get the ruby sword” just works.

World events — the world fights back

Up to 4 recurring world events fire on real timers (1-120 minutes): mob surge spawns a wave of any mob around a random online player, item rain drops items from the sky above them, lightning storm strikes the ground nearby, and announcement posts a chat line — each event can carry its own herald message (“The horde approaches…”). Events skip cleanly when nobody is online and survive chunk unloads. Combine with quests for emergent gameplay: a zombie-surge event every 10 minutes plus a “kill 50 zombies” quest turns any world into a siege-survival mode.

Armor set bonuses & starter kits

Set bonuses (up to 3): list 2-4 armor piece ids — usually the full custom set the AI made — and pick a persistent effect (resistance, speed, strength, regeneration, fire resistance, jump boost, night vision) at level 1-3. The script checks worn equipment every 4 seconds and quietly re-applies the effect while the full set is on; take a piece off and it fades. The Studio lists your mod's armor ids so you don't have to remember them. Starter kit: a one-per-player gift on first join — up to 9 item lines (“bread x 8”, custom ids fine) plus an optional welcome message, remembered forever by the world so re-joins never double-pay.

How gameplay compiles — stable Script API

Everything Gameplay Studio makes lands in ONE generated scripts/main.js inside the behavior pack, using only the stable @minecraft/server 1.9.0 module — no Beta APIs toggle, no experiments, works on Minecraft 1.20.70+ (the same module that powers weapon lifesteal and right-click abilities since Update 34). The AI mod designer speaks the whole schema: “a ruby mod with a mining quest line, hourly meteor showers and a full-set speed bonus” yields quests + events + set_bonus in one shot, sanitized server-side (counts 1-500, intervals 1-120 min, max 6/4/3 systems). The health check opens the built .mcaddon and verifies each system actually landed in the script; Auto-fix drops set bonuses with fewer than 2 pieces and clamps out-of-range numbers.

Share links — builds that travel as URLs

Every Workshop build’s Share button is now a menu: Copy link, Copy code, or your device’s native Share… sheet. A share link packs the ENTIRE build — exact block-for-block snapshot included — into the URL fragment (gzip + base64): no server ever stores it, no account needed, and the part after # is never even sent over the network. Opening the link shows a consent prompt, then imports straight into the recipient’s Workshop. The Copy share link button under Download does the same for the current build without saving it first. Big builds make long links — the app warns past ~8 KB because some chat apps truncate URLs; fall back to the plain code or a library file.

Mod share links — whole add-ons in a URL

In the Mod Creator, Copy mod share link wraps your full spec — items, blocks, recipes, textures, biomes, worldgen, gameplay — into a #modshare= URL. The recipient opens it, confirms, and the exact add-on loads into THEIR Mod Creator, ready to tweak, health-check and download as .mcaddon. It shares the recipe (the spec), not the baked file, so they can remix it — change the namespace to avoid clashes if you both install it. Also new: the Workshop’s “Import share code” box now accepts pasted links, not just codes — it strips the URL wrapper automatically.

Build + add-on bundle (.zip)

One friend-ready file: Build + add-on bundle (Mod Creator, next to the share link button) zips your current build’s .mcstructure, your add-on’s .mcaddon and a README.txt with install steps for each piece. Works with either half alone — just a build, or just a mod. The .mcaddon installs with a double-click; the .mcstructure loads via a structure block (or use the .mcpack export for 1-click). Everything is compiled in your browser at download time, so the bundle always matches what the preview shows.

Sharing’s honest limits — why no .mcworld

Straight talk: this app does not export .mcworld files. A Bedrock world is a LevelDB database — a binary key-value store with compressed sub-chunk records that a browser cannot write reliably; a broken one corrupts on open. The bundle .zip covers the same need honestly: import the pieces into any world you own. Other limits worth knowing: share links live entirely in the URL, so there’s no central gallery — a link only exists where you paste it (that’s also why it’s private); chat apps may truncate links past a few KB (use codes or library files for mega-builds); and links from a future app version always import, but very old MCB1 codes carry plans only, no hand-edits.

Keyboard block hotbar — edit at Minecraft speed

The 3D editor now has a hotbar, just like the game: every block you pick (typed, eyedropper, or clicked) joins a most-recently-used bar of 9 swatches in the editor toolbar. Shift+1–9 swaps the active block instantly (plain 1–5 still switch tools), [ and ] cycle through the bar without reshuffling it, and clicking a swatch works too — if you were on Remove or Select, it flips you to Paint so the pick is immediately useful. The bar persists in the browser, so tomorrow’s session starts with today’s palette. Combine with the eyedropper (4): sample a block from the model, place a few, Shift+2 back to the previous one — no typing.

Version history — saving over keeps the past

Saving a build with the same name + description used to silently replace it. Now the Workshop keeps up to 3 prior versions: the card grows a ⏲ badge — click it for each version’s date, size and a block-count diff against the current save, plus a Restore button that loads that exact snapshot back into the 3D preview (press Save afterwards and today’s build becomes a version itself — that’s your redo). Bonus fix: saving over now carries your tags, notes, rating and world filing forward — they used to be wiped. Honest storage math: each kept version is a full snapshot in IndexedDB, and old ones beyond 3 (plus everything on delete) are freed properly — a leak that existed before this update.

Printable shopping list — gather with checkboxes

Printable shopping list (under the materials panel) exports a single self-contained HTML file: every block with its count, stack math (×64 + remainder) and a shulker-box column for bulk hauls, plus a checkbox per row. Open it on any device — phone next to your console works great — and tick blocks off as you gather; checked rows strike through, a progress counter tracks you, and the state is remembered by that browser (localStorage keyed to the build name). Hit Print for a clean paper copy — the button hides itself, checkboxes print. No app needed to use the file, ever.

Startup performance — what actually changed

Honest engineering notes: the app is 15+ ES modules, and browsers normally discover imports one file at a time as each downloads — a waterfall. Update 34 adds modulepreload hints for the whole static import graph, so everything fetches in parallel from the first byte of HTML. What was already fast stays honest too: the world importer (mcworld.js) only loads when you actually import a world, and the local AI’s model runtimes (WebLLM / llama.cpp WASM, tens of MB) download only when you enable local AI — never at startup. What this does NOT change: AI generation speed (that’s the model), and the service worker already made repeat visits near-instant — this mainly helps first visits and post-update reloads.

Keyboard & screen-reader pass — what Update 35 fixes

The app now plays properly with keyboards and assistive tech: a Skip to main content link appears when you press Tab on a fresh page, every focused control gets a visible green outline (:focus-visible, so mouse clicks stay clean), the tab bar exposes real tab/tablist roles with aria-selected, and status messages + toasts are live regions — screen readers announce them without stealing focus. The command palette (Ctrl/Cmd+K) is now a proper combobox: arrow keys move a highlighted option that assistive tech tracks via aria-activedescendant, Tab is trapped inside while it's open, and when you close it focus returns to where you were — no getting dumped at the top of the page.

Reduced motion — now follows your system setting

Settings → Motion has a new default: Auto, which reads your operating system's "reduce motion" preference live (prefers-reduced-motion) — flip it in Windows/macOS/iOS/Android accessibility settings and the app reacts instantly, no reload. When motion is reduced (by Auto or by choosing Reduced explicitly), UI transitions and pulse animations stop and the 3D preview's auto-rotate is forced off — a slowly spinning build is exactly the kind of ambient motion the OS setting is asking apps to avoid. You can still orbit manually with the mouse; reduced motion never takes away control, it only removes movement you didn't ask for.

Storage & diagnostics — see and free what the app stores

Settings now ends with a Storage & diagnostics panel that itemizes everything this app keeps on your device: Workshop entries, version-history snapshots (the real byte sizes from IndexedDB), drafts & histories (mod autosave, prompt history, favorites, learned style), settings, API-key entries (counted, never shown), and offline caches. Each row shows a human-readable size so you know what's big before you clear it. The buttons are surgical: Clear drafts wipes autosaves/histories but never touches your Workshop; Clear caches deletes the offline cache (next visit re-downloads, nothing of yours is lost); Download report saves a JSON snapshot of settings + storage + recent errors for debugging — with every secret replaced by [redacted].

Honest limits — the error log & accessibility scope

Straight talk about Update 35's reliability tooling: the error log is session-only and on-device — it captures uncaught errors and failed promises while the tab is open, and resets on reload; nothing is ever sent anywhere unless you download the report and share it yourself. The diagnostics report deliberately excludes key values (only counts), and browser storage estimates are approximations — localStorage sizing assumes UTF-16 and cache totals come from the browser's own estimate(), which varies by engine. On accessibility: this pass covers focus, overlays, live regions, and motion — but not every icon-only button got a bespoke aria-label; most rely on their existing title text, which readers do announce, just less elegantly. More polish will come; we won't pretend a checklist is done when it isn't.

Local AI on low-end laptops — Eco & CPU-lite

Update 36 adds two tiers built for weak hardware. Eco (~0.3GB) runs Qwen 0.5B on your GPU when WebGPU exists and automatically drops to SmolLM2-360M on CPU when it doesn't — made for machines like an old 8GB-RAM Dell with a 4GB GPU. CPU-lite (~0.26GB) is the tiniest model and runs on literally any modern browser, no GPU at all. Pick them in Settings → AI → Local model, or press Detect my GPU / open the Model setup wizard and let the app recommend one — the recommendation now also considers your RAM (navigator.deviceMemory), capping big models on 8GB machines. Honesty: small models write simpler JSON and weaker lore than the 3B/7B tiers — that's the physics of the size; the procedural engine still backs them up if output parsing fails.

Resource use levels — how the heat control actually works

Settings → AI → Resource use has three levels. Eco: 2 CPU threads, half the context window, 75% of the answer length, and a 1.5s cooling pause between AI calls. Balanced (default): half your cores, short pauses. Max: everything the machine has. Changing it unloads the model; the new limits apply on the next load. Straight talk: a web page cannot read your CPU/GPU temperature — no browser exposes it. What Eco really does is duty-cycling: fewer threads and smaller batches mean less sustained load, which is what actually makes a hot laptop cooler and quieter. Anyone claiming an in-browser "temperature monitor" is guessing; we'd rather give you the real lever.

Model setup wizard & fixing failed downloads

After you install the app (PWA), a setup wizard offers to pre-download local AI model(s) — tick one or several, and they download in sequence with a progress bar; the last one becomes your active tier. Reopen it anytime via Settings → AI → Model setup wizard. Downloads got tougher in Update 36: every model load retries automatically on a dropped connection, resumes from the browser cache (you don't restart a 5GB download from zero), and if huggingface.co is blocked on your network the CPU models try a mirror. Errors are now in plain language — "not enough browser storage" points you at Storage & diagnostics, "GPU out of memory" tells you to pick a smaller tier. Wizard downloads are per-browser: clear site data and they're gone.

Lifesteal game mode — permanent hearts, the honest way

The Gameplay Studio's new lifesteal system is the full game mode servers play: kill a player (optionally mobs too) and you permanently gain bonus hearts (1-3 per kill, capped 2-20); die and you lose some (0-3). Hearts persist per player in the world's dynamic properties and re-apply on every respawn. How it really works: Bedrock add-ons cannot change a player's max health attribute — the accepted community technique (which we use) is a permanent-duration Health Boost effect at the right amplifier, re-applied on spawn. That means bonus hearts appear above the vanilla row, and drinking milk clears them for a moment until the next re-apply tick. The old on-hit "lifesteal" weapon effect (heal yourself when you hit) still exists and is a different, simpler thing.

Custom effects — invent your own status effects

Update 36 lets mods add new effects (max 3 per mod). In the Gameplay Studio pick custom effect: give it a name, an aura particle (hearts, flames, souls…), up to 3 built-in effects it layers on (e.g. speed II + resistance I), and an optional pulse that heals or damages up to 3 hearts every 2 seconds for 5-60s. Then attach it to gear: in the item builder's on-hit or right-click power dropdowns your effects appear as custom:<id> — on-hit lands it on the target, on-use on yourself. Honest limit: Bedrock's vanilla effects HUD (the icons by your hotbar) is hard-coded — no add-on can put new icons there. Your effect shows itself through its particles and an actionbar label with its name, which is exactly how the big marketplace add-ons do it.

Settings sub-tabs & the iOS white-screen fix

Two quality-of-life fixes in Update 36. Settings sub-tabs: the chips at the top of Settings now filter — click AI and you see only the AI card instead of scrolling a mile; All restores the classic long page, your choice is remembered, and searching temporarily shows everything so results can't hide. iOS first-open: the app's styling loads from a CDN script, and on a fresh iPhone/iPad visit the page could paint before it arrived — a white screen with every panel visible at once. Now a tiny built-in stylesheet keeps the dark layout correct from the first frame and a loading splash covers startup; if startup genuinely fails you get the actual error with a Reload and a Reset-settings link instead of an endless spinner. Already-installed apps pick this up on their next update check.

Reporting a bug (beta testers, this one's for you)

Settings → Diagnostics now has a Report a bug button (also in the command palette). It opens a small form — what happened, steps to reproduce, what you expected — and packages your answers together with a diagnostics snapshot: app version, browser, device memory, active tab, AI mode and tier, recent errors. Honesty first: nothing is ever sent automatically. The app has no telemetry — you get a JSON file to download or a text summary to copy, and you hand it to whoever is collecting reports. API keys and other secrets are explicitly excluded from the snapshot, so the file is safe to share.

The getting-started checklist

New users now see a small Getting started checklist at the top of the Build tab: generate a structure, download a file, save something to the Workshop, build a mod, open the tutorials, install the app. Each step ticks itself off from real activity — it watches your build history, downloads and Workshop saves rather than just being clicked away. It disappears on its own once all six are done, or you can dismiss it early with the × button. Dismissed it and want it back? Open the command palette and run Getting-started checklist to restore it.

Why iPhones stopped zooming into every text box

iOS Safari auto-zooms the whole page whenever you tap an input whose text is smaller than 16px — which was most of ours, so every prompt box tap lurched the layout sideways. Update 37 bumps inputs, selects and textareas to 16px on small touch screens only (desktop keeps its compact sizing), which switches the zoom off at the source rather than fighting it with viewport hacks. We also capped the pixel-art editor's height so its buttons can't slide off the bottom of a phone screen — it scrolls inside its own panel now, like every other overlay.

Mod export hardening — fewer silent failures

Exporting a mod now fails loudly and early instead of producing a broken .mcaddon. An empty mod (no items, blocks, recipes or gameplay rules) is refused with a plain-language message; so is an invalid namespace — it must start with a letter and use only lowercase letters, numbers and underscores, and minecraft itself is reserved by the game and rejected. The health check also got stricter: it flags duplicate ids across items and blocks (Bedrock silently drops the second one — a classic "where did my sword go?" bug), bad namespaces, and display names over 40 characters that get clipped in the inventory UI.

Writing a bug report that actually gets fixed

A quick guide for beta testers: the best reports have three parts. 1) What happened — one sentence, specific ("the .mcaddon downloaded but Minecraft says it's invalid"), not "it's broken". 2) Steps to reproduce — the exact clicks, starting from a fresh tab if possible; a bug we can reproduce is a bug half-fixed. 3) What you expected — sometimes the "bug" is actually a Bedrock engine limit (see the honesty cards in this list), and knowing what you expected tells us whether to fix code or fix documentation. Attach the diagnostics JSON from the Report-a-bug form — it answers the "what device, what version, what mode" questions before we have to ask.

Full backup & restore — your safety net

Settings → Storage & diagnostics → Download full backup produces one JSON file containing everything: settings, prompt history, mod drafts, learning notes, and your whole Workshop including the exact byte-perfect snapshots stored in the browser database. Restore backup loads it onto any device (it asks before replacing anything, then reloads). Honesty notes: API keys are deliberately excluded — a backup file might be shared or synced, and keys never should be, so re-enter them after a restore. And since builds live only in your browser, a backup file on a real disk is the one copy a cleared cache or lost phone can't take from you — make one before big experiments.

The blueprint-editor crash — what happened

Transparency card: a tester's iPhone reported "undefined is not an object (evaluating f.openings.length)". The cause: the blueprint editor's status line counts the objects on the current floor, but the counter was written against an old data shape — floors store separate doors and windows lists, and there is no "openings" list, so the counter threw an error on every single redraw. Update 38 fixes the counter to read the real lists (defensively, so a missing list can never crash it again). This is exactly why the Report-a-bug flow exists — one line from a real device found a bug that every desktop test had walked past.

Why the app starts faster now

Before Update 38, the very first thing startup did was wait for the 651-block catalog to download before wiring up a single button — on a slow phone connection that meant seconds of dead interface. Now the catalog loads in the background: the UI is interactive immediately, and anything that genuinely needs the catalog (generating, importing a .mcstructure, map art) quietly waits for it — you'll see "Loading block catalog…" for a moment at worst. A failed download also retries once automatically before showing an error, which forgives the classic flaky-mobile-network blip.

Workshop paging for big libraries

A full 60-build Workshop renders roughly 600 wired buttons, thumbnails and star rows in one go — phones noticed. Update 38 renders the first 24 builds instantly and puts the rest behind a single "Show all" button at the bottom of the grid. Nothing is hidden from search or filters: searching, tag chips, world folders and sorting all still consider your entire library — only the initial card rendering is capped, and one click expands it for the session. Load, Merge, Share and every other card action work identically on paged and expanded views.

The beta welcome screen

First-time visitors now see a short orientation before anything else: what to test (generate builds, install mods in a real world, use it on a phone, try to break it), how to report problems (the Report-a-bug flow — nothing auto-sent, you deliver the file), and the honest limits that are engine facts rather than bugs — custom effects living on the actionbar, Bedrock's add-on boundaries, everything being stored in your browser. It ends with a choice: start the guided tour or explore freely. Dismissed it and want it back? Ctrl/Cmd+K → Beta welcome & testing guide, or the button in Settings → About this build.

About this build — knowing exactly what you're running

Settings → Storage & diagnostics → About this build shows the update number, the offline-cache version the service worker is serving, whether you're in the installed app or a browser tab, and your browser identity. Why it matters for beta testing: "it's broken" on an old cached version is a very different bug from the same report on the newest build — Copy version info puts the whole line on your clipboard so every report starts with the answer. If the cache version looks old, the app updates itself on the next load with internet; a hard refresh (Ctrl+Shift+R) forces it.

Errors that tell you what to do next

Browsers report failures in developer-speak: "Failed to fetch" means the network dropped, "QuotaExceededError" means storage is full, a JSON parse error usually means the AI hiccuped once. Update 39 translates these at the moment they happen: a network failure now says to check your connection or firewall, a full-storage error points at the exact Settings panel that frees space, and an AI formatting hiccup says to simply press Generate again. Where a message is already specific (mod health-check findings, namespace rules) it stays untouched — translation is only applied to the cryptic cases.

The release-candidate wiring audit

Before opening the doors, Update 39 ran a full static cross-check of the app's plumbing: all 13 tabs verified against their content panels (no button leads to an empty page), all 23 API calls in the front-end verified against real server routes (no request can 404 by design), and the long-running id sweep confirming every element the code touches actually exists in the page — zero dangling references, zero duplicate ids. None of this proves the app is bug-free (that's what you're here for!), but it does mean the failures you find will be real logic bugs worth reporting, not broken wiring.

Update 40's speed shortcuts

Three tiny habits that make the app feel twice as fast. Ctrl/Cmd+S saves whatever build is on screen straight into the Workshop — no menu hunting (if nothing is generated yet it tells you so instead of silently doing nothing). Double-click the 3D viewer to instantly reset the camera so your build fits the frame again after you've orbited off into space. And Esc now closes every overlay — including the bug reporter, the beta welcome screen and the AI setup wizard — so you're never trapped behind a dialog. All three are listed in the shortcut sheet (press ?).

Offline & online toasts — what they mean

Since Update 40 the app tells you the moment your connection drops or comes back. Being honest about what that means: generating new builds and mods needs internet — the AI runs on a server, not on your device. What still works offline: viewing already-generated builds, browsing your Workshop, the blueprint editor, the 3D editor, and re-downloading files you already made this session. If a generation fails right after an "offline" toast, that's your network — not a bug worth reporting. If it fails while you're clearly online, that IS worth a bug report.

Workshop: Duplicate before you experiment

The new Duplicate button on each Workshop card makes an independent copy — including the exact block-for-block snapshot — named "… (copy)". Use it before risky edits: duplicate first, load the copy, and hack away knowing the original is untouched. Copies count against the same 60-entry cap, so the oldest unpinned entries still roll off when full. Bonus micro-feature: your Workshop search text and sort order now persist between visits, so if you always sort by name, it stays sorted by name.

Mod Creator: the dice and the live namespace check

Stuck for a mod idea? The Surprise me dice next to the idea box fills it with one of 16 curated starters — edit it freely before generating, it's a starting point, not a commitment. And the namespace field now validates as you type: a ✓ means it's a legal Bedrock namespace (starts with a letter, only a-z, 0-9 and _, 2-16 chars), a ❌ explains exactly what's wrong — including the reserved words "minecraft" and "minecort" which the game itself refuses. Catching a bad namespace before generation beats a broken .mcaddon after.

Three new copy buttons for beta testers

Copy last error (Settings → diagnostics) puts the newest error message + stack trace on your clipboard — paste it into a bug report and the developer sees exactly what broke. Copy beta invite text gives you an honest one-paragraph invite for recruiting fellow testers; nothing is auto-sent or tracked — you paste it wherever you choose. And Copy build stats (Ctrl/Cmd+K → "Copy build stats") produces one line with your build's block count, unique block types and dimensions — perfect for sharing or comparing builds. All three copy to your clipboard only; the app sends nothing anywhere on its own.

The app now beta-tests itself (and what that does NOT cover)

Since Update 41, every release is checked by an automated browser that loads the app, clicks all 13 tabs, opens the palette and shortcut sheet, runs the Workshop, blueprint editor and Mod Creator checks, and blocks the release if any JavaScript error occurs. Being honest about the boundary: automation proves the app doesn't crash — it cannot judge whether a generated castle looks majestic, whether the app feels good on your phone, or whether a .mcstructure imports into your copy of Minecraft. Those three things are exactly why human beta testers matter, and why your bug reports are gold.

One-click Retry after a failed generation

When a generation fails, a Retry generation button now appears under the status message for 30 seconds. It re-runs the exact same request — same description, size, style, everything — with one click. Use it when the error message suggests a temporary cause: network hiccup, a busy AI provider, or a timeout. If the same generation fails twice in a row, the problem is probably not temporary — read the error text, and if it doesn't make sense, that's a bug worth reporting.

The honest time estimate on the loading screen

The loading overlay now shows something like "usually 20–55s on this device". Where that number comes from: your own last 8 generations on this device — not a marketing number, not a global average. That's why it's blank at first: the app refuses to guess before it has at least two real data points from you. Big builds, higher detail levels and slower AI providers all push the real time up, so treat it as a rough range, not a promise.

Checking for updates manually

The app updates itself automatically — the offline cache version quietly advances when you're online. But if you've just been told a fix shipped and want it now, use Settings → About → Check for updates. It asks the browser's service worker to look immediately and tells you plainly: either "you are on the newest version" or "update found — reload to use it". Nothing installs silently mid-session, and the About panel always shows exactly which update you're running.

Release notes — what changed, in plain words

Settings → About → Release notes (or Ctrl/Cmd+K → "Release notes") opens a plain-language summary of the recent updates — no changelog jargon, just what each release actually added and why. The list covers the last dozen releases; the complete history back to day one lives in the project README. The What's New banner at the top of the app still announces each new release once — the release notes screen is where you go when you want to look back further, or when you dismissed the banner too fast.

The beta survey lives in the app now

Settings → About → Beta survey (or Ctrl/Cmd+K) opens the full 79-question tester survey in 13 sections: first impressions, navigation, the text-to-build core, the "moment of truth" import into real Minecraft, performance, a feature deep-dive, ecosystem & workflow, an honesty check, pricing and favorites — plus a task checklist framed honestly as ideal targets, not requirements. Copy all questions puts it on your clipboard; Download as .md saves a file you can answer in any text editor. Nothing is submitted automatically — you answer at your own pace and send it back however you normally reach the developer. Skipping questions is explicitly fine; a half-filled survey that gets sent beats a complete one that doesn't.

Moving to another device — the safe way

Settings → About → Move to another device walks you through it: download a full backup (one .json file: all settings, the Workshop, exact snapshots — API keys deliberately excluded), move the file by email/USB/cloud, then on the new device use Settings → Storage & diagnostics → Restore backup. Addresses matter: browsers key their storage to the web address, and the app's permanent home is now minecraft-architect.pages.dev. If you have builds at an older temporary preview address, they did not follow you here on their own — back up there, restore here, done.

The road to v5.0 — where the app is heading

The v5.0 milestone landed: the app lives at its permanent address, minecraft-architect.pages.dev, on Cloudflare's global edge network. From here, the direction (not a promise — beta feedback outranks any roadmap): a Texture Pack Studio, landscape & terrain tools, an asset library, and longer-term "world intelligence" — the app understanding your whole world so districts, materials and build order fit together. Two things stay true the whole way: honesty about Bedrock's hard limits (add-ons cannot add true new dimensions — that's an engine restriction, not a missing feature), and everything you make staying yours, in your browser.

The app is live — what the permanent address means for you

minecraft-architect.pages.dev is the app's real home, served from Cloudflare's network of 300+ locations worldwide — it loads from a server near you, not one distant machine. Because the address is now stable, everything keyed to it is stable too: your browser storage, your PWA install, your bookmarks. Updates deploy atomically — when a new release ships, you get it on the next reload (or press Check for updates in Settings → About). And the honest privacy model is unchanged by going live: your builds, mods and API keys still live only in your browser — the server hands out files and stores nothing about you.

Install it like a real app (it is one)

On the permanent address the PWA install is worth doing: desktop — Chrome/Edge/Brave menu → "Install app" gives you a windowed app with its own icon; Android — browser menu → "Add to Home Screen"; iPhone/iPad — Safari share button → "Add to Home Screen" (Safari only — iOS restricts other browsers from installing PWAs, an Apple limit, not ours). After one online visit the service worker caches the whole app, so it opens and works offline — generation needs internet (or a local AI model), but viewing, editing and exporting saved work doesn't. Installed copies update themselves the same way the tab does.

Mega Auto size — let the app pick the grid

Both Mega pickers now have an Auto option (Update 45, a beta tester request). Auto reads your description for scale cues — keywords like village, castle, town, city, kingdom, metropolis, or explicit sizes like "800×600", "1200 blocks wide" or "2 km" — and picks the grid and section size for you, preferring fewer, larger sections (fewer AI calls, fewer seams). Honesty built in: the size summary line tells you why it picked what it picked ("castle keyword", "800×600 stated"), and the choice is deterministic — no extra AI call, no cost. If Auto guesses wrong, just pick a grid manually; manual always wins.

Smarter unknown-block rescue — no more gray stand-ins

AI models sometimes invent block names that don't exist in Bedrock — cut_quartz is the classic (it mixes the real cut_copper/cut_sandstone naming pattern into a block no edition has). Before Update 45 such names fell back to plain stone, turning white quartz builds gray. Now the rescue is family-aware: cut_quartz → quartz_block, unknown purpur variants stay purple, marble → quartz, limestone → smooth sandstone, slate → deepslate — 25+ material families keep their color. You still see every substitution in the warnings list after generation (honesty rule: the app never swaps blocks silently), but the swaps now respect what the AI meant.

Real Build research levels — Standard vs Deep

The Real Build research pass now has two levels (Update 45, a beta tester request). Standard is the dossier you know: verified dimensions in meters, proportions, signature features with exact counts, facade rhythm, common recreation mistakes. Deep asks the researcher to additionally write a per-element BLOCK SPEC: exact Bedrock block ids for every major surface, 2-3-block texture gradients instead of flat fills ("walls: 60% sandstone, 30% smooth_sandstone…"), and relief detailing with stairs/slabs/walls/trapdoors — plus color-honesty notes where no block truly matches. Same single AI call either way, just a longer answer; Deep dossiers are cached separately from Standard ones, and both stay editable in the dossier panel.

Sticky action bar — the primary button never scrolls away

Long forms used to push Generate / Compose / Compile off-screen — now each tab's primary action is mirrored into a bar pinned to the bottom of the left panel. It triggers the exact same button (and mirrors its disabled state during generation), so there's no second code path to distrust. Works on Build, Real Build, Mega, Map Art, Director, Image→Build, Base, Blueprint CAD, Prompt Builder and Mod Creator. Don't want it? Settings → Workflow → Sticky action bar → Off, or toggle from Ctrl+K.

Prompt Builder accordions — 19 sections, 5 groups

The Prompt Builder's 19 sections are now organized into five collapsible modules: Vision & story, Architecture, Interiors & systems, Terrain & landscape, and Palette & rules. Each group's header shows a live filled-count (e.g. “2/5 filled”) so you see what's inside without opening it. The first group starts open; everything you type still saves automatically and Compose works exactly as before — only the layout changed, not your data.

Tutorial category filters

The tutorial library grew past 185 cards — scrolling it stopped being reasonable. New category chips above the search box filter by topic: Building & AI, Editing & 3D, Export & game, Mod Creator, AI & keys, App & settings. Chips combine with the text search (pick a category, then type to narrow further). Honesty note: cards are matched by keywords, so a card can appear in more than one category — that's by design, not double-counting.

Focus mode (F) & Ctrl+/ shortcuts

Press F (outside a text field) to enter focus mode: the header, What's New banner and footer disappear, leaving tabs and your work area. Unlike zen mode (a saved Setting), focus mode is per-session on purpose — an accidental keypress can never leave you “stuck” minimal after a reload; press F again to restore. Also new: Ctrl+/ opens the keyboard shortcut sheet — the old ? still works, but Ctrl+/ matches what most editors use.

Storage health meter

Settings → Storage & diagnostics now opens with a quota bar: how much browser storage this site uses out of what the browser allows, color-coded green / amber / red with plain-language advice at each level. Why it matters: local AI models are up to 5GB each, and a full quota fails silently mid-download. Honesty notes: the number is the browser's own estimate (it can be conservative), and even green storage can be evicted by the OS under system-wide pressure — backups remain the only real safety.

One green to launch them all — button color unification

Testers counted five different colors on primary buttons (indigo Compose, orange Mega, pink Map Art, cyan Compile, rose Director…) — color stopped meaning anything. Now every primary execution button is the same accent green, and utility actions (Import, Export, Scan, History) stay neutral dark/outline. Bonus: because they all share one class, your Settings → Appearance → Accent color choice now recolors every primary button in the app, not just Generate.

World Context Importer — .mcarch files

Build tab → World Context card → Import world context (.mcarch) (also in Ctrl+K). A .mcarch file — produced by a compatible seed-analyzer app, or hand-written JSON following the world_context_v1 schema — carries your world's terrain DNA: archetype, biome profile, established build style, suggested palette, seed, spawn point and ranked ideal build locations with exact coordinates. Once imported, every generation (Build + Mega Build) automatically designs for the active site — right biome, right slope, right footprint, matching palette. The raw file is preserved byte-for-byte inside the app for future features like the district planner.

World Analyzer ↔ Architect — who does what

Since Update 63 the two apps have a clean division of labor: the World Analyzer answers "I understand your world" — it scores build sites, measures terrain, estimates ground prep and detects structures against ITS terrain model. Architect answers "I understand your creations" — it reads the Analyzer's frozen world_context_v1 export and designs for the chosen spot. Architect deliberately contains no terrain generator and no site-scoring engine: every terrain number you see here is the Analyzer's, always attributed, never re-measured. That way one team of specialists owns each half, and neither app pretends to do the other's job.

Ground prep numbers — where they come from

World details (Build tab → World Context → info button) now show each site's ground preparation estimate: blocks to clear, blocks to fill, and the net balance — e.g. "clear 340 · fill 120 · net +220". These are the Analyzer's deterministic volume calculations against its own terrain model, which is an approximation of real Minecraft terrain (its docs say so, and so do we) — treat them as planning figures, not gospel, and verify big earthworks in-game. The active site's ground-prep line also flows into generation prompts, labeled "analyzer estimate", so the AI designs with the terraforming burden in mind.

Detected structures & the scoring target

Two more things Update 63 reads from .mcarch files: the detected structures list (villages, ancient cities, monuments the Analyzer found) shown as chips in world details — click any chip to copy a /tp to it — and the build requirement the sites were scored FOR ("Sites scored for: Fortress Keep, 24×24×20"). That second one matters for honesty: a site's 91% fitness means 91% for that specific requirement, not universally — so Architect shows the target instead of letting the number float context-free. District data now also loads from the frozen exporter's districtPlan block (older per-site and top-level homes still work).

Why this score — the per-factor breakdown

Since Update 64, a build site's fitness score is no longer an unexplained number. Open world details and each site shows a "Why this score" panel: the Analyzer's own per-factor breakdown — flatness, terraform cost, biome compatibility, expansion space, view & orientation, infrastructure access — rendered as labeled bars with the exact values from the file. Architect displays these verbatim: it never rescales, reweights or recomputes them, because the scoring engine lives in the World Analyzer (Architect has no terrain model to score against). If a future Analyzer version adds factors we don't know yet, they're shown with a prettified name instead of being dropped — your data survives the app being older than the file.

Score vs confidence — two different numbers

Update 64 also surfaces the Analyzer's evidence confidence — and it's important not to confuse it with the site score. Score = how good the site is for your build requirement. Confidence = how much the Analyzer trusts its own data about that site (procedural-noise terrain scores lower than terrain sampled from a real world file; 2D heightmaps can't see caves, so "underground" confidence is often low). When overall confidence is below 60%, Architect shows the Analyzer's own recommended warning: inspect the site in-game before committing to a large build. A 95%-fit site at 40% confidence is a great site if the data is right — now you can see both halves of that sentence.

In the Analyzer's words — pros, cons & declared limits

Newer .mcarch files can carry an explainable report (the Analyzer's own plain-language pros and cons for the recommended site, plus "what would improve the score") and a list of self-declared analysis limitations — e.g. "sub-surface cavern geometry inferred from noise; verify before deep excavation". Update 64 shows all of it verbatim in world details, attributed to the Analyzer. Files without these fields look exactly as before: every new field is optional, absence is shown as absence, and Architect never fabricates an explanation the Analyzer didn't write. That's the standing honesty rule — external numbers are attributed, missing data says "not provided".

Ground prep as a haul plan — stacks, shulkers, double chests

Update 65 turns the Analyzer's raw terraform volumes into inventory language. Under each site's ground-prep line in world details you'll now see two chips: haul out (blocks to clear, packed into stacks / shulker boxes / double chests) and bring in (fill blocks, same packing). 2,304 fill blocks stops being an abstract number and becomes "36 stacks — 1.3 shulker boxes — under one double chest": you know before you leave base how many shulkers to bring. The packing constants are Minecraft's own — 64 per stack, 1,728 (27×64) per shulker box, 3,456 per double chest.

One printout, whole job — ground prep in the shopping list

The printable shopping list (Materials → Shopping list) now appends a Ground-prep section when World Awareness is on and the active world's selected site carries terraform volumes: haul-out and bring-in rows with blocks, stacks and shulkers, clearly attributed as "Volumes are the World Analyzer's estimate". Your build's block-by-block materials and the site's earthworks live on the same page — tick off gathering, print it, take it to the site. If no world file is imported (or you toggled world awareness off), the list looks exactly as before: the section only exists when real Analyzer data does.

Who owns which math — the B73 ownership line

Batch 73's rule, stated plainly: the World Analyzer owns terrain math — it computed the clear/fill volumes against its terrain model, and Architect consumes them verbatim, never re-measuring. Architect owns inventory math — dividing a block count into stacks and shulkers is pure unit conversion with no terrain knowledge, the same arithmetic the shopping list has used since Batch 44. The Analyzer's full terraform calculator also knows fill block types, tool times, TNT counts and /fill commands — but its export file carries volumes only, so Architect says "fill block types not specified in the file" rather than guessing. Regression tests pin that no terrain calculation ever migrates into Architect.

Builds remember their site — Workshop provenance

Since Update 66, "Design for this site" does more than pre-fill a description — it remembers the site. Generate your build, save it to the Workshop, and the entry carries site provenance: the world name, site name, coordinates, biome and the Analyzer's fitness score. The Workshop card shows a sky-blue site chip so months later you still know exactly which spot a build was designed for. It survives save-over the same way tags, notes and ratings do, and loading an entry restores its own provenance — a build saved without a site never inherits one by accident.

From saved build to its spot in one click

The site chip on a Workshop card is clickable: it copies the /tp command to the build's intended location straight to your clipboard — paste it in-game and you're standing where the Analyzer scored the site. This closes the loop the ecosystem has been building toward: World → Site → Score → Why → Terraform → Materials → saved Project that knows its place. If the Analyzer file carried no coordinates for that site, the chip says so honestly instead of copying a broken command.

Imported worlds now shape local generation too

Update 66 fixed a quiet gap: with World Awareness on, the local generation path (no API key needed) used to inherit style and materials only from saved-build DNA — an imported Analyzer world shaped the four AI paths but was silently ignored locally. Now the newest usable world entry of either kind feeds it: build DNA behaves exactly as before, and an imported world contributes the Analyzer's primary style plus its palette read in plain order — first entry as the wall material, second as the accent — values taken verbatim from the file, never inferred. Your description's own style words still win; the world only fills what you left unspecified.

The pending-site chip — see what your session is attached to

Since Update 67, clicking "Design for this site" shows a chip right under the description box: site name · world · coordinates · fitness score. It answers a question Update 66 left silent — "is this session going to save with a site or not?" — before you press Save, not after. The fitness number is the Analyzer's own score displayed verbatim; Architect never recomputes it. If no chip is showing, the next Workshop save carries no site provenance — what you see is exactly what gets saved.

Detach a site — builds never wear a site they weren't designed for

The pending-site chip has an × button: click it and the site detaches — the next Workshop save stores no provenance. Use it when a design drifts away from its original location ("this started as a ridge fort but it's really a generic tower now"). The same honesty applies automatically at the edges: importing a .mcstructure or .schem file clears any pending site (an imported file is a new session), and loading a Workshop entry replaces the chip with that entry's own provenance — or hides it if the entry has none. Nothing ever attaches silently.

Which builds live at this site?

The reverse of site provenance: open a world's details in World Context and each site card shows a "saved builds designed for this site" line whenever your Workshop holds matching builds — with their names listed. It only appears when there are real matches: exact site + world name equality against each build's saved provenance, nothing fuzzy. If a site card shows no such line, no saved build names that site — an honest empty state, not a hidden one.

Jump from a site to its builds

Click the "saved builds" line on a site card and Architect switches to the Workshop tab with the search box pre-filled with that site's exact name — the grid instantly filters to the builds designed there. It's ordinary search, visible in the box: clear it and the full library returns. Nothing is hidden behind a special mode.

Search your Workshop by place

Workshop search now matches site provenance too: type a site name ("North Ridge") or a world name and every build saved with that provenance appears — alongside the usual matching on build names, tags and notes. Handy for "what did I make for the desert world?" moments, with zero new UI to learn: it's the same search box.

One shopping list for the whole mega build

Since Update 75, once at least one mega section is built, a Mega shopping list button appears with the other whole-mega actions. It prints one list uniting every built section's materials — same checkbox/print format as the single-build list, same ÷64 stack and shulker arithmetic. If a world file with terraform volumes is active, the Ground-prep section (haul out / bring in) rides along: blocks and earthworks on one printout.

Counted at full resolution — never the preview

The combined mega preview is downsampled for big grids so it stays viewable — counting blocks from it would undercount by roughly the downsample factor cubed. The mega shopping list never touches the preview: it re-executes each built section's plan at full resolution and counts the real blocks. A materials number you haul chests by has to be exact, not approximately shaped.

Unbuilt sections: named, never estimated

If your outline has sections you haven't built yet, the list says so on the printout: "N sections not yet built and NOT counted here." It never estimates what an unbuilt section might need — those counts would be invented numbers. Build more sections, then download the list again; it recounts everything that exists.

Timeline map: pan & zoom — adjust where you're looking

Since Update 76 the World Timeline map isn't locked to the whole-dimension fit: drag the map to pan, scroll (or use the +/− buttons) to zoom up to 16× around your cursor, and hit the reset button to snap back. The replay slider, heatmap and player layers all keep working while zoomed — and hover tooltips plus click-to-copy /tp stay exact at every zoom level, because one shared inverse of the view transform does all the coordinate math. A drag never fires the /tp copy; switching dimension or opening a new world resets the view (old pan would point at nothing).

Structures on the timeline map — the seed cross-reference

Tick Structures (from World Context) and the timeline cross-references the open world against your World Context entries: an exact seed match (the world's seed is now read straight from level.dat, both Java and Bedrock) or an exact world-name match pulls in the World Analyzer's detected structures — villages, ancient cities and friends — drawn as rose diamonds at their real coordinates, with attribution printed under the map. Hover a diamond for its name and block position. To feed it: import the Analyzer's .mcarch for that world under Build → World Context.

Exact matches only — nothing fuzzy, nothing guessed

The cross-reference is deliberately strict: seed string equality or exact name equality — never "close enough". Seeds are 64-bit, so they're compared as verbatim strings (a rounded seed would silently match the wrong world). No matching entry? A note says so and tells you what to import. Matched a seed-only entry (which carries no structure list)? The note says that too — markers only appear for structures the Analyzer actually detected. Honest absence over invented map pins, always.

Light viewer backgrounds you can actually read

If you set the 3D viewer background to White (or Sky/Sunset) in Settings → Appearance, the overlays drawn on top of the canvas used to stay styled for darkness: the "Generate a structure…" hint was gray-on-white, near invisible, and the loading veil was a black slab over a white canvas — especially glaring on phones, where the viewer fills the screen. Update 83 classifies the background's actual brightness (Rec. 601 luma on the same hex the 3D scene renders — including your custom color-picker choice, so the canvas and overlays can never disagree) and switches those overlays to light-background styling. Dark backgrounds keep the original look, pixel for pixel.

No more white flash, green bar or black tap-box

Three mobile paper-cuts, fixed at the source. White overscroll flash: pulling past the end of the page on iOS revealed a white page behind the dark UI — color-scheme: dark plus overscroll containment ends it, and native form controls, scrollbars and autofill stop defaulting to white too. Wrong status-bar color: the browser/PWA theme-color was still the old green #166534 against the #17181c interface — both the meta tag and manifest.json now agree on the real UI color. Black tap-flash: Android/iOS painted a gray/black rectangle over every button you tapped — removed, while keyboard focus outlines remain fully intact for accessibility.

A 63-update-old dead CSS rule, confessed

Total honesty includes our own archaeology: since Batch 29, the CSS rule meant to lift bottom toasts above the iPhone home indicator targeted #toast-container — an element that has never existed (the code creates #toast-holder). The rule silently matched nothing for 63 updates, so bottom-position toasts sat partly under the home indicator the entire time. Update 83 points the rule at the real element and leaves the confession in a comment. Also fixed: the Max viewer height now uses dvh where supported — 100vh on mobile Safari includes the collapsed URL bar, which pushed the viewer's bottom controls below the visible screen (old browsers keep the vh fallback).

Library import that tells the whole truth

Importing a Workshop library file (Workshop → Import library) now classifies every build in the file before anything is written, and the result line names every bucket: how many were imported, how many were duplicates (already in your library, or repeated inside the file itself), how many entries had no plan or snapshot to import, and how many didn't fit the 30-build cap. Previously, overflow builds were silently sliced away after the status line claimed they were imported — the classifier makes that lie structurally impossible. The line always ends with the scope guarantee: existing builds untouched — import only adds.

Import guards: size limit & plan-only honesty

Two guards protect the import path. A 25 MB size limit is checked before parsing — a runaway file would freeze the tab mid-parse, so the app refuses it up front and reports the exact measured size ("That file is 68.4 MB — over the 25 MB import limit"), never a guess. And when a build's snapshot fails to store (browser storage full or blocked), the build still arrives with its plan, but it's counted and reported as "plan-only" — the import never silently downgrades a snapshot build and lets you believe it's byte-perfect when it isn't.

Provenance read-back & honest estimates

Since Update 79, library exports carry provenance (export date + app update). Now the import reads it back: "File exported 2026-08-13 by Update 82" appears in the result — and when a file carries no provenance (older exports, hand-made files), the import claims nothing rather than inventing a date. Elsewhere: the per-device generation-time estimate now states its own sample size — "usually 12–31s on this device (from your last 8 runs)" — because a range built from 2 runs deserves less trust than one from 8, and you should know which you got. Escape also clears the Settings search now, matching the Workshop and prompt search contract.

Search your prompt library

The prompt panel (clock button next to the description box) now has a live search that filters favorites and recent prompts together as you type. The query is persisted, Escape clears it without closing the panel, and the panel is honest about results: a filtered view prints "showing X of Y matching …" so it never masquerades as the whole library, and "no prompts match" is a different message from "no prompts yet".

Prune recent prompts — favorites always survive

Every recent prompt now carries a delete button, and the header gains Clear recent. Both respect the store boundary: favorites live in their own list and are never touched by either action — the Clear confirm says so out loud, names the exact count being removed, and the toast reports what actually happened. Deleting a recent prompt that is also a favorite leaves the favorite standing.

Copy prompts with honest feedback

Each prompt row has a copy button. On success the toast reports the exact character count placed on the clipboard; if the browser blocks clipboard access, the app says so instead of showing a fake success. Hovering any prompt reveals its full text plus exact length and save timestamp — the truth behind the truncated preview.

Pin your best builds in Recent history

The Recent-builds panel keeps your last 8 generations — and now the tack button lets you pin the ones that matter. A pinned build is never auto-evicted: the 8-slot cap applies to unpinned entries only, so pins survive any number of new generations. The pin even survives re-generating the same build (the dedupe carries the flag forward). Pinning is a promise the app keeps, not a hint it may ignore under pressure — the only ways a pinned build leaves history are you unpinning it or pressing Clear.

Clearing history is now a safe delete too

The Clear button follows the same doctrine as Workshop deletes: the confirm names the exact count of builds being removed, calls out how many are pinned — with "pins do not survive Clear" stated out loud, never buried — and lists what is NOT touched (Workshop builds, settings, keys). After clearing, the toast reports the exact count removed. No vague "are you sure?", no silent scope surprises.

History panel: honest counts & exact timestamps

The panel header now shows an honest count — "N of 8 slots" normally, or the pinned breakdown ("6 builds · 2 pinned") with the cap rule spelled out right where it applies. Each entry still shows the friendly rounded age ("3h ago"), but hovering the age reveals the exact generation timestamp — the rounded bucket is a convenience, never a replacement for the real time. Pin buttons carry aria-labels naming each build, so screen readers hear "Pin Castle", not "button".

Safe deletes — an honest confirm + 10 seconds of Undo

Deleting a Workshop build now tells you exactly what is destroyed: the confirm lists the build's name, its block count, whether an exact snapshot dies with it, and how many earlier versions (with their snapshots) go too. After you confirm, the status line offers Undo for 10 seconds — during that window the snapshot bytes are deliberately kept, so Undo restores the build exactly: same library position, same snapshot, same version history. When the window closes (timeout, a newer delete, or leaving the page) the storage is freed for real — and the app says so instead of pretending an expired undo still works.

Workshop polish — search, ratings & timestamps

Small things that make the Workshop feel finished: press Escape in the search box to clear it instantly (the saved search is cleared too, and you stay in the field). Rating a build now confirms itself in a toast — and finally explains the convention: tap the same star again to clear a rating (that's why an unrated build is "unrated", never zero stars). And every card's date reveals the full saved timestamp on hover — down to the minute, not just the day.

Library exports with provenance

Exporting your Workshop library now produces a dated file — workshop_library_2026-08-13.json — so backups sort themselves and you always know which is newest. Inside, the file carries provenance metadata: when it was exported and which app update wrote it (extra fields only — files import fine into older versions). The status line reports the exact file size, measured from the real bytes written — never an estimate. Icon-only card buttons also gained aria-labels naming the build they act on, so screen readers hear "Delete Castle", not eight anonymous buttons per card.

Workshop library statistics — honest numbers about your collection

The Workshop shows a statistics strip above your builds: how many builds, exact snapshots, world folders and branch families you have, your average star rating, total blocks, your largest build, and the date span of the library. Every number is honest by construction: the average covers rated builds only (an unrated build is excluded, never counted as a zero star); total blocks sums only builds that store a count and says "across N of M builds" out loud; families count only when they truly have 2+ variants. Everything comes from data already saved with your builds — nothing is decoded, estimated or invented.

New Workshop sorts + honest filter counts

The sort picker gains Oldest first (revisit your earliest saves) and Smallest builds. Smallest has an honesty rule worth knowing: builds saved without a stored block count sort last, not first — treating "unknown" as zero would dishonestly crown them the smallest. And whenever a search, tag or world filter is active, the status line reads "Showing N of M builds (filtered)" — a filtered view never pretends to be your whole library, and zero matches says "0 of M shown" instead of a bare empty grid.

Block list percentages & exact shulker packing

The Block list panel now opens with a summary header: block types × total blocks × stack slots → shulker boxes. The packing math is exact, not the naive shortcut: each block type occupies its own stack slots (⌈count÷64⌉), and a shulker holds 27 slots — different block types never share a slot, so dividing the grand total by 1,728 would under-count what a mixed load really needs. Every material row also shows its percentage of the build; shares under 0.1% print "<0.1%" instead of rounding to a fake 0.0%. Exact arithmetic, labeled scope — as always.

Release-notes search & permalinks — find any update fast

The Release notes viewer (About → Release notes) now has a live search box — it filters titles AND descriptions as you type, with an honest match count ("no matches" means no matches, never a hidden truncation). Every "Update NN" entry also carries a permalink button (): click it to copy a URL ending in #rh-uNN that opens the app straight to that entry, highlighted. Broken or outdated anchor? The viewer opens anyway and a note says the entry wasn't found — links never fail silently.

Prompt counters & hints — honest and optional

Under the description box you now see word count, character count, and a ~token estimate — the token number is a plain chars÷4 heuristic and is labeled "(est.)" because that's what it is. Below that, up to three completeness hints may appear: no size mentioned, no style named, no materials named. These are simple word-list checks — hints, never blockers. A short poetic prompt with none of the three can still generate beautifully ("Auto" fills the gaps); the hints just tell you which levers you haven't pulled.

Micro-features everywhere — the 30% rule

From Batch 86 onward, up to 30% of each batch is small functionality polish — the constant-small-updates rhythm professional software lives by, tracked in a permanent ledger so progress is counted, never claimed. This tranche: the printable shopping list now shows blocks still needed live as you tick items off (exact ÷64 stack and ÷1728 shulker arithmetic on the real counts); the timeline map exports the current view as a PNG (the literal canvas pixels — pan and zoom included); and matched Analyzer structure diamonds are clickable — one click copies /tp to the structure's real file coordinates, with attribution in the toast.

Does the whole mega build fit?

Since Update 74 the Mega Builds outline shows a fit verdict for the plan's total ground plan — columns × section size by rows × section size, the exact same numbers the placement instructions use — against your pending site's declared footprint. It's the fit family's third surface, driven by the same pure check as the chip badge and the size hint: one arithmetic, three surfaces, they can never disagree.

Total bounds only — declared in the verdict itself

The mega verdict judges the grid's overall rectangle and says so right in the rendered text: "total bounds only — per-section placement not judged." Section roles, internal layout and where each section sits are the master planner's design — a green verdict means the whole footprint fits, not that every section is placed well. Honest scope, spelled out where you read it.

Read-only by design — a re-plan is not a dimension swap

Unlike the preview chip (rotate to fit) and the size hint (match the footprint), the mega verdict carries no action button. Reshaping a planned outline means changing its grid, its sections and their roles — that's a re-plan, not a dimension swap, and a badge click must never silently redesign a master plan. And if there's no outline, no site, or no declared footprint: no verdict at all — absence over guessing.

No stale verdicts

The fit badge's whole value is that it's always the truth about this build on this site. Update 73 audited every path that changes the build in the preview — generate, merge, transforms, imports, world-region extraction, version restore, Workshop load — and made sure every single one re-judges the verdict. A verdict that can go stale is worse than no verdict.

Fixed at the choke point

The two stale paths (world-region extraction, version restore) both flow through the one adoption function every parsed structure passes on its way into the preview. The re-judge now lives there — so all four current callers and every future caller refresh the verdict by construction, not by remembering to.

Restore a version, trust the badge

Workshop version history lets you restore an older save into the preview. Before Update 73 the fit badge kept describing the current build after a restore — now it re-judges the restored build's actual size against the pending site immediately. Same for extracting a region from an opened world.

Match the site footprint

When your planned Custom W×D differs from the pending site's declared footprint, a "match the site footprint (W×D → 20×24)" link appears under the size hint. One click sets Width and Depth to the footprint verbatim — Height untouched, because the fit check judges the X/Z ground plan only. It shrinks oversized plans and grows undersized ones to use the whole site.

Verdict → action, both ends of the pipeline

Update 70 gave the post-generation verdict an action (rotate to fit); Update 72 gives the pre-generation verdict one (match the footprint). Both follow the same doctrine: the action drives existing machinery, and the verdict updates by live re-judging — never by assuming the click worked.

Withheld, never clamped

If the site's footprint falls outside the 1–256 custom-size range, the match link simply doesn't appear. Clamping would set dimensions that don't actually match the footprint while claiming they do — so the action is withheld instead. Same rule as everywhere else: absence over a plausible lie.

Know before you generate

The fit check now runs before the AI quota is spent. Pick Custom size with a site attached and the W×H×D hint appends a live verdict for your planned footprint: "fits the pending site's 20×24 footprint", "…if rotated 90°", or "over … by 8 on X, 14 on Z" — recomputed on every keystroke. Shrink the plan (or pick a bigger site) before generating, not after a wasted generation.

One arithmetic, two surfaces

The size-hint verdict and the chip's fit badge run the same pure check — they can never disagree. Attaching or detaching a site refreshes the hint instantly; typing a new width or depth re-judges it on the spot. The planned height is passed along but honestly ignored: the check is X/Z ground plan only, and height/terrain stay World Analyzer's domain.

When the hint says nothing

No pending site? No declared footprint in the Analyzer file? The custom-size hint shows its usual volume + size-class line and nothing more — no verdict invented from missing data. The moment you attach a site that declares a footprint, the verdict appears; detach it and the verdict leaves. Absence is honest, always.

Rotate to fit — one click

When the fit badge says fits rotated, you no longer have to act on it manually: the pending-site chip's amber badge carries a "rotate to fit" button. One click turns the whole build 90° clockwise — the same trusted rotation as Utilities → Rotate 90° (stairs, doors and every directional block re-oriented; downloads use the rotated structure). The badge flips to green by live re-judging, not by assumption.

Transforms keep the verdict honest

Every Utilities transform — rotate, mirror, hollow, weathering — now refreshes the fit badge the moment it finishes. Previously a manual rotation left the verdict stale until your next generate; now the chip re-judges after every change that could move the ground plan. What you see on the badge is always the current build against the declared footprint — no stale answers.

Why saved builds don't get the button

Deliberate boundary: the "rotate to fit" button appears only on the live pending-site chip. Workshop card badges show the same verdict but stay read-only — a saved entry's stored structure must never be silently mutated by clicking a badge. To rotate a saved build, load it into the session first (Workshop → Load), rotate, and save again — an explicit, visible edit with a new save, never a hidden one.

Does the build actually fit the site?

Analyzer sites declare a footprint — the usable width×length of ground. Attach a site with Design here and the pending-site chip now shows a live fit badge: fits (green), fits rotated (amber — turn the build 90° and it fits), or over by N (red — how many blocks the ground plan overruns on each axis, using the least-bad orientation). It re-judges automatically after every generate, merge, or combine. No footprint in the file, or no build yet? No badge — absence is honest, never guessed.

Reading the fit verdict

The badge compares the build's X/Z ground plan only against the declared footprint — pure plan arithmetic. Fits rotated means the raw orientation overruns, but swapping width and depth (a 90° turn in-game) makes it fit. Over by N on X, M on Z reports the smallest possible overrun across both orientations, so you know exactly how much to shrink — or how much ground to clear. Width-only footprints are treated as square sites. Hover the badge for the full numbers.

What the fit check does NOT judge

Deliberate boundary: the fit badge says nothing about height clearance, slope, or terrain shape — those need World Analyzer's terrain model, and Architect consumes the Analyzer's declarations rather than re-deriving terrain math. The footprint number is the Analyzer's measurement (credited in the badge tooltip); the subtraction against your build's size is Architect's own arithmetic. A green badge means the plan fits the declared clearing — check the site's slope and foundation advice for the vertical story.

The full site loop — from Analyzer file to saved project

Putting Updates 64–67 together: import a World Analyzer .mcarch file → read why each site scored what it did (factor bars, confidence, pros & cons) → check the haul plan (clear/fill volumes as stacks and shulkers) → click "Design for this site" and watch the pending-site chip attach → generate and refine → save to the Workshop, where the card keeps the site chip with one-click /tp forever. Every number along the way is attributed to whichever app computed it — the Analyzer owns terrain intelligence, Architect owns build and inventory math.

Ideal build sites — pick where the AI designs for

Tap the info button on an imported world to open the details view: every candidate site shows its fit / flatness / scenic scores, exact X Y Z coordinates, biome and neighbors, slope angle, suggested foundation and footprint, distance from spawn, nearby landmarks with bearings, build opportunities with confidence levels, hazards and expansion room. If the file offers several candidates, press Use this site on any of them — the active site is what flows into your prompts. Design for this site goes one step further: it pre-fills the Build description from the site's facts (style, biome, slope, foundation, footprint, palette, top opportunity) so you can generate immediately.

World data honesty — estimates say so

World-context terrain data comes in two fidelity grades and the app tells you which you got. Analyzer estimate (the default): the site data is an approximate simulation of the seed, not a sample of your actual world — the details view shows an amber warning telling you to verify the spot in-game before a large build. Sampled from world file: only files that declare they read your real world data get the green checkmark. Same policy for opportunity confidence — if the file doesn't state one, the card says “confidence not provided” instead of inventing a number. This app never fakes certainty it doesn't have.

World Timeline — watch your world grow

The Timeline tab opens a real world file — Bedrock .mcworld or a zipped Java save folder — completely in your browser (nothing uploads). A top-down map replays every chunk in the order it was written: press play for a ~10-second replay, scrub the slider, switch dimensions, or flip on the age heatmap (blue = oldest, amber = newest) to see at a glance where you built first and last. Hover any chunk for its coordinates and time; click to copy a /tp command to its center. Player last-known positions (each player in their own color since Update 62) and world spawn (gold ring) are overlaid from the file's actual data.

Timeline player identity — who is who

Since Update 62 every player in the Timeline gets their own deterministic color — the same player is the same color on every reload (no randomness), on both their map dot and their card in the player list. Each card lets you rename the player and pick a custom color — both stored only in your browser, honestly labeled: save files contain no gamertags, so a viewer that claims to read real names from a file is making them up. Ids like “Player 3f2a91bc” are derived from the file's real storage keys (UUID fragments) — that part IS from the file. A focus button flashes a player's markers on the map so you can find them instantly even on a huge world.

Find a lost base — the bed/respawn square

Lost your base? The Timeline shows each player's bed/respawn point as a colored square on the map (their color), with a one-click /tp copy button on their card. This is real data: both editions store per-player SpawnX/SpawnZ, and it's set by sleeping in a bed — which players almost always do at home, making it the single best “where was my base” clue a save file contains. Pair it with the player's last-seen dot (where they were at the final save) and the age heatmap (your oldest chunks are usually your first base) and most lost bases fall in minutes. Some worlds have no stored bed point (never slept, or respawn reset) — the card says so honestly instead of guessing.

Why the Timeline shows dots, not routes

The dashed line between a player's last-seen dot and their bed square is a pairing of two real data points — deliberately drawn straight so it can't be mistaken for a path. Neither edition records player movement paths: Java stores one position per player in playerdata/, Bedrock one per player key in its database — that's it. If a viewer shows you a winding “player trail” from a save file, it's guessing; this one doesn't. What the file DOES give you for tracking someone down: their last position, their bed/respawn point, and the footprint + order of every chunk they caused to be written — all three are shown, and nothing more is invented.

Timeline honesty — what world files really store

Two editions, two truths, both labeled in the viewer. Java: region files store a real clock timestamp per chunk, so you get a true dated timeline (green badge). Bedrock: the LevelDB database stores no dates at all — but every write has a sequence number, so the replay shows genuine save order (amber badge), and database compaction may have squashed the earliest history. Neither edition records player movement paths — only last-known positions — so the app shows dots, not routes. If a viewer shows you a “player trail” from a save file, it's guessing; this one doesn't.

Seed-only world context — you are the analyzer

No .mcarch file? Build tab → World Context → “Seed only — no file? Type what you know”. Enter your seed (required) plus optional world name, the biome at your build spot, coordinates, and terrain notes (“cliff to the north, river below”). Exactly those facts — marked player-described — flow into every generation, and the prompt explicitly tells the AI not to assume anything else about the world. Honesty note: a seed number alone tells the app nothing (it can't simulate world generation), which is why this feature asks you instead of pretending to know.

Quickstart — your first 60 seconds

Brand-new users (no builds in this browser yet) get a small welcome card on first visit with three real choices: Try an example now loads a ready prompt into the box so your first Generate takes zero thinking; Read the guides first jumps to this Tutorial tab; I want a mod, not a build goes straight to the Mod Creator. It shows exactly once and never nags — returning users skip it entirely. Want it back? Ctrl/Cmd+K → Quickstart. It pairs with the getting-started checklist under the prompt, which ticks off your real progress (first build, first download, first Workshop save…) — nothing ticks itself.

Recent builds drawer — history from any tab

The Recent button in the header (also Ctrl/Cmd+K → “Recent builds”) slides open a drawer with your last 8 builds — name, age and description — reachable from every tab, not just Build. Click one and the app switches to the Build tab, reloads the full plan into the 3D preview and restores your prompt text, ready to edit, re-download or remix. Storage honesty: history lives in this browser only (localStorage, biggest plans skipped over 256KB) — clear site data and it's gone; the Workshop tab is the place for builds you want to keep long-term.

Honest progress bar — stages, not theater

While generating, the loading overlay now shows a progress bar above the five pipeline steps (understand → plan → exterior → interior → quality gates). Honesty rule: it advances only when a stage actually completes — it will sit still during a long AI pass rather than fake-crawl to 99% like most loading bars. That means a bar stuck at 20% for two minutes is telling you the truth (the design pass is genuinely still running, and the per-device time estimate above it says how long is normal), not lying to keep you calm. The elapsed timer and honest per-size estimates from earlier updates still apply.

Palette presets — re-skin the whole build

Builder Utilities → Palette presets (also Ctrl+K): pick a theme — Winter spruce, Cherry blossom, Nether fortress, Desert sandstone or Deepslate gothic — and one click swaps entire material families: every wood type’s planks, logs, stairs, slabs, fences, doors and buttons move together, and the stone presets remap the stone/cobble/brick family too. Because mapping is same-category (stairs→stairs, door→door), block orientations survive the swap. It’s deterministic and instant — no AI pass. Preview it, download it, or press it again on top: presets stack with the single-block swap and the vertical gradient above them.

Preset honesty — what re-skins will never do

Palette presets follow the app’s honesty rules. No invention: a preset only applies its explicit family mapping — blocks with no counterpart in the theme (glass, terracotta, your custom accents) are left untouched, and the status line says so. No unverifiable blocks: if a mapping target isn’t in the app’s block catalog it is skipped and counted in the report (“2 skipped — target not in this app’s block catalog”) rather than written blind into your download. No hidden edits: the status lists the actual swaps made (oak_planks → spruce_planks…) so you can verify. Downloads always contain exactly what the 3D preview shows.

Colorblind assist — blue/orange status colors

Settings → Colorblind assist (or toggle instantly via Ctrl+K): the app’s meaning-carrying colors switch from green/red to blue/orange, which stays distinguishable with the most common color-vision differences (deuteranopia/protanopia). It covers success and error text, pass/fail score colors, beauty-score bars, and the World Timeline’s age heatmap, which re-routes its ramp around the green zone. What it deliberately does not touch: block colors in the 3D preview — those are the blocks’ real Minecraft colors, and repainting them would misrepresent your build. The setting is remembered by this browser and applies instantly, no reload.

Undo timeline — visual history with jump-back

Next to Undo/Redo lives the Undo timeline button (also in Ctrl+K): it opens a list of every earlier state of your current build, newest first. Each row shows a thumbnail, the block count at that point, how long ago it was, and how many steps back it is. Click any row and the app walks the real undo chain to that exact state — no shortcuts, no reconstruction. Because it uses the same undo mechanism, every step lands in Redo (Ctrl+Y), so nothing is lost: jump back five steps, change your mind, and walk forward again.

Timeline thumbnails — real screenshots or an honest placeholder

Each timeline thumbnail is a real screenshot captured from the 3D preview at the moment the edit was made, downscaled to keep memory small. If a capture wasn't possible (the preview wasn't rendering yet, or WebGL declined), that row shows a plain placeholder icon instead — never a substitute image and never a rendering faked after the fact. So what you see in the list is what your build actually looked like at that step, or an honest "no capture" marker. History keeps up to 30 states; older ones fall off the back.

Parameter jumps — Ctrl+K takes you to the exact input

Type jump in the Ctrl+K palette to see 8 commands that land you directly on a specific control: build size, detail level, build style, prompt box, mod idea box, Java version (schem export), accent color, world seed input. Each one switches to the right tab if needed, scrolls the control into view, focuses it, and flashes a purple ring around it for a moment so your eye finds it instantly. Nothing is changed for you — the jump only moves focus; the value stays yours to edit.

Armor stands & paintings — why some things stay empty

Armor stands, item frames, paintings, minecarts and boats are entities, not blocks — a .mcstructure block grid physically cannot contain them. Older versions replaced them with a wrong block like stone; since Update 52 the app is honest instead: the spot is left empty and a warning tells you exactly which entity to place there in-game after loading. Meanwhile legacy block names the AI sometimes uses (red_flower, yellow_flower, tallgrass…) are silently renamed to their correct modern ids (poppy, dandelion, short_grass) — those are real renames, not guesses, so they no longer produce warnings.

Vine physics — no more floating plants

In Minecraft, a vine must touch a solid wall face (or hang below another vine), twisting vines grow up from a solid block, and weeping vines hang down from a ceiling. AI plans sometimes scattered vines in mid-air — they looked fine in the preview but popped off the moment the world ticked. Update 52 fixes this at both ends: the AI is taught the attachment rules up front, and a new quality gate checks every climbing plant after generation and removes any that in-game physics would break — iterating until the whole hanging chain is consistent. The gate reports how many it removed, so you always know what changed.

Staircases that actually connect floors

Beta feedback showed multi-story builds sometimes placed the upper floor off to the side of where the stairs arrived, with barely a gap to squeeze through. Update 52 adds strict staircase geometry to the AI's core rules: one continuous run (each step 1 up + 1 forward), a 2-wide opening cut in the upper floor directly above the stair head (never solid floor over it), 3 blocks of headroom on every step, the foot opening into the lower room and the head into the upper room — walkable without jumping — and the stair volume reserved before furniture is placed. Also fixed: a malformed AI answer now retries once automatically before showing an error, and “barrel” written in the op field is recovered as a real barrel block instead of a guess.

District planner — your world's master plan

When you import a .mcarch world context, the app preserves the raw file byte-for-byte — and the District planner is why. Open it via the map button on the world's entry in the World Context card, from the world details view, or Ctrl+K → “District planner”. It reads the Analyzer's districtSuggestions: each suggested district with its role, description, exact coordinates (click to copy a /tp command), footprint size and priority. A checkbox per district tracks what you've already built — remembered per world in this browser — and the progress counter shows how far your city has come.

Design this district — from plan to prompt in one tap

Every district row has a Design this district button: it pre-fills the Build description with the district's name, role and description, the world's established style, the world palette, and the suggested footprint — then jumps you to the Build tab with the text ready to edit. Combined with the active build site (fed into every generation automatically), the result is a build designed for that spot in that world, not a generic structure. The infrastructure roadmap below the districts renders the Analyzer's suggested build order as a numbered sequence — roads before houses, walls before towers.

Planner honesty — only what the file contains

Analyzer exports vary: some .mcarch files carry rich district plans, others none at all, and the shapes differ between versions — so extraction is deliberately lenient (plain strings or full objects, every field optional, legacy top-level districts[] accepted). But one rule is absolute: the planner shows only what the Analyzer actually provided. A file with no district data gets an honest “no district suggestions in this file” message with pointers to re-export or use Mega Build instead — the app never fabricates districts, coordinates or priorities that aren't in your file.

A/B diff — what actually changed between builds

The compare button next to Undo/Redo (or Ctrl+K → “A/B diff”) puts your current build against any recent build: the app re-executes the older plan and walks both grids cell by cell — no sampling, no estimates. You get exact counts of blocks added, removed, changed and identical, the top-5 materials your build gained and lost, and a top-down map where every column is colored by its topmost difference (added / removed / changed / unchanged footprint — and it says exactly that, because a top-down view can only show one difference per column). Perfect for checking what an AI edit or a re-generation really did.

Diff honesty — different sizes, counted separately

Comparing a 40×40 build against a 64×64 one raises an honest question: is the extra area “added”? The diff answers precisely: the overlapping region is compared block-by-block, and blocks outside the smaller build’s bounds are counted in the added/removed totals but reported separately with an explicit note — so you always know how much of the change is real edits versus footprint growth. Both diff colors and the summary respect colorblind assist, switching green/red to blue/orange when enabled.

Mini-map — your build from above, in real colors

The map button next to Undo/Redo (or Ctrl+K → “Mini-map”) renders a top-down map of the current build using the blocks’ real catalog colors — the same ones the 3D preview uses, never stylized. Surface mode shows the topmost block of every column with subtle height shading (higher = brighter); single-layer mode slices exactly one y level with a slider — great for checking floor plans, hidden rooms and interior layouts floor by floor. Hover any cell for the block name and coordinates; click to copy a build-relative /tp command. North (−z) is up, matching the structure’s export orientation.

Test Lab — how this app tests itself

Behind the scenes, every release passes through an internal Test Lab before it reaches you. It runs the exact production code — the same voxel engine, block catalog and .mcstructure exporter your browser uses — against a library of test builds, then applies 15 deterministic structure validators: floating blocks, unsupported overhangs, sealed-off rooms, floors without staircases, roof holes, dark interiors, liquid leaks, invalid block ids, attachment physics (torches/ladders/vines), plant ground rules, entrance pathfinding, material-count exactness, lossless export round-trip, terrain fit and an advisory symmetry check. Deterministic checks are the source of truth; AI opinions can never override them.

Fixed bugs stay fixed — the regression library

Every bug ever reported (including all six beta issues: entity honesty, legacy block names, op-field recovery, floating vines, malformed-answer retries, missing staircases) is preserved as a permanent regression test that replays on every release forever. The library even includes deliberately broken builds — houses with planted floating blocks, sealed rooms and stairless floors — and the release fails if the validators don’t catch every planted defect. Paired good/broken twins prove each check detects the fix, not just the bug. Nothing is discarded: every test run archives the full build, its validation results and diagnostic renders, so any failure is reproducible months later.

Release Health Report — the deployment gate

No release ships on a hunch. Before each deployment the Test Lab produces a Release Health Report with a confidence score built from a fully disclosed formula: fresh clean fixture runs (40 pts), a clean regression-library run (40 pts) and optional live prompt-library runs (20 pts) — stale evidence loses credit, failures cost points, and a low score means NO-GO. Honesty rules baked in: a skipped check never counts as a pass, screenshots are labeled as diagnostic voxel projections (not staged renders), and when the AI reviewer has no key configured the report says exactly that instead of inventing an opinion. You never see the Lab — you just get releases that earned their way out.

Texture Pack Studio — repaint vanilla blocks

Mod Creator tab → Texture Pack Studio: choose a vanilla block from the dropdown (■ marks ones you've painted), and paint its 16×16 texture in the pixel editor. Tools: pencil (drag to paint), flood fill, color picker (grab a color off the canvas), eraser, undo (40 strokes) and clear. Not sure where to start? The four seed buttons — Noise, Bricks, Planks, Tiles — generate a solid starting texture from your current color (deterministic: the same block + seed always gives the same art), then hand-edit pixels on top. Or Import image: any picture gets nearest-scaled onto the 16×16 grid, keeping pixels crisp. Everything autosaves in this browser per block as you paint.

Exporting and installing your texture pack

Name your pack and press Download texture pack (.mcpack) — you get a resources-only pack: manifest, a pack icon made from your first texture (honest: the icon IS your art, not a stock image), and each painted texture at the exact textures/blocks/….png path the game reads. Install: double-click the .mcpack (or open it with Minecraft), then enable it in Settings → Global Resources for everywhere, or per-world under the world's Resource Packs. Deactivate the pack and vanilla textures return instantly — resource packs never modify the game's own files. Unpainted blocks are simply absent from the pack, so they stay vanilla.

Texture pack honesty — what the Studio can't do

Straight answers. Why only ~30 blocks? The Studio offers only textures whose file names have been stable across Bedrock versions for years — if Mojang renames one in a future update, that single override silently stops applying (the game never breaks, your pack just does nothing for that block). Why no grass or leaves? Their textures are biome-tinted: the game multiplies them by a biome color, so what you paint would NOT be what you see — we don't offer what we can't deliver faithfully. Resolution: vanilla 16×16 only, no pretend-HD. Scope: a texture pack changes how blocks look for whoever has it active — it does not change .mcstructure files or other players' views. The app's 3D preview normally uses its own procedural textures; since Update 61 an opt-in toggle can overlay your painted textures there too — preview-only, with its simplifications stated right at the toggle (all six faces share one texture, exact block matches only).

Painted textures in the 3D preview — how to use it

Since Update 61: paint any Studio block (Mod Creator tab), tick “Show painted textures in the 3D preview” under the editor, then load or generate any build — every matching block renders with your texture, pixel-for-pixel, and updates live as you keep painting. The toggle is off by default and remembered per browser. Uncheck it (or erase a texture fully) and those blocks return to the app’s procedural look instantly. Tip: paint with the noise or bricks seed first, then recolor — flat single-color textures can look startlingly bare on a whole wall.

Preview overlay honesty — the simplifications

Straight answers about what the overlay does NOT do. Six faces, one texture: the real game gives blocks per-face textures (grass top vs side); the preview applies your one painting to every face of the box — a stated simplification, not a bug. Exact matches only: painting Oak Planks affects oak planks blocks — oak stairs, slabs and fences keep the procedural look, because pretending a full-block texture maps correctly onto cut geometry would be a lie. Side wins: if you paint both a side and a top texture (oak log), the preview shows the side one everywhere. Jitter off: painted blocks skip the per-block color variation so your art shows unmodified. In-game, the real pack behaves per Bedrock’s rules — the .mcpack you export is unchanged by this toggle.

Preview-only, guaranteed — why exports can’t be affected

The overlay lives entirely in the rendering layer: it swaps the material texture the viewer paints on screen, and never touches the voxel grid, the block palette, or any exporter. Your .mcstructure bytes are computed from the grid alone; the .mcpack is built from the Studio’s saved pixels regardless of the toggle; .schem and mod exports never read preview state at all. So there is no combination of toggle states that changes what you download — verified by an automated round-trip test that flips the overlay on and off and confirms engagement, disengagement, and zero errors. If you see painted textures in the preview but vanilla in-game, that’s not drift: it means the exported pack isn’t activated in Minecraft yet (Settings → Global Resources).

Testing the real thing — production e2e runs

Since Update 60 the automated browser suite runs in two modes against identical assertions: local mode drives the development build, production mode drives the live site at minecraft-architect.pages.dev. Only network timeout budgets differ — the deployed site's first paint takes ~33s in the headless rig versus ~2s locally, purely connection setup across several origins. Production runs catch what local runs structurally cannot: edge routing (_routes.json behavior), cache headers, CDN asset availability and service-worker registration on real HTTPS. Deliberate design: prod mode is inferred from the target URL inside the same script — there is no separate “lenient” prod test that could quietly drift weaker.

When the test fails but the site is fine

A diagnostic lesson from building production e2e, kept honest: during bring-up the production run timed out repeatedly — yet direct requests answered in 140ms and the site was healthy the whole time. The real culprit was the test machine itself running low on memory, which throttled the headless browser's page loads until they blew every budget. The doctrine now written into the test runner: “a prod-mode timeout is a memory signal first” — check the machine before blaming the deployment. Generalizable rule: when a test fails, first establish which side failed — the system under test or the test harness. We publish this because a QA system that hides its own false alarms teaches you to distrust it.

The deploy loop, closed — verify with the same tests

Release verification used to be manual spot checks: fetch the live page, grep for the new banner, count the tutorial cards. Since Update 60 the loop is closed properly: deploy, then run the full 30-test browser suite against production (one npm script). Every future release gets the same treatment — the exact tests that gated the build locally re-run against the edge deployment, so a deploy that uploads fine but misbehaves at the edge (stale cache, missing asset, broken route) fails loudly instead of waiting for a user to find it. Honest limits, unchanged from local mode: this cannot judge AI generation quality, WebGL pixel output, or real-Minecraft imports — humans still cover those.

The regression library — fixed bugs stay fixed

Every bug we fix earns a permanent regression case in the internal Test Lab — replayed on every release, forever. Two kinds: code pins grep the exact fix in the source (the fix itself is the artifact — if anyone removes it, the case fails and the release gate goes red), and fixtures replay a deterministic broken build through the real validators to prove they still catch it. As of Update 59 the library holds 13 cases: all six original beta issues plus pins guarding viewport suspension (U56), Workshop branch mechanics (U57) and the Texture Pack Studio honesty contract (U58). None need an AI key, so they run everywhere, always.

The Release Health gate — how we decide to ship

Before deployment, the Test Lab computes a Release Health score from three evidence tiers: the fixture suite (40 pts — validators prove they still catch known-broken builds), the regression library (40 pts — fixed bugs stay fixed), and an optional live-prompt tier (20 pts — needs a paid AI key). ≥80 is GO, ≥60 is CAUTION, below is NO-GO. The formula is fully disclosed in the report, evidence goes stale after 24 hours (stale clean runs only earn 60%), and never-run tiers score zero — missing evidence is never counted as passing. Update 59 re-ran the gate for the first time since Update 55: GO 80/100, the honest maximum without a live AI key.

Anatomy of a flaky-test hunt — the zombie browser

A war story from our own QA, shared because the lesson generalizes. Our automated browser tests began timing out even though the app answered instantly — the culprit was zombie browser processes from previously interrupted runs eating all available memory. The subtle part: the headless browser's real binary is named headless_shell, so cleanup that killed “chromium” or “chrome” by name had never actually matched anything. Since Update 59 the test runner sweeps stale processes by their real name before and after every run, a crash-safe exit hook guarantees the reap, and a watchdog aborts wedged runs loudly instead of hanging. The fix itself is pinned in the regression library — if it's ever removed, the release gate fails.

Workshop branches — variants without fear

Since Update 57, every Workshop card has a Branch button (). Click it, name the variant — “bigger towers”, “spruce version” — and you get a full independent copy of the build, exact snapshot included, with the branch name appended in [brackets]. Load the branch, edit it in the 3D editor, save over it as many times as you like (it even keeps its own version history) — the original is never touched. Branch a branch and the name tag is replaced, not piled up. Use Branch when you want the variants linked as a family; use Duplicate when you want a completely unrelated copy.

Build families — comparing your variants

Builds connected by branching form a family. Each member’s card shows an amber badge with its branch name, plus a family button showing how many variants exist. Click it for the family panel: every variant listed oldest-first with its block count, save date and an honest block-count delta against the card you clicked from, each with a one-click Load. The original build is labeled main. Deltas compare stored totals — for a cell-by-cell comparison of two loaded builds, the A/B diff tool (Ctrl/Cmd+K → “Compare”) remains the precise instrument.

Branch honesty — what they cost and where they travel

Straight answers about branches. Storage: a branch is a real, full copy — snapshot bytes and all — so it counts against the 60-entry cap and the storage meter like any other build; nothing is deduplicated behind your back. Deletion: members are independent — deleting one never touches the others, and deleting the original “main” leaves every branch fully working (the panel notes when main is gone). Travel: family links survive library export/import files, but share codes and share links deliberately carry only the build itself — recipients get your creation, not your private experiment tree. Save-over: re-saving a branch keeps it in its family and carries tags, notes and rating forward.

Renderer suspension — zero cost on hidden tabs

The 3D viewer renders on demand — and since Update 56 it goes further: on tabs without a preview panel (Tutorial, Settings, Mod Creator, Timeline), or when the browser tab itself is backgrounded, the render loop parks completely. Not throttled — stopped: no animation frames are scheduled at all, so CPU and GPU cost is genuinely zero while hidden. The moment you return, the loop wakes and draws a fresh frame first thing. Honest note: frames are deliberately not drawn while hidden — that IS the saving. One exception, by design: video recording overrides suspension so a flythrough capture is never silently truncated.

Reading the render stats — including park time

Settings → render stats shows what the viewer is really doing: render mode (auto = draw only on change; always = classic loop), draw calls, triangles, instanced meshes/instances, and frames rendered this session. Update 56 adds suspension accounting: if the renderer is parked right now the readout says SUSPENDED outright, and once the loop has spent time parked it reports the total seconds — phrased exactly as what it is: no frames drawn while hidden, which is the saving and not a bug. Numbers come straight from the WebGL renderer's own counters; nothing is estimated.

The empty viewport is now a launchpad

Before your first build, the 3D viewport used to show just a cube icon. Since Update 56 it's a launchpad: starter chips — one per Starters category (Medieval, Fantasy, Modern, Industrial & Redstone, Nature & Cozy, Epic & Mega) — each load a complete example prompt into the description box, ready to edit and generate. An import shortcut opens the same .mcstructure/.schem picker as the Import card, so you can inspect an existing file in seconds. Honest by construction: the chips are the exact prompts from the Starters library (nothing invented for show), and the placeholder states plainly that the preview shows exactly the blocks that will be exported — no beauty filters.

Create Engineer mode

Tick Create Engineer mode to design builds like Create-mod kinetic factories: water wheel / windmill power zone, ceiling shaft spine, framed machine bays in a production line, copper-brass-andesite palette. Honest note: Create blocks don't exist on Bedrock — this builds the aesthetic and layout with vanilla blocks, with open bays sized for real Create components on Java.

Lore generation

Tick Generate lore before generating: you get a title, backstory, design philosophy, eras, inhabitants, secrets, room stories and adventure hooks — plus Minecraft-book-ready pages (≤256 chars each) to paste in-game.

Animated build mode & layers

The play button in the preview toolbar replays construction block-by-block. The layer slider shows one Y-slice at a time — combine with the layer-by-layer build guide download to hand-build in survival (HoloPrint-style).

Local AI (no key, offline)

AI Settings → mode Local. Tiers: Max (Llama 8B HQ / Qwen 7B, ~6.5GB VRAM — RTX 5080/5090/4080-class), Ultra (8B, RTX 3080+), Quality (3B), Fast (1B), CPU+ (1.5B) and CPU (0.5B — runs with no GPU at all). One-time download, then fully offline.

Cloud providers & keys

10 providers: Gemini (free), Groq (free), Cerebras (free + fastest), Mistral (free tier), OpenRouter (free models), OpenAI, DeepSeek, Together, xAI, Fireworks. Add a key in AI Settings, press Load models to list exactly what your key can use. Per-task keys let different features use different providers.

Key Pool (rate-limit rotation)

AI Settings → Key Pool: paste several keys (one per line, provider:key). When one hits a 429 rate limit the server rotates to the next automatically — essential for Mega Builds on free tiers.

AI diagnostics

AI Settings → Diagnostics tests your main key, task keys, key pool, local AI and the built-in service, with latency and clear error hints ("key invalid", "model 404", "out of quota"). Run it whenever generation misbehaves.

Import .mcstructure

Expand Import → load any existing .mcstructure to preview it in 3D, analyze it, add it to World Context, or edit it with AI. Great for fixing or extending builds you made in-game.

Export: .mcpack, .mcstructure & build guide

.mcpack = double-click import (recommended, and the only easy path on iOS). .mcstructure = raw file for the world's structures/ folder. Build guide = printable layer-by-layer text plan with materials. Mega builds also export ALL sections in one .mcpack.

Beauty score & auto-critique

Every build is measured (silhouette, depth, palette, lighting, boring zones) into a beauty score. The critic AI reads the metrics and auto-improves weak areas. See the analysis panel for the breakdown.

iOS & iPadOS install

Safari → Share → Add to Home Screen → full-screen app with icon, offline-capable. Import structures via .mcpack from the Files app. Local CPU AI works on any recent iPhone; WebGPU models need iOS 18+. Android: Chrome → Add to Home screen.

Java Edition export (.schem)

Next to the downloads: Java Edition .schem exports a Sponge schematic with automatic Bedrock→Java block translation (doors, stairs, logs, lanterns keep orientation). Pick your Java version, then load with WorldEdit (//schem load name → //paste) or import in Litematica.

Desktop app & installers

Install as PWA from Chrome/Edge (Install app button) on Windows/macOS/Linux — or build native installers with the included Tauri project (see DISTRIBUTION.md; GitHub Actions builds .msi/.dmg/.deb automatically).

Reverse engineering (3D → Blueprint)

Loaded any structure — AI-generated or imported .mcstructure/.schem? Blueprint tab → From 3D build extracts editable architecture: floors, wall runs, doors, windows (with sill heights), roof type and material palette all become CAD objects. Edit parametrically, then Compile → 3D rebuilds it deterministically. The full loop: generate → reverse → edit → recompile.

Blueprint CAD hotkeys & drag editing

Work like a pro drafter: V/W/D/N/R/S/E switch tools (select, wall, door, window, room, stairs, erase). With Select: drag objects to move them, arrow keys nudge (Shift = 5 cells), Ctrl+D duplicates, Del deletes. Click any object to edit exact coordinates in the inspector. Invalid moves (door dragged off a wall) auto-revert.

Custom exact sizes

Size → 📏 Custom reveals W × H × D inputs (1-256 each) — the AI is instructed to make the plan exactly that volume and fill it purposefully. Works in text generate, AI Team, image-to-build and video-to-build. The Blueprint grid has its own Custom… W×D option (8-128) for non-standard floor plans.

Ultra & Extreme quality (6-7)

Quality 6 ✨ Ultra mandates micro-detail in every wall region, 3-material roofs with dormers, weathering gradients and designed grounds. 7 💎 Extreme adds structural storytelling, window mastery, interior scenes and 60/30/10 color theory at the full 3000-op budget. Both run three AI passes — expect 5-10 minutes and the best results the AI can produce.

Viewer performance & render modes

Settings → Viewer: Render mode "auto" only draws frames when something changes (huge battery/GPU saving on laptops and phones); "always" renders continuously for recording. Color jitter toggles per-block shade variation. Show render stats reveals draw calls, triangles and instancing counts — useful before recording cinematics of gianormous builds.

Theming & UI customization

Settings → Appearance: accent color presets or a custom color picker, font size, UI density, corner roundness, layout width. Toasts: position (4 corners), duration, sounds. Set a default tab and default size/quality so the app opens ready-to-go. Every setting exports/imports as JSON for moving between devices.

Safety nets: leave-confirm, autosave, undo

A loaded structure warns before you close the tab (Settings → toggle). The Blueprint editor auto-saves continuously and keeps full undo/redo history. 3D editor edits support Ctrl+Z/Ctrl+Y. Generation defaults, hidden features and your whole workspace survive refreshes via localStorage — export Settings JSON as a backup.

Block names: what the AI can use

The engine knows 650+ Bedrock blocks and auto-translates Java names (colored beds → bed, crimson_wood → crimson_hyphae), strips [state] suffixes, fixes plurals and hyphens. Truly unknown names fall back material-aware (cherry-ish wood → cherry log, copper stairs → matching oxidation stage) with a warning listed under the preview.

Mod Creator — make a Bedrock add-on

The Mod Creator tab turns an idea into a working Bedrock Add-On: describe your mod ("a ruby mod with glowing ore, a super sword and recipes"), pick a size (small/medium/large) and texture vibe, hit Generate Mod. The AI designs custom items (food with real hunger/effects, swords with damage & durability, tools), custom blocks (hardness, blast resistance, light emission, flammability) and crafting recipes linking them to vanilla materials. Every item and block gets a unique procedurally-drawn 16×16 pixel texture. Review the preview cards, then Download .mcaddon. Set your own mod name and namespace before generating, or open Customize spec after — a full JSON editor where you can change any name, color, damage value, texture pattern or recipe and instantly refresh the preview.

Installing your .mcaddon

Open the downloaded .mcaddon file — Minecraft Bedrock imports the behavior + resource packs automatically (Windows, Android, iOS; consoles need a file manager workaround). Create/edit a world → Behavior Packs → activate your mod (the resource pack comes with it). Get items with /give @s yourmod:item_id or from Creative inventory; recipes work in the crafting table immediately. Tip: each generation uses a unique namespace, so multiple mods can be installed side by side.

Mod Converter (Bedrock ⇄ Java)

Mod Creator tab → Mod Converter card: import an existing .mcaddon/.mcpack (Bedrock) or Fabric .jar/source .zip (Java) — items, blocks, crafting recipes and the original textures are recovered into an editable spec, and for Java mods the declared dependencies are scanned and classified (platform / library / external mod) with install notes. Edit anything in Customize spec, then export for the other edition. The report is honest: data-driven content converts; compiled Java code and Bedrock scripts (custom entities, GUIs, events, world-gen) can't be auto-translated — they're itemized under “Not carried over”.

Mod spec save / load & example ideas

Save spec (.json) stores your whole mod design as a file — reload it any time with Load spec to keep iterating, share it, or keep versions. The example chips above the idea box (💎 Ruby, 🥐 Bakery, 🌌 Void, 🔨 Copper) drop a well-written mod brief into the box — the fastest way to learn what detail level gets the best mods.

Java Edition & Modrinth export

The Mod Creator also exports for Java 1.21.1: Fabric source (.zip) is a complete compilable mod project — Java registration code, item/block models, blockstates, your procedural textures, Java-format recipes, lang file and a GitHub Actions workflow that builds the jar automatically (upload the folder to a GitHub repo → Actions tab → download the jar artifact; or build locally with JDK 21 + Gradle). Modrinth pack (.mrpack) imports straight into the Modrinth App, Prism Launcher or ATLauncher (“Add instance → Import”) and sets up a Fabric instance with the mod's resource pack pre-installed.

GPU detection & local AI tiers

AI Settings → Detect my GPU probes your graphics card via WebGPU and recommends the best local model with one-click apply. Tiers now cover every card class: Max (16GB — RTX 5080/5090/4080/5060 Ti 16GB) runs Llama 8B high-precision, the new Gamer tier (8-12GB — RTX 5060 Ti, 4060 Ti, 5070, 3060 12GB) runs Qwen 7B — the strongest JSON model that fits mid-range VRAM, Ultra/Quality/Fast cover 4-6GB and iGPUs, and CPU modes work with no GPU at all.

Phone & tablet interface

The mobile UI is tuned for touch: 42px+ touch targets, inputs sized so iOS never auto-zooms, the tab bar swipes with snap and shows a fade hint when more tabs are off-screen (the active tab auto-scrolls into view), the 3D preview keeps a usable height, and notch/home-indicator safe areas are respected. Prefer a specific layout? Settings → Layout → force Mobile or Desktop mode.

Settings reference — how to use this section

The cards below document every single setting in the Settings tab — what each option does, its default, and when to change it. Fastest routes: every settings card has a ? button in its corner that jumps straight to its reference card here, the quick-nav chips at the top of Settings jump between cards, and the settings search box filters by keyword. All settings save instantly to your browser (localStorage), never to a server, and all of them travel in the Settings backup JSON.

Settings reference — Interface

Workspace profile: one-click layouts — Everything (default, all tools), Beginner (only describe & generate), Builder (practical tools, no AI extras), Architect (analysis/pro tools + compact density), AI Playground (Director/mutation/DNA), Creator (Map Art/image/cinematics), Performance (minimal UI + fast rendering). It just sets the visibility checkboxes + density — fine-tune afterwards. · Layout mode: Auto detects your device; Desktop forces the two-column split with the draggable divider; Mobile forces single-column stacking with bigger touch targets. · Reset panel split: restores the default controls/viewer width if you dragged the divider too far. · 3D viewer height: Mini 320px → Huge 860px, Max fills the window, "Match content" tracks the left panel; the drag handle under the viewer and the ↕ toolbar button set the same thing. · Viewer background: 6 presets + Custom with a full color picker (affects the 3D canvas only). · Auto-rotate: slow/normal turntable until you grab the camera — showcase mode. · Default tab on open: "Remember" reopens your last tab; or pin Build / Base / Workshop / Tutorial. · Session auto-save + Auto-save interval (15s/30s/1min/2min): crash-recovery snapshot of description + build; after an unexpected reload you're offered a restore (24h window). · Slim header: shrinks the title bar to a thin strip. · Scroll-to-top button: floating ↑ after you scroll one screen down. · Notifications: floating toasts vs. status-line only. · Preview performance: Quality (full resolution) / Balanced (capped pixel ratio) / Fast (low res — weak GPUs, battery saving).

Settings reference — Workflow

All six live in Workflow & alerts, made for long generations you don't want to babysit. Completion sound: Off / Soft chime (two notes) / Level-up arpeggio (four rising notes) — plays when any generation finishes; picking one previews it instantly; loudness comes from Appearance → Sound volume. · Browser notification: "Only in background" pings you just when the tab isn't focused (recommended); "Always" pings every time; first use asks browser permission; shows the build's block count and elapsed time. · Auto-download: Off / .mcstructure / .mcpack — every successful generation immediately saves the chosen file with zero clicks (mcpack is the 1-click Minecraft import). · Generation timer: shows a live elapsed clock on the loading overlay and stamps the total in the result status — useful for judging model speed. · Confirm before huge generations: asks before Gianormous / World Wonder jobs so you never accidentally launch a 5-minute quota-hungry mega build. · Copy summary: after each generation, a paste-ready summary (name, size, block count, top materials) lands on your clipboard for Discord or notes.

Settings reference — Appearance

Accent color: recolors every primary action button — 6 presets (emerald default, sky, violet, amber, rose, understated slate) or Custom with a full color picker. · UI density: Compact tightens paddings/margins ~35% to fit more on screen — pairs well with small text. · Text size: Small 14px / Normal / Large 17.5px — scales the whole app. · UI font: Inter (default), System (your OS font — fastest, no webfont download), Monospace (terminal look), Serif (book-like). · Corner style: Rounded or Square — square gives a blocky, Minecraft-flavored UI. · Animations: Reduced kills all transitions/animations — accessibility (vestibular comfort) and snappier feel on slow devices. · App background tint: Charcoal / True black (OLED battery saver) / Midnight blue / Deep forest / Dark violet / Warm coffee — tints the page behind cards, independent of the 3D viewer background. · Toast duration (1.8s / 3.5s / 6.5s), Toast position (4 corners + top center), Toast style (Standard icon+border, Minimal plain text, Bold solid-fill) — picking a position shows a demo toast right there. · Sound volume: Quiet / Normal / Loud for the completion chime. · Leaving with unsaved work: Warn asks before closing the tab while a structure is loaded; Off closes silently. · Tab bar style: Full / Icons only (all 12 tabs on one row, hover for names) / Compact. · Zen mode: hides footer, banners & session stats. · Custom app title & subtitle: rename the header (and browser tab) to anything; clear to restore defaults. · Guided tour: replay the 7-step first-visit walkthrough.

Settings reference — 3D viewer

Everything applies live, no rebuild. Field of view (30-100°): low ≈ flat orthographic architecture-drawing feel, 50° default, high = wide-angle drama for cinematics. · Lighting preset: Studio (warm key + cool fill, default), Noon (bright neutral — true colors), Golden hour (warm sunset key), Moody (dim blue night), Flat (shadowless — best for checking palette colors). · Ground grid: hide it for clean screenshots and Build Cards. · Block rendering: Textured (procedural noise + per-block variation, Minecraft look) or Flat colors (solid tones — faster and better for reading the palette). · Camera speed: slow/normal/fast multiplies orbit + zoom rates. · Render mode: On-demand renders a frame only when something changes — huge CPU/battery saver (default); Continuous renders every frame — pick it when recording smooth video. · Per-block color variation: the subtle HSL jitter that makes walls look natural; off = uniform colors and slightly faster rebuilds. · Render statistics: click Measure now for draw calls, triangles, instanced mesh and instance counts, plus frames rendered this session — check before recording cinematics of gianormous builds.

Settings reference — Generation preferences

Your standing architectural taste — set once, every AI generation on every tab silently obeys unless your description contradicts it (your text always wins). Leave anything on Auto for zero influence. Roof style: steep pitched (stairs), hipped/low-slope, flat modern with parapets, domed/curved, pagoda tiers. · Symmetry: symmetric formal facades vs. asymmetric organic massing. · Palette bias: warm woods & earth, cool stone & gray, bright & light, dark & dramatic, or colorful accents (terracotta/wool). · Window style: tall multi-pane, small cottage with flower boxes, floor-to-ceiling glass, arched, or castle arrow slits. · Foundation: raised stone + entrance steps, ground-level entry, or stilts/piers. · Roof overhang: generous 1-2 block eaves vs. flush roofline. · Default size / Default quality on open: pre-select your usual size preset and quality level every time the app opens. · Blocks to never use: comma-separated blacklist (e.g. "calcite, copper, purpur") — the AI is told to avoid them in every build, and it's honored by re-skins too.

Settings reference — Inspection

Controls which Building Code checks run on the result panel. Survival legality: On flags survival-unobtainable blocks (bedrock, barriers, command blocks) as violations — turn Off if you build in creative and anything goes. · Overhang / floating advice: Auto (default) mutes the advice when the floating look is clearly intentional (many balconies, floating islands); On always comments on deep unsupported sections (as advice, never a violation); Off never mentions overhangs. · The non-negotiables — gravity blocks that will fall when placed, flammables touching lava/campfires, mob-spawnable dark floors, and doors with no ground — always run because they're real in-game physics, not style opinions. Every finding comes with exact block coordinates.

Settings reference — Visibility

Menu & feature visibility hides what you don't use — nothing is deleted, untick to hide and tick to bring back. Three groups: Tabs (Map & Wall Art, Mega, Real Build, Director, Base, Blueprint, Image/Video, Workshop, Tutorial — Build Generator and Settings can never be hidden, and if you hide the tab you're on, you hop home to Build), Build-tab tools (Ruleset, Structured prompt builder, World Context, Inventory constraint, both import cards, Prompt Library, Blueprint Editor, Time budget, Create Engineer mode, Lore option) and Result-panel tools (Build Doctor, Code inspection, Mutation engine, Expansion planner, DNA tools, Report a problem, Builder utilities). Workspace profiles set these checkboxes in bulk; your manual choices stick until you pick another profile. Hidden state exports with Settings backup.

Settings reference — Backup

Export settings (JSON) downloads every setting, generation preference, ruleset, architect learning notes, structured-prompt drafts, workspace profile and visibility choice as one file — AI keys are never included (they stay only in your browser). Import settings loads such a file and applies everything instantly — move between devices or restore after clearing browser data. Reset everything to defaults wipes all settings and preferences after a confirm — AI keys and your saved Workshop builds are kept. Tip: export once whenever you've dialed in a setup you like; the file is tiny and diff-able.

Settings reference — AI configuration

AI mode: Auto (cloud if a key is saved, else local), Local (your GPU via WebGPU/WASM — private, free, no key) or Cloud. · Local model: 8 tiers from Max (Llama 8B HQ, 16GB cards) through Gamer (Qwen 7B, 8-12GB), Ultra, Quality, Fast, down to CPU modes that need no GPU — or press Detect my GPU for a WebGPU probe with a one-click recommendation. · Provider + key: 10 providers (Gemini, Groq, Cerebras and Mistral have FREE tiers); the key lives in localStorage and is sent only with generate requests. Load models fetches the models your key can actually use. · Per-task keys: separate keys for Generate / Enhance / Lore / Analyze so heavy tasks never eat your generation quota (4 free Gemini keys = 4× daily budget). · Key Pool: multiple keys (provider:key per line) with automatic rotation whenever one hits a 429 rate limit — essential for Mega Builds; Distribute pool spreads pool keys across the per-task rows. · Diagnostics: test the main key, per-task keys, pool, local AI, built-in AI and the deterministic engine — each test costs ~1 token. Run ALL before a big job.

Armor sets (Mod Creator)

The Mod Creator now builds wearable armor: ask for "a ruby armor set" and the AI designs matching helmet, chestplate, leggings and boots with themed 16×16 textures. Each piece gets a real Bedrock wearable component (correct equip slot) and an armor protection value (1-10 points; chestplates highest, sensible defaults per piece). Armor always stacks to 1 and gets its own durability. Craft it with the classic recipe shapes the AI includes, equip it from your inventory, and the protection applies in survival. In the preview each piece shows 🛡️ +N armor. Java exports register armor as items — the generated README explains how to extend to full ArmorItem stats.

Weapon powers & lifesteal (Mod Creator)

Weapons can now have real on-hit powers: ask for "a lifesteal sword" or "a flaming poison blade" and the AI adds an on_hit power — lifesteal (heals you 1-10 hearts per hit, with heart particles), fire (ignites the target), poison / wither / slowness / weakness (applies the effect for 1-30s). Because Bedrock's stable item format can't do this declaratively, the compiler generates a Script API gameplay module (scripts/main.js + @minecraft/server dependency) inside the .mcaddon that listens for your hits and applies the power — food effects work the same way now (the old declarative food-effect path silently did nothing on current Bedrock; this fixes it). Requirements: activate the behavior pack and keep "Beta APIs" OFF — it uses the stable 1.9.0 script module. Powers show in the preview as 🩸 or 💫.

Pixel-art texture editor

Every item and block card in the Mod Creator preview has a ✏️ button that opens a full 16×16 pixel editor loaded with the current texture. Tools: Paint (drag to draw), Erase (transparent pixels), Fill (flood-fill an area), Pick (eyedropper) — plus a color picker, 12 quick swatches seeded from your mod's palette, Undo (40 steps), Clear, and Regenerate from colors to start over from the procedural texture. Works with touch on phones. Save texture embeds your pixels into the spec (as png_b64) so they're used in EVERY export — .mcaddon, Fabric, NeoForge and .mrpack — and survive spec save/load. Your art, in the game, exactly pixel for pixel.

NeoForge export (Java)

Alongside Fabric, the Mod Creator now exports a complete NeoForge 1.21.1 source project (.zip): Gradle build with the official ModDev plugin, neoforge.mods.toml, a generated Java class using DeferredRegister (the idiomatic NeoForge registration API), the same models/blockstates/lang/recipes as the Fabric export, and a GitHub Actions workflow that compiles the jar for you — push the folder to a repo, open the Actions tab, download the artifact, drop it in mods/. Custom pixel-edited textures carry over automatically. Same mod, three ecosystems: Bedrock (.mcaddon), Fabric and NeoForge.

Guided tour

First time here? A 7-step interactive walkthrough starts automatically on your first visit: it spotlights the tab bar, the description box, the Generate button, the 3D preview, the Mod Creator, this Tutorial tab and Settings — with a dimmed backdrop and a glowing ring around each element. Next/Back to navigate, Skip or click the backdrop to exit; it never auto-shows again once finished. Replay any time from Settings → Appearance → Replay the interactive tour, or via Ctrl+K → "Start the guided tour".

Add-on not working? Troubleshooting checklist

1) Remove old copies first: in Minecraft go to Settings → Storage → Behavior/Resource Packs and delete previous versions of your mod, then re-import the fresh .mcaddon (downloads now update in place, but pre-Update-23 copies must be deleted once). 2) Apply BOTH packs to the world: the behavior pack auto-links its resource pack, but verify both show under the world's pack lists. 3) No experiments needed — exports use only stable APIs; weapon powers need Minecraft 1.20.70+. 4) Missing texture / dead lifesteal usually means an old pack copy is still applied — see step 1. 5) Pros: enable Settings → Creator → Content Log GUI to see any load errors on world start. 6) Run the 🩺 Health check button in the Mod Creator — it builds your .mcaddon and validates its internal structure with a pass/fail report before you ever leave the app.

Right-click abilities (wands, talismans & charms)

Non-food items can now carry a right-click ability: ask for "a healing wand", "a speed talisman" or "an invisibility charm" and the AI adds an on_use power — heal (restores 1-10 hearts instantly, with heart particles) or a timed buff: speed, jump boost, fire resistance, invisibility, regeneration, night vision, strength (1-60s). Every ability has a cooldown (1-120s) enforced by the gameplay script AND shown as the vanilla cooldown overlay on the hotbar slot (via minecraft:cooldown). Abilities appear in the preview as ⚡ lines and live in the same scripts/main.js module as weapon powers — stable APIs only, no experiments. Requires Minecraft 1.20.70+.

Add-on health check & guaranteed block drops

The 🩺 Health check button (Mod Creator, next to the export buttons — or Ctrl+K → "Run add-on health check") compiles your .mcaddon, unzips it right in the browser and validates every structural guarantee: manifests + BP↔RP link, auto-bumping pack version, script module wiring + engine pairing, every item icon↔atlas↔PNG chain, armor attachables, recipe-book unlock arrays, block loot tables, lang entries and pack icons — then shows a ✅/❌ checklist. Also new: custom blocks always drop themselves when mined — the compiler emits a loot table per block (BP/loot_tables/blocks/) wired via minecraft:loot, so no more silent empty drops.

Shovels & hoes — full tool sets

The Mod Creator now covers all five vanilla tool types: sword, pickaxe, axe, shovel, hoe. Ask for "a complete emerald tool set" and the AI generates matching pieces with the same colors, each with its own hand-drawn pixel pattern (🪩 scoop blade, 🌾 bent hoe blade) and the right dig speeds: shovels break dirt/sand/gravel/snow fast, hoes shred leaves and plants, pickaxes handle stone/metal, axes chop wood — all via minecraft:digger tag queries. Shovels and hoes can also carry on-hit powers (a lifesteal shovel is entirely legal). Recipes use the classic vanilla shapes automatically.

Power levels I–III — stronger effects

Weapon powers (on_hit) and right-click abilities (on_use) now support an effect level from 1 to 3, mapped to the Bedrock effect amplifier (level 2 = "Poison II" etc.). Just ask: "a blade that inflicts Wither III" or "a charm with Speed II for a minute". The AI keeps level 1 unless you ask for something strong/OP, the server clamps levels to 1-3, and the preview shows roman numerals on the 💫 and ⚡ stat lines. Note lifesteal and heal scale with hearts (1-10) instead of levels, and fire scales with duration.

Settings reference — Mod Creator

Creator name (author credit): type your name once and every export carries it — .mcaddon behavior + resource pack manifests get a metadata.authors entry, Fabric's fabric.mod.json and NeoForge's mods.toml list you as the author (visible in mod menus and pack screens). Max 40 characters; clear the field to fall back to the default credit. Auto health check: when On, every Generate run is followed by the full structural validation (same as the 🩺 button) — the pass count lands in the status line and the detailed ✅/❌ report only pops up when something fails. Both settings live in Settings → Mod Creator (or Ctrl+K → "Mod Creator settings") and apply to generated, imported and pixel-edited mods alike.

Mobile experience — bottom nav, swipe & haptics

On phones the app now feels native: turn on Tab bar position → Bottom (Settings → Mobile) and the tabs pin to the bottom of the screen above your thumb, with iPhone safe-area padding and toasts moving out of the way automatically. Swipe navigation (on by default) switches tabs with a quick horizontal flick — it deliberately ignores swipes over the 3D viewer, text boxes, the pixel editor and other scrollable areas so it never fights your controls. Optional haptic feedback adds a tiny vibration on tab switches and toasts (Android; iOS Safari has no vibration API). Also applied everywhere: 16px inputs so iOS stops zooming in on focus, 44px minimum touch targets in the tab bar, and momentum scrolling with snap points.

Settings reference — Mobile

Tab bar position (phones): Top (default) keeps the classic layout; Bottom fixes the tab bar to the bottom edge on screens ≤ 640px — desktop is never affected. Swipe between tabs: On (default) lets a horizontal swipe (≥ 70px, mostly horizontal, under 600ms) move to the next/previous visible tab — hidden tabs are skipped, and swipes starting on canvases, inputs, selects, text areas or horizontally scrollable strips are ignored. Haptic feedback: Off by default; when On, tab switches and toasts trigger a ~10ms vibration via navigator.vibrate where supported. All three apply instantly — no reload — and can be reached via Ctrl+K → "Mobile settings".

Custom item builder — full property control

Mod Creator → Add custom item opens a form where you hand-craft an item without touching JSON: name, category, texture pattern + colors, stack size 1-64, attack damage, durability, furnace fuel seconds (coal burns 80s, blaze rods 120s), rarity (uncommon = yellow, rare = aqua, epic = light purple name color), enchantment glint and a lore line. Category-specific sections appear automatically: food gets nutrition/saturation/eat-effects, armor gets protection points, tools get on-hit powers, and every non-food item can carry a right-click ability with cooldown. The item is appended to your current spec (or starts a fresh one) — then repaint its texture with the ✏️ pixel editor or fine-tune values in Customize spec. Also reachable via Ctrl+K → "Add custom item".

Mod drafts — offline-first saves

Never lose a mod again: Save draft stores the current spec in your browser (up to 20 drafts), and every preview refresh also writes an auto-saved session — both work fully offline thanks to the PWA. Open Drafts to see the list with item/block/recipe counts and age (“3h ago”), then Load one to continue exactly where you left off or Delete old experiments. Drafts are per-browser; for a portable file that moves between devices use Save spec (.json) instead. Texture edits made in the pixel editor are included, since they live inside the spec.

Block shapes, sounds & translucency

Blocks are no longer limited to full cubes. Ask for “a ruby slab”, “a soft wool carpet” or “a crystal post” and the AI sets a shape: slab (half height), carpet (thin 1-pixel layer) or post (slim 4×16×4 pillar) — each ships real Bedrock geometry with matching collision and selection boxes, so you walk on half-slabs and step over carpets correctly. translucent: true renders the block glass-like (blend) and lets light pass through, and the sound field picks the footstep/break family: stone, wood, grass, metal, glass, sand, wool or gravel. All editable in Customize spec; the preview shows ◧ shape, 🫧 translucent and 🔊 sound badges. The health check verifies non-cube shapes ship their geometry models.

Custom block builder — hand-craft any block

Mod Creator → Add custom block (also in the Ctrl+K palette): a visual form with 9 shapes — cube, slab, stairs, fence, wall, pane, pillar, carpet, post — each shipping real Bedrock geometry with matching collision. Set mining time, explosion resistance, light emission (0-15), friction (0.1 = ice-slippery), footstep sound family, flammability and translucency, plus a texture pattern (planks/bricks/ore/gem/swirl/noise/tiles/pillar) with base + accent colors. Blocks land in the working spec exactly like AI-generated ones: preview card, pixel-editor repainting, drafts, health check and .mcaddon export all just work.

Recipe Studio — every crafting station

Mod Creator → Recipe Studio: visual recipes for all 8 data-driven stations — shaped 3×3 grid (letters + pattern are generated automatically, empty rows/columns trimmed), shapeless, furnace, blast furnace, smoker, campfire (one input → one output), stonecutter and smithing table (base + addition + template). Bare names auto-prefix: your mod's content gets its namespace, everything else minecraft:, and the input dropdown suggests your mod ids + common vanilla items. Click any id on a preview card to copy it. Brewing recipes aren't data-driven on Bedrock, so no add-on can add them — that's a Mojang limit, not ours.

Edit-in-place, duplicate & Auto-fix

Every preview card now has ⚙️ edit (reopens the item/block builder or Recipe Studio prefilled — the id stays stable so recipes keep working, painted textures survive), ⧉ duplicate and 🗑️ delete (deleting content also removes recipes that reference it). The health check gained spec-level rules: duplicate ids and recipes pointing at missing content are caught before compiling, and every station type is byte-verified in the built .mcaddon. When something fails, press Auto-fix in the report: it renames duplicate ids, removes broken recipe references, clamps armor stacks to 1 and restores sane block physics — then re-checks automatically.

Tab styles, zen mode & custom title

Three more Appearance settings: Tab bar style — Full (icons + labels, default), Icons only (all 12 tabs fit one row on narrow screens; hover a tab for its name) or Compact (smaller labels, tighter spacing). Zen mode hides the footer, What's New banner and session stats for a distraction-free workspace — toggle it instantly from Ctrl+K → "Toggle zen mode". Custom app title & subtitle rename the header to anything — your server name, "Steve's Build Lab"… the browser tab title follows, and clearing the field restores the default. All three export/import with Settings backup and apply instantly.

Rename world folders in place

Workshop → world bar → ✏️ rename button: change a world folder's name and every build inside follows automatically — the status line reports the exact count moved ("12 builds inside followed automatically"). Before this, renaming meant create-new + move-every-build-by-hand + delete-old, and any build you missed was stranded. Renaming onto an existing world merges the folders (you'll see "Merged … — N builds moved over"), adopting the target's exact casing so the dropdown never shows "SMP" and "smp" as separate folders. Renaming to the same name does nothing; cancelling the prompt is silent, not an error.

World limits that speak up

World-folder limits are now announced, never silent. Type a name over 40 characters and creation is refused with the count ("World name is 47 chars — the cap is 40") instead of silently cutting it to a folder you never named. The 50-world cap used to be enforced by a silent trim that could drop your newest folder on save — it's now checked before anything is created, with a clear "nothing was created" refusal. Duplicate names are refused case-insensitively, and the internal __none__ marker (the Unfiled group) can't be taken as a real world name.

Honest moves & counted deletes

The move-to-world prompt on each build card got the same honesty pass: typing an existing world's name in any casing adopts its exact casing (no accidental case-twin folders), a new name is validated with real refusal messages instead of silent truncation, and hitting the 50-world cap tells you the build was not moved. Deleting a world now counts what's affected — "The 12 builds inside are kept — they become unfiled" — and the result confirms "12 builds unfiled (nothing was destroyed)". Builds are never deleted with their folder; only the folder label goes away.

Folder saves that can't crash the button

Before Update 145, if browser storage was completely full, saving the world-folder list didn't fail politely — it crashed the button you clicked mid-operation with no message: creating, renaming or deleting a world, or moving a build, could simply stop working. Now every folder-list write reports whether it actually landed on disk, and every button checks the answer before announcing success. A failed new-world creation says "was NOT created — nothing changed"; a failed move says the build stays where it was. Same truth doctrine Update 144 gave the build library, extended to its last unguarded corner.

Renames that roll back instead of half-landing

Renaming or deleting a world writes two things: the build library (every build's world field) and the folder list. Update 145 makes that pair atomic in practice: the library bytes are captured first, and if the folder write fails after the library write already landed, the library is rolled back byte-exact — disk never shows a half-rename where builds point at a folder that kept its old name. The failure message says exactly that: "The library was rolled back; folders and builds are unchanged." Moving a build into a new folder writes the folder first, so a failure aborts before the build is touched at all.

Cap drops announced — and imports outrank labels

The 50-folder cap's drops are now announced from every path with the count and grammar ("2 folders … were dropped") — before, the move-to-world and import paths dropped extras silently. The warning also names the safety net: builds keep their world name, and the folder reappears when a slot frees up — a drop from the list was never a loss of the label. One deliberate exception: a failed folder write never blocks a library import — the build always lands with its world name intact, because blocking the more valuable thing to protect the less valuable one would be backwards.

Favorites that keep their promise

The prompt panel's ⭐ used to say "keep forever" while silently evicting your oldest favorite when a 21st was saved. No more: favorites are never auto-evicted. At the 20-slot cap the save is refused out loud — "unfavorite one first; nothing was evicted and nothing was saved" — same doctrine as pinned history. Every save reports the honest count ("⭐ 14 of 20 slots used"), favoriting a duplicate says so instead of faking a "Saved" toast, and unfavoriting reports the freed slot. If browser storage is full, the failure is stated — the app never pretends a favorite landed when it didn't.

Settings that can't crash mid-change

Every dropdown, slider, colour picker and drag handle used to write straight to storage — a full store crashed the control with no message. All ~30 writes now go through one guarded path that contains the failure and reports the truth (Update 146).

"NOT saved" replaces the false checkmark

When a setting can't persist, the panel now says "NOT saved — storage full" in red, the toast names the exact setting, the consequence (resets on reload) and the remedy. Your change still applies live — only persistence failed, and the app says exactly that.

Storm-safe disclosure & honest import counts

Dragging a slider fires many writes per second — failure toasts are throttled to one per setting per 2.5s, so a drag across a full store produces one message, not sixty. The settings importer now counts only writes that actually landed.

"Key saved ✓" that means it

Saving your API key with a full browser store used to crash the button — or print "Key saved ✓" over a write that never landed, while the app silently kept billing the previous key. The status line now checks the verdict: "Key NOT saved — storage full" in red, and model verification is skipped when the key never landed (Update 147).

Pool & task-key counts that check first

The key-pool counter reads storage — on a failed write it would have counted your OLD pool as if it were the new one. Both the rotation-pool and per-task-key status lines now check whether the write landed before counting, and say "the pool is unchanged" when it didn't.

Quiet failures where quiet is honest

Not every failed write deserves a toast: the model-list cache costs a refetch, not correctness, and the setup wizard simply re-offers later. Those writes fail quietly by documented design — while every write that changes which key or mode the app uses discloses loudly.

A storage meter that measures in real bytes

The Workshop meter counted characters and printed them as KB — but browser storage bills 2 bytes per character (UTF-16), so real usage was roughly double the printed number. The meter now measures with the same formula Diagnostics has always used, and says its unit out loud (Update 148).

The 80% warning finally fires at 80%

The near-quota warning compared characters against a byte budget — in real bytes it fired only near 160%, so the "export your library" advice could arrive after an eviction instead of before it. The threshold now lives in the judge and is computed in the unit your budget is stated in.

Every project store on the meter — largest named

Only the library and templates were metered; work sessions, blueprints, the fingerprint ledger, schedules and more filled the same quota invisibly. The meter now reads every project store and names the largest non-library one — a quota mystery gets a first suspect.

A storage forecast before every save

Every library write now runs a pre-flight: the exact bytes about to be written are projected through the same judge the storage meter uses, so a save that would cross your 80% warning line — or the full budget — announces itself before the bytes land, naming the current KB, projected KB, the delta, and the store growing most (Update 149).

Crossings announce once — transitions, not states

A library already past 80% does not re-warn on every save — that standing state belongs to the storage meter. The preflight speaks only at the moment a write crosses a line, so its advice stays a signal instead of becoming wallpaper.

Exact or refused — a forecast never bluffs

The preflight projects from the exact serialized bytes about to be written. When a final size cannot be known exactly, it says "cannot determine exactly" and steps aside — an estimate dressed up as a byte guarantee would be a new kind of lie, and this app just spent an update killing one of those. Advisory only: nothing is ever blocked.

Your snapshots can't be hijacked by an import

Library files carry each build's internal ID, and snapshots are stored under that ID. Before Update 150, importing a file whose ID matched a build already in your library made both builds share one snapshot slot — the import silently overwrote your build's exact snapshot. Now a colliding import is given a fresh local ID and its own snapshot slot; your existing build is never touched. This bug was reproduced and measured in a read-only experiment against the live app before the fix was written.

Deleting one build can no longer break another

The worst half of the collision bug: when two builds shared one snapshot key, deleting EITHER of them freed the shared snapshot after the 10-second undo window — the surviving build's card still said it had a snapshot, but the bytes were gone. With every build owning a unique ID, delete frees only its own snapshot. The regression suite proves the exact scenario end-to-end: import a collision, delete the imported copy, and verify the original's snapshot bytes are intact.

A remint is reported, never hidden

When an imported build arrives with an ID your library already uses, the import status says so: "N carried an ID already used in this library — kept separate under a fresh local ID (nothing was overwritten)." A silent remint would leave you wondering why a branch family from the shared file looks different — instead the app states the one honest limit out loud: the reminted build's family link degrades to standalone rather than pointing at the wrong build.

"Failed" must mean failed

Update 95 established that "Saved" must mean saved; Update 151 closes the mirror case. A library entry with a malformed DNA field crashed the card render after the import had already committed — so the status said "Library import failed" over a success, and you might re-import or give up on a file that had actually landed. A failure report over a success is the same lie as a success report over a failure. The DNA summary is now total: it never throws, so a render hiccup can never rewrite history.

Unreadable DNA gets a chip, not a crash

A build whose DNA the app cannot interpret (hand-edited files, foreign exports) now shows "DNA unreadable (malformed or foreign format) — kept as-is; the build itself is unaffected" where the style summary would sit. The build loads, exports, duplicates and deletes normally — only the DNA-powered extras (Remix, style summaries) have nothing truthful to say, so they say so. The readability check is deliberately shallow: it asks only what the summary itself reads, and it validates nothing else.

Malformed data is preserved, never "repaired"

When an import arrives with unreadable DNA, the status counts it ("N arrived with unreadable DNA … kept as-is on the build, never treated as valid") and the original bytes stay on the entry untouched. The app could silently coerce a malformed value into a plausible DNA object — but that would manufacture provenance the build never had, dressing invented style data up as recorded fact. Disclosure over fabrication: the doctrine that runs the whole app.

A dead button is a lie of omission

Update 152 closes the follow-on that Update 151's honest-limits note predicted: Remix and Template on a build with unreadable DNA crashed mid-click with no catch — the button simply did nothing, no message, no console hint for the user. Silent failure tells you the app is fine when it isn't. Both buttons now check briefability first and refuse with a toast that names the situation exactly — the same honesty rule the import status follows, applied to clicks.

One predicate per boundary

dnaReadable (Update 151) asks what the card summary dereferences — palette and traits. dnaBriefable (Update 152) asks what the remix-prompt builder needs on top: an accents array and real style/walls/roof strings, because those are interpolated verbatim into an AI prompt and "undefined walls" would be invented garbage. Each boundary gets a predicate matching exactly its own dereferences — no universal validator that guesses, no schema police that rejects foreign data it could have displayed.

Refusal is honest; repair would be forgery

When Remix meets DNA it cannot interpret, the app could quietly invent defaults — "stone walls, gable roof" — and produce a prompt anyway. It refuses instead, and says why: fabricated style data dressed up as the build's recorded DNA would poison every downstream generation with provenance the build never had. The refusal toast also tells you what still works — the build loads, peeks and downloads fine. Scoping the refusal honestly matters as much as refusing.

Nine fields, one boundary

Update 153 closes a whole bug class at a single seam. The library importer trusted nine metadata fields from any file — and each raw shape was proven harmful against the real code before fixing: string tags crashed the card renderer, a foreign thumbnail became attribute injection in an unescaped src, rating: 7 claimed "7 of 5 stars" to screen readers, a string size rendered "b×i×g". One pure judge at the import boundary (wsImportEntryPlan, the 104th test hook) normalizes them all — instead of nine scattered guards at nine consumer sites that the tenth consumer would forget.

Normalize to the editor's own rule — nothing stricter, nothing invented

Where does the "correct" shape come from? Not from a schema the importer made up: from the app's own editors. Tags get exactly the tag editor's rule (lowercase, a–z 0–9 _ -, cap 8); notes get the notes editor's 300-char cap; ratings the star widget's integers 0–5; thumbnails only the canvas data-URL form the app itself generates. A shape the editors could have produced passes byte-identical — the round-trip guarantee — and a shape they never could is brought to their rule and disclosed. Contrast with DNA (Update 151): that's provenance, so it's preserved verbatim, never normalized. Metadata is app-owned; provenance is not.

Silent mending is still a lie

Fixing bad data quietly would trade one dishonesty for another: the user would see clean tags and a cleared rating with no idea the file carried something else. So the judge records every normalization it makes, and the import status line names them by field kind — "2 had out-of-spec metadata (tags, rating) normalized to the app's editor rules — build data (plan, snapshot, DNA) untouched." The disclosure also scopes what was NOT touched, because a reassurance that doesn't state its limits reads as a claim about everything.

Destruction must announce its blast radius

A census of all 52 destructive-primitive sites against the app's 29 confirm gates convicted six ungated or understating paths — the worst a boot-splash link that said "Reset saved settings" while wiping the ENTIRE local store: every build, draft, API key and preference, bypassing every gate in the app. The pure law confirmGateLiar (118th hook, Update 183) convicts five lie shapes: ungated destruction of persisted data, a gate that identifies nothing, an undisclosed exact count (the Update 146 standard — counts are measured, never estimated), materially understated scope, and mutation proceeding after cancel. Every gate now counts and names its casualties before anything moves, and cancel changes nothing — and says so.

A confirm on housekeeping is noise, not consent

Not every deletion needs a dialog. The census classified each of the 52 destructive sites before judging: snapshot garbage-collection after a landed write, quota-eviction rollbacks that restore pre-failure bytes, corrupt-cache discards that can never destroy good data, draft autosave overwrites, UI-preference resets and the Composer's in-memory working list are all lawfully silent — gating them would train users to click through dialogs, which destroys the value of the gates that matter. The law encodes the exemptions itself: internal cleanup, deterministic recovery and unpersisted state return no conviction by rule, not by fiat — so the census cannot be passed by weakening the law, only by fixing the liars.

A funnel is only as honest as its narrowest proof

Twenty toast call sites compute their kind at runtime — verdict funnels, outcome judges, a queue reporter, the autosave state machine — and nothing proved those computed values stay inside the ok/warn/err/info vocabulary. A stranger kind would fall through every ternary to the GREEN success branch: a lie by default. Update 184's census traced every computed producer to its actual value set — the storage-write judges speak only ok/err, the world-folder judge only ok/warn/err, the queue reporter's status set makes its consumer exhaustive, and the autosave machine's two announce kinds are both handled. The census came back clean — but the behavioral suite now pins every producer's value set, so a clean census today cannot rot unnoticed tomorrow.

Assert at the sink, prove at the source

Proving every producer safe today is a snapshot; asserting at the sink makes it a contract. The pure law kindFunnelLiar (119th hook, Update 184) now stands inside toast() itself, judging every kind after the convicted Update 181 dialect is normalized: an out-of-vocabulary kind is downgraded to a visible warning and names itself in the console instead of silently wearing the success green with the screen-reader word OK. An omitted kind lawfully defaults to the success style — that is the API's documented contract — but null, numbers and stranger strings all convict. The next person who adds a toast call with a typo'd kind gets an honest amber triangle and a console receipt, not a green check on a failure.

A disabled button that explains itself is honest

A census of all 35 dynamic busy-disable sites and every statically gated control (Update 185) drew the line: disabling a button is lawful when the user can see WHY — the region tools stay dark next to a label that says 'No selection', undo/redo toggle against the history they reflect, and 33 busy-disable sites re-enable inside a finally with visible progress text. Two sites lied: the wizard download button parked its re-enable AFTER the loop — one throw outside the per-tier catch stranded it dead forever — and the Architect Regenerate button's only re-enable was the panel re-render replacing it, a fragile side channel that left 'Working…' on screen forever if the render bailed. The pure law disabledHonestyLiar (120th hook) convicts a busy-disable with no visible feedback and a re-enable not guaranteed on failure; both stranded re-enables now live in finally blocks.

A no-op is a lie of availability

A button that looks enabled makes a promise: clicking it will do something. A census of 72 bare-return click guards (Update 185) convicted two silent liars — the genome-copy button did nothing when there was no genome to copy (its sibling explains itself; the copy said nothing), and the PWA install button went silently dead the moment the browser withdrew the install prompt while still sitting there looking clickable. The law's third lie shape convicts an enabled-looking control that silently does nothing when clicked. The cure never disables the buttons — it makes them speak: the genome-copy refusal now names its precondition ('No genome to copy — generate or import a structure first'), and the install button explains the withdrawal and points at the browser menu. Hidden-panel guards, prompt-cancels and element-existence guards stay lawfully silent — the user never saw a promise, so no promise was broken.

A silent status line is a lie of omission

A census of all 38 status-like sinks (Update 186) asked one question of every dynamic status surface: when this line changes, does a screen-reader user HEAR it? Thirty panel status lines in the page shell and two more built by JavaScript failed — each was the SOLE feedback channel for its panel (key saves, world imports, structure mutations, mod conversions, diagnostics), written for the eye and never for the ear: a sighted user reads 'Key saved ✓' while a screen-reader user hears silence and clicks again. All 32 now carry role=status aria-live=polite, so the outcome is spoken the moment it is written, with zero visual change. The pure law ariaLiveLiar (121st hook) convicts a dynamic sole-feedback status that never announces — a status the sighted can read but a screen reader never hears.

Noise is the other lie — silence can be the kinder truth

The aria-live census (Update 186) refused to cure by carpet-bombing: making everything announce would have committed the opposite lie. Per-keystroke character counters (the build-description and mod-idea counters) stay deliberately silent — announcing every keystroke is spam, and noise drowns the one update that matters; the command-palette result count is the lawful exception, result-count announcements being the recommended combobox pattern. Supplementary badges whose triggering action already toasts (the history and preset counters) stay silent too — the toast holder has been role=status since Batch 45, and the same news read twice is noise, not honesty. The law convicts both directions: it convicts a live per-keystroke counter and a live duplicate badge exactly as it convicts a silent sole-feedback status. Announcement is a channel, not a virtue — the law routes news to the ear once, and only once.

A placeholder is not a label

A census of all 271 shell form controls plus every JavaScript-built input (Update 187) asked one question: does this field have a name that SURVIVES typing? A placeholder vanishes on the first keystroke, is skipped by some screen readers entirely, and its low-contrast gray was never meant to carry the field's identity — yet 39 shell inputs and 4 JS-built shapes (including the nine crafting-grid cells whose only name was a placeholder dot) had no other name at all. All 43 now carry an aria-label written from the field's actual meaning, with zero visual change. The pure law placeholderLabelLiar (122nd hook) convicts the vanishing name — an input whose only name is its placeholder — while every label-wrapped input, label-for pair and existing aria-label passes: a persistent name survives typing.

A wrong name is a worse lie than a missing one

The placeholder census (Update 187) found a second population: ~180 controls whose visible label sits directly adjacent in the markup but was never programmatically associated — the eye pairs them instantly, the accessibility tree cannot (adjacency is not association). The law codifies this as its own conviction shape, but the CURE was deliberately deferred to its own named batch instead of being bulk-applied here: mechanically pairing 180 labels from proximity heuristics risks associating the wrong label with the wrong field, and a field that confidently announces the WRONG name is more dangerous than one that announces none — the user acts on the lie. Scope discipline is part of honesty: convict everything you find, cure only what you can cure correctly, and name what remains so it cannot be quietly forgotten.

A tooltip is not a name

The title-attribute census (Update 188) checked all 348 tooltips in the app against three lies. Contradicting the code? Every factual claim — hotkeys, caps, counts, the 40-level undo, the 7 tour stops, the 79-question survey — was verified against the code it describes: zero contradictions, zero stale descriptions. The tooltips tell the truth, measured, not assumed. But 89 interactive controls had their title as their ONLY name — and a title is hover-only: keyboard users tabbing to the button and touch users tapping it never see it, and the accessibility tree treats it as a last resort. All 89 now carry an explicit aria-label; every title stays, because a truthful tooltip is a courtesy for the mouse — it just must never be the only name.

Documentation is not identity

The pure law titleTruthLiar (123rd hook, Update 188) draws the line the title census enforced: a tooltip DOCUMENTS a control (what it does, what it costs, what its caps are); a name IDENTIFIES it (what a screen reader announces on focus). The two jobs need different channels — title for the hover courtesy, aria-label or visible text for the identity — and a control that pours both jobs into title serves only the mouse. The law convicts three shapes: a tooltip that promises what the control does not do (documentation lying under oath), a tooltip describing a removed feature (a museum label on an empty case), and the title-as-sole-name. It acquits a truthful title over a named control — documentation is not a crime, it is just not identity.

A mouse-only control is a mouse accessory

The keyboard-reachability census (Update 189) walked every click handler in the app — 233 id-bound targets, every click loop, every delegated container — and asked: can the Tab key reach what the mouse can click? Fourteen overlays were closable by backdrop-click but not by Escape — a mouse user taps the dark area to leave; a keyboard user was walled in. All 14 joined the global Escape closer, verified behavior-identical (every close path was already a plain remove). Six clickable copy/jump affordances lived on non-focusable spans and divs the Tab key could never land on — all six now carry role=button, tabindex=0, and Enter/Space firing the exact same click path the mouse uses. One behavior, two input devices: a control you can only reach with a mouse is not a control.

Acquittal requires evidence too

The reachability law keyboardReachLiar (124th hook, Update 189) convicts three shapes: the positive tabindex that jumps the tab-order queue, the overlay a mouse can leave but a keyboard cannot, and the clickable element focus can never land on. But the census acquitted as carefully as it convicted — on evidence, not assumption: the command palette already had full ArrowUp/Down/Enter navigation plus its own Escape; the star-rating rows have had a keyboard-parity slider since Batch 96; the queue, schedule and session containers delegate to real labelled buttons inside; and the whole codebase carries zero positive tabindex values. A false conviction wastes a cure on the innocent and buries the guilty in noise — an audit that convicts everything proves nothing.

An unassociated label is decoration

The label-association census (Update 190) walked all 227 label elements in the app and hand-verified every pairing. 108 labels sat right beside their control with no for= and no wrapping — visually perfect, programmatically nothing: a screen reader announced the control nameless, and clicking the label text did nothing. Each was cured with a for= only after three programmatic proofs per label — the target id exists, exactly once, and is the very next labelable control after the label — then all 126 resulting pairs were re-audited, including the 18 that predated the census. Never bulk-guess an association: a wrong for= announces the wrong name and sends the click to the wrong control, which is strictly worse than no label at all. Clicking any cured label now focuses its control — the visible proof the association is real.

A cure must not change behavior

The association law labelAssocLiar (125th hook, Update 190) convicts three shapes — the ghost for= pointing at nothing, the wrong-target for=, and the bare-adjacent label — but its exemptions are as deliberate as its convictions. Two labels caption buttons: a for= there would make clicking the caption text TRIGGER the button — a behavior change disguised as an accessibility cure, so those buttons keep their own visible names instead. Three captions head groups of three inputs each (region corner, region size, merge offset): a for= would name only the first input and orphan the other two, so each input carries its own aria-label and the caption stays a caption. And the 56 labels that wrap their control were acquitted outright — implicit association is already law. The fix that changes what a click does is not a fix.

The cache had the app the whole time

The slow-open fix (Update 191) is a lesson in WHERE the user waits. The service worker was network-first for pages and every one of our scripts: each open paid a full set of network round-trips — or, on a flaky connection, their timeouts — before the first pixel painted, even though the versioned cache held the complete app. Flipping navigations and statics to cache-first makes the cached generation paint instantly, and the freshness job moves to where it belongs: a background registration.update() that fires 3.5 seconds AFTER load and cannot touch the running page. Version coherence survives the flip because a generation is precached whole at install with cache:'reload' — the HTML and the JS it references always come from the SAME generation, never a mid-deploy mix. Fast and fresh are not enemies; they were just doing each other's jobs.

Consent is a click, not an assumption

The boot law bootUpdateLiar (126th hook, Update 191) convicts three shapes: the boot that waits on the network before painting, the update applied without consent, and the cache-first that never checks after load. The second is the subtle one — install() used to call skipWaiting() unconditionally, so a new service-worker generation activated itself mid-session, swapping the cache under a running page nobody asked to change. Now a freshly installed generation WAITS: the page offers a non-blocking "Reload now / Later" banner, and only the Reload click posts SKIP_WAITING to the waiting worker (controllerchange then reloads exactly once, guarded against loops). The third shape guards the guard: cache-first with no after-load check is staleness forever wearing a speed medal. The check must run — just after paint, and the apply must ask.

The writers that bypass the law

setStatus (Update 179) and toast (Update 181) both had their severity channels put under law — but ~329 innerHTML/textContent assignments write status wording directly into panels, bypassing both. A census of every failure-worded inline writer convicted four liars: a failed hardware check in default cyan, a per-file download failure and a refused save whispering in gray, and a module-build failure whose panel stayed gray while only its toast spoke err — a split voice. The new pure law inlineStatusLiar (117th hook) judges each write by its message plus the styling that will actually be visible, completing the severity trilogy: a law that governs only the front door is a suggestion.

Judge the rendered text, not the code

A naive census regex convicted the storage quota label because its template literal interpolates est.quota — but "quota" there is an identifier, not a word the user ever reads. The law's interpolation rule strips template spans before judging, so exemptions are earned by the rule, not granted by fiat: the storage label cleared honestly, while the four real liars — whose failure wording survives interpolation-stripping because it is literal rendered text — stayed convicted. The census that cries wolf trains everyone to ignore the census.

A failure in green is still a lie

toast(msg, kind) speaks a four-word vocabulary — ok, warn, err, info — and any kind outside it falls through every ternary to the GREEN success branch: green border, check icon, the screen-reader word "OK:". A census of all 421 call sites convicted 19 sites speaking the 'error' dialect — a rejected backup file announced its failure with a green check — plus two default-kind liars whose failures toasted green. Update 181 adds the pure law toastKindLiar: a kind outside the vocabulary, failure wording without the err/warn kind, or success wording carrying the err/warn kind are all convictions, with hard failure words beating okish openers.

The dialect that fell through

The 'error' kind was never in the vocabulary — it was a dialect that every ternary silently routed to the success branch, so the lie was invisible in code review: the call site LOOKED like it was reporting an error. The cure works both ends of the channel: all 19 dialect sites now speak 'err', and the sink normalizes any surviving 'error' defensively with a receipt at the crime scene. 'info' — previously also falling through to green — earned an honest neutral voice: sky-blue, circle-info, "Note:". The pre-fix bytes were convicted verbatim by the live law and proven gone from source; 216 literal sites judged, zero liars remain.

A witness must leave the room as it found it

The 292-test browser e2e drives one long-lived shared page, and its witnesses override shared globals to force rare conditions — confirm and prompt to script dialogs, fetch to stage a race, Storage.prototype.setItem to force quota failures, navigator.onLine to fake offline. An override that is never restored, or restored outside a finally where a throw skips it, poisons every later test: a leaked confirm=true silently approves destructive dialogs, a leaked quota-poisoned setItem makes honest saves fail. Update 180 adds the witness-restoration law: witnessLeaks statically walks the e2e bytes — six families, 15 override sites — and convicts any override lacking a capture, a restore, or a finally between them.

The gate that judges its own courtroom

A law that only lives in a test can rot in a drawer; the e2e now runs witnessLeaks against its OWN bytes before the browser even launches, and a leaking e2e refuses to run rather than testify with poisoned witnesses. At end of run the shared page is inspected empirically: every overridable global must be native code again, and onLine must answer from the prototype getter — a static promise backed by a live proof. The negative controls are deliberate leaks convicted by name, and the law's own first draft was convicted in-batch: its backtracking regex miscounted restore lines as poisons, and the cure (a pinned lookahead) is itself documented in the law's source. Even the auditor gets audited.

Severity is a claim

The status line carries a severity flag — true speaks red with an error toast, false whispers routine gray — but for 188 updates nothing audited whether failure lines actually claim their severity. A paren-balanced census of all 124 call sites found exactly two liars: both continuity-guard discards announced a refusal in success-gray, the visual twin of the async-blind pass. Update 179 adds a pure law, statusSeverityLiar, that names any line whose wording and flag contradict each other, and the census pins every call site so a future gray-whispering failure is convicted before it ships. Severity, like persistence, is a claim: earned, never assumed.

A refusal that whispers

"Balance pass discarded by the continuity guard — your build is untouched." is a refusal: the app rejected the AI's answer to protect your build. But it rendered in the same gray as "Done!", so a user watching the status line saw a routine hum where an intervention had happened. Both discard lines now pass the error flag and raise the err toast their siblings (the warn toast, the yellow shield) always did. The honest grays stay gray: "Build cancelled." keeps its explicit false because cancelling is the user's own act — the law distinguishes a refusal the app made from a choice the user made, and only the former must speak up.

A promise is not a proof

A test runner that accepts any truthy value will bless a JavaScript Promise — an answer that hasn't finished computing — as a pass, even if it eventually resolves to false. 119 of this app's 138 quality-gate suites ran on exactly that kind of runner; nothing had gone wrong yet only because nobody had written an async callback into them. Update 178 swept every runner and injected a thenable conviction: a Promise reaching a sync runner is now an immediate FAIL that names the disease. A test that hasn't finished isn't a pass — it's a promise, and test suites exist to distrust promises.

The runner that convicts its own blindness

The proof that the guard matters is the old runner convicting itself: its exact bytes were resurrected from git history and fed a deliberately-vacuous test — a Promise that resolves to FALSE. The old runner counted it as a pass; the new guarded runner refuses it, while still passing plain true, failing plain false, and honoring throws. Three safe families now cover the whole fleet — strict (only the literal true passes), cured (async results are awaited before the verdict), and guarded (thenables are convicted on contact) — and a census test convicts any future suite that ships a fourth, unclassified runner shape.

Exempt by proof, not by assertion

Update 174's persister census parked five save helpers on an "observer" roster — exempt from the boolean contract because supposedly no success claim rides their writes. Update 177 audited that word "supposedly": four exemptions survived with evidence (the ledger's caller claims nothing; build history and the material tracker re-render from DISK, so their UIs are incapable of showing an unlanded write; the A/B history's warn toast owns its misses), and one collapsed — saveWorldContext had FIVE callers celebrating over a possibly-unwritten disk. The census now pins each surviving exemption to the specific evidence that earns it. An exemption is a claim like any other: audit it, or it's just a bug wearing a title.

A context that never landed flows into nothing

The world-context feature's promise is continuity: "future builds will inherit this world's language." But activeWorldContext() reads the DISK at generation time — so when the registry write died under a full store, the celebratory status line described a flow that did not exist. The user builds on, believing every generation knows their world; the generator sees an empty list. The fix gates all five claiming callers on the boolean return, and the seed form keeps the user's typed inputs on failure — a retry should cost a click, not a re-type. The deepest damage of a false success line is directional: it tells the user to stop checking exactly where checking was needed.

One failure, one voice

The block-catalog loader had two failure sites, each hand-maintaining its own message strings — and they had already drifted into two different online voices. Worse, a shape rejection while online (the exact case the Update-171 judge exists to name) was flattened into "refresh the page", discarding the diagnosis the judge had just written. Update 176 funnels every failure into ONE function, catalogFailLine, keyed on navigator.onLine: offline keeps Update 139's sentence verbatim, an online shape rejection names the rejected payload with the judge's own reason, and an online network failure keeps refresh advice in the one place it can help. The honest sentence now exists exactly once in the app — a message that lives in two places is a message that will eventually disagree with itself.

A retry that cannot see new bytes is theater

The catalog retry loop's second attempt fetched with the browser's default cache mode — and /api/blocks ships Cache-Control max-age=3600. So attempt 2 could be satisfied by the IDENTICAL hour-old cached payload attempt 1 had just rejected: a retry ritual with no possibility of a different outcome. Update 171 had already cured this exact disease for the service worker's precache with cache:'reload'; the runtime retry had the same disease and no cure. Update 176 escalates: attempt 2 forces cache:'reload', guaranteed fresh bytes past the HTTP cache and the SW alike, and the loader stores its final error as evidence so downstream consumers report the real cause instead of guessing. Before retrying, ask what the retry will do DIFFERENTLY — if the answer is nothing, the retry is a lie told to yourself.

A roster that cannot forget goes to trial

Update 174's persister census left two helpers — saveWorkspaces and saveWsSavedQueries — on a "known-open" roster: convicted of the silent-swallow disease, but their callers still under QA verification. The roster's whole point was that it cannot forget; Update 175 is the trial it demanded. Both helpers now carry the boolean-persister contract, all four of their call sites are gated on the return value, and the census itself was amended in lockstep: it now demands the contract of both former known-open members and demands the known-open family be EMPTY. That last part matters most — a roster move enforced only by memory is a roster move that reverts in silence. The census keeps the empty slot visible so the NEXT convicted persister has a place to be honestly parked, and a mechanical trial date it cannot dodge.

Never switch into a phantom drawer

The worst caller of the batch: workspace-create pushed the new entry, attempted the registry write, and then switched your tab into the new workspace — whether or not the write landed. With storage full you were standing in a drawer that does not exist: it vanishes on reload, and everything you filed there goes with it. Delete had the mirror image — the bar stopped showing a workspace the disk still remembered. The fix follows the same order-of-operations doctrine as Update 174's boot scheduler: persist FIRST, act on the world only after the write is confirmed. Create now re-renders and stops when the registry write fails; the switch never happens; the honest error line names the disk truth. A browser witness proves it end to end: poison the real registry key, click the real new-workspace button, and assert the active workspace never changed.

A save that cannot fail out loud will lie

Update 174 fixed the fourth confirmed recurrence of one disease: a persister that swallows the quota throw and returns nothing, under a caller that announces success unconditionally. Queue a build with storage full and the app said "press Run queue to start" over an empty disk slot; save a mod draft and it counted a phantom "(n/20)". The cure is a contract, not a message: each helper now returns true only when the write landed, announces its own failure with a line that owns the disk truth — "did NOT reach storage — unchanged" — and every success line is EARNED by checking the return value. Nine call sites gated; five call sites that make no success claim carry an explicit audited receipt, because "verified harmless" and "missed" must never look alike.

Four recurrences are one missing convention

saveWorkSessions (Update 143), saveWorkshop (144), saveWsWorlds (145) — and now four more helpers with the identical hole. When the same bug appears four times in four families, fixing the fourth instance is not the job; ending the series is. Update 174's recurrence prevention is a persister roster census in the test fleet: every save function in the app must be classified into exactly one contract family — boolean (returns the truth), verdict (returns a structured outcome), observer-exempt (no success claim exists by design), or known-open (convicted, awaiting its own batch). An unclassified fifth persister fails the suite at birth. The known-open roster is the honest part: saveWorkspaces and saveWsSavedQueries share the disease but their callers are still under QA verification — the census refuses to let them be forgotten, and refuses to let a fix move them without moving their classification.

Seven copies of a contract are seven chances to drift

Update 173 censused the test fleet for the README's "Last updated" standing-form check and found seven suites each carrying a private copy of the same regex. Seven copies is seven chances to drift: amend the form in one place and six stale copies keep passing against yesterday's contract, or worse, keep failing against today's. And drift had already happened in the quietest way possible — one copy captured all three numbers from the line (WN version, service-worker version, release-entry count) but compared only two of them. The third capture was read and never verified: the README could have claimed any entry count and no test would have noticed. The fix is the same doctrine every batch has taught: a contract that lives in seven places lives nowhere. The form, the bracket-walking entry counter, and the all-three-number cross-check now live in one named invariant module (tests/inv_d10), and all seven suites import it with a receipt naming the migration.

A cross-check that skips a number is a promise with a hole

The shared invariant doesn't just centralize the regex — it closes the hole. checkD10 demands exactly one "Last updated" line, the exact standing form, and then compares all THREE captured numbers against the live source: the WN version against app.js's counter, the sw version against the cache name, and the release-entry count against the REAL length of RELEASE_HISTORY, computed by a depth-aware bracket walk and a genuine JavaScript evaluation of the extracted array — the number the old check forgot. And because a validator you've never watched catch a lie is just a wish, the new suite feeds it six sabotage witnesses — wrong entry count, wrong WN, wrong sw, missing form, doubled line, absent array — and requires a conviction with a named reason for every one. Self-maintaining by design: the invariant reads today's counters from today's source bytes, so it never expires and never needs a floor bump.

A subsystem that can die must be allowed to die alone

Update 172's audit of init()'s startup path acquitted nearly everything — all 785 referenced DOM ids exist, every boot-path storage touch flows through the judged chokepoints — and convicted the very first statement: the WebGL viewer was constructed unguarded, and THREE's renderer throws whenever the browser refuses a WebGL context (hardware acceleration off, blocklisted GPU, remote desktop). That single throw killed the whole app: no catalog, no tabs, no settings, no downloads — the boot splash mourned a dead APP when only the 3D canvas was dead. Everything else here is WebGL-free: the Blueprint editor draws on 2D canvas; the Mod Creator, Texture Studio, Workshop and every deterministic download never touch a GPU. The bitter detail: the little peek viewer already had a try/catch and an honest toast — the main viewer, whose failure takes everything hostage, never got the same standard. Now a failed viewer costs exactly the viewer: an amber notice names what broke, what still works (everything), and how to bring it back.

One honest stand-in beats thirty call-site guards

The obvious fix for "the viewer might be dead" is to guard all ~30 places that touch it — and the obvious fix is wrong, because guard #31, added next month, won't exist. Update 172 instead installs one stand-in object that satisfies the viewer's whole surface honestly: no-ops where a no-op is true (setData on a viewer with nothing to render), null where every caller already handles null (voxel picking returns "you didn't hit anything"), false where the caller checks the return (flythrough start), and a NAMED throw — "3D preview unavailable" plus the real reason — exactly where callers already sit in try/catch and show e.message (screenshot, cinematic recording). Members the stand-in deliberately lacks (getStats, controls, scene, renderer) are precisely the ones every consumer already null-guards, and a member-access census test convicts any future unguarded touch of an absent member before it ships. The health of the arrangement is itself observable: the 110th diagnostic hook reports whether the viewer is real or the stand-in, and why.

A cached copy is a time traveler — judge it at the border

Update 171 audited the offline catalog promise (Update 139) across releases and found two holes. The staleness hole: cache.addAll() fetches through the browser's HTTP cache, and /api/blocks ships max-age 3600 — so a new service-worker generation could "precache" an hour-old catalog from the previous deploy. New app code, old catalog, no error anywhere: the worst kind of bug, the one that files no report. Every precache entry now fetches with cache:'reload', forcing byte-fresh copies whenever a new generation installs. The trust hole: the app assigned whatever the endpoint returned — await r.json() straight into state — so a truncated cache write or foreign payload would poison every downstream consumer with scattered per-feature failures. catalogShapeVerdict (the 109th hook) now judges the payload once, at the boundary: object map, 300+ entries, the four anchor blocks present and holding the color contract, plus a deterministic sample. One honest message beats twelve confusing ones.

A sample that skips the anchors can be fooled where it matters most

The shape judge's first draft spot-checked the value contract on the first 25 catalog keys — and its own e2e witness convicted it before it shipped: a payload with a corrupt stone entry (c: 42, a number where every renderer expects '#hex') sailed through, because 'stone' sat outside the sample window. The witness had been written to drive five hostile-payload classes through the real browser hook expecting a named conviction for each, and the contract-breaking class came back ok:true. The repair: anchors aren't just existence-checked, they hold the full value contract directly — the four blocks every build path actually reads are exactly the four entries whose corruption hurts most, so they get judged by name, not by lottery. Same lesson as B180's simulator convicting its own pin: an instrument that can catch its author's first draft is the only kind worth keeping.

A guard with an unexamined upper bound is a resignation letter with a future date

Update 170 asked one question of every numeric pin in the permanent regression library: at what counter value do you stop matching? A simulator substituted every future value — through the thousands — into each pattern and recorded the first failure. Twenty-one manifest pins and six test-suite floors were hundreds-locked: bounded regexes that all die the day the What's-new version or the service-worker cache reaches 200, plus a micro-total floor capped at 999 — some dating back to Batch 127, over fifty batches old. None of them was wrong today; all of them were wrong on a schedule. The rewrite makes each one a true monotonic floor (every value below rejected, every value at-or-above accepted, four-digit futures included), and each amended pin carries the receipt in its why-field. A regression pin's job is forever; a pattern that quietly retires at a rollover was never doing that job — it was doing it until.

Don't fix the instances — hire the simulator

Fixing 27 expiring patterns by hand would leave the 28th free to land next month, because the bug class is a habit, not a typo: bounded ranges feel precise when you write them against today's value. So the future-probe simulator that convicted the 27 became a permanent employee — the B180 suite re-derives every counter pin from the manifest on every run, substitutes futures across the next several thousand values, and fails the build the moment any pin acquires an expiry date. The same sweep enforces the floor direction downward: values below the floor must NOT match, so a "floor" that accidentally accepts a regression is convicted by the same instrument. This is the B179 lesson translated from browsers to regexes — a pin you never probed against the future is an opinion about today, not a guard on tomorrow.

A green suite that never opens a browser is an opinion, not evidence

Update 166 added datalist-population lines at the top of init() using the imported STYLES vocabulary. Fifteen hundred lines below, inside the same function, an older local list was also named STYLES — and a block-scoped declaration shadows the import across the whole function, putting the top lines in the temporal dead zone. init() crashed on every page load in every real browser, for three releases, while 128 unit suites stayed green — because they read source bytes and none of them RUNS init(). The e2e browser run convicted it on first contact: 61 failures, all cascading from one line. The fix is a rename (STYLE_CHOICES — distinct vocabularies deserve distinct names); the lesson is structural: source tests prove the code exists, only a browser proves it runs.

Four witnesses that watch what source tests cannot

Update 169 pays the e2e debt for four releases of GUI promises, each pinned where only a browser can look. The interior dropdown must serve exactly the furnisher's 7 themes in engine order. The Type/Style datalists — shipped empty in the HTML — must be POPULATED at runtime with the real vocabulary (13 types, 10 styles) and linked to their inputs: the exact surface the shadowing crash was silently emptying. The smart429 select must round-trip both directions with the REAL command palette, driven through its real UI: open, filter, Enter — not a reimplementation. And the live What's-new banner must render, hold the one-body-span law in the real DOM, and dismiss with a persisted latch. Every witness restores what it touched; the run ends with the same zero-console-error sweep that caught the crash.

A precache list is an offline promise — audit it in three directions

Update 168 cross-examined the service worker's PRECACHE array against reality from three sides at once. Linked-but-not-cached: four icons the page head and PWA manifest reference — three Apple touch icons and icon-maskable-512.png, the one Android launchers actually draw — were never precached, leaving offline holes in exactly the surface a PWA exists for; all four are cached now. Cached-but-missing: every precache entry was verified to exist on disk, because a precached path with no file behind it poisons the install event with a cached 404 — there are none. Cached-but-unreferenced: three modules looked dead and were acquitted with receipts — mcworld.js and timeline.js load through lazy import() when a user opens a world (precaching them IS that feature's offline story), texstudio.js is statically imported. One direction of the audit finds broken promises; the other two find lies and waste. You need all three.

Template scaffolding is dead code with seniority

The precache census also surfaced two files older than every feature: style.css, holding one template-era rule (an h1 font the app never renders — styling has been Tailwind + inline since day one), and renderer.tsx, the Hono starter's JSX renderer that no code imports and that the build provably excludes from the shipped worker (the built worker was grepped to confirm). Their age is what protected them — nobody deletes a file that predates the project's first real commit, because surely something needs it. The census treated them like any other suspect: trace consumers, sweep test pins, check the built artifact. Zero consumers, zero pins, zero bytes shipped. Both deleted. Scaffolding earns no immunity from the export-integrity doctrine; if anything it deserves less, because it wears the costume of infrastructure while doing nothing at all.

A setting that exists in only one place is half a setting

Update 167's census walked every palette-toggled preference looking for its Settings-panel twin. Header, grid, chime, exec bar — all had both surfaces. Smart 429 wait alone was palette-only: the switch deciding whether a rate-limited AI call waits out a 75-second reset window or fails on the spot was an easter egg. The fix is boring on purpose — a select in the panel, the same bind machinery as every sibling, membership in the re-sync list, and the palette flip now re-syncs the panel so the two surfaces can never disagree. The census became a test: the next palette toggle added without a panel control fails the suite. Discoverability isn't a nicety; a behavior the user can't find is a behavior they never chose.

One voice for every failure — and raw voices where raw is honest

Since Update 51, generate() has translated failures into fixes: "Failed to fetch" becomes "Network problem — check your connection"; a full store points at Settings → Storage. But the census found four sibling AI doors — Build Doctor, apply-suggestions, auto-balance, lore — reporting the raw exception verbatim. Same server, same failure modes, different honesty: which door you happened to use decided whether you got a fix or a stack-trace fragment. All four now speak through the same humanizeError law. Equally deliberate: local doors (screenshot, exports, share links) KEEP their raw messages, because their exceptions are already human-sized — routing "canvas is empty" through a network-flavored translator would invent a wrong cause. The pin holds both directions: AI doors must translate, local doors must not.

An export nobody imports is documentation that lies

Update 166 audited the module surface itself and found every export list padded with claims no code relied on: functions wearing an export keyword that nothing anywhere imported, and one import (dnaToContextLine) that its importer never called. None of it was broken — that's exactly why it matters. A reader budgeting a change to an "exported" function must assume unknown callers and tread carefully; when those callers don't exist, the export keyword taxed every future edit with imaginary risk. The dead surface is deleted, the internal-only functions demoted to plain functions — each demotion preceded by a zero-consumer proof and a zero-test-pin sweep, and followed by a real import() smoke proving the public names survived. A module's export list is a contract, and a contract stuffed with clauses nobody invokes stops being readable as a contract at all.

Four copies of the tag law — and only one knew LongArray

The NBT tag-id table was written four times across the parsers, and the copies had already diverged: only timeline.js's copy knew LongArray (tag 12), while javanbt.js handled that very tag with a bare magic "case 12" its own table couldn't name — the code worked, but the law it obeyed was written nowhere it claimed to live. Update 166 consolidated the superset into nbt.js and made the other three modules import it, turning the magic number into case TAG.LongArray. The payoff isn't today's behavior (byte-identical, proven by the parser fixtures) — it's the next tag: when Mojang invents tag 13, there is exactly one table to teach, and every parser learns it at once. The same batch put the one wrongly-idle export to work: the engine's STYLES and TYPES vocabularies now feed the Blueprint Editor's datalist suggestions, so the legal words are one click away instead of tribal knowledge.

One law, every consumer

Update 165 found the same rule written twice — and the copies had already diverged. The blueprint engine allows 1–6 floors (its own tower preset ships [3,5]), but the local critic's change-applier carried a private clamp of 1–4: a legal recommendation of "floors: 5" was silently vetoed by a copy of a rule its owner had outgrown. The fix wasn't to update the copy — it was to delete it. The engine now EXPORTS its law (FLOORS_MAX, INTERIOR_THEMES) and every consumer imports it, so the next time the ceiling rises, there is exactly one place for it to rise. A copy of a rule is a bug that hasn't diverged yet; a shared export can't diverge because there's nothing to diverge FROM.

The silent cozy — judge at the door, not in the basement

The interior theme was the only blueprint field nobody judged: building type and style were normalized on entry, but a typo'd "libary" or a case-mangled "Library" sailed through untouched — and the furnisher, seven floors down, quietly fell back to cozy. The user asked for a library, got a fireplace and a bed, and no surface anywhere said why. Update 165 fixes it at both ends: the form's free-text input became a dropdown of the seven real themes (an input that can only say legal things needs no apology), and the engine's normalizer now judges the field like its siblings — lowercasing, trimming, mapping honest aliases (forge→workshop, temple→shrine) and only THEN defaulting. The deep fallback stays as defense, but defense is what it is now, not the primary line. A default that fires silently isn't a default — it's a substitution the user never agreed to.

The order of guards is a promise about failure

Update 164's bug wasn't a missing guard — every check existed. It was the ORDER: /api/generate resolved AI credentials before validating the request, so an empty or over-cap description with no key configured answered 500 "No AI key available" instead of the honest 400. The user would add a key, retry, and only then learn the request itself was invalid — two errors to fix one mistake, and the first error message pointed at the wrong culprit entirely. A client error must never masquerade as a server error: the request is judged first, the infrastructure second, because that order decides WHICH failure the user is told about when both apply. The census that keeps it closed: a test walks every endpoint and fails if any validation sits after credential resolution — the next door added wrong is caught before it ships.

The unit test proves the logic; only the browser proves the promise

Updates 171–173 were proven with unit tests on the source — honest, but a promise about text, not about the running system. Update 164 pays the witness debt three ways: door probes now fetch the SERVED worker (oversized→400 with the exact wording, malformed JSON→400, sibling parity); the Update 162 storage guards run in a browser whose localStorage is genuinely full — and "genuinely" was itself audited when the first fill cascade left a sub-1KB gap and the probe write landed, so the cascade now descends to single characters (a test's own premise deserves the same rigor as its claim); and the Update 163 debounce runs against real keystrokes — five letters, zero synchronous repaints, one deferred render, Escape instant with no ghost render after it. Each browser twin also restores everything it touched in a finally block, because a witness that poisons the scene for the next witness is worse than none.

A fix without a measurement is a guess

Update 163 is a performance batch that refused to touch anything a stopwatch had not convicted. The recon harness loaded the VERBATIM pure judges from the shipped bundle into Node and timed them against a realistic 200-build library carrying base64 thumbnails (2.44 MB of characters — the thumbnails dominate, exactly as in real libraries). The verdict was surgical: every keystroke in the Workshop search re-ran the full render, whose first act re-parsed the ENTIRE library JSON — 5.6ms of pure JavaScript per letter (parse alone 5.2ms), 15.9ms at 300 builds with 20KB thumbs, a whole frame budget before the browser draws a pixel. Equally important were the acquittals: the storage meter measured 0.07ms, the stats strip 0.68ms, the query planner 0.60ms — all noise next to the parse, all left byte-identical, and the suite pins them unchanged. Optimizing them would have been motion without progress; the measurement is what kept the diff honest and small.

Debounce the render, never the truth

The fix draws a line through the keystroke handler: the WRITE stays per-keystroke, only the PAINT waits. Persistence at full fidelity on every letter means a tab closed mid-word restores exactly what was typed — and the Update 172 quota guards around that write survive byte-identical. The render debounces on a 150ms typing pause and reads the LIVE box value when it fires, so it can never paint results for a query that has already changed. Deliberate single actions keep their synchronous render: Escape clears instantly AND cancels the pending debounce (no ghost refresh follows it), saved-search chips, the site→Workshop jump and the sort dropdown all repaint on the click — because a click is one decision, while typing is a stream. The trap this pattern avoids: debouncing the persist along with the render feels symmetrical but silently gambles the user's input against a timer; the truth must land immediately, and only its reflection may lag.

A guard that skips the twins is a promise with a hole in it

Update 172 audited every remaining localStorage write against a hard-full store. Updates 145–157 had fixed the big families — settings, AI config, the Workshop's persisters — but each fix was scoped to its family, and the twins outside the scope kept the disease. The prompt-search Escape-clear was guarded in Update 105; the Workshop search's identical Escape-clear was not — the same keystroke, the same write, one crashed and one didn't, for seventeen updates. The tab switcher's FIRST statement was a bare write: storage full meant tab switching died app-wide, everything else pristine and unreachable. The beta-welcome overlay wrote its seen-flag before removing itself, so on a full store every close click re-threw and the panel trapped you. The lesson made permanent: a census — zero unguarded writes in live code — is now an automated test, so the next write added bare fails the suite before it ships.

Where the reader lives decides what the failed write must say

Not every guarded write deserves the same honesty budget — it depends on who READS the value. If the consumer reads the DOM (the inventory checkbox, the mega-inline toggle, the research-level select), a failed persist only costs the reload-restore: the change is live right now, so a quiet "not saved, resets on reload" notice is the whole truth. But if the consumer reads STORAGE — the ruleset text a generation embeds, the Architect's learning notes, the Real Build mode the API request body quotes — then a swallowed failure means the feature silently uses the OLD value while the UI claims the new one. Those writes now gate their success toast on the write actually landing: "Ruleset saved" only when it saved, and "NOT saved — generations still use the previous rules" when it didn't. Same guard, different disclosure, because the lie being prevented is different: one write risks an inconvenience, the other risks a green checkmark over wrong behavior.

A limit on one side of the wire is a suggestion

Update 161 audited every AI endpoint against a simple law: the server must judge its own inputs, because nothing forces a client to be the client we shipped. The generate door has always refused a 50,001-character description with a clean 400 — but seven sibling doors (lore, expand, mutate, crossbreed, team stages, analyze, mega sections) read the same field and trusted that the client had already enforced the cap. A 60,000-character description sailed through, burned provider quota, and came back as a confusing provider error instead of an honest refusal. Every gap was proven live with curl against the real door before a fix was written — the guarded door said "too long", the unguarded doors reached the key stage untouched. Now all seven apply the same law: refused at the door, named and numbered, before a single token is spent.

The wire is not a chain of custody

Two deeper finds from the same audit. First: the lore endpoint accepted a plan whose ops field was a string — an internal .map crashed and the error quoted the server's own source expression back to the user ("(r2.ops || []).map is not a function"). An endpoint that survives its input never quotes its own code; the shape is now judged before use. Second: mega section builds interpolated client-supplied outline text (name, theme, edge rules, section descriptions) raw into the AI prompt. The mega planner mints those fields capped and sanitized — but nothing forces the client to relay them unmodified, so a 100,000-character "section description" rode straight into the prompt. Every outline field is now capped at the section door itself: what the planner minted capped, the builder verifies again, because a value's history is not evidence of its present.

A unit test proves the logic; the browser test proves the wiring

Updates 157–159 fixed five bugs with Node-proven evidence — recon scripts that drove verbatim copies of the broken logic and watched them fail, then the fixed logic and watched it hold. Honest, but incomplete: a copy can drift from the page it copies, and a fix can be perfect in logic yet unwired in the DOM (the wrong element id, a handler never attached, a hook shadowed). Update 160 pays the debt: the same five fixes are re-proven in headless Chromium against the REAL page — real localStorage, the real dropdown's change event, the real Import button behind a prompt override, the real toast holder. The division of labor is permanent: Node suites are fast and surgical and run 119-strong on every release; the browser run is slower but is the only witness that the wiring — not just the logic — is honest.

Test races with a gate, not a sleep

The Update 159 race fix is exercised in the browser with a gated fetch stub: the stubbed /api/models response is a promise the test holds closed while it clicks the real Load-models button, switches the real provider dropdown, and only THEN releases. That makes the race deterministic — the stale response is guaranteed to land after the switch, every run, instead of hoping a timeout loses a lottery. Sleeps make race tests flaky in both directions: too short and the honest path fails, too long and the racy path passes by luck. A gate has no lottery — the test owns the interleaving. The stub is surgical (only /api/models is intercepted; every other fetch passes through) and the real fetch, keys, model choice and panel are restored afterward, because a test that leaves fingerprints is itself a bug.

A response must prove it still belongs

Update 159's hunt found the classic stale-response race in Load models: the function captured your provider, awaited the network, then wrote the panel unconditionally — while the provider dropdown stayed ENABLED the whole flight. Switch from Gemini to OpenAI mid-fetch and Gemini's late answer landed anyway: the wrong models painted into OpenAI's panel, and a Gemini model silently saved as your GLOBAL choice — a wound that outlived the page. The fix draws the line where authority changes hands: the cache write stays (it's keyed by the provider that ASKED, so it's always correct), but the panel and the global model belong to the LIVE provider — so after every await, the response must prove it still belongs before it may touch the screen. A stale response is cached and named honestly; even a stale FAILURE names the provider it belongs to instead of clobbering the new one's status.

A timer's world ends when the world it measured is replaced

The second Update 159 bug was an undead timer: the animated-build sweep captures the build's height (sy) in its closure when it starts — and none of the four build-swap doors (combined preview, file import, post-inventory adopt, merge) stopped a running animation. Import a taller build mid-animation and the old timer kept slicing the NEW build at the OLD ceiling, then finished by writing the old height as the layer cap under a label lying "All layers" — a 12-tall build frozen at 5 layers, permanently, with the UI claiming everything was shown. Worse, the timer clobbered the fresh layerCap=null the swap had just written. The fix is one call at every door: stop the animation BEFORE the world it measured is replaced. A closure over stale geometry isn't an animation anymore — it's a ghost measuring a house that no longer exists.

A door's first step belongs behind the same door frame

Update 158's hunt found the Workshop's paste-a-code box doing its FIRST step — decoding a pasted share link — before its error handling began. A link truncated by a chat app (the exact hazard the app's own share copy warns about: "some chat apps truncate URLs") ends mid-percent-escape, and the decoder throws. Thrown before the try, in an async function, that's an unhandled rejection: the status line was never written, and Import silently did NOTHING — the silent form of the status-lie class, strictly worse than lying. The rule: everything that can fail on the way through a door fails INSIDE the door's own catch, so every failure ends in an honest sentence. A door that can be jammed from outside its own frame isn't a door, it's a gap.

A message renderer renders text — escape at the sink, not at 129 callers

Update 158 proved the toast system was an injection sink: it assembled its bubbles with raw HTML in all three style variants, and foreign strings reach it — a share link's build name, a shared add-on's label, even your own typed input echoed back in a refusal toast. A crafted name became LIVE markup in the page. The fix location is the doctrine: a sweep of all 129 toast callers proved not one passes intentional HTML, so the sink itself escapes every message — one line guarding every present and FUTURE caller, instead of 129 fixes that a new caller could forget. Honest messages render byte-identically; crafted ones render as the text they always claimed to be. Escape where the text meets the page, and the whole class dies at once.

A cache is a courtesy, never an authority

Update 157's bug hunt found the AI-settings panel trusting its localStorage model-list cache blind: one corrupt value (bad JSON, or JSON of the wrong shape) crashed the whole panel on every open — and the crash blocked the very UI that could have cleared the bad value, a lock-in loop. The doctrine every import door already follows applies to the app's OWN storage too: bytes you didn't just write are foreign bytes. The cache is now judged (valid JSON, an array, every entry a string), and an unusable cache is DISCARDED on sight so it can never crash twice — the provider's built-in list stands in. A cache may only ever make things faster, never make them impossible.

Parallel arrays must move as one — a lying timeline is worse than none

The undo timeline keeps two arrays side by side: the plan states, and their metadata (timestamp, block count, thumbnail). Update 157 proved they drifted: the 30-step cap dropped the OLDEST plan but the NEWEST metadata slot, so past 30 steps every row wore its neighbor's timestamp and screenshot — and two pushers (redo, reviewer suggestions) grew one array without the other, desyncing them forever after. A timeline that shows real data in the wrong rows is worse than no timeline, because it converts trust into misdirection. The fix is structural, not cosmetic: every site that grows one array grows both, and the cap shifts both together. Parallel state has one law — move as one or don't move.

An id mint must refuse what it cannot name

The Recipe Studio minted recipe ids from the text after the FIRST colon of the result item. A result typed 'mymod::sword' slipped past the trailing-colon guard but minted an EMPTY id segment — so 'mymod::sword' and 'other::axe', two different mistakes, silently collided on the same id and the dedup loop renamed the second to a name describing neither. Update 157's rule: an identifier is a claim about what a thing IS, so a mint that cannot extract a real name must REFUSE with the reason named — "not a valid item id — use namespace:item with a single colon" — never emit a placeholder that two different inputs share. Collisions between different things are corruption with a delay on it.

The parser is the authority — the judge invents no vocabulary

Update 156's snapshot judge (snapShapePlan, the 107th test hook) faces the same design question Update 155's plan judge did: what is a "valid" snapshot? The answer mirrors engine parity — the PARSER decides. The judge calls the real parseMcStructure and quotes its error VERBATIM in the refusal: "Not an NBT compound root — is this a valid .mcstructure file?" is the parser's own sentence, not the judge's paraphrase. A judge with its own vocabulary would eventually disagree with the parser about what parses — refusing files that load, or admitting files that crash Load later. Quoting the authority means judge and consumer can never drift apart. The judge adds only what the parser deliberately doesn't own: budgets, name legality, index range.

Never vouch for bytes you haven't read

Before Update 156, importing a share code stored its snapshot bytes UNREAD: b64ToBytes succeeded, snapPut wrote them, entry.snap said true — the library was vouching for bytes nobody had parsed. Garbage surfaced only when Load threw, sometimes weeks later, when the sender was long gone. That's a data corpse: dead on arrival, discovered at the funeral. And the budget lesson cuts deeper — a 500MB base64 string kills the tab INSIDE atob, so the size check runs on string LENGTH, before any decoding: when the decoder itself is the attack surface, validation after decoding is validation after the crash. Every door now parses before it stores; entry.snap = true means a parser actually said yes.

Judge order is a correctness property — kill the data corpse

The library door judges the SNAPSHOT before the plan, and the order isn't style — it's what the user ends up believing. Run the plan judge first and a build with both halves broken gets skipped with only the PLAN reason disclosed, while the unusable bytes may already sit in IndexedDB. Run the snapshot judge first and the corpse dies at the door with the parser's reason named; the plan judge then decides whether a fallback exists. Update 156 also mirrors Update 155's asymmetry: where 155 said "the snapshot IS the build" and dropped the bad plan, 156 says "the plan IS the build here" and drops the bad snapshot — same doctrine, opposite half. Both halves broken refuses whole, naming BOTH reasons, because a refusal that knows two facts and names one is lying by omission.

Engine parity — accept exactly what the engine tolerates

Update 155's plan judge (planShapePlan, the 106th test hook) had one hard design question: what is a "valid" plan? Not what a schema says — what the ENGINE says. executePlan skips unknown op kinds through its switch as harmless no-ops, so the judge accepts them; a sphere whose radius cannot iterate places nothing, so it's accepted without demanding a center; a missing block name defaults exactly as it always did. The acceptance rule is engine parity, and it's proven, not assumed: a 16-plan parity suite feeds every accepted shape to the verbatim extracted engine and asserts none throws. A judge stricter than the engine would refuse builds that work; looser, and the crashes come back. Parity is the only honest line.

A freeze is a crash you can't even report

Nine foreign-plan shapes crashed the engine outright — but the tenth vector was quieter and worse: the engine runs loops sized by foreign numbers, so a crafted 2000³ fill freezes the tab for a measured ~60 seconds and a radius-1e6 sphere kills it dead, with no error, no status line, no chance to disclose anything. Update 155's answer is a per-op WORK ESTIMATE modeled on the engine's real loops — box volume for fills, bounding cube for spheres, base×height for pyramids — summed and capped at 268,435,456 cells. The refusal names the op index, its kind and the number that broke the budget, because "too big" without the number would leave a legitimate mega-builder guessing which op to shrink.

The snapshot IS the build — drop the plan, say so

When a share code carries both an exact snapshot and a bad plan, refusing the whole import would destroy something valuable to protect something broken. Update 155 draws the line the Update 153 doctrine demands: a plan is EXECUTABLE data, never repaired — but the snapshot is byte-exact and self-sufficient, so the import keeps the snapshot, drops the plan, and DISCLOSES it: "imported from the exact snapshot instead; the plan was dropped, never repaired." A snapshot-less bad plan has nothing to fall back on and is refused whole with the reason. And the Workshop's Load button — which used to die silently on a bad stored plan, an unhandled rejection with no toast — is now a total function: judge first, catch second, every press ends in a build or an honest sentence.

Two mod doors, one judge

The Mod Creator accepts foreign add-on specs at exactly two doors — the .json file loader and the share link. Update 154 gives both the same treatment the library import got in Update 153: one pure judge (modImportSpecPlan, the 105th test hook) that both doors call before anything renders or commits. Before it, a spec missing its items array crashed the share door; string worldgen biomes, a non-string event type and a null set-bonus effect each crashed a different preview panel; and a crafted namespace injected raw markup into the page. Every one of those shapes was proven to crash the real code in Node before a single fix was written — the doctrine is evidence first, then the fix.

Normalized to the app's own rules — nothing invented

The judge doesn't impose new rules on foreign specs — it applies the exact rules the app's OWN editors already enforce: the JSON editor's namespace rule (lowercase, 16 chars, "minecraft" reserved), the item and block builders' id mint, the Gameplay Studio's clamps and fallbacks, the texture editor's #rrggbb form. Nothing stricter, nothing looser. The guarantee that proves it: export a spec the app authored, import it back, and it round-trips byte-identical with ZERO coercions counted — the judge only ever fires on shapes the app itself could never have produced. Absent optional fields default exactly as they always did, silently, because defaulting an absent field is not a repair.

The status lie's third funeral

Update 151 killed "Library import failed" printed over a successful import (DNA field). Update 153 killed it again one field over (tags). Update 154 found the same disease at a THIRD boundary: the mod file loader committed the spec, THEN rendered — so a render crash made the catch print "Load failed" over a spec that had loaded. The cure is the same shape every time: judge the foreign data BEFORE the commit, so the render can never throw on it, and disclose what was normalized — "N field group(s) (namespace, items…) were out of spec — normalized to the app's own builder rules; nothing was invented." A status line that reports failure after success is the same lie as the reverse; the direction changes, the dishonesty does not.

Prompt panel counts that explain themselves

The panel header now reads "N of 20 favorite slots · M recent" — the cap stated exactly where the count appears, with the full policy one hover away (favorites: kept until you remove them; recent: rolling newest-25). The Recent list shows the newest 12 for space, and now says so inline: "showing the newest 12 of 19 — search reaches all of them" — no more quietly hidden tail. The star tooltips tell the truth too: "kept until YOU remove it (20 slots, never auto-evicted)" instead of a bare "keep forever".

No more silent clipboard & storage failures

Two failure paths in the prompts flow used to vanish without a trace. Copying the Architect's expanded prompt with a blocked clipboard did nothing at all — it now reports "Clipboard blocked by the browser — select the text manually" (and success states the exact character count copied). And when browser storage is full, adding a prompt to Recent failed invisibly — you'd believe it was saved when it never landed; the failure is now announced, with the scope stated: favorites and builds are unaffected.

The ZIP reader stopped trusting liars

An external QA lane proved that a corrupted .mcworld could declare an entry bigger than the data actually present, tricking the reader into slicing ZIP bookkeeping bytes in as world data — garbage chunks wearing a valid face. Every entry read is now bounds-checked against the archive's true central-directory boundary and rejected if its declared size crosses it. Verified both ways: permanent corruption fixtures (accepted before, rejected after) and positive controls proving valid STORED and DEFLATE worlds still import byte-exact.

Best-effort, out loud

Opening a world is best-effort by design — a corrupt database file is skipped so the rest can load. But that skip used to be silent: a damaged export opened "successfully" and you found the missing chunks by staring at holes. The status line now reports it exactly — "2 of 14 database files could not be read" — naming the skipped files and their reasons, saying what it means (chunks stored in them are missing), and advising a re-export. Doctrine: best-effort reading is fine; silent best-effort is a lie of omission.

Region extraction with specific answers

Three vague moments in world-region extraction got specific. A region entirely outside the generated area now says so — quoting the world's real X/Z range — instead of a generic "all air". The genuine all-air case names the exact coordinates and size it checked, so you can see your own typo. And any correction the app makes to your inputs (non-numeric corner → 0, size clamped into 1..320) is reported in the result line — a correction applied silently would mean extracting a different box than the one you asked for.

"Saved" must mean saved

The research dossier's edit box used to toast "Dossier edits saved" even when the browser's storage quota rejected the write — a confirmation wrapping a failure, and your edits were gone after reload. Update 95 routes every dossier save through one honest judge: a clean save says "Saved.", an over-budget save reports the truncation with both numbers, and a failed save says NOT saved — with what that means (session-only, gone on reload) and the remedy. Doctrine: a success message is a promise; showing it without checking is lying.

The honest cost of a failed cache

Fresh research that can't be cached isn't just an invisible technical hiccup — it has a price: the next Generate will re-fetch and re-bill the same research. Update 95 states that cost the moment the cache write fails, so you can free storage space before paying twice, not discover the double charge afterwards. The 6,000-character dossier budget — enforced since Update 40 but never stated — is now printed under the edit box with a live character count.

A toggle that admits being overruled

You turned notifications ON in Settings — but the browser can still overrule that: iOS Safari blocks them without a home-screen install, and the permission prompt can be declined. Before Update 95 both failures were silent, so you waited for a ping that never came. Now each path reports once per session: "the browser blocked the notification you enabled" or "the permission was just declined — no pings until you allow them". A setting that can be overruled must say when it was.

A safety net that admits when it's down

Crash-recovery autosave failed silently when browser storage filled up — every tick, forever, while you kept taking risks you believed were covered. Update 96 judges every tick: the first failure announces "crash recovery is NOT saving" with the consequence and the remedy, recovery announces the net is back, and steady states stay quiet so the warning never nags. Doctrine: a safety net that stops working silently is worse than none.

The age belongs in the decision

"Restore your last session?" — from when? The auto-save's age used to be revealed only after you restored: backwards, because an hours-old copy deserves different trust than one from 30 seconds ago. Update 96 puts the age in the restore prompt itself — "(auto-saved 3h ago)" — so the decision is informed, not blind. Information that changes a decision must arrive before the decision, not after.

A quiet "No" that deleted data

Declining the session restore deletes the auto-save — by design, so it never asks twice about the same session. But that deletion was silent: the one copy of your session, destroyed behind a "No" with no acknowledgment. Update 96 says it plainly: "Auto-saved session discarded — it is gone for good", with the reason the deletion exists. Destroying data is sometimes right; destroying it without saying so never is.

Corrupted data announces itself

A corrupted saved blob used to become an empty store, silently: per-task AI keys vanished (and the app quietly billed a different provider with your base key), hidden tabs reappeared unexplained, favorites emptied as if you never had any. Update 97 routes every persisted-store read through one judge — absent is normal, unparseable is corruption, and wrong-shaped data is corruption too. The first corrupt read announces the loss, the fallback, and the recovery path. Corruption is data loss, and data loss is announced, never absorbed.

The app never destroys evidence

When a judged store is found corrupted, the unreadable bytes are preserved under a *_corrupt key before the store resets — extending Update 95's draft-preservation doctrine to every persisted store. The diagnostics panel lists every corruption caught this session with its evidence key, so recovery (or a bug report) always has the original bytes to work from. Resetting a store may be necessary; discarding the only evidence of what was lost never is.

You can't lose what you never had

The service-worker registration failure was swallowed since Update 2. But announcing every failure would nag first-time visitors about an offline mode they never had. Update 97 latches success: only a registration that worked before and now fails announces that airplane-mode use may break — a regression deserves a warning, a never-was does not. The right honesty rule isn't "announce everything"; it's announce what changed the user's actual expectations.

Salvage, don't just mourn

The most common real corruption is a quota-interrupted write: the save dies mid-string and leaves a truncated list whose prefix still holds complete entries. Update 98 walks the damaged bytes — tracking strings, escapes, and nesting — finds every complete entry before the damage point, and recovers them all. A truncated write now costs only the damaged tail, never the whole library. Announced data loss is good; recovered data is better.

Recovery reports its own limits

A salvage that says only "recovered!" would be a half-truth. Update 98's announcements state both sides: how many entries were recovered and that everything after the damage point is gone — plus where the untouched original bytes live (*_corrupt keys). When nothing is recoverable, it says that too, with the blast radius ("snapshots in IndexedDB are untouched"). Good news delivered without its limits is just a softer lie.

A silent auto-copy is worse than none

The auto-copy build summary had a .catch(() => {'{}'}): if the clipboard was blocked (common when the tab loses focus during a long generation), the user saw no error, assumed the copy worked, and pasted their previous clipboard into chat — wrong data, delivered confidently. Update 98 announces the failure and states plainly that the summary is NOT on the clipboard, pointing to the manual Copy button. A convenience feature that fails silently converts convenience into misinformation.

Damage found the moment you arrive

Updates 97–98 announce and salvage damage when a store is read — but a store you never open is a store whose damage you never learn about. A corrupted Workshop library discovered three weeks late is three weeks of lost recovery options. Update 99 runs a startup census: all ten saved-data stores are checked in one pass on every load, and any damage is announced immediately, with recoverable-entry counts. Discovery latency is part of honesty — damage discovered today is damage you can act on today.

Preserve evidence before you latch

The census marks damaged stores as already-announced so the lazy per-store toast doesn't fire twice. But order matters: latching first would make the lazy path early-return and never preserve the corrupt bytes under *_corrupt — silently destroying the evidence to save a toast. The census therefore preserves the bytes first, then latches. When two safety mechanisms interact, verify the combination doesn't quietly cancel one of them out.

A healthy census is a silent census

The startup census announces nothing when all stores are healthy — no “all good!” toast, no reassurance banner. A check that celebrates every normal day trains you to dismiss it, and the one time it matters, you swipe it away on reflex. Warnings keep their power by being rare. The census result still lands in the diagnostics panel (Startup data check: healthy · empty · damaged) for anyone who wants to look — quiet availability, not noisy insistence.

Evidence needs an exit path

Updates 97–99 preserve every damaged store’s bytes under *_corrupt keys — but preservation alone is a dead end. You couldn’t export the evidence for recovery attempts outside the app, and you couldn’t discard it once satisfied, so it sat in quota forever. Update 100 adds both: a dated JSON export with the raw bytes verbatim, and an informed discard. Evidence you cannot act on is just clutter.

Deletion earns consent, not a click

The Discard-evidence confirmation is never a bare “Are you sure?”. It names each store, states the exact space freed, warns that future recovery becomes impossible and suggests exporting first, and promises live data is untouched. A user who says yes to that dialog knows exactly what they traded away — that is the difference between consent and a reflex click.

The last stores learn to salvage

Favorite prompts, recent prompts, and feature-visibility settings were still announce-only: corruption was reported honestly, but nothing was recovered. Update 100 upgrades all three to full salvage — favorites especially, because they are hand-curated: every entry represents a deliberate choice, the exact data worth recovering one by one. All nine array stores now recover readable entries instead of just mourning them.

Recovery becomes one click, not a ritual

Update 100’s export assumed recovery happens elsewhere: download the JSON, extract entries by hand, re-import — a ritual beyond most users, so recoverable entries sat in evidence while the live store stayed empty. Update 101 adds Restore from evidence to the diagnostics panel: recoverable entries from every stored blob merge back into the live stores with one click.

Restoring twice never duplicates

The restore plans before it acts: entries are deduplicated by content, so restoring twice — or restoring entries the live data already regained — never creates duplicates. And the restore is non-destructive: the evidence itself is kept until you explicitly discard it, so a restore can never destroy its own source. A quota-full failure hits only that one store and says so honestly.

A promise that survives the next save

Update 95’s corruption toast promised a recoverable copy of your structured-prompt draft — but the very next field edit overwrote it. Update 101 preserves the corrupt bytes of both the structured-prompt draft and the mod autosave session under *_corrupt keys before any save can touch them, and both drafts join the census/evidence/restore lifecycle as registry stores eleven and twelve.

Your keys and drafts recover too

Update 101's restore honestly skipped the three object-kind stores — per-task AI keys, mod autosave, structured-prompt draft — with "cannot be auto-restored". Update 102 closes the loop: object-kind evidence merges back by key. Objects must parse whole (a truncated object is ambiguous in a way a truncated array is not), so damaged-beyond-parsing evidence stays honestly unrestorable — export it for manual recovery instead.

Your live keys always win

The object merge has one absolute rule: live keys are never overwritten. A key you re-entered after the corruption is newer than the evidence, so the restore adds only what's missing; conflicting keys are counted and reported — "kept YOUR current value" — never applied. Restoring twice still never duplicates, and the evidence is still kept until you explicitly discard it.

Discard warns before deleting the recoverable

Discarding unreadable bytes and discarding still-recoverable data are different decisions, so they get different warnings: the discard confirmation now states explicitly how many entries or keys Restore from evidence could still bring back. The diagnostics row and the evidence export carry the same recoverable counts — the file a future tool imports knows what a merge would yield without re-deriving it.

One click, but never a blind click

Update 102's restore wrote to your live data the instant the button was clicked. Update 103 adds the preview: Restore from evidence now shows exactly what will change — per store, with additions, conflicts kept and skips — and asks before writing anything. Restoring changes live data just like discarding destroys evidence; both now earn the same informed consent.

The plan you approve is the plan that runs

The preview isn't a separate estimate that might drift from reality: preview and execution run the same judges on the same bytes, so the confirmation dialog is a contract, not a guess. When nothing would change, no confirmation interrupts you — a no-op needs no consent — and cancelling changes nothing and says so honestly.

Every announcement names the way back

Before Update 103, some corruption toasts named DevTools as the only recovery route — accurate, but a dead end for most players. Now the structured-prompt toast, the mod-autosave toast and the startup data check all point at Diagnostics → Restore from evidence, and the evidence export notes when its contents are also restorable in-app. An announcement that names a loss should also name the way back.

The backup is judged before it writes

A restore used to trust the backup file's own bytes — a corrupt entry inside a backup went straight into live data. Update 105 audits every entry in the file BEFORE the restore writes anything, using the same verdict logic the live stores use. Corruption is caught at the boundary where it can be explained: for a restore, that boundary is the import, not the next read.

Corrupt-in-backup goes to quarantine

A corrupt backup entry is never written into live data. It is routed to the *_corrupt damage-evidence slot instead — where census, restore preview, one-click restore and discard already know how to handle it. Existing evidence wins here too: an evidence slot that already holds preserved bytes is never overwritten by a backup's corruption. The outcome toast reports what was kept out and where it went.

A song becomes a build plan

Update 107: upload a MIDI (.mid) file with Convert MIDI song to note blocks in the Workshop tab. The converter reads the song's tempo map, pairs every note-on with its note-off, and produces a step-by-step plan — which note block to place at each 0.1s redstone tick and how many right-clicks tune it. The result lands in your Workshop library like any other design.

25 notes, honestly

Minecraft note blocks cover exactly 25 chromatic pitches (F#3–F#5), so the converter measures every compromise the medium forces and reports it BEFORE anything is saved: out-of-range notes are octave-transposed (pitch class always preserved — the two-octave span means no melody note is ever dropped), percussion channels are excluded and counted, and worst grid drift is stated in milliseconds. A clean conversion says "No compromises needed" — the absence of compromises is information too.

Audio arrived (phase 2 delivered)

What the last update promised, this one delivers: audio-to-note-blocks shipped, feeding the same pipeline as MIDI. Drop an mp3/wav on the MIDI button and the signpost routes you to the audio button beside it — and MIDI or audio files dropped on the evidence-import or backup-restore buttons are routed back to the Workshop converters. Wrong file, right signpost.

The app listens now

Upload an audio recording (mp3/wav/ogg/m4a) in the Workshop tab and the melody is pitch-tracked with the YIN detector, fully in-browser — nothing is uploaded anywhere. The heard notes feed the exact same note-block planner as the MIDI converter: one honest set of rules, two doors in. Hum a tune, record it, upload it, build it.

Listening is not reading

A MIDI file states its notes; a recording must be heard, and hearing forces compromises the consent dialog discloses before saving: the conversion is monophonic (chords collapse to a single pitch — said plainly, never hidden), sub-musical blips are discarded and counted, recordings over 90s are truncated with the truncation disclosed, and the dialog reports what percentage of the recording carried a confident pitch.

25 presets, one per tab

Settings holds a library of up to 25 named API-key configurations. The library is shared across tabs, but activation is per-tab (sessionStorage — survives reload, never leaks): open three tabs, activate three presets, run three builds simultaneously on three separate provider quotas. The 26th preset is refused with the cap named — limits are stated, not discovered.

The badge says whose quota burns

When a preset is active in a tab, its name appears as a badge next to the Generate button — parallel-build users always know which key each tab bills to. Delete a preset another tab is using and that tab announces its fallback to the main key: a wrong bill is never silent. Resolution order: this tab's preset → per-task keys → main key.

Presets are secrets

The preset library carries API keys, so it is treated as a secret like every other key store: excluded from full backups and diagnostic exports by design (re-enter keys after a device migration) — while still enjoying the full corruption-honesty lifecycle: damaged preset data is announced, its bytes preserved as evidence, and restorable from Diagnostics like any other store.

Whole songs, chords included

Update 110 finishes the note-block arc: the polyphonic button transcribes a full mp3 — chords and harmony kept — using Spotify's Basic Pitch model running entirely in your browser. Your recording never leaves this device.

An estimate, never a fact

AI transcription guesses. The consent reports the model's average note confidence, counts discarded blips, measures polyphony, and says plainly that quality varies — strong for piano, weaker for dense mixes. You approve the estimate before anything is saved.

Three doors, one planner

MIDI reads notes exactly. The monophonic converter works offline for hummed melodies. The polyphonic door hears whole songs after a consented ~9 MB model download. All three feed the same honest note-block planner — and each tooltip points to the neighbor when your file fits it better.

Queueing never spends

The Build queue (Build tab) holds up to 20 descriptions, and adding one runs nothing — the toast says so: "press Run queue to start; nothing runs until you do". Jobs then run strictly one at a time through the same engine the Generate button uses, and Stop after current job halts cleanly.

A preset for each job, restored every time

Bind any saved API-key preset to a queued job and it's swapped in for that job alone — then restored in a finally block, so a crash, a failure or a mid-run stop can never leak it. Every finished row names whose quota was spent: "preset X" or "the main key".

Jobs that fail tell the truth

A failed row carries the REAL error text, a job stranded by a closed tab is demoted at boot with an honest "interrupted" line, running jobs can't be deleted, only failed jobs can be retried, and the 20-job cap names itself when refusing. A queue you can trust is a queue that admits what happened.

What did this key spend?

The Cost & quota ledger (AI Settings) tallies every AI call against the credential that paid: requests, failures, rate-limit hits, and a per-task breakdown. Running builds on multiple keys? Each key's row answers for itself — no more digging through provider dashboards mid-session.

Unknown is not zero

Token counts appear only when the provider reports them, and the line names its coverage: "reported on N of M calls — the rest are unknown, not zero." A provider that reports nothing gets "the ledger will not invent them." Every report ends the same way: these are estimates; the provider's bill is authoritative.

The ledger observes, never interferes

Metering is wrapped so a ledger bug — full storage, corrupt data, a missing panel — can never break the generation it was measuring. And a corrupt ledger restarts from zero while saying so: past spending was always on your provider's dashboard, the authoritative record.

Five versions, zero silent losses

Saving over a Workshop build keeps up to 5 prior versions (the clock badge on the card opens them). When the cap pushes the oldest out, a toast says so and names the cap — the drop is a disclosed decision, never a quiet disappearance. Restore any snapshot into the preview; today's build becomes a version, so nothing is lost either direction.

Diffs that admit what they don't know

Every version row shows an honest diff against the current build: block delta with sign, size from→to, and palette changes (+quartz_block, −stone_bricks). Versions saved before palette recording began say "recorded from now on" — and one that predates block counting says "unknown is not zero" instead of inventing a delta.

Compare-only is stated, not hidden

A version whose snapshot couldn't be stored still keeps its stats — its row says plainly it can be compared but not restored, instead of showing a restore button that would fail. And the history header states the whole policy up front: up to 5 saves kept, oldest dropped with a notice, never silently.

Peek without paying for it

The Peek button on every Workshop card opens a rotatable 3D view in an overlay — your main viewer's build, camera and state stay untouched. No more loading a build (and losing your current one) just to answer a 10-second question, and no more exporting to Minecraft just to look.

The peek names its source

The overlay footer states where the voxels came from: an exact snapshot is "pixel-true including hand edits", a plan rebuild admits hand edits outside the plan are not in the view, and an entry with neither is refused plainly. A preview that might be wrong about itself says so before you trust it.

Too big is a number, not a shrug

Size is judged before meshing: a build past 64³ voxels gets a warning with the real voxel count, and one past the 128³ engine cap is refused with both numbers named. And one more disclosed fact: the peek reuses the 3D engine already loaded for the main preview — zero extra download, stated out loud.

Composition multiplies your Workshop

The Build Composer (Workshop tab) lays out several saved builds on one shared grid — offset each in blocks, rotate in 90° steps — and combines them into ONE structure. Houses + farms + a note-block song become a village, exported like any other build. Every single-structure feature you've used now feeds a bigger whole.

Estimates and truths, never conflated

While you lay out, overlap numbers are labeled bounding-box estimates — only the actual paste can count real block-vs-block collisions. The combine then reports the real collision count next to the earlier estimate. Two different numbers, two different labels — the app never lets one wear the other's confidence.

What the plan judged is what gets built

The layout judge and the combine share the same pure rotation function — the footprint you approved is literally the footprint that gets pasted (four 90° turns provably return the original grid). The 320-block safety cap is refused with the numbers named, new builds auto-place past the current bounds so nothing starts overlapped, and a failed combine changes nothing.

A link that would break is never offered

URLs have practical limits, and a link past them corrupts silently in transit — the recipient gets a broken build and no explanation. Update 116 judges every share link's size before offering it: four tiers with the real numbers named, and past 60,000 characters the link button simply doesn't appear — the plain code and Export library remain. Refusing honestly beats handing over a lie.

A whole scene in one serverless link

The Composer's layouts travel: Share scene packs the builds AND their offsets AND rotations into one link — the entire composition rides inside the URL fragment, so no server ever stores it. On arrival the recipient sees every build named in the consent dialog and the viewer-replacement warning before anything is touched, and the rebuild counts real collisions through the Composer's own spine.

Sender honesty is never assumed

A shared scene is judged twice: before encoding on the sender's side, and again on arrival — because a hand-crafted or corrupted code must not crash the receiver. One unrebuildable build refuses the scene whole, naming the build and the reason: a half-arriving layout that silently drops pieces is worse than an honest refusal.

Judge a song plan by ear

Update 117 adds Play preview to every song-conversion consent: hear the note-block plan in the browser before a single block is saved. The pitch math is Minecraft's own — note value 15 is exactly 440 Hz (concert A), the full 0–24 range spans F♯3 to F♯5 — and playback runs on the exact 0.1-second redstone grid the plan was judged on. The plan you heard is the plan that is saved.

An approximation that says so

The preview is browser synthesis, not Minecraft's exact sampler — and the dialog says exactly that, in a badge you can't miss. Pretending a triangle-wave oscillator is the real note-block harp would be a lie about fidelity; naming the approximation lets you judge timing, melody and chords honestly while knowing the timbre in-game will differ.

Silence never blocks the save

Browsers may refuse audio until a page has been interacted with — and one malformed tick would make a preview that silently skipped notes a lie, so the schedule judge refuses whole rather than plays partially. In both cases the dialog discloses what happened and Save still works: hearing the plan is a courtesy, never a gate. Every exit — Escape, ×, backdrop, Cancel — stops the sound and saves nothing.

A drawer becomes a filing cabinet

Update 118's project workspaces give each project its own Workshop, history, favorites and drafts — switched per browser tab, so two tabs can work in two projects at once (the same parallelism trick as per-tab API presets). The Default workspace is your existing data, untouched and unmigrated: a migration that could fail is a risk you never asked for, so the original keys simply keep being read.

Switching reads, never rewrites

A workspace switch changes which keys are read — it copies, moves and deletes nothing. Removing a workspace from the list deletes no builds (the confirm says exactly what is destroyed: the list entry, and what is not: every byte under its keys), and the data reappears if the workspace is recreated with the same id. Even corruption honesty follows: each workspace's damage evidence lives beside its own data.

A search that refuses to guess

The Workshop search now understands tag:music >500 rated:4 — and an unparseable token refuses the whole query with the reason, because a filter that guesses hides builds, and hidden builds are a lie by omission. The line under the box states how your query was read; builds without a stored block count are excluded from >N matches (unknown is not zero); and any query saves as a chip that re-runs live — a smart collection, never a stale list.

A template is a starting point, not a result

Press Template on any Workshop card and its prompt becomes a chip above the tag bar. Clicking the chip asks for optional parameters — width, depth, height (3–64), material, roof — and fills them into the prompt as explicit requirements before a fresh generation. Like a saved search, a template re-runs, it never replays: what you stored is the recipe, and the tooltip shows the exact stored prompt, its source build and its save date — a chip is never a mystery button.

The same house in spruce costs nothing

Templates saved from a build with an exact snapshot carry a material-swap button: the snapshot loads and palette entries are renamed deterministically — 0 tokens, no AI call, and the result line says exactly that, so a derived build is never mistaken for a generated one. Stairs swapped to stairs keep their orientation; stairs swapped to a full block honestly cannot, and the plan tells you which happened. Rebuilding oak → spruce → stone used to cost three generations; now it costs one.

Whole-or-nothing parameter fills

A height of 999, a width of 4.5, a parameter named colour — each refuses the entire fill with the limit named (dimensions are whole numbers, 3–64 blocks), never a silent correction. A prompt built from a quietly-clamped parameter would generate a building you did not ask for — the same doctrine as the search that refuses to guess and the song plan that refuses to skip notes. Empty parameters are simply skipped: unset is not an error, it just means "keep the template's own idea".

A scheduler with no server, and it says so

Update 120's Scheduled builds panel attaches a once or daily schedule to a build description — and states its own limit in its own header: there is no server, so a schedule fires at the next app open at or after its due time, never while the app is closed. Daily schedules re-arm for the next 6:00 AM and say so. Pretending otherwise would promise background work this app cannot do — the honest version tells you exactly when your castle actually gets built.

Two gates before a token is spent

Due schedules are offered at boot, never executed: "N scheduled builds are due — queue them now? Queueing spends NOTHING." Consenting moves them into the build queue as [scheduled] jobs; quota is spent only at the second gate — the queue's own Run button. Declining changes nothing: every schedule stays as it was and is offered again next open. No boot path ever auto-spends a request, because a scheduler that quietly burns quota overnight is a scheduler you cannot trust.

Overflow is disclosed, never dropped

If more schedules are due than the 20-job queue can hold, the surplus is named in the consent line ("2 more won't fit — the queue is full") and stays scheduled for the next open — a schedule silently discarded because a queue happened to be full would be data loss by coincidence. Deleting a schedule states what is not touched: jobs already queued and builds already made. The list is workspace-scoped: a recurring build belongs to a project, not to the person.

An A/B run names both bills before either is paid

Prompt Studio runs the same prompt twice — once per model preset — so its consent line says exactly that: "this runs the SAME prompt TWICE — two real AI generations, two requests against your quota. Nothing runs until you confirm." A comparison tool that hid one of its two costs would be a tool that lies about half its price. Each arm binds its preset per-tab and restores yours in a finally block — a crashed arm can never leave your workspace wearing the wrong model.

A forfeit is not a fair win

If one arm errors out, the verdict says the other arm completed — it never says it won, because beating an opponent that never showed up proves nothing about quality. When both arms finish, block count and size are reported as what they are: a fact, not a score. Bigger is not better and smaller is not better; they are properties you weigh against your own intent, and the verdict refuses to pretend otherwise.

The same model twice answers nothing

Pick the identical preset for both arms and Prompt Studio refuses to run: "comparing a model against itself answers nothing" — and spends nothing. The beauty number in the verdict carries its own disclaimer: it is a render-free heuristic (symmetry, variety, structure), not a judgment of how the build looks in the game. Keeping a winner routes through the normal plan-history path, so the arm you didn't keep is undoable history, not a deletion.

Color is never the only channel

Update 122's accessibility pass enforces a three-channel status doctrine: every toast carries a color AND an icon AND a text word (screen-reader-only, so sighted layouts don't change). The 'minimal' toast style previously signalled status by color alone — a colorblind user literally could not tell success from failure; that was a defect, not a style, and it is fixed. The status palette itself is now data the tests pin: every status color is verified at WCAG AA contrast (4.5:1+) against the app's real card surfaces — asserted by a measuring judge, not promised by a designer.

Every control now has a name

Fifty icon-only buttons (undo, zoom, dismiss…) had a title but no accessible name — hover users saw a tooltip, screen-reader users heard "button". A boot pass now copies each human-written title into an aria-label: a mechanical copy, never a guess — no control gets a name a human didn't write. The audit judge is yours too: the command palette's "Run an accessibility self-audit" measures names, contrast, and motion state live on your device and reports the numbers, because an accessibility claim you can't re-verify is just marketing.

The research pattern, rebuilt on real code

Update 122 also salvages the two approved ideas from the Level-11 research review — rebuilt against the real production pipeline this time, not a lookalike. A 5-tier divergence tracer hashes the actual executePlan → buildMcStructure chain at every stage (grid, palette, bytes) with baselines minted from production code and reproduced twice before being pinned. The four Golden Rules (integer coordinates, canonical sort before hashing, seeded randomness only, UTF-8 byte-length NBT strings) are now codified doctrine with a static scan enforcing them — the research's one honest lesson, kept; its fabricated numbers, discarded.

The module is the message

A 1,000-block road should not be a 1,000-block file — it would be impractical to generate, enormous to load, and dull to place. Update 123's Principled micro-structures panel inverts the problem: the app designs one full-quality 16-block exemplar module (road, bridge, defensive wall, aqueduct, or canal — a genuine .mcstructure built by the real pipeline) and you repeat it along your route. The design intelligence goes into the module's repetition grammar, not into brute-force length: lantern posts every 8 blocks keep spawn-proof light; seeded palette jitter breaks the copy-paste read; one pier per bridge module is the rhythm the eye expects.

The principle sheet: rules you carry, not files you load

Every module ships with a printed principle sheet: the grammar (what recurs, and why), the junction & terminus kit (how a T-junction shares its corner post, how a bridge steps down onto the road), and terrain rules for when the ground disagrees — roads insert a stair row and continue level; aqueduct channels never slope because water needs level runs (the piers absorb all height change, the Roman answer); canals climb in lock-steps, never slopes. Material counts on the sheet are measured from the real build by the real materials counter — multiply by your module count before you mine, and the number is honest.

Honest division of labor

The whole micro-structures path is deterministic — 0 tokens, no AI call, byte-exact on every run (seeded scatter only, a Golden Rule). And every sheet prints the same honest line: the app built the module; you extend the distance. That's not a limitation dressed up — it's the correct split. A tool that pretends to build your kilometer of road ships you a file your world can't load; a tool that builds the module and teaches the grammar ships you something better: the ability to build the next kilometer too.

Six builds before you type a word

Update 124's Starter Gallery solves the empty-textarea problem: a new user with no API key saw a generator they couldn't use. Six complete small builds — cottage, watchtower, farm plot, lighthouse, arch gate, dock — load instantly with 0 tokens, no key, no prompt. They're pinned deterministic plans built by the real pipeline, byte-exact on every run. A starter is a starting point, not a showcase: every card's tooltip names what to try changing first.

No second door into the workshop

A gallery starter is adopted through the exact same path as a generated build — pushPlanHistory + adoptPlan — so quality gates run, materials are counted, the inventory audit fires, and the undo timeline records it. No forked pipeline means no feature ever has to ask "but does this work for starters?" — templates, material swaps, A/B keeps and exports all treat a starter identically, because to them it is a build like any other.

The gallery is immutable — your copy is yours

Loading a starter hands you a deep copy of the pinned plan — edit it, swap its materials, carve it up: the gallery data can never be mutated by anything downstream, so the seventh load is as pristine as the first. The judge refuses unknown ids naming the menu ("nothing is loaded on a guess"), and its status line makes two promises the code keeps: 0 tokens spent, and your previous build is one undo away — pushPlanHistory runs before the starter ever touches your workspace.

Near-infinite mega grids — hour math first

Update 126: the Mega grid picker gains Custom… up to 32×32 — 1,024 sections, a beta request granted in full. The honesty that makes it safe: the live summary prints the real duration arithmetic (2.5–6 min per section plus your cooldowns — the same numbers the build loop has always measured) before anything spends, and past the old 16-section maximum a consent gate names the true bill — one AI generation per section against your quota. Declining is a complete no-op. Marathon caveat, stated up front: one master-planner response must describe every section, so very large grids may come back partially filled — and the outline status counts the terrain-filler sections out loud before you spend a single section call.

Your Workshop, your caps

Update 126: the 60-build save cap and the 5MB storage-warning budget are now Settings → Workflow values — 10–500 builds, 1–50 MB. The judge (wsCapPlan) refuses out-of-range values with the span named and stores nothing — never a silent clamp to a number you didn't pick; blank returns to the default silently, because a default is not an error. Every cap site reads through the judge — saves, duplicates, branches, song conversions, share-code imports, library imports — and the sweep caught a real bug: library import measured room against a stale hardcoded 30, half the real cap, refusing imports it had room for.

The budget moves the warning, not the wall

Raising your storage budget to 50 MB does not give you 50 MB — the browser enforces its own real quota and no setting here can raise it. The meter says this every time the setting renders, because a slider that pretends to control the browser's limit would be a lie with a handle on it. What the budget really moves: the point where our meter starts urging you to export a safe copy. The measured near-quota warning (real stored bytes, never estimated — the B99 doctrine) now fires at 80% of your number instead of the old fixed 5 MB.

Every doc in the app, one search away

Update 127's Help Center (F1, or the header's Help button) is one search over everything the app has ever documented — all the tutorial cards on this tab plus every release note. The index is built from the real rendered cards at open time, so there is no second copy to drift out of date: edit a card, and the help answer changes with it. Ranking is honest — multi-token AND with title matches first, and a query the docs don't cover says "0 entries match — the docs do not cover it" instead of showing a broken-looking empty pane. Every result is quoted from real documentation; nothing is generated.

"What does this do?" — point and find out

Arm the pointer (the Help Center's What does this do? button, or the palette command) and click any control: you get that control's own tooltip text plus the closest matching doc entry. Two teeth keep it honest: the probe click never activates the control it touches — asking about a button must not press it — and an element that carries no title or aria-label gets a plain refusal ("no explanation is invented for it") instead of a guessed answer. Esc disarms with nothing probed.

Why Help is F1, not Ctrl+/

The plan called for Ctrl+/ — but Ctrl+/ was promised to the keyboard-shortcut sheet in Update 54 at a tester's request, and reassigning it would quietly break that promise. A feature built on honesty doesn't get to start with a broken commitment, so the Help Center took F1 — the key that has meant "help" since before browsers existed — and the shortcut sheet lists it. When two features want the same key, the earlier promise wins; the newer feature adapts.

A/B comparisons recognize what you've downloaded before

Each A/B arm's fingerprint is looked up in the recorded-identity ledger — with the same match logic imports use, so the three verdicts and every boundary carry over verbatim (composition, not duplication). If an arm is byte-identical to a recorded build, the comparison shows it with the source and seen-count; if it shares a grid but the bytes differ, the earliest diverging tier is named. The boundary rides on every line: a recorded twin is the same build, never a better or good build — identity is not correctness, in comparisons too.

Unknown is the expected state — and the lookup never blocks

A freshly generated arm has normally never been recorded, so "unknown" is the expected state, not a red flag: it stays explicit in the result but silent in the UI, because interrupting you to say "this new build is new" would be noise wearing an insight's clothes. And the lookup is advisory by design: it is never required for a comparison, and a corrupt or missing ledger degrades to "unknown" instead of throwing — the comparison itself can never be blocked by its own footnote.

Old history entries are protected on purpose

Comparisons saved before Update 133 carry no fingerprint fields — and they render safely with no fabricated badge, side by side with modern entries that keep theirs. That tolerance is now pinned by permanent regression coverage, making it intentional rather than correct-by-accident. No migration was invented, because none is technically necessary: absence of evidence is displayed as absence, never backfilled, never guessed. An old entry saying nothing about fingerprints is telling the truth.

Work sessions — park a build, resume it exactly

Build tab → Work sessions: park up to 10 named works-in-progress per project, each keeping the build plan, the last 10 undo steps, and your typed description. Resume brings all three back exactly — even days later, even mid-undo-chain — with the session's age shown ("saved 3d ago · 7 undo"). This is different from the Workshop (finished voxel snapshots without the undo trail) and from crash recovery (one slot, overwritten every 30 seconds, 24-hour lifetime): sessions are deliberate parking spots for editable work. Saving under an existing name overwrites that session and says so.

Sessions never lose work silently — the caps refuse, they don't evict

The 11th save is refused with the remedy named — delete a session or reuse an existing name to overwrite — because silently evicting your oldest session would be data loss wearing a convenience costume. The undo trail is trimmed to the last 10 steps with the trim stated at save time, not discovered at resume. Resuming warns before replacing the build currently in your viewer (parking the current build first takes one click). And a damaged session refuses to resume without being deleted: it stays in the list untouched so Diagnostics → Restore from evidence can still recover its bytes.

Sessions follow every storage rule the other 22 stores obey

Saved sessions are the app's 23rd registered store, joining the full lifecycle from day one: workspace-scoped (each project keeps its own ten — switch projects and you see that project's sessions), counted in the Diagnostics storage census, corruption-announced (a corrupt session list starts empty but says so, and the damaged bytes are preserved under an evidence key for one-click recovery), and included in backups/exports. A rule is only a rule when every store obeys it. Honest edge: a resumed session's redo stack starts empty — redo is relative to the undo you just left, so carrying an old redo forward would redo the wrong thing.

Local AI models no longer re-download after every update

The bug is root-fixed: on every app update, the service worker's cache cleanup deleted every cache in the browser except its own — including WebLLM's model store, which is why the GPU local AI kept re-downloading gigabytes it had already downloaded (CPU models survived because they live in a different storage system the cleanup never touched). The cleanup is now scoped to the app's own versioned caches only, and before the first model load the app asks the browser for persistent storage so the model also survives disk-pressure eviction. Download once, keep it across updates. Honest edge: persistent storage is a request — most browsers grant it to installed/frequently-used apps, but they may decline, in which case extreme disk pressure can still evict the model.

Bring your own AI server — Ollama, LM Studio, anything OpenAI-compatible

Settings → AI mode → My own AI server points the app at an AI you run yourself: Ollama (port 11434), LM Studio (port 1234), or any server speaking the OpenAI /v1/chat/completions API. Paste the URL — the app auto-normalizes common paste formats (trailing slashes, a pasted full /chat/completions path, missing /v1) — click List to fetch your server's models, pick one, then Save & test runs a real 1-token completion before declaring success. Your browser talks directly to your server: nothing is downloaded, prompts never leave your machines, and every local-AI feature (build generation, chat) rides your model unchanged. The optional API key is stored locally and classified as a secret — diagnostics exports never include it.

Own-server checklist: CORS, http vs https, and what the errors mean

Because the browser calls your server (this app's edge servers can never reach your localhost — that's a platform fact, not a limitation we hide), your server must allow browser requests: for Ollama set OLLAMA_ORIGINS=* (or this site's origin) before starting it; for LM Studio enable CORS in Developer settings. A blocked or unreachable server is reported as exactly that — "CORS or unreachable, here's the fix" — never a silent hang. Plain http:// URLs are accepted only for localhost / 127.0.0.1 / [::1]: for a remote address the browser itself blocks mixed content from an https page, so the app refuses upfront with the reason named instead of letting the request die invisibly. Remote servers need https://.

The new menu navigation — Create, Design, Library, Help

The 14 tabs are grouped into four dropdown menus, the way Google Docs and professional software organize theirs: Create (Build Generator, Real Build, Mega Build, Base), Design (Blueprint, Map & Wall Art, Image/Video, Prompt Builder, Director), Library (Workshop, Timeline, Mod Creator), Help (Tutorial, Settings). Click a menu to open it, then slide across — while a menu is open, hovering the next one opens it instantly (hover never opens anything when all menus are closed, so there are no accidental popups). Pick a tab and the menu closes. The bar always shows where you are: the owning menu stays lit and a breadcrumb reads e.g. Design › Blueprint.

Prefer the old flat tabs? One setting brings them back

Settings → Appearance → Navigation style → Classic restores the original one-row tab bar — same buttons, same order, nothing removed (also toggleable from Ctrl+K → "Navigation: menus / classic flat tabs"). Under the hood both layouts are the same markup: Classic simply flattens the menu groups with CSS, so keyboard shortcuts, swipe navigation on mobile, the command palette and feature hiding work identically in both modes, and the two layouts can never drift apart. Icons-only and Compact tab styles apply to the Classic row (menu items always keep their labels — an unlabeled dropdown row would be unreadable).

Menus: keyboard, mobile and hidden-feature behavior

Escape closes an open menu; clicking anywhere outside closes it too. On mobile with the bottom tab bar setting, menus open upward from the bar so they never render off-screen. If you've hidden tabs via Feature visibility, a menu whose every tab is hidden disappears entirely — an empty dropdown is a broken promise (Help can never empty: Settings is always available). Swipe navigation still moves through tabs in menu order: Create's tabs first, then Design's, Library's, Help's.

Groq's old default model is dead — the app moved off it

Verified against Groq's live deprecation docs: llama-3.3-70b-versatile — the model this app used whenever a Groq key had no model specified — was shut down on 2026-08-16. Every such call was failing against a model that no longer exists. The server default is now openai/gpt-oss-120b (Groq's own recommended replacement), and the quick-pick lists, task hints and key-pool examples all name living models: openai/gpt-oss-120b, openai/gpt-oss-20b, qwen/qwen3.6-27b. If you pinned a dead model on your key yourself, pick a new one from the quick list.

Key rotation now tells you what happened

With a key pool (multiple keys separated by ;), a key hitting a rate limit, running out of credits or being rejected used to fail over silently — the event went to a server log you can't read. Rotation events now arrive as build warnings: the result names which key failed, why (rate-limited / out of credits / rejected 401-403), and which key took over — in Build, Edit, Mod Creator, Map Art and Mega-build sections. Later requests stick with the working key, so one note usually means one dashboard to check.

Bench your key pool in Diagnostics

Diagnostics → key-pool test now ends with a Pool bench line: every key is tested and ranked by measured latency — fastest, slowest, and any dead keys named by position (key #2, key #4…). The honest cost is stated right there: rotation wastes a try on every dead key each time it fails over, so remove or replace them before a long mega-build relies on the pool. Honest edge: endpoints that return plain text (Lore, Enhance) still rotate without a visible note — the bench is your audit tool for those.

One online visit, then offline builds just work

Every build path in this app waits for the 651-block catalog — and until Update 139 it was never cached, so going offline killed even the pure-JS procedural engine at "Failed to load block catalog". The catalog is now precached the moment the app installs its service worker and refreshed on every online visit. Visit once online, and from then on airplane mode, a dead hotspot or a school network outage can't stop an offline build. If you somehow hit the message on a never-cached device, it now tells you the real fix (visit once while online) instead of suggesting a refresh that can't help.

Offline generation routes honestly — and only refuses with a remedy

Going offline used to refuse generation unless the local AI model was downloaded — but the local pipeline was designed to fall back to the procedural engine (keyword parsing, zero network, no key). A pure routing judge now decides: keyless users build offline with the procedural engine, honestly labeled — "results are simpler than AI builds, but real and exportable", never sold as AI; users with the local model downloaded build with local AI; and only an explicit cloud user is refused — with the remedy named: switch AI mode to Local. A false refusal and a false promise are both bugs; the label is what keeps the fix honest.

No more "Unexpected token <" — offline errors say what's wrong

The single most cryptic offline failure was a plumbing bug: an API request with no cached answer was served the cached HTML page instead. The code saw a "successful" response, tried to parse the page as JSON, and you saw Unexpected token < — an error about angle brackets when the actual problem was you're offline. Offline API requests now answer an honest JSON error naming the real cause and what still works (offline builds via the local engine). The connectivity toast was corrected too: it no longer claims "AI generation needs internet" — cloud AI does; offline builds, viewing, editing and exporting all keep working.

The direction you drew is the direction built

Beta testers reported Blueprint stairs facing the wrong direction — and the root cause was found, not patched: the compiler dropped the ascent direction you chose. The inspector stored it, the canvas drew it, but the emitted stair blocks carried no facing at all, so every stair defaulted to east and a later auto-orient pass had to guess. Update 138 emits your drawn direction on every stair block and locks it against the guesser. Deterministic — no AI, no heuristics: what you drew is what compiles.

An edit only ever lands on the floor you can see

A Blueprint selection could survive a floor switch (the add-floor button forgot to clear it) while every tool edited the visible floor: delete removed nothing but left a phantom undo entry, duplicate copied a floor-1 wall onto floor 2, arrow-nudge moved an object you couldn't even see. Update 138 adds a selection-integrity judge that every mutating path — delete, duplicate, nudge, the property inspector — passes first. A refusal names the object's real floor and guarantees nothing was changed — never a silent retarget, because an edit applied to a guessed floor is exactly the reported bug.

Every project now has its own blueprint — honestly persisted

The blueprint drawing was the app's last unregistered store: every project shared one blueprint (switching workspaces left the old project's floors in the editor for the next stroke to save into the new project — the reported “layer state mixed up”), a corrupt save was silently replaced with a fresh drawing, and save failures vanished into an empty catch. As the 22nd registered store it is workspace-scoped (the editor reloads on every switch), corruption is announced with the bytes preserved under bp_workspace_corrupt, and a blueprint that stops saving says so once — with the remedy named (export a safe copy) and recovery announced when saving works again. Pre-existing blueprints stay exactly where they were: no migration, because a migration that could fail is a risk you never asked for.

Every project’s bytes are checked at the border

Since Update 115 a backup restore has refused to write corrupt bytes into your live data — but that audit only covered the Default workspace’s keys. Projects in named workspaces travelled inside the same backup file and were restored blindly. Update 137 closes that border: a workspace-aware audit judges every project’s entries in the backup with the same production judge the Default workspace uses — composition, never a second judge that could eventually disagree — before a single byte is written.

Consent that names the damaged project

When a backup carries corrupt workspace entries, the restore confirmation lists them by workspace name — informed consent means knowing which project carries the damage, not approving an anonymous count. Approved restores keep those bytes out of live data and quarantine them into their own workspace’s evidence slots, where Restore-from-evidence and the workspace census already know how to find them. Existing evidence on this device always wins — the backup’s copy never overwrites what your device already preserved.

Unjudged is not unwritten — the audit’s honest edges

The audit judges only registered stores under well-formed workspace ids. Unregistered keys and malformed ids follow the same generic write path as before — inventing a verdict for keys the registry cannot name would be a guess wearing an audit. A lone travelling evidence key never conjures a workspace into the report. And exports gained the mirror courtesy: a backup carrying corrupt workspace bytes says so at download time, not at a future restore — possibly after the originals are gone.

The census that sees every workspace

The startup data check (Update 99) reads only the workspace active in this tab — damage in a parked project could hide until you next switched to it, while every backup you exported already carried the broken bytes. The new Workspace data census (Settings → Diagnostics → Scan all workspaces) runs the same store-by-store health check across every workspace at once, plus every orphaned wsp__ keyspace left by removed workspaces — with measured byte sizes, never estimates. It runs on demand, not at boot: a report most sessions never read should not tax every load.

A scan that keeps its hands off

This census is strictly read-only — it never repairs, salvages, or even preserves evidence by itself, because discovery and modification are separate consents. When it finds damage in another workspace, it names the honest path: switch to that workspace, so its own load machinery can preserve evidence and salvage under the rules every load already obeys (Updates 97–99). The scan’s summary line says it in as many words: “This scan is READ-ONLY: nothing was modified, repaired, or preserved by it.” A diagnostic tool that silently fixed things would be making decisions the user never saw.

Freeing orphaned data names its price first

Removing a workspace keeps its data on purpose (Update 118) — but that data was invisible afterward, filling quota silently. The census lists it as orphaned: parked, not lost (it reappears if the id is recreated). The Free… button plans before it touches: the confirmation names the exact key count, the measured KB, and how many IndexedDB snapshots ride along — and an unreadable Workshop list is disclosed as “snapshots cannot be enumerated”, never silently skipped. Declining removes nothing; a live workspace is refused whole (“not an orphan”); and a failed removal reports exactly which keys are still on the device.

Browse everything the ledger remembers

The Ledger Browser (command palette → “Show recorded-identity ledger”) lists every identity this browser has recorded — newest-first by when its bytes were last seen, filterable live by name, fingerprint prefix, or source (download / re-export). It is a read-only window over the real ledger, re-read on every render, never a second copy that could drift. Each row carries the build’s name, its seen-count, and its master digest (FNV-1a 64, not SHA — a drift detector, never cryptographic) with a one-click copy so you can prove those exact bytes anywhere. An empty ledger says so plainly: recording happens on download or re-export, and proves identity, never correctness.

Forgetting is honest — it says what it forgot

Each recorded identity can be forgotten — and the forget is held to the same honesty bar as everything else. It removes exactly one named identity and states the full consequence: the name, the digest, the seen-count, and the fact that future imports of those bytes will report unknown — which is not an accusation, just the ledger no longer remembering. It also says plainly that it cannot be undone. A forget aimed at a fingerprint the ledger never recorded refuses — “Nothing forgotten” — and the ledger is untouched; and if the storage write fails, nothing is forgotten at all rather than half-forgotten.

Why you can inspect and forget, but never edit

The browser deliberately has no edit button. A ledger entry is a measurement — a fingerprint computed from real exported bytes at a real moment — and editing a measurement would turn evidence into fiction: a renamed or re-dated entry could “prove” an identity that never existed. So the only operations are the two that keep the record truthful: inspect (see exactly what was measured) and forget (stop remembering it, with full disclosure). Anything in between would let the ledger say things its bytes never said — and a ledger that can be talked into agreeing with you proves nothing.

A/B verdicts now carry fingerprint evidence

Every A/B comparison fingerprints both arms on the real export pipeline (FNV-1a 64, not SHA — a drift detector, never cryptographic) and adds one evidence line under the verdict: byte-identical (same master digest — the two prompts produced the same structure, which is a fact worth knowing before you argue about which is better) or diverged, with the Update-131 ladder naming the earliest diverging tier — grid before palette before nbt, because later tiers derive from earlier ones — and both digests shown so the difference is measured, not guessed. History rows get a compact badge: byte-identical or diverged@tier, masters preserved in the tooltip.

Divergence is a fact, not a score

The evidence line never touches the metric rows: neither arm wins for being different, and byte-identical arms don't make a run a tie — the metrics still speak for themselves. This is the same facts-not-scores rule the A/B table has always kept, extended to identity: the fingerprint tells you whether and where the two structures differ, and stops there. And the Update-131 boundary rides along on every line — identical bytes are the same build, not a good build. Two arms can produce byte-identical structures that both have floating roofs; the fingerprint won't warn you, but the validators will.

A refusal has no identity — in comparisons too

If an arm's generation failed, there are no bytes to digest — so the evidence line says "arm A did not produce a successful fingerprint — a refusal has no identity to compare" instead of inventing one (Update-131 rules apply here too; both arms failing refuses the whole line). And fingerprinting is best-effort by design: if minting an identity throws, the comparison itself still runs, because the metric rows stand on their own. The evidence line is an addition to the A/B verdict, never a gatekeeper in front of it.

A ledger that remembers what left this browser

Every download or re-export records its fingerprint in the fingerprint ledger — a normal registered store, so it is censused, backed up, corruption-honest, and workspace-scoped (a build's identity belongs to its project). It holds 200 entries; when full, the oldest drops and the status line says so — a silent cap would be a quiet lie about what is remembered. Re-downloading the same bytes bumps a seen-count instead of duplicating. Recording is best-effort by design: a full storage quota can never block the download itself, because the file matters more than the memory of it.

Match, diverged, or unknown — and unknown is not an accusation

Importing a .mcstructure matches it against the ledger with three verdicts. Exact match: byte-identical to a recorded download, named with source and seen-count. Diverged: the voxel grid matches a recorded build but the file differs — the Update-131 ladder names the earliest diverging tier (palette before nbt, because later tiers derive from earlier ones), so you know where it changed. Unknown: never recorded here — which accuses nobody, because the ledger only knows what this browser recorded, not what the world contains. A file from a friend is unknown, not suspicious.

Identity is not correctness

The boundary every ledger line states out loud: a matching fingerprint proves this is the same file this browser produced — it never proves the file is good. A build with a floating roof fingerprints just as cleanly as a perfect one, and re-importing it will match exactly. Correctness lives in the validators (floating blocks, invalid blocks, attachments); identity lives in the ledger. Two different questions, two different tools — and the app never lets one borrow the other's authority.

A fingerprint measured on the pipeline you actually use

Verify reproducibility (under the export buttons) digests your build in three tiers — the voxel grid byte-exact as executePlan filled it, the palette in canonical sorted-key JSON, and the .mcstructure bytes exactly as the download writes them — then re-runs the real pipeline fresh on the same plan and catalog and compares. "Bit-reproducible" is a measurement made just now on the same modules your download uses, never a promise copied from a report. Click the fingerprint to copy it; paste it anywhere you need to prove these exact bytes.

Earliest divergence: "fix here first" as a measurement

The three tiers form a ladder — grid → palette → .mcstructure — where each later tier is derived from the earlier ones. So when two fingerprints disagree, the comparison walks the ladder and names the first tier that differs: a grid divergence means the plan executed differently; matching grids with a palette divergence isolates the palette assembly; matching both with an NBT divergence isolates the file writer. That localization is the one legitimately good idea salvaged from a research track that had twice "verified" lookalike modules instead of these real ones — the idea survives; the forged baselines did not.

Named FNV-1a, because it is FNV-1a

Two independent reviews caught the same defect in the research packages: FNV-1a hashes labeled "SHA-256" — a fast checksum wearing a cryptographic name. The production version answers that by construction: the digest function is named fnv1a64, every printed line says "FNV-1a 64, not SHA", and the docs call it what it is — a drift detector, excellent at noticing that two builds differ, never a cryptographic commitment against an adversary. An honest label on a modest tool beats a grand label on a lie. Refusals are honest too: a build missing a tier gets no fingerprint at all — "a fingerprint with a hole in it is a guess wearing an identity."

A light theme that had to earn daylight

Update 128 deferred the light theme with a stated ship condition: "it ships when it can measure true across the whole app, not before." Update 130 is that condition fulfilled. Every text-color class the app uses — all 61 of them, censused from the real markup — was assigned a same-family dark ink, and lightInkAuditPlan re-measures the entire map with the WCAG formula at apply time, against all three light surfaces. If even one ink fails AA, the whole theme refuses with the failing class named. A deferral with a condition is a promise; this is what keeping it looks like.

Hue survives the flip — meaning does too

In dark mode, color carries meaning: amber warns, red refuses, emerald confirms. A light theme that flattened everything to black ink would keep the letters and lose the language. So each family maps to its own measured dark shade — amber-400 becomes deep amber #92400e (6.2:1), red-400 becomes brick #b91c1c (5.7:1), emerald stays emerald at #047857 (4.8:1). Two deliberate exceptions: white text stays white on solid colored buttons (dark ink on a green button would be the new lie), and translucent notice tints flip to same-family light tints so a warning panel still reads amber in daylight.

Refused whole, never patched quiet

The light theme's admission gate runs every apply, not once at design time: applyTheme calls the audit before the theme may paint, and a failure falls back to Overworld with the judge's line as a toast — never a silent half-repaint. Why so strict? A theme that ships 60 readable classes and 1 unreadable one has shipped an unreadable app for whoever lands on that class. The audit's verdict names the worst pair and its measured ratio (worst in the shipped map: 4.53:1, text-blue-400 on the page surface — above the 4.5:1 AA bar), so the claim is checkable, not decorative.

Numbers that only move for real events

Settings → Progress & milestones counts your workspace history — builds, songs, exports, lifetime blocks, days, streaks. Every counter moves at the same chokepoint the feature itself flows through: a build counts when it is adopted (with its real measured block total), a song counts only after you consent to the conversion (declining the dialog is not a song), an export counts when the file actually downloads. A build whose block count could not be measured adds zero to the lifetime total — unknown is never estimated. And counting can never break the thing it counts: if the stats system fails, your build still builds.

Milestones fire once, ever

A milestone toast ("100th build!") celebrates a crossing: it fires exactly when a counter passes a tier — was below, now at-or-above. That one rule quietly guarantees two honest behaviors: no milestone can ever toast twice, and restoring an old backup can never re-celebrate glory you already had. Streaks are equally strict — a day counts at most once per calendar day, and a gap resets the current streak to 1 (your best streak is kept separately, so a broken chain never erases the record). The full tier table is printed in the panel as your next goals.

Stats live on this device only

The progress panel says it, every milestone toast repeats it, and the code enforces it: nothing about your stats is uploaded, ever. The counters are a registered store like everything else — they are included in your full backups, damaged bytes are preserved as evidence with counters restarting from zero (announced, never silent), and the reset button's confirmation names exactly what it clears (counters, streaks, milestone history) and what it never touches (your builds, workshop, settings). A stats system you cannot audit would just be a scoreboard — this one plays by the same storage honesty rules as your real data.

Themes that are measured, not promised

Settings → Appearance → Dimension theme repaints the whole app — Nether crimson, End purple, Deep Dark teal, or pure-black High Contrast — over the exact same layout, so nothing you learned moves. The honest part: when a theme applies, the app measures its text contrast with the WCAG formula against the real surface colors and requires 4.5:1+ (AA) at the worst pair. A theme that failed the measurement would refuse to apply and tell you the ratio it got. That is also why there is no light theme yet: the app's text was authored for dark surfaces, and a light repaint would fail the measurement all over — it ships when it measures true, not before.

Sound, only if you ask for it

Settings → Appearance → Sound cues gives clicks a wood tap, successes a two-note XP chime, and errors a low buzz — all synthesized in your browser with WebAudio. Nothing is downloaded, and the audio engine is not even created until the first cue actually plays, so the feature costs zero while off. And it is off by default, permanently: an app must never make a sound without consent. Every cue is judged before it plays — off wins over everything, and an unknown cue refuses instead of guessing at a noise.

One background, one owner

The app already had a page tint setting (Batch 31) that colors the area behind the cards. A dimension theme also paints that area — and two features silently fighting over one background would repaint each other blind. The rule, stated where you set it: while a non-Overworld theme is active, the theme owns the whole surface stack and the tint is dormant; switch back to Overworld and your tint is honored again, exactly as you left it. Neither setting is deleted by the other — ownership is disclosed, not fought over.

A tour of the real thing

Update 125's guided tour (the header's Tour button, or Ctrl/Cmd+K → "Take the guided tour") walks seven stops over the app's live controls — describe, starters, Generate, preview, materials, Workshop, palette — with a moving highlight ring. Never a screenshot, never a mock: the ring wraps the actual element you'll click later. The stops are pinned data (TOUR_STOPS), so the walk the tests verify is the walk you take.

The tour spends nothing

The tour's only self-made clicks are tab switches — it never presses Generate, never adopts a plan, never writes a store. Every step's card carries the promise in writing: "the tour spends nothing". A tour that quietly ran an AI call to show you the preview would be teaching you the app by billing you for it; this one points at the Generate button and names its cost without pressing it.

No highlight is faked

Some targets don't exist yet — the materials panel appears only after your first build. The tour's honest-degradation rule: when a stop's target isn't on screen, the card says so in an amber note ("it appears after your first build") and centers itself, instead of drawing a confident ring around empty space. And tourStepPlan (the 68th hook) refuses out-of-range steps naming the real span — nothing is highlighted on a guess.

One planner, two doors

MIDI and audio converters both emit the same note format and feed the same planner — so transposition, percussion exclusion and grid-drift measurement behave identically whichever door you enter by. Polyphonic transcription (full chords from an mp3) is the planned final phase of the song-converter arc, and it will feed this same pipeline too.

Evidence travels with your backup

Your full backup has always carried your preserved damage evidence — the *_corrupt slots are ordinary entries, so evidence survives a device migration along with everything else. Update 106 makes this a proper feature: the export toast announces when evidence travels, and the restore merges it honestly instead of writing it blindly.

Only-if-absent holds everywhere

Since Update 97, every writer of evidence slots has obeyed one rule: never overwrite existing evidence. The backup restore was the last exception — it wrote travelling evidence slots blindly over whatever the target device had preserved. Update 106 closes it: a free slot receives the backup's evidence, an occupied slot keeps its own bytes. A rule is only a rule when every writer obeys it.

The merge plan is in the consent

Before a restore writes anything, the confirm now states the evidence-merge plan: how many evidence slots travel with the backup, how many will be preserved onto this device, and how many are skipped because this device's own evidence wins. The outcome toast then reports what actually happened — the plan you approve is the plan that runs.

Wrong file, right signpost

Dropping a damage-evidence export on Restore backup — or a full backup on Import damage evidence — is recognized for what it is: the toast names the file's actual type and points at the button that can read it, in both directions. And the export toast now warns at export time when a backup carries corruption, so the trap is announced before it travels.

The export loop closes

Update 100's evidence export promised that "a future version of this app" could attempt deeper recovery, and Update 102's export carried a machine-readable map for "a future import". Update 104 is that future version: Import damage evidence accepts any exported damage-evidence JSON and re-populates the *_corrupt evidence slots — after which census, preview, restore and discard all work on them. A promise made in one update is a debt; Update 104 pays it.

Existing evidence wins

An import never overwrites an evidence slot that already holds preserved bytes — the same only-if-absent rule preservation has followed since Update 97. If a slot is occupied, the import keeps YOUR stored copy and says so, per store. And an import never touches live data at all: it writes only the *_corrupt evidence slots, leaving every build, draft and setting exactly where it was.

Consent knows the file's origin

The import confirm doesn't just list which slots will be written — it states the export's provenance: which update produced the file, and when. Approving a write is more informed when you know where the bytes came from. As always: a no-op needs no consent (nothing importable, no dialog), and cancelling changes nothing and says so.

Quick start — how to use this app

1. Generate a structure

  1. Open the Build Generator tab and describe what you want (e.g. "medieval cottage with a garden and a secure iron door").
  2. Pick a size preset and functionality level, then press Generate.
  3. Watch the 3D preview build in real time — orbit with the mouse, scroll to zoom.
  4. Not happy? Use Enhance, Variations, or Director Mode to iterate, or edit blocks directly in the preview.
  5. Check the beauty score & critique panel — the AI auto-improves flat walls, boring silhouettes and empty interiors.

2. Generate map art

  1. Switch to the Map Art tab and upload any image.
  2. The app converts it to a flat block mosaic matched to Minecraft map colors.
  3. Export it like any other structure and place it under a locked map.

3. Choose your AI mode (Settings )

  • Local AI — runs entirely in your browser, no API key or internet needed after the one-time model download. Uses your GPU (WebGPU) or falls back to CPU mode — works even on a Fortinet-hosted Windows 10/11 VM with no graphics card.
  • Cloud (Gemini) — highest quality, needs an API key.
  • Auto — uses cloud when a key is set, local otherwise.
  • Use the performance selector to force Quality (3B), Fast (1B) or CPU-only (0.5B) local models.

4. Export & play

  1. Download as .mcpack (1-click import) or raw .mcstructure.
  2. Load it in-game with a Structure Block — full steps below.
  3. Redstone features (secure doors, auto-smelters, lamp posts) work out of the box on Bedrock.

How to import into Minecraft Bedrock

Easiest way: .mcpack (1-click)

  1. Click Download .mcpack — then just double-click the downloaded file. Minecraft opens and imports it automatically.
  2. Create/open a world with the behavior pack enabled (Edit world → Behavior Packs → add the imported pack).
  3. Place a Structure Block (/give @s structure_block), set mode to Load, enter mystructure:<name>, press Load.

Manual way: .mcstructure file

  1. Download the .mcstructure file above.
  2. In your world, enable cheats and give yourself a Structure Block: /give @s structure_block
  3. Locate your world's behavior pack or use the world folder: place the file in <world>/structures/ (create the folder if needed). Alternatively, in-game: place a Structure Block, set mode to Load, and type the structure name mystructure:<name>.
  4. Files exported here use the namespace mystructure, so load with mystructure:<name>.
  5. Press Load — your build appears!

Install as a desktop app — Windows, macOS & Linux

  1. Windows 10 / 11: open in Edge or Chrome, click the Install app button in the header (or Edge menu → Apps → Install this site as an app). You get a Start-menu entry, taskbar icon and its own window.
  2. macOS: in Chrome/Edge/Brave click Install app (or the install icon in the address bar) — the app lands in Launchpad and the Dock. In Safari 17+: File → Add to Dock.
  3. Linux (Ubuntu, Fedora, Mint, Steam Deck desktop mode…): open in Chrome / Chromium / Edge / Brave and click Install app — it appears in your application launcher (GNOME/KDE) like any native app.
  4. Everything works offline after the first load (local AI mode included) — generated files land in your normal Downloads folder on every OS.
  5. No install button? Update your browser (2020+ versions support PWA install) — or just keep using it in a normal tab; it's the same app.

Install on iPhone & iPad (iOS / iPadOS)

  1. Open this site in Safari (must be Safari — other iOS browsers can't install web apps).
  2. Tap the Share button in the toolbar.
  3. Scroll down and tap Add to Home Screen, then Add.
  4. Launch from the home-screen icon — it runs full-screen like a native app, works offline after first load, and downloads land in the Files app (On My iPhone → Downloads).
  5. To get a .mcstructure into Minecraft on iOS: download the .mcpack version instead — tap it in Files and it imports straight into Minecraft.

Notes: cloud AI providers all work on iOS. Local GPU AI needs WebGPU (iOS 18+/Safari 26 rolling out); the CPU local model works on any modern iPhone. Android: Chrome → menu → Add to Home screen.

Files are standard Bedrock NBT (little-endian) structure files compatible with Structure Blocks and add-on structure folders. Format version 1, Minecraft Bedrock 1.16+.