The bazaar is not an art project, and this paper holds no prompt tricks. The bazaar is this site's index: a pixel-art night market, ten stalls, one route per stall, a talking keeper in each. gpt-image-class models generated every pixel. Codex CLI drove the jobs, Claude supervised the fleets, and I directed by eye. This paper is the engineering method.
A capable image model is the obvious explanation, and it is the wrong one. A plain prompt never shipped a single asset here. The market shipped 259 files because 314 archived orders pinned every pixel. A human rejected everything else. The fight ran over two weeks. There was no one-prompt big bang. We looked.
An order is a datasheet. A brief describes a mood. A datasheet pins a measurement. Angles arrive as integer ratios. Positions arrive as pixel coordinates. Color arrives as a closed hex list. Attachments support the data. They are never the base of the generation.
The method earned a name: adversarial asset direction. Every order faces a hostile review before it flies. Every landing faces a ruler. Every approval survives an attempted refutation. One ratio, 68:81, recurs below. It is the thesis in two integers. The console stall failed the most rounds, so it supplies most of the examples.
A market instead of a menu
A list of links is the predictable index, so this index became a place. Every stall is a route, and navigation is wandering. The reference cocktail is exact.
- Final Fantasy IX item shops · the interaction grammar: hover dialogs, typewriter text, shopkeeper personality
- Neo-Tokyo · the mood: neon, rust, cable clutter
- 16-bit market scenes · the rendering: chunky color, outlined sprites, flat depth
The mapping rule: the stall's fiction rhymes with the route's content. The console stall is a hacker den because /console is a terminal. The talks stall is a video club because talks live on tapes. The w98 stall grows plants because /w98 is an old machine still alive.
Keepers carry the whole personality budget. Each stall has exactly one focusable interaction. The dialog types at 9ms per character (TYPEWRITER_INTERVAL_MS = 9). Links type in last, so the eye lands on them.
The market runs vertical. A street sits on top and sells the fiction: bus stop, neon sign, a door that opens. Market floors hang below, chained by spiral stairs. You scroll down into the underground.
Five builds, one survivor
Five builds happened, and the fifth ships. The four before it each proved one thing and died of another. No build was wasted. Each one turned a vague objection into a law for the next build.
v1 proved the fiction: tall framed cards, one keeper each, the first dialog engine, a street sky still raw chroma green. It was a place. It was not yet a market.




v2 built the effects language: neon blink, dust motes, parallax foreground, FFIX dialog styling. Its street composition survived every rebuild since: bus stop, alley, neon sign, door.



v3 was the takeover: the full generation campaign, a written bible, shared architecture with glass bays and H-beams, behavior cards per keeper. It assembled, and it passed mechanical validation. I rejected it by eye with one sentence: the stalls still looked placed on top of the environment. That sentence steered everything after. The build survives as evidence.




v4 mounted the campaign winners on the v2 skeleton: layered animated stalls, new architecture, ninety-two placeable props, the restyled street. It looked right and measured wrong. A layout audit killed it, and the numbers arrive below. v5 inverted the order and survived: prove the layout in empty boxes, then mount final sprites.




Three roles, one law
Three roles run the pipeline, strictly separated.
- Director. Rules by eye, supplies reference images, never writes prompts. I pasted film stills, SVG diagrams and crops with circles of anger. The supervisor translated taste into contracts.
- Supervisor. Writes orders, flies fleets, verifies mechanically, reports with numbers.
- Contractor. Executes one order per job. Talented, unreliable, forgetful.
The whole pipeline exists to compensate for that third adjective.
The first law: never trust the contractor. Every landing gets mechanical verification: canvas dimensions, content bounding box, chroma coverage, hash uniqueness across concurrent jobs, measured angles. A ruler catches what an eye forgives. The model claims nothing. The ruler decides.
Each job writes one status file, and a watcher polls for landings.
nohup bash -c "codex exec ... - < order.md ; echo EXIT=$? >> status" & disownThe order goes through stdin because positional "$(cat)" arguments silently vanish inside nohup bash -c. Concurrent jobs in one working directory collide on image-gen temp files. Two jobs once returned byte-identical PNGs, and only md5 caught it. The fix is per-job directory isolation, a random launch stagger, and absolute output paths inside every order. One physical constant: the model renders 1536x1024 and 1024x1536 exactly, and its square is a 1254x1254 preset. Ask for anything else and you get a preset anyway.
VISUAL // ARCHIVEAn early whole-floor master, round 1: one image, every mistake still undiscovered.1400×933px
Every round ends the same way. The fleet lands into an HTML gallery. Captions carry the verdict numbers, references sit at the top, and the director judges in one tab. Fleets fly detached. Approval never does. Nothing self-approves.
The order is a datasheet
An order is a markdown file with four parts. Each part exists because a recorded failure demanded it.
- Attachment declarations with roles. "Image 1 is the composition plan: all invisible constraints. Obey the layout, never draw any of it." The never-draw clause is standing law, because models paint attached diagrams into the output. It happened.
- Canvas and chroma contract. Flat
#00ff00outside the content, explicitly scoped: background key only, zero content pixels. - The laws, priority-ordered, numbers first. Camera law, angle law, composition schema with pixel boxes, light law, style law, palette clamp, an avoid list. Scene orders add a numbered inventory of every element.
- Output contract. Exact size, exact destination path, print
GENERATED=<path>.
The deepest lesson sits in part three. Specificity is the whole game. A data-anchored order pins the picture as data: the slab's six vertices as absolute canvas coordinates, checkpoint dots every 20 rows along each edge, element boxes like x=464..1072, color blocks never smaller than 4x4 pixels, one hex list with one scope per exception. An order is a measurement of the image, taken before the image exists. Adjectives fill the gaps between numbers, and the model fills adjectives with its own taste.
VISUAL // ARCHIVEComposition plan 9: slab vertices as pixel coordinates, checkpoint dots along each edge, doctrine panels.1400×933px
Attachments enter as exhibits for that data. A drawn plan restates coordinates the text already carries. A corrective render carries its own measured failure. The numbers lead. The pictures testify.
Verbosity is a dial, not a virtue. Scene orders need inventory-grade transcription, or the model drifts identity. Pose edits on isolated characters need three sentences, and every extra sentence degrades them. The same contractor wants opposite briefings for different jobs. That lesson cost real fleets.
Before a fleet flies, the order itself goes on trial. The draft and its attachments go to a hostile reviewer with one brief: break this before the model does. Those reviews convicted real orders of generation-ruining contradictions.
- A keyboard mandated in the inventory and banned in the avoid list.
- A palette law with its own mandated background color missing from the list.
- A diagonal ban no character with hair could satisfy.
Each finding costs one review. Each miss costs a fleet.
The largest single failure proves the rule from the other side. Thirty concurrent jobs flew one order body for the console den. Thirty renders failed identically: dropped camera, bloated rug, furniture rotated inward. Identical failure across independent samples means the shared input carries the defect. The audit read the order and found my own capitals: "camera slightly LOWER", "the rug band is DEEP", "racks ROTATED TOWARD Ed". The model had obeyed, thirty times. The order was the bug.
- error
- Thirty den masters, thirty rejections, every render failing identically: dropped camera, deep rug, furniture rotated inward.
- insight
- When every job fails the same way, the shared order is the poison. The model obeys. That is the problem.
- fix
- Audit your own orders with the hostility you reserve for output. The conviction came from reading the instructions, and the instructions confessed.
VISUAL // ARCHIVEThe audit that convicted the supervisor: all thirty order texts in one viewer, the shared poison highlighted.1300×1083px
VISUAL // ARCHIVEThe thirty den masters, all rejected. Every one obeyed the same poisoned order.1100×1625px
Probes tune the model in flight
You cannot fine-tune the weights mid-campaign. You can fine-tune the order, per round, with the model in the loop. A round never flies one job. It flies four probes: same layout contract, one instrument varied per probe. The gallery verdict picks the surviving instrument, and the next round breeds from it. Across rounds this behaves like optimization, with the order file as the parameter vector.
The clearest example is the flatness round on the scavenger stall. Renders kept arriving detailed and noisy under a locked layout. Four probes flew four instruments against the same clamp.
Cut the style block to its shortest legal form.
Style: authored low-res 16-bit pixel art, large flat bounded regions, near-black outlines, LOW DETAIL. [every optional style word deleted, all other laws unchanged]
verdictFlatter than the baseline and the lowest raw color count. Kept as the lean gospel.
Two verdicts from that round travel. First, redefining the medium beat policing the style: the winner stopped asking for flat paint and declared a grid the render could not escape. Second, the raw color counts measured 120k to 160k on all four probes, and the flattest probe by eye held no advantage in the count. Raw counts never track macro flatness. The eye rules. The counts only catch regressions.
VISUAL // ARCHIVEOne round, one war board: probes, references and verdict captions in a single gallery tab.1300×1213px
The instrument search has a failure mode: searching for the wrong deliverable. One round flew thirty strategies to transplant a single character camera, and two strategies worked. All thirty landed rejected, because the deliverable was the full stall master and every probe shipped an isolated character. Confirm the unit of delivery before you fly thirty jobs.
VISUAL // ARCHIVEThirty strategies for one camera transplant on a single board: two worked, zero shipped.1100×917px
Attachments carry data, or they lie
Attachments outrank prose in raw power, and the ranking comes from measurements.
- Corrective attachment. The model's own rejected render, labeled "approved content, rejected geometry: you drew 62 degrees, the law is 50". The only instrument that ever bent geometry.
- Layout-lock repaint. An approved render attached as "the layout is CLOSED, your only task is the paint". It shrinks the degrees of freedom to the one axis still wrong.
- Drawn law. A rendered diagram beats the same rule as text, every time.
- Canvas orientation. A 1536x1024 canvas pulls every stall wide, whatever the text says. The medium is an instrument.
- World-camera gospel. The approved neighbor stall: "copy the camera, zero content".
- Character gospel. The film still: "copy the kid, zero camera". Models split a reference into channels if the order names the channels.
- Verbal geometry. Coordinates and angles in prose. Necessary on every order, sufficient on none.
Rank four decided the longest war. Stall width lost eleven straight rounds to language: frame guides lost, measure clauses lost, coverage guards lost.
- error
- Stalls render 15 to 70% wider than ordered, round after round, on every landscape canvas.
- insight
- The canvas composes. Orientation outranks prose, and aspect is unfixable in post: scaling preserves it.
- fix
- Generate stalls on a 1024x1536 portrait canvas. The page refuses to compose a wide stall.
Rank one is the console slab. Rules-only probes sat at 62 degrees across a whole round. The corrective attachment moved the next round to 55.5, and a second corrective round reached acceptance. Convergence by self-reference, measured and repeatable. The shipped master still fails two mechanical checks, aspect 0.92 and a measured slope of 61, and the eye shipped it anyway. Numbers make the conversation precise. The eye is the gate.
VISUAL // ARCHIVEThe console lineage: 62 degrees, then 55.5 after the corrective attachment, then the layout-lock repaint, then the shipped portrait.1600×333px
Then the hierarchy failed upward. On the scavenger campaign, one round flew four probes with four attached gospels: the angle law, the camera authority, two correctives. All four probes returned near-identical renders. Variance is the entire point of a fleet, and the attachment chain had strangled it. When every probe agrees, the attachments are lying.
The law inverted for scene masters: attach zero images. The supervisor reads the gospels and transcribes them into the order as prose with numbers. The camera construction as text. The paint manner as text. The full numbered inventory. Every recorded failure with its measurements: "you drew 1333x945, aspect 1.41. The law is 1.12." Identity held for nine straight rounds on words alone. The hierarchy still governs pose sheets. An isolated sprite still needs its anchor attached. For scene masters the second law now reads: describe, and bring the numbers.




The axonometric camera
No order asks for perspective, and every raw render arrives with one. The market needs the opposite: an authored axonometric projection, flat and game-like. Fourteen rounds went into the camera doctrine, and I vectorized the final form myself.
The shipped doctrine is a flat storefront elevation. The camera sits dead-on at standing eye height. No vanishing points, no room interiors, no side walls. Tall furniture obeys the two-surface law: a front rectangle plus one thin horizontal top band, about a fifth of the width deep. A visible side face is a rejection. Depth between objects is overlap only. Every vertical is dead vertical.
VISUAL // ARCHIVEThe first drawn law: the green legal construction beside the red crossed-out isometric.1024×512px
The slab is the one exception, and it ended a war between two demands. The world must read flat like the games stall. The keeper still needs a floor plane under him. The world stays a flat elevation. Each stall stands on a shallow platform, and the platform's top face is the single legal foreshortened plane. That face is a symmetric trapezoid with interior corners 130/50/50/130. The sides slope exactly 68 pixels inward per 81 pixels down, coprime integers on purpose. Any rounded restatement, 60:72 for instance, got flagged in review as not-the-authority. Orders carried the six vertices as absolute canvas coordinates plus checkpoint dots every 20 rows. Give the model exactly one plane to be deep in and it stops inventing cameras.
VISUAL // ARCHIVEThe slab law as vectors: interior corners 130/50/50/130, sides exactly 68:81.1500×554px
The verdict card closed the argument. It pairs the legal construction with the model's previous failure, crossed out, its measured numbers named in the image and in the text. Naming the failure's own numbers moved the needle.
VISUAL // ARCHIVEThe verdict card: the legal construction beside the crossed-out 62-degree failure with its measured numbers.1200×560px
One early draft banned diagonals outright, and the hostile review convicted it as unsatisfiable: a bent pole and spiky hair were both illegal under the ban. The scope narrowed. Constructed diagonals are only ever the 68:81 sides, and organic lines are exempt.
The games stall is the world-camera authority, and its winning phrasing is canon: "a FLAT STOREFRONT seen dead-on, NOT a room, NOT a stage, NOT a diorama, the floor is a THIN HORIZONTAL STRIP". Every new stall order carries those words untouched. Winning words travel verbatim across assets.
VISUAL // ARCHIVEThe world-camera authority: the games stall, flat storefront, floor as a thin strip.662×899px
Flatness is a palette count
Diffusion output is smooth by nature: gradients, stipple, mottle. The market look is the opposite. Eight rounds distilled the style block into canon: "authored low-res 16-bit pixel art, large flat bounded color regions, chunky square clusters, near-black outlines, exactly three tones per material, sparse hard highlights, LOW DETAIL". Renders kept weaving anyway, so the anti-texture law joined it. Zero stipple, zero noise, blocks never smaller than 4x4 pixels. Rust is one or two flat patches. A dead screen is one dark tone plus one flat glare band.
Palettes are sampled, never invented. A 16-level bucketed dominant-color scan reads the approved authority render, because exact-hex counting on diffusion output ranks outlines first. Every order clamps to the sampled set: "use ONLY these colors, merge strays into the nearest listed value". The console war drove its clamp from 24 hexes to 15. Both clamps sit below, each over its own master. Select a swatch.
Two details in that diff carry the doctrine. The cyan trio is gone, replaced by pale white-grey, because any teal in a palette leaks into screens. Select the cyans in the sampled view and watch them light the CRT static. Screens are white-grey forever now, standing law. And three survivors carry scopes, one legal use each: one hex for the hair, one for the goggle lenses, one for LED dots. A fenced color cannot leak.
The scavenger campaign added two palette instruments. The first is descriptive reduction: "build the palette yourself: one midnight-navy family of three, one bone pair, one wood pair, one gold, plus these fixed scoped accents". It matched or beat explicit hex lists on law compliance. Families plus scoped accents transfer intent better than long lists.
The second is palettes per frame. The scavenger keeper walks from a dark bay into counter light, and lighting prose achieved nothing. Five palettes did. The supervisor computes a five-step lightness ladder per material and pastes each step into its sheet cell as a complete hex list. Flat light is law: no directional light, no rim light. The march from shadow to counter is the palette swap. A deterministic post pass enforces the ladder a second time, multipliers from x0.55 to x1.00. The eyes and the pipe ember stay out of the multiply.
VISUAL // ARCHIVEThe shipped cycle: seated in the dark, the wake, two strides up the palette ladder, the offer.1528×320px
The animation never redraws the master
Three dead ends came first.
- error
- Whole-frame edits ("same image, arm raised") re-stage the entire composition: 17 to 57% of pixels drift. Patch edits fix registration at 0.2 to 0.8%, then hallucinate content: a moustache appeared.
- insight
- Diffusion cannot edit less than everything it touches. Registration and identity fail on different axes, so no single edit mode fixes both.
- fix
- Decompose every stall into layers and never redraw the composition: a plate that never changes, effect loops, prop layers, a character layer.
VISUAL // ARCHIVEThe same hover edit, measured twice: whole-frame drift on the left, patch-window drift on the right. Red marks changed pixels.1572×520px
The prime invariant makes the architecture testable: the rest composite is byte-identical to the approved static. A script asserts it, and a self-healing pass joins orphan pixels to the nearest layer. "The animation broke the master" stopped being a review argument and became a failing assertion.
Poses are diffusion on the flattened character alone, on chroma, three-sentence orders. Chaining each frame from the previous held identity briefly, then compounded: every chained leg re-diffuses the sprite, saturation drifts, detail mushes. The sheet doctrine ended it. Poses are one generation. Frame 0 goes in as the only attachment, and the order asks for a four-cell sprite-sheet row. The first cell copies frame 0 exactly. All poses share one diffusion pass and one palette. Slice by column gaps, register to the rest baseline. Start from the good one, never send the ones-to-fix back.
The scavenger keeper added the fixed-canvas law. Every character frame lives in one viewport: full stall height, about 2.2 times the doorway width, at a fixed plate offset. The walk toward the counter is drawn inside that window, never post-scaled into a clipping box. Every cell declares its figure height and its head line in exact pixels. Single-feature rulers on diffusion output lie: sheets draw eyes oversized, and the pipe hand sits at eye height. Rulings happen on a lettered grid instead, and that grid appears two sections down.
Keying a black cloak off a black doorway is impossible, so the character generates on chroma green and the plate carries a black bay at his seat. The hole costs one rectangle fill. The cloak greens are chosen keyer-safe by construction, g at most r+24, so the key predicate and the de-green clamp both pass them untouched.
VISUAL // ARCHIVEThe character master, generated on chroma so the keyer has something to key.760×1140px
The smallest trick is my favorite. The idle head-bob is an implant: copy the rest frame, shift only the head region down one pixel, leave the body planted. The one-pixel overlap at the neck swallows the seam. The feet never move. Zero new colors, zero diffusion.
At runtime every frame of every layer mounts once, absolutely stacked, and animation flips opacity on timers. An earlier src-swapping runtime generated over 8000 network requests and flashed mid-decode. prefers-reduced-motion renders final poses statically.
CSS replaces assets
The scavenger stall shipped ten files, and the older stalls needed more, because depth used to be an asset. The talks pattern cut a byte-true occluder of the counter band and parked the keeper behind it. The occluder is dead. Depth is a clip-path now. This is real shipped CSS:
/* scavenger depth: char frames clip at the counter band top (y545/971),
so legs read behind the counter with no occluder asset */
[data-stall="scavenger"] .sceneStack img[data-layer="char"] {
clip-path: polygon(0% 0%, 100% 0%, 100% 56.13%, 0% 56.13%);
}The hold frame alone carries an 18-point polygon. The clip hugs each finger, so the offered palm lies on the counter while the body stays behind it. One sprite, two depths. The runtime stamps data-layer and data-frame on every image, so one rule targets one stall, one layer, or one frame. The polygon came out of a disposable clip editor: one HTML file over file://, the sprite at 400 percent zoom, one finger at a time.
Below is the real pair, live: the shipped plate behind the shipped hold frame, and the shipped polygon on top. Drag the counter line and the legs walk over the counter. Drag the notch and the palm sinks behind it.


Drag a point, or focus one and nudge with the arrow keys. Shift moves faster. Dropped pixels fade to a faint silhouette and the stall shows through.
clip-path: polygon(0% 0%, 100% 0%, 100% 67.5%, 44.7% 67.7%, 44.2% 69%, 42.2% 69.1%, 41.2% 67.3%, 40.9% 69.2%, 39.1% 69.9%, 37.4% 69.2%, 37.4% 67.2%, 35.7% 69.8%, 34.1% 69.8%, 33% 68.2%, 34.2% 64.5%, 31.5% 67%, 30.5% 67.5%, 0% 67.5%)The idle eyes are HTML and CSS, zero assets: a dark mask over the baked eye slits plus two amber dots, one element, and rotate(180deg) mirrors the glance direction. Hover hides them, focus hides them, reduced motion freezes them. The keeper glances left, then right, for the price of two pseudo-elements.
Two light systems coexist, and the boundary is doctrine. Baked light belongs to the fiction: the one lit CRT in the den, the story's own neon reflection on a wall. Projected light belongs to the page: if a light moves, responds or repositions, the page projects it. Editor-placed radial glow spots come in seven colors plus black, and the black ones run mix-blend-mode: multiply as paintable shadow pools. Sign halos sync to the same keyframes as their sprite swaps. The street neon blinks on an 8-second steps() cycle with two stutter clusters, and the tuning ruling was exact: increase the delay between blinks, never the speed. Motion frequency reads as life.
One shipped bug earned a law. The papers hologram flickers as a group, from a wrapper div, because animating the frame images directly fought the opacity engine. And one screen per stall is lit, white-grey, maximum. Glow is the easiest thing for diffusion to overdo, and one overdone screen turns a stall into a slot machine.
Ten strangers, one market
A good stall is half the job. Ten independently generated sprites then have to sit in one architecture, and stopping them from reading as stickers cost as many rounds as the renders.
- error
- The official keyer greyed the w98 violets and turned the games stall half transparent. Clean sprites on white shipped with tinted rims.
- insight
- Despill color metrics execute hues, not intentions, and diffusion always blends content into the key: a 1-2px tinted rim survives any threshold.
- fix
- Key without despill, resolve partial alpha geometrically (edges to 0, interiors to 255), then verify every sprite composited on a hostile color, never on white.
Scale next. Canvas pixels are not comparable across generations. Bake scales ranged 0.49 to 0.59, so every cross-stall argument happens in display pixels. Character heights calibrate the family: seated Ed displays at 170 pixels, the same as a standing games kid, and the w98 robot tops out at 294. The editor then applied per-stall tune factors, console times 0.86, travel times 1.05: the eye correcting the last five percent.
VISUAL // ARCHIVEStalls at family display scale, bottom aligned. Canvas pixels lie, display pixels do not.1600×263px
Grounding last. Stall feet plant on a painted walkway strip that overlaps their base. Contact shadows are CSS ellipses, so they survive repositioning. Beams occlude stall edges by law. The enabling refactor was one absolute stacking context per floor. Before it, sibling bands ate z-indexes silently. After it, negative z goes behind stalls and every value works globally. An IntersectionObserver keeps the most visible floor bright and dims the rest. Depth of field by attention.
Ninety-two props and a sealed street
Baked backgrounds die in responsive layouts, so the world's furniture is ninety-two individually keyed sprites: graffiti, pachinko, a torii gate, a ramen machine, server towers, grow lamps, a sign family. The recipe runs in five rules.
- Sheets. 1536x1024 with pixel-boxed cells, one prop per cell, sliced by script.
- Per-cell palettes. Sampled from the previous approved round, capped at eight hexes per prop. The verdict "all of them have many colors" rejected an entire fleet first.
- Front-facing law. One prop per cell, frontal, because cylinders drift isometric.
- Completeness law. Max-footprint numbers per cell. Croppers recur: the toolbox, the standee and the hung bicycle all came back cut before the law.
- Lamp law. The emitter is lit and the halo hugs the glass, but the sprite carries no projected light.
Projection belongs to CSS.
VISUAL // ARCHIVEThe 92-sprite decoration inventory: graffiti, pachinko, torii gate, ramen machine, server towers, grow lamps.1200×1200px
Two props refused diffusion, so code draws them deterministically. The wall recess, because symmetry kept breaking. The wall-floor tiles, spliced from the approved tile's measured floor strip under new walls, seams fixed by column-luminance trimming. That pipeline also caught two variant files shipped content-swapped. The luminance fingerprint caught what the eye missed.
The contractor works review too. It read the placement manifest and the stall x-ranges and returned six adjustments as JSON. Five were true hits. Reviewer, never oracle: every suggestion gets verified against coordinates before it lands.
The street predates the market's unit system and keeps its own, so it ships as a sealed component inside its own variable context. Porting it onto the market layout broke it instantly. Its restyle taught the fidelity lesson: every regeneration risks losing an approved property, so orders carry a keep-list. "Magenta side-wall glow mandatory." "Rust as flat two-tone patches." Some originals never lost to a challenger, and keeping them is a ruling too.
The tileable floor is the street's best pipeline story. Generated edges never matched, so no single render would tile. The fix took three moves: a horizontal rail law, the exact 1536 canvas, then a continuation generation with a 500-pixel frozen overlap. The stitch lands at the column of minimum difference, about 2 units of error per pixel. One 1920 strip on repeat-x, and the seam is invisible.
Boxes first, sprites second
v4 looked right and measured wrong, and the audit had numbers. Hand-placed absolute coordinates made every resize a lie.
- error
- Three disagreeing container widths in one view. Floor-3 gaps of 89, 12.7 and 2.2px at 1680w. No regime between 700 and 1400px. A stairs sprite squashed 3.9x by a preflight img rule.
- insight
- Decorating before validating means auditing never. Every baked coordinate is a resize bug on a timer.
- fix
- A layout system proven in empty boxes from 500 to 1900px, with live rulers asserting gap equality, before a single sprite rode it.
The rebuild started with a spec in my own notation, ratified before any code.
_ = gap, dynamic, ALL EQUAL within a floor
x = undefined leftover | = screen edges
sc/ec = container edges a = stall S/SM = stairs desktop/mobile
wide |xS_sc_a_a_a_ecx|
mid |S_a_a_a_|
narrow |SM_a_| one floor = ONE SM + TWO stalls, one per story
|SM_a_|A standalone prototype then drew dashed rulers between every box. Green means all gaps on a floor are equal within 1.5 pixels. Red means broken. Amber means a stairs crop, with a percentage. Headless Chrome read the real geometry from 500 to 1900 pixels wide. The system was proven in empty boxes before one sprite rode it.
VISUAL // ARCHIVEThe layout prototype: dashed rulers between every box, green means equal gaps within 1.5px.1000×800px
The shipped market derives everything from one unit. The stage is a CSS container, so the math runs in container units and never reads the viewport. This is the live stylesheet:
.scene {
/* composition law: per floor, stairs (324 su, fixed) + stalls (1483
su) form ONE 1807 su group capped at 1440px, with 60px horizontal
padding around the stall area, centered */
--su: min(
calc((1440px - 120px) / 1807),
calc((100cqw - 136px) / 1807),
calc(74cqh / 597)
);
}Three ceilings, one unit: the container cap, the stage width, and the floor height at 74cqh over 597. The 597 is the stairs sprite. Floor height equals stairs height, the aspect is never modified, and the whole vertical rhythm of the market derives from one hand-polished sprite. The same unit then bridges three worlds: su is the pipeline's canvas pixel, the stylesheet's calc math, and the editor's export unit. Every drift bug in the project traced back to a second coordinate system.
Mobile is its own design
Below 700 pixels the market is a second design. The desktop plan never shrinks into it.
The floor plans differ at the source. Desktop runs four floors: three stalls and a stairwell each, and the scavenger holds a solo floor. Mobile runs six floors from a separate plan: the map stall alone at the entrance, pairs after it, the scavenger alone at the bottom. Both plans live side by side in floors.ts, eleven lines apart.
One mobile stairwell spans two stacked stories, so all four gaps across both stories come out equal by construction. The stairwell slides offscreen on a clamp ramp. The crop caps at exactly half the sprite width, and the reclaimed width grows stalls. Its two CSS knobs are measured from the sprite: trim aspect 0.464, deck line at 0.497 of its height. A script found the deck as the densest wide band beyond the cage. The sprite wins. The layout bends.
VISUAL // ARCHIVEThe mobile stairwell gate: candidates side by side, measured aspects and deck lines, a LAW PASS verdict per probe.1400×933px
Hover does not exist here, so the interaction contract changes with it. Dialogs open on hover only under (hover: hover). On coarse pointers the first tap opens the dialog and blocks navigation, and the second tap follows the link (guardTap in market-stall.tsx). Scroll snap runs proximity by default and hardens to mandatory only under (pointer: fine), because mandatory snap fights touch momentum.
VISUAL // ARCHIVEThe same prototype at mobile width: one stairwell spanning two stories, four gaps equal by construction.650×900px
The last mile is manual
Nearly every shipped file crossed a manual last mile, and the mile has a toolset.
The first tool is the in-page editor. External tools edit a copy, and only the page renders the truth, so the editor mounts as a dev overlay on the real route and manipulates inline styles on the shipping DOM. Picking collects every tagged ancestor under the pointer and sorts by area, so the smallest target wins and occluded props stay reachable. Scaling uses eight handles: corners lock aspect, edges move one axis. The sensitivity is damped: a full element-width drag changes scale by 40 percent. Transform origin stays bottom-center, because things sit on floors. Exports land as JSON in su, band-local to the floor's stage element. The export is intent, never absolutes. The standing order: update in a harmonious way and responsively. Every editor session became tune factors, gap rules and anchor offsets.
The second tool is the lettered grid, because size arguments need shared nouns. A pink proposal div renders the candidate canvas over the live stall. A 20-line lettered grid, 48.5 pixels per step, turns size talk into "the head starts at H and ends between E and F". A dev tool spread all six frames over the market, played the cycle in place, and returned the verdicts as data: offsets as JSON, clips as the CSS polygon string itself. Then the tool got deleted. Editors are disposable. The numbers are the deliverable.
VISUAL // ARCHIVEThe negotiation instrument: the lettered grid and the named frame boxes, over the live stall.700×1015px
The third tool is Affinity: edge repair at sprite scale, palette snapping after clamp leaks, limb repaint after chain drift. I reworked three shipped files in place in the assets directory, so a law now forbids scripts from overwriting it and every exporter skips existing files. The generated file is a draft. The polished file is the asset.
The fourth tool is the stylesheet. Ambience is hand-placed CSS: glow spots, shadow pools, reflections masked through a building's own alpha, floor dimming. It iterates in devtools at taste speed, at zero regeneration cost.
A synthesizer instead of samples
A 309-line synthesizer scores the market. One audio file exists in the whole system, the door slam. Everything else comes from two primitives: an oscillator with an exponential pitch ramp and decay envelope, and filtered white noise. Even the reverb is procedural, a convolver fed a generated impulse response.
verb = c.createConvolver()
const len = c.sampleRate * 1.6
const ir = c.createBuffer(2, len, c.sampleRate)
for (let ch = 0; ch < 2; ch++) {
const data = ir.getChannelData(ch)
for (let i = 0; i < len; i++) {
data[i] = (Math.random() * 2 - 1) * (1 - i / len) ** 2.8
}
}Every stall has a leitmotif, a half-second sting on hover, matched to its keeper.
- uses · a 220-to-55Hz sine drop plus a sizzle burst, a pot hitting a stove
- games · a three-note square-wave coin-up
- travel · two sine chirps bending like alien small talk
- w98 · a pair of descending sweeps, a machine powering down or up depending on your faith
The pads below run the shipped recipes on their own bus. The market gates its synth behind an opt-in toggle, and a demo that stays silent proves nothing.
Four design rules survived. Synthesis over samples, because a recorded foley reads like a photograph inside a drawing. One sting per encounter, never looped. Wet equals big, so reverb marks the door and the floor transitions, and dry marks UI. Everything is gesture-gated and opt-in, because autoplay sound gets muted.
The ride is a performance budget
The homepage parks a hand-built SVG car on the hero bridge, engine off. That parked car is the affordance, and the drive it offers is a loading strategy wearing a costume.
The car is code-split, and the intro warms its import 320 milliseconds in, so the sprite never blocks first paint and never misses its cue. The bazaar link prefetches the route on mouseenter, focus and touchstart: intent arrives before the click, and the gap is free loading time. The helper reads navigator.connection and skips the prefetch under Save-Data and on 2g, because a guess is only free on a connection that can absorb one. By click time the route payload has a head start.
const duration = isFirstRide
? BAZAAR_SIGNATURE_DURATION // 3100ms, the cinematic one
: BAZAAR_EXPRESS_DURATION // 2500ms, the commute
dispatch({ type: 'depart', duration })
transition.navigateLater('/bazaar', Math.max(duration - 360, 0))The route change fires 360 milliseconds before the drive ends. The page swaps while the car exits the viewport, and the cut hides inside the motion. The first ride each session takes the signature drive, and repeats take the express: ceremony on arrival, speed on habit. A sessionStorage flag claims the first ride optimistically and falls back to ceremony if storage throws. Escape skips the whole fiction. Reduced motion never enters it: the click navigates plain, and the transition machine still owns the swap so history stays consistent.
The easing curve lives twice. CSS holds it as a custom property for the transform. JS solves it numerically, so the code knows the car position at any millisecond. When CSS and JS must agree about a moving object, share the curve, never the guesses. On the far side, the street runs the same car sprite driving through, and the bus stop links back to the homepage. Two vehicles, one loop.
One edge case earned its scar. The router cache can revive the homepage with the car frozen mid-departure. An effect notices its second run on the same tree, bumps an epoch key, and remounts the stage clean. Page-transition fiction has state, and that state survives navigation. Plain pages never test this.
The same budget discipline runs through the market itself. The market weighs 259 files and 22 megabytes, and nobody downloads it at once. Each stall's plate loads eager. Every other layer declares loading="lazy": frames, effects and props arrive as their floor scrolls near. After arrival, every animation frame has mounted once and timers flip opacity, so scrolling costs zero network and zero decode. Sound is synthesized, so the score costs one audio file. Sprites render under image-rendering: pixelated, so low-resolution files upscale crisp. The fiction is expensive to write and cheap to run.
A tool in the belt
A tidy arithmetic went around this project early: the model paints 90 percent, the human adds 10. The arithmetic is wrong, and the error is the point. Generation is one tool in a belt, and the belt shipped this market.
The composition tool is pen and paper. The vertical market, the street entry and every keeper pose existed as sketches before any order, and the pipeline never invented a composition. The geometry tool is a vector editor: the slab law entered the world as my SVG, and orders restated its integers. The color tool is the sampler and the clamp. The finish tool is Affinity. The atmosphere tool is CSS. The layout tool is a prototype with rulers. The model sits in the middle of that belt and does one thing at industrial speed: it turns closed specifications into pixels.
The belt's placement tool deserves its own exhibit. The editor from the last mile carries three palettes: props, architecture and light. Props and beams drag onto the scene. Light drops as a glow spot, and the drop point picks its anchor.



VISUAL // ARCHIVEThe editor over the live desktop route: the travel stall selected, the inspector scoped to the 1188px breakpoint.1512×982px
VISUAL // ARCHIVEThe same editor on the mobile street: the neon tower selected, offsets in raw pixels, decor.json saved.1512×982px
The evidence is the ledger. Over two weeks of daily rounds, 314 archived orders, five builds, ten stalls, 259 shipped files. The one-prompt masterpiece was our first attempt, and it alone shipped nothing. Without the belt the output is generic, unmeasured and unusable at family scale. With it, the model is the fastest painter on the team.
Nothing here is hand-drawn. Everything is hand-specified.
Run your own
The method transfers. Point an image model at a real asset family and this is the distilled procedure.
- Sketch the composition first, on paper. The model executes compositions and carries none of its own.
- Write data-anchored orders. Vertices, checkpoint dots, pixel boxes, closed hex lists, a minimum block size. Numbers first.
- Fly four probes per round, one instrument each. Breed the next round from the verdict. Read zero variance as an indictment of your attachments.
- Measure every landing. Dimensions, bounding boxes, hashes, angles. Then let the eye rule. The shipped console master fails two of its own checks.
- Freeze what is won. Close the layout, then fight the paint. One axis of freedom per round.
The traps cost fleets, so take the list.
- The one-prompt masterpiece. At family scale it produces strangers.
- Attachments as the base image. Chains hyperfit, variance dies, and every probe returns the same render.
- Whole-frame animation edits. Decompose into layers and assert byte-identity at rest.
- A second coordinate system. One unit from canvas to stylesheet to editor.
- Unguarded hand work. One rerun clobbered three polished files. Guardrails belong in code. Memory forgets.
The market is open. Walk in.





















