# Before images

The left-hand half of every card on the homepage. Chosen to be plain, dated or
badly shot on purpose: the "after" only reads as a result if the "before" looks
like something a seller would actually send us.

Found through the Openverse API and filtered to **CC0 and Public Domain Mark
only**, because a homepage has nowhere to put an attribution line and CC BY
would require one. Cropped to 16:10 and capped at 1280px wide.

| File | Source | Title | Licence |
|---|---|---|---|
| restyle-before.jpg | [rawpixel](https://www.rawpixel.com/image/6042547/photo-image-public-domain-wood-house) | Living room furniture, interior design | CC0 1.0 |
| stage-before.jpg | [rawpixel](https://www.rawpixel.com/image/5903577/photo-image-public-domain-house-living-room) | Free empty living room image | CC0 1.0 |
| exterior-before.jpg | [rawpixel](https://www.rawpixel.com/image/3290508/free-photo-image-outdoor-house-background-automobile-building) | old house car parked driveway | CC0 1.0 |
| garden-before.jpg | [rawpixel](https://www.rawpixel.com/image/5919900/field-grass-free-public-domain-cc0-photo) | Field grass | CC0 1.0 |
| sketch-before.jpg | [rawpixel](https://www.rawpixel.com/image/9295707/architectural-sketch) | Architectural Sketch | CC0 1.0 |
| material-before.jpg | [rawpixel](https://www.rawpixel.com/image/6042963/photo-image-public-domain-house-red) | Red bathroom interior | CC0 1.0 |
| declutter-before.jpg | [rawpixel](https://www.rawpixel.com/image/5940247/free-public-domain-cc0-photo) | untitled | CC0 1.0 |
| remove-before.jpg | [rawpixel](https://www.rawpixel.com/image/4021211/photo-image-house-building) | Cookie cutter homes Northwood. Your | CC0 1.0 |
| enhance-before.jpg | [rawpixel](https://www.rawpixel.com/image/3288728/free-photo-image-banister-bowl-cc0) | Window green frame dark interior | CC0 1.0 |

CC0 and Public Domain Mark carry no attribution requirement. This file exists so
the provenance is recorded rather than assumed.

## The afters

Generated 19 August 2026, one attempt each, no retries and no cherry-picking.
Model `nano-banana-pro` through `lib/providers/kie.ts`, prompts built by
`buildPrompt` from `lib/prompts/features.ts` — the same path the studio runs.
Reproduce with:

    npx tsx --conditions=react-server scripts/showcase-after.ts [kind]

Asked for `resolution: '2K'` via `JobSpec.extra`, which overrides the
catalogue's fixed `1K`. Every run returned 2612x1632 and billed **18 kie
credits**, the same as 1K did on 18 August — so 2K appears to cost nothing
extra, which is worth confirming before the catalogue is changed. Nine runs,
162 credits, about $0.81, 31 to 57 seconds each.

The 2K originals are in `out/showcase/`. Until 18 September 2026 the files here
were those images scaled down to the before's 1024x640, on the belief that the
slider only lines up when both halves are the same size. It only needs the same
shape: CompareSlider lays the after over the before with `object-cover`, so a
1920x1200 after on a 1024x640 before lands on it exactly. The afters are now the
2K originals at 1920 wide (Lanczos, JPEG q90), which is the widest source
`lib/responsiveImage.ts` ever asks for. At 1024 they were being stretched on any
screen scaled past 100%, and on every screen in the large homepage frame.

The befores stay at 1024: that is the photograph the model was given, and
enlarging it now would invent detail it never had.

### What held, what did not, and what was fixed

Seven of the nine kept the room on the first attempt. Two did not, and both
turned out to be faults in our own templates rather than in the model. The
templates were changed and the two were re-run; `lib/prompts/features.ts`
carries the reasoning at each one.

- **declutter** produced a different kitchen: wider viewpoint, cream units in
  place of the dark ones, the oven moved. Cause: the template opened with "You
  are photographing a {{room_type_label}} after it has been completely
  cleared", which asks for a new photograph, and the model delivered one. The
  `remove` template survived the identical test because it opens by naming the
  job as retouching one frame. Rewritten in that idiom, plus "clean" removed
  (it read as permission to resurface) and an "if unsure whether it is loose or
  fitted, it is fitted" rule. The re-run keeps the camera, the dark timber
  worktop, the white units, the oven and the hob, and empties the room.

- **enhance** barely moved: measured mean luminance 62.4 to 72.3, about half a
  stop, on a frame that needed two. Two causes, both ours. The template was
  written as if every photograph were of a building, so on an interior the only
  applicable instruction was the fourth bullet; and it ended with "Light the
  photograph as {{time_of_day}}", whose default text is "the same light as the
  source photograph" — a direct contradiction of lifting the shadows, which the
  model resolved in favour of the later unconditional sentence. Fixed by
  putting exposure first and unconditional, covering interiors explicitly,
  restating time of day as a fact about the scene rather than an instruction
  about the file, and quantifying the correction ("underexposed by two to three
  stops... not a little lifted"). Third attempt: median 12 to 33, sub-32 pixels
  62.6% to 49.5%, and the tablecloth, bowl, window frame and wall picture are
  all readable. Structure untouched.

  Worth knowing before this feature ships: the model damps global tonal edits.
  Quantifying the instruction got it most of the way, but exposure is arithmetic
  and a diffusion model is the wrong tool for it. The right build is a
  deterministic tone and white-balance pass, with the model left to do the sky,
  the lawn and the perspective.

## Page-specific pairs

Six pages shared a photo with another page of the same kind (bathrooms /
one-surface / paint were all showing the identical `material` pair; interiors /
renovations / structure-lock / brief were all showing the identical `restyle`
pair) -- the repetition read as filler rather than a claim about that specific
page. `lib/content.ts`'s `EntryShowcase.imageKey` now lets an entry point at its
own `<key>-before.jpg`/`<key>-after.jpg` instead of the shared `<kind>-*.jpg`.

Befores are not new sourcing -- each is a copy of an existing, already-licensed
photo from `public/rooms/` (see that folder's own CREDITS.md for provenance;
all Flickr, Public Domain Mark 1.0, no attribution required). Afters were
generated 28 August 2026 the same way as the nine above, one attempt each,
via `npx tsx --conditions=react-server scripts/showcase-after.ts <outKey>`:

| Key | Before (from public/rooms/) | kind | vars | Credits |
|---|---|---|---|---|
| kitchens | kitchen.jpg | material | surface: cabinet-fronts, finish: sage green shaker + brass | 18 |
| one-surface | room-a.jpg | material | surface: floor, finish: European oak boards | 18 |
| paint | room-b.jpg | material | surface: wall-paint, finish: deep forest green matt | 18 |
| renovations | room-c.jpg | restyle | style: modern-farmhouse | 18 |
| structure-lock | room-d.jpg | restyle | style: industrial-loft | 18 |
| brief | room-e.jpg | restyle | style: traditional-english, note: the page's own quoted brief | 18 |

108 credits total, about $0.54. `sketch-to-render` still shares `new-builds`'
pair -- there is no second real architectural sketch in the repo to pair it
with, only interior/exterior room photos, so it was left alone rather than
forcing a mismatched source image into a sketch-to-render claim.

## sketch-to-render's own pair, 29 August 2026

`sketch-to-render` (a CAPABILITY_PAGES entry) and `new-builds` (a USE_CASES
entry) were both defaulting to the plain `sketch-before.jpg`/`sketch-after.jpg`
pair -- the one literal image duplicate a visitor would actually see, since
they sit on two different hub pages (`/features`, `/use-cases`) that a
customer comparing "what's the difference" would browse back to back.

`sketch-to-render-before.jpg`: invented, not sourced -- no real architect's
sketch in this repo was fair game for a second use, and the point was a
*different* drawing anyway (a plain contemporary house elevation, a more
general "any hand sketch" claim than `sketch-before.jpg`'s ornate Gothic
mansion). `nano-banana-pro`, pure text-to-image, no reference, via
`scripts/sketch-to-render-source.ts`. 18 credits, $0.09.

`sketch-to-render-after.jpg`: `scripts/showcase-after.ts sketch-to-render`,
the product's own path (`buildPrompt('sketch', ...)`), smooth white render +
dark aluminium frames + anthracite door, bright day. 18 credits, $0.09, one
attempt. Both files resized to 1280x956 (`sharp`, matching each other exactly
so the slider handle tracks correctly, same reasoning as the original nine's
1024x640 above) -- the raw after came back 2400x1792 and the raw before at
2K, both far heavier than a slider needs. On 18 September 2026 the after went
back up to 1920x1434 from that 2400x1792 original, for the reason given under
the nine above; the before stays at 1280.

One result needed a second attempt rather than being quietly accepted:
`structure-lock` asked for the `industrial-loft` preset (grey micro-cement,
black steel, tan leather) and nano-banana-pro returned something closer to a
light coastal/minimal room (whitewashed stone, cream boxy sofa, bamboo)
instead. Structural fidelity was fine either way -- window, shelving and lamp
positions held -- but the named style did not land, and this is the page the
homepage's whole "structure lock" framing points at, so it was worth fixing
rather than leaving as a known miss.

Re-run 28 August 2026 on `nano-banana-2` at 4K (docs.kie.ai/market/google/
nanobanana2; see lib/models/catalog.ts's entry) with the identical vars --
this time it landed: micro-cement wall, oxblood leather chesterfield, black
steel shelving and caged pendant lighting, steel-and-timber coffee table, all
of what the preset asks for. 18 credits, same as nano-banana-pro's 2K despite
the 4K request. The raw output was 14MB (5056x3392) -- far too heavy to ship
as-is for a slider that renders at a few hundred pixels wide -- so
scripts/showcase-after.ts now runs every result through sharp on the way out
(resize to a 3200px cap, mozjpeg quality 82) regardless of which model or
resolution produced it. structure-lock-after.jpg is 3200x2147, 527KB.

## how-its-made-web.mp4

Our own footage, not a stock or CC source, so nothing here needs attribution.
The 45s promo re-encoded to 720p at ~1.15 Mbps, matching the other web videos
on the site (public/templates/*-web.mp4). Source file is the 1080p master kept
outside the repo; the poster is the frame at t=2s.

Used on /how-its-made, which is the page linked in replies to agents who ask to
see output before signing up.

## plan-3d and plan-room

Different from everything above: neither "before" is a stock photo. Both source
plans belong to a real property and were supplied to us, and both "afters" are
our own output, so there is nothing here to attribute to a third party.

Run 14 September 2026 on `nano-banana-pro` through `lib/providers/kie.ts`, one
attempt each, prompts built by `buildPrompt` from `lib/prompts/features.ts` --
the same path the studio runs. 18 kie credits per run, about $0.09.

| File | What it is |
|---|---|
| plan-3d-before.jpg | The property's own CAD floor plan, labelled, areas in m2 |
| plan-3d-after.jpg | That plan raised into the doll's house, roof off |
| plan-room-before.jpg | A second property, hand drawn on paper and photographed, run through the same job |
| plan-room-after.jpg | The master bedroom of that view, re-shot at eye level |

The pair is deliberately split across two properties. The CAD one is the run
that proves the room names stay behind on the drawing, which was a real fault
on the first attempt and the reason the CONSTRAINTS block was rewritten. The
hand-drawn one is what an estate agent actually has in the drawer, so proving
the chain on it is worth more than proving it on a clean drawing.

plan-room-before.jpg is also the exact image plan-room-after.jpg was generated
from. The slider is not an illustration of the chain, it is the chain.

Both plan-3d files are letterboxed rather than cropped to 16:10: a floor plan
with its outer wall cut off reads as broken. The bars are white, which is what
both images already sit on, and both halves carry the same 40px band so the
slider wipes without the picture shifting.

The plan-room pair is cropped instead, and not letterboxed, because the render
leaves 440px of empty ground to the right of the property: a crop anchored to
the left edge takes that empty ground and nothing else. Measured rather than
eyeballed, by walking the non-background bounding box.

### Replaced 15 September 2026

Both plan-room halves were re-run and replaced, and so were all three
`/apps-thumbs/plan-chain-*` steps. Three more nano-banana-pro runs, 18 kie
credits each.

The old pair was honest but stale. Its doll's house came from the wording that
was in the repo before the run that fixed it, so the terrace the plan draws
outside the walls had never been built. The replacement is the same hand-drawn
plan through the current prompt, and the terrace is there, paved and furnished.

| File | Run |
|---|---|
| plan-room-before.jpg | p2 through `plan-3d`, patched wording. The run that proves the fix holds on a drawing made with a pencil, not only on CAD |
| plan-room-after.jpg | That view through `plan-room`, `roomType: bedroom`, `roomPick: top-right` |

The "after" is the first picture ever made with `roomPick`, the pick that says
which of a property's three bedrooms to stand in. It was run beside a second
shot, `roomPick: bottom-right`, which is not published: the two exist to be
compared, and they came back as two different rooms, each carrying the
furniture its own corner of the view holds. The published half is the master,
identifiable by the bathroom through the open door, which is where the plan
puts Bathroom 1.

The chain steps were rebuilt at 4:3 rather than re-cropped. The card draws them
into an `aspect-[4/3]` box with `object-cover`, and the plan and the doll's
house are both nearly 1.8:1, so a quarter of each was being taken off either
side: the plan lost its kitchen and its far bedrooms, the doll's house lost the
same rooms. Letterboxing them into the box the card actually draws leaves
`object-cover` nothing to crop. The room photograph is still cropped, because
that is what happens to photographs.

## floor-plan, published 18 September 2026

The pair on /features/floor-plan-to-render, and the job's only run: 29 August
2026 through `scripts/apps-thumbnails.ts`, which is also where both halves came
from. Prompt built by `buildPrompt('floor-plan', {})`, model
`defaultModelFor('floor-plan')` as it stood that day, one attempt, submitted
straight to `lib/providers/kie.ts` -- the same path the studio runs, without the
jobs table.

The plan it was run on was generated from text in the same script, for the
reason `gen-test-photo.ts` gives about its villa: no real floor plan in this
repo is ours to publish, and nothing else here supplies one. So this is the one
pair on the site where the "before" is generated as well as the "after". The
page says so under its steps, in those words.

| File | What it is |
|---|---|
| floor-plan-before.jpg | A bare black-and-white 2D plan of an invented two-bedroom apartment: labels, floor areas, door swings, a north arrow and a scale bar. Not a real property |
| floor-plan-after.jpg | That plan through `floor-plan`, exactly as it came back |

Both published at 1920x1434 (Lanczos, JPEG q90 progressive) from the 2400x1792
originals in `out/thumb-floor-plan-source.jpg` and `out/thumb-floor-plan.jpg`,
for the reason given at the top of this file. `/apps-thumbs/floor-plan.jpg` is
the same output at 1600x1195 and predates both.

What the run held, checked by reading the two side by side: every wall and its
thickness, every door and the direction it swings, every window, all five room
names, all five floor areas, the north arrow and the scale bar. What it added is
the job: flat colour and floor fills per room, top-down furniture, and kitchen
and bathroom fittings. It stayed flat and top-down, which is the distinction
between this job and `plan-3d`.

The honest limit, and the reason the page does not claim more: this job has
never been run against a photograph of a real floor plan. The note on the
feature in `lib/prompts/features.ts` says the same thing and stays true.

## render-real, 17 September 2026

The first real run of the render to photo job, and the pair on its page. Model
`gpt-image-2-5-sunburst` through `lib/providers/kie.ts`, prompt built by
`buildPrompt` from `lib/prompts/features.ts` with `scene: interior`, run by
`scripts/run-feature.ts`. 1K, 6 kie credits (about $0.03), 117 seconds, one
attempt.

| File | What it is |
|---|---|
| render-real-before.jpg | A living room drawn as a flat line illustration, generated for this card with an image model (Gemini). Not a real room and not a real building |
| render-real-after.jpg | That drawing through `render-real`, exactly as it came back, 1531x1027 |
| /apps-thumbs/render-real.jpg | The same two images cut to the 3:4 app card: the drawing on the left, the photograph on the right, split on the centre line |

What was checked, and how:

- The ratio held, 1.4906 in and 1.4907 out, so both halves of the slider take
  the same crop.
- The drawing's edges, laid over the photograph, land on it almost line for
  line: three pendants, two chairs, the sofa, the coffee table with its vase,
  bowl and books, the floor lamp, the artwork, the fireplace, the staircase,
  two potted olive trees, the fig, four glass panels and the pool.
- Mean brightness fell by 29%. Expected: a line drawing is mostly white paper,
  and the photograph has real shadow in it.
- What the model decided for itself: the floor, which the drawing leaves
  undefined, came back as polished concrete, and the flat green band behind
  the pool came back as a hedge of trees.

A second run the same evening, a 3D exterior render through `scene: exterior`,
75 seconds, the same 6 kie credits, one attempt. It held as well (brightness
down 5%, every counted object in place) but added one small weed at the foot of
a garage door that the render did not have. That is the thing to watch on this
job: the prompt asks for the wear a real camera finds, and the page promises
nothing is added. The entropy line in `lib/prompts/features.ts` was bounded the
next day so that it adds no new object; that has not yet been run again.

Published 18 September 2026 as the page's second tab and as the three pictures
over its steps, exactly as it came back, weed included:

| File | What it is |
|---|---|
| render-real-exterior-before.jpg | A 3D render of a two-storey house with a detached garage, in the style of an Enscape or Lumion export, generated for this page with an image model (Gemini). Not a real building |
| render-real-exterior-after.jpg | That render through `render-real` with `scene: exterior`, exactly as it came back, 1531x1027 |

The same day `render-real-after.jpg` was re-saved from the untouched PNG at
JPEG q92 rather than q85, since every later encode starts from it.

## What was set on each run, as data (19 September 2026)

Every feature and use-case page now walks its own pair step by step: the file
that went in, the control that was used, the result that came back. The middle
card names a real setting, so it is read from the same table the job was
submitted from rather than from copy typed onto the page.

That table is `lib/showcaseRuns.ts`. It used to live inside
`scripts/showcase-after.ts`, which is why only that script could see it; the
script now imports it and filters to its own runs. The plan chain and the two
render-to-photo pairs are in there too, marked with the script or the studio
job that made them, because a page has to be able to say what was set on those
as well -- they are recorded, not reproducible from that file.

This file stays the narrative record. If either changes, check it against the
other: the settings in that table and the sections above are two halves of the
same story, and a page believes the table.
