A construction client's build (unnamed) · Hero · 02/10/2026
A construction client's build, hero section
A builder's hero that shows a house as found, then wipes across to a visualisation of the finished renovation, with controls to replay it or go back to the starting point. The strongest trade hero in our builds, and on a first visit in Chrome its signature wipe uncovers an empty layer.
Findings at a glance
12 of 12 findings
| Ref | ||||
|---|---|---|---|---|
| I7 | On a phone profile, a Chromium screenshot forces the deferred lazy load, so a visual test hides the bugverify-live takes no screenshot during a loading test | Instrument trap | Instrument | In the probe |
| I6 | currentSrc and complete tell you when a picture is really there; the frame alone does not | Instrument trap | Instrument | Recorded |
| I5 | A Safari check returns clean: the fault is Chromium-onlyTest reveals in Chromium as well as WebKit | Instrument trap | Instrument | Promoted |
| F3 | The subject waits 4.1 s behind a logo introNot a lock: all 9 first-screen actions were pressable | Failure mode | Motion | Recorded |
| F2 | 32 visible text runs under 12px on a phone, the visualisation label at 7pxThird exemplar behind the 12px floor; routed to the build | Failure mode | Type | Already covered |
| F1 | A lazy after-picture in a keyframe clip: the wipe uncovers an empty layer in ChromiumIn web-frontend with the mechanism tables, 02/10/2026 | Failure mode | Performance | Promoted |
| C6 | A lens over the house as found that shows the finished house, with the plan drawn around itPromoted 03/10/2026 as an option, not the better choice: proven buildable and accessible, not proven on buyers | Technique | Interaction | Promoted |
| C5 | Flat daylight before, blue hour afterAmplifies the change and flatters it: pair it with C4 | Technique | Colour | Recorded |
| C4 | The finished picture labelled as a visualisation, in the frameIn web-frontend, extended to materially altered photos: label in the frame, at 12px or above | Technique | Content | Promoted |
| C3 | Replay, and a starting-point button whose label names where it goes nextOurs adds a pressed state and a keyboard slider | Technique | Interaction | Recorded |
| C2 | A wipe, not a fade: a clip-path over 2.8 s on a slow-in, slow-out curveOurs keeps the wipe and adds a draggable seam | Technique | Motion | Recorded |
| C1 | One house, one camera position, before and after, as the heroweb-frontend rule 1 cites this build: for a trade, the transformation is the product | Technique | Composition | Already covered |
Analysed: 02/10/2026 · By: Design Lab · Evidence:
captures/construction-client-a/2026-10-02/ (probe summary, frames, transform/transform.json, and the
follow-up scripts' output quoted below). This is one of our own client builds, so it is not named
here. The specimen's business and copy are invented. Its two pictures are the pair Pete supplied to
that build, used here on his ruling (§5).
Instruments: the exemplar-probe skill on full Chromium (renderer ANGLE Metal), a timed
follow-up that sampled the hero's layers and document.getAnimations() for 30 seconds and pressed each
control, a cold-cache load check on three network profiles, and a mechanism test on a page served by
request interception (no server), run in Chromium and WebKit.
1. Why this build
Pete pointed at it: "the 2 houses". web-frontend rule 1 already cites it as the winning build of a
two-engine comparison, because its hero shows the product instead of describing it. It is the first of
our own builds this lab has analysed, which is why it is anonymous: protection is a setting someone can
change, and a client's name inside our site would then be public (steward ruling, 02/10/2026).
2. What it does, measured
| time | what happens | how |
|---|---|---|
| 0 to 2.5 s | the logo assembles from five parts | CSS keyframes, 1.4 s each, staggered 140 ms |
| 2.4 s | the headline and lead rise in | 1.1 s, opacity and transform |
| 0 to 4.1 s | the logo travels to the top-left corner | one 4.1 s keyframe animation |
| 4.1 to 6.9 s | the finished house wipes in over the house as found | clip-path: inset(0 100% 0 0) → inset(0), 2.8 s, cubic-bezier(0.6, 0, 0.3, 1), on a layer above the first picture |
Below it sit three controls: Replay transformation (named "Replay the house transformation"), a pause button that exists only while motion runs, and See the starting point, which wipes back and renames itself See the possibility. Two corner tags carry the context: one with the tagline, one saying Design visualisation.
3. The techniques
C1 · One house, one camera position
The before and the after are the same house from the same spot, so the wipe reads as the house changing, not as one picture replacing another. This is the whole technique, and it is easy to lose: two pictures from different angles turn the same wipe into a slideshow. Registration matters more than either picture's quality.
Suits: any trade whose product is a change to something that already exists (extensions, renovation, landscaping, kitchens, restoration, cleaning, signwriting). Does not suit: new builds with no before; services with nothing visible to compare; any client without a real before-and-after pair, or the right to use one.
C2 · A wipe, not a fade
A cross-fade blends two houses into a ghost in the middle. A hard-edged wipe keeps both readable at every instant, and the edge itself becomes a line the eye follows across the change. The 2.8 s curve starts and ends slowly, so the middle, where the most change is visible, is the fastest part.
C3 · Controls that name the destination
See the starting point becomes See the possibility once pressed. The button says where it takes
you, not what state it is in, which reads well. It carries no aria-pressed, so a screen reader hears
only a renamed button; the renaming is adequate, and a pressed state would be better.
C4 · The finished picture labelled as a visualisation
A Design visualisation tag sits in the frame. For a trade this is more than courtesy: a render shown as finished work is a claim the client cannot stand behind. The label lets the hero show the possibility without saying it was built. (Its type is 7 px on a phone, which defeats the point: F2.)
Promoted to web-frontend (02/10/2026), as proposed and extended by the steward to photographs
that have been materially altered (relit, sky replaced, interiors composited): a visible label in the
frame, never only in a caption, at the 12 px floor or above; never present a render as completed
work. The 7 px label on this build is the reason for the floor clause: it labels the render in the
markup and nobody can read it.
C5 · Flat daylight before, blue hour after
The before is shot in dull daylight; the after is dusk with every light on. The light change does as much work as the building work, and it flatters. That is fine when C4 is present and misleading when it is not.
4. Failures
F1 · The wipe uncovers an empty layer
The after picture is loading="lazy" inside the clipped layer. On a cold cache in Chromium,
img.complete && naturalWidth was false for the whole wipe on every run:
| run | wipe | after picture ready | samples revealed but empty |
|---|---|---|---|
| desktop, unthrottled | 4359 → 6962 ms | 7116 ms | 18, up to 100% revealed |
| desktop, fast 4G | 4639 → 7393 ms | 7694 ms | 20 |
| phone, fast 4G | 4625 → 7366 ms | 7672 ms | 20 |
Positive control: the same check reads the first picture loaded at 1.5 s, and reads the after picture loaded mid-replay (clip at 61%), where the wipe visibly works. So the instrument can see the picture; the picture was not there. A visitor sees the house as found, then the finished house pops in after the wipe has ended. Replay works because the picture is cached by then, which is why nobody building it would notice.
The mechanism, isolated (a 64 px PNG served by request interception, one lazy image in one layer):
| layer | Chromium requests it at | WebKit |
|---|---|---|
| no clip (control) | 15 ms | 88 ms |
static clip-path: inset(0 100% 0 0) |
never | 17 ms |
| keyframe clip-path, wipe 1000 → 3800 ms | 3813 ms, as it ends | 9 ms |
| clip-path set per frame from script | 1018 ms, the first open frame | 10 ms |
| a CSS variable set per frame | 1019 ms | 17 ms |
opacity: 0 |
8 ms | 14 ms |
transform: scaleX(0) · translateX(-100%) · animated scale |
8 · 8 · 7 ms | not run |
So: in Chromium, a lazy picture inside a keyframe-animated clip-path is not fetched until the animation ends. A script-driven clip is seen, but the fetch then starts as the wipe starts, so the opening of the reveal is still empty on a slow connection. WebKit fetches at once, so a check in Safari comes back clean (I5). Why Chromium behaves this way is not established here; the table is the finding.
The rule (promoted): the revealed picture is eager, and the reveal waits for img.decode().
I6: a screenshot taken mid-wipe looked like a wipe over the starting picture and could have passed
as "the reveal is subtle". Only currentSrc, complete and naturalWidth, sampled against the clip,
showed that nothing was there to reveal.
I7 · A screenshot can fetch the picture the bug withholds
Found while verifying our own specimen. Its lazy replay showed the picture arriving 1.32s into the wipe on a Pixel profile, twice, instead of at the end. The phone check took a screenshot at 1.30s. Measured on the live specimen with a cold URL:
| profile | screenshot at 1.3s | lazy picture requested at | wipe ends |
|---|---|---|---|
| Pixel 7 emulation | no | 2601 ms | 2600 ms |
| Pixel 7 emulation | yes | 1265 ms | 2598 ms |
| desktop 1440 | no | 2601 ms | 2600 ms |
| desktop 1440 | yes | 2601 ms | 2600 ms |
So a screenshot-driven visual check on a phone profile makes the reveal work, and hides the
fault. My first test of this was unsound and reported "no effect": its screenshot targeted
/dev/null, which Playwright rejects, and the error was swallowed. Recorded via learn.sh.
F2 · Labels under the floor
Visible text runs under 12 px (hidden and screen-reader-only text excluded): 32 at 390 px wide, including the visualisation label at 7 px, the replay control's label at 9 px and the section eyebrows at 8 to 9 px; 28 at 1440 px, at 10 to 11 px. Already covered by the 12 px floor; routed to the build's own session.
F3 · The subject waits behind a logo
The house as found appears only after a 4.1 s logo intro. It is not a lock (all nine actions on the first screen were pressable and the wheel scrolled), so it costs time rather than control. For a trade, the house is the argument; leading with the logo delays it.
5. The specimens
The technique, Pete's direction (02/10/2026): "we already had a house with a slider; I wanted the
landonorris technique done to the houses." A before-and-after slider is what this build already had,
so a slider specimen added nothing. The craft worth rebuilding was the award technique, applied to this
material: /specimens/house-lens puts the house as found under the pointer, draws the new design
in line over it, and shows the finished house through a glass lens. It is landonorris.com's T9 on a
renovation.
Promoted to web-frontend (03/10/2026) as an option with conditions, never as the better choice.
Evidence status, in the steward's words, kept because it protects the technique: built and verified
(60 fps on both phone engines, follows a tap to 0 px), so proven buildable and accessible; NOT proven
on real visitors. Nobody has measured whether buyers prefer exploring to watching. The steward added
four conditions, and the specimen now meets all four:
- the idle tour stops under reduced motion
- each place carries a short description of what changes there, announced when chosen
- the lens goes live only on a frame that has actually drawn (read back, alpha 255), and falls back to the photograph on a lost context
- a "Show it finished" view serves visitors who only want the result
On phones the copy now flows below the picture, so it can never sit over the lens.
The rule: /specimens/decode-gated-reveal, below, keeps the wipe for the one thing it is good for:
showing F1 live.
The wipe, as a rule specimen
The pictures are Pete's. He supplied this before-and-after pair, a photograph and a visualisation made from it on the same footprint, and cleared them for this internal specimen (02/10/2026). That is the one exception to the lab's rule of using no material from the studied site, and the reason for it is recorded here. The pair registers well: in a 50/50 blend the roofline, rooflights, eaves, ground line and the neighbour's roof coincide, and only the parts the renovation changes show twice. (An edge phase-correlation peak was no stronger than its noise control, so it could not judge this; the blend did.) The rebuild:
- the after picture loads eagerly and the wipe waits for it to decode; the readout states how long before the wipe it was ready
- the seam is a real control: drag it, swipe it on a phone (vertical scrolling still scrolls), or move it with the keyboard as a slider
- Starting point and Finished are a pressed-state toggle; every label is 12 px or larger
- "Replay it lazily (the bug)" rebuilds the exemplar's construction on purpose (a fresh lazy picture in a keyframe clip, with the measured curve) and the readout reports when the picture arrived against the wipe. In Chrome it arrives after the wipe has ended; in Safari it does not
- no logo intro: it plays when the stage is in view, and reduced motion shows the finished house