PRIMITIVE
Scene
A picture behind the words. Two classes and an image element — the section it lands on keeps every decision it already had, and the photograph is mixed into whatever surface that section is sitting on.
A picture behind a hero
Nothing about the hero changed. The image is a sibling of the body, and scene-media lifts it out of flow.
Everything worth building runs out into the fog first.
The photograph is mixed into whatever surface this band is sitting on, at the strength the theme states — so this paragraph reads at the ratio it would have had on a plain section. Switch the theme at the top of the page: the picture has not changed, and what it is mixed into has.
<!-- The section is untouched. The picture is a SIBLING of the body: `scene-media`
lifts it out of flow and puts it one layer down, so the hero goes on being
a hero and nothing about its markup has to change. -->
<section class="hero scene shell" style="width:100%">
<img class="scene-media" src="/scenery/causeway.webp" alt="" loading="lazy" decoding="async" />
<div class="hero-body">
<div class="section-head">
<span class="section-head-kicker section-head-kicker-quiet">FIELD NOTES · ISSUE 04</span>
<span class="section-head-rule"></span>
</div>
<h1 class="hero-title">Everything worth building runs out into the fog first.</h1>
<p class="hero-lede">The photograph is mixed into whatever surface this band is sitting on, at the strength the theme states — so this paragraph reads at the ratio it would have had on a plain section. Switch the theme at the top of the page: the picture has not changed, and what it is mixed into has.</p>
<div class="cluster hero-actions">
<a href="#" class="btn btn-primary">READ THE ISSUE</a>
<a href="#" class="hero-link">Every back issue</a>
</div>
</div>
</section>Four ways to hold the words
Same photograph, four jobs. The default mixes it into the surface everywhere; the other three hand it back its full strength and buy the legibility somewhere else.
SCENE
Mixed into the surface, everywhere. Words go anywhere on it.
SCENE-FOOT
Full strength up top, gone at the foot.
SCENE-LEAD
Full strength beyond the copy, gone behind it.
<!-- One photograph, four jobs. Only the class on the box changes. -->
<div class="hairline-grid" style="--cell:230px; width:100%">
<div class="hairline-cell scene" style="min-block-size:210px">
<img class="scene-media" src="/scenery/facets.webp" alt="" loading="lazy" />
<span class="section-head-kicker">SCENE</span>
<p class="placeholder-caption">Mixed into the surface, everywhere. Words go anywhere on it.</p>
</div>
<div class="hairline-cell scene scene-foot" style="min-block-size:210px; display:flex; flex-direction:column; justify-content:flex-end">
<img class="scene-media" src="/scenery/facets.webp" alt="" loading="lazy" />
<span class="section-head-kicker">SCENE-FOOT</span>
<p class="placeholder-caption">Full strength up top, gone at the foot.</p>
</div>
<div class="hairline-cell scene scene-lead" style="min-block-size:210px">
<img class="scene-media" src="/scenery/facets.webp" alt="" loading="lazy" />
<span class="section-head-kicker">SCENE-LEAD</span>
<p class="placeholder-caption" style="max-inline-size:18ch">Full strength beyond the copy, gone behind it.</p>
</div>
<div class="hairline-cell scene scene-clear" style="min-block-size:210px">
<img class="scene-media" src="/scenery/facets.webp" alt="" loading="lazy" />
</div>
</div>It composes, and it owns nothing
A slab is still cream. A card is still a card. A scene decides where a photograph sits and stops there.
Thirty minutes, no deck, no obligation.
No scene at all. This is the card the library has always drawn.
The same card with a picture behind it, at full strength where nothing is written and gone where these words are.
<!-- A scene is two classes and an image, and it has no opinion about what it is
composed onto. The slab keeps every one of its own decisions — it is still
the cream surface, and the photograph is mixed into the cream. -->
<div class="cta-slab scene" style="width:100%">
<img class="scene-media" src="/scenery/marbled.webp" alt="" loading="lazy" />
<div class="cta-slab-body">
<span class="cta-slab-kicker">ONE SLOT OPEN THIS QUARTER</span>
<span class="cta-slab-title">Bring me the part nobody wants to estimate.</span>
</div>
<div class="cta-slab-action">
<a href="#" class="btn btn-on-cream">BOOK AN INTRO CALL</a>
<p class="cta-slab-note">Thirty minutes, no deck, no obligation.</p>
</div>
</div>
<div class="hairline-grid" style="--cell:280px; width:100%; margin-block-start:32px">
<div class="hairline-cell offer-card">
<div class="offer-card-head">
<span class="offer-card-kicker">MOST COMMON</span>
<span class="offer-card-title">Project</span>
</div>
<p class="offer-card-text">No scene at all. This is the card the library has always drawn.</p>
</div>
<!-- A faded variant clears a band and the content has to BE in it, so this
card pushes itself to the foot. Leave it at the top and the head sits on
a photograph at full strength, which is the one thing the fade exists to
prevent. `--scene-clean` is widened here so the band covers all three
lines rather than cutting through the kicker. -->
<div class="hairline-cell offer-card scene scene-foot" style="min-block-size:300px; justify-content:flex-end; --scene-clean:58%">
<img class="scene-media" src="/scenery/curl.webp" alt="" loading="lazy" style="--scene-focus:50% 30%" />
<div class="offer-card-head">
<span class="offer-card-kicker">RETAINER</span>
<span class="offer-card-title">A day a week</span>
</div>
<p class="offer-card-text">The same card with a picture behind it, at full strength where nothing is written and gone where these words are.</p>
</div>
</div>Reference
Read from primitives/scene.css when this page was built, so it cannot fall behind the stylesheet.
.scene.scene-media.scene-clear.scene-foot.scene-lead--scene-strength — falls back to --ds-scene-strength--scene-clean — falls back to --ds-scene-clean--scene-full — falls back to --ds-scene-fullNotes
A scene composes onto anything, which is not the same as belonging on everything. The line is easy: a picture behind a box somebody reads is an accent, and a picture behind a box somebody operates is noise the operator has to see past.
| REACH FOR IT | WHY |
|---|---|
hero | The opening statement. The one every client asks for first. |
cta-slab | The warm plate that asks for the work. A picture in the cream, and the button unchanged. |
shell-flush | The full-bleed band. A scene is more at home here than anywhere else in the library. |
fact-strip | Numbers over a texture, breaking a page that has been prose for a while. |
offer-card, interest-card, feature-cell | A card that has to sell something rather than list it. |
testimonial, case-plate | A quote or a study wants a quiet thing behind it, not beside it. |
work-entry, feature-band | A row or a band that is itself the argument, carrying its own subject. |
site-footer, article | The closing block, and a piece's opening band — never the body of one. |
Not these, and each for its own reason. site-header, dock, settings-row, process-list, timeline and ledger are dense chrome and data — a reader is scanning them, not looking at them. enquiry-card is full of fields, and a field's border and its error ink both owe a ratio that a photograph will not respect. gallery, triptych, collage and walkthrough are already pictures, and a picture behind pictures is mud.
And not an atom, ever. A frame or a clip already is the picture, an avatar is round and 32px across, and a button with a photograph in it is a button nobody can read.
Fair question, because background-image is the obvious spelling. It is also the one that cannot be lazy, cannot be found by the browser's preload scanner, cannot carry a srcset, and cannot say it is decorative.
The one that settles it is responsive art direction. Swapping a background by width takes a media query, and this system has none — while an <img> does the whole job with srcset and sizes, which are not breakpoints and ask the browser rather than telling it.
A photograph you have not seen yet is behind somebody's paragraph. That is a contrast problem with no page to look at, so it is answered with arithmetic: composite the two extremes an image can reach — an all-white frame and an all-black one — over all four of the library's surfaces, in both themes, at the shipped --ds-scene-strength.
| ROLE | WORST | OVER A SCENE |
|---|---|---|
--ds-ink | 5.85:1 | Holds AA over any picture |
--ds-ink-read | 4.81:1 | Holds AA over any picture |
--ds-ink-soft | 3.27:1 | Does not. Keep it off a scene |
--ds-ink-faint | 2.20:1 | Does not. Keep it off a scene |
So the rule is one sentence: a scene carries ink and ink-read. The two quiet inks cannot be rescued by mixing harder — the strength that would carry ink-faint is about a tenth, and a photograph at a tenth is a smudge. If you want a caption on a picture, that is what scene-foot is for: the band it clears is the surface itself, so the caption reads at its full ratio.
tools/check-theme.mjs holds the first two rows and prints all four, so a retheme cannot walk away from the promise quietly — and cannot leave this table out of date either.
--scene-strength is the picture's opacity, so what it mixes into is whatever is actually painted behind it. Look at the third specimen: the same two classes on a cta slab put the photograph into cream, with no line of CSS anywhere that knows cream exists.
A --ds-scene-veil token would have to name one surface, and would then be visibly the wrong colour on the other three. This way the mix follows the box, for free, in every theme.
A gradient veil leaves a thinning film of colour over the photograph, so the contrast where the words are still depends on the photograph. A mask removes the picture — the cleared band is the surface itself, at the full ratio the theme states, whatever the image turns out to be.
Between --scene-clean and --scene-full the picture is fading back in. No word belongs in that band.
This one is easy to miss because it fails quietly. Put scene-foot on a card that lays its content out from the top and the kicker lands on a photograph at full strength — which is the one thing the fade exists to prevent. It happened here while this page was being written, and it was a screenshot that found it, because nothing else can.
So a faded variant is two decisions, not one: pick the side, then put the content on it. The card in the third specimen pushes itself to the foot and widens --scene-clean until the band covers all three lines. If you would rather not think about it, that is exactly what the plain scene is for.
The picture sits at z-index: -1, which is what lets the content stay exactly as it was — no wrapper, no positioning of its own. A negative layer escapes to the nearest stacking context though, and without one here the photograph would slide behind the page and vanish, so .scene isolates.
The bill: anything inside a scene that lifts itself with z-index is now trapped in that box and can no longer paint over a later section. A panel that has to escape belongs outside the scene, or in the top layer where a modal already lives.
A picture behind a headline adds nothing that a reader of the headline has missed. Announcing "photograph of fog on a treeline" before the words is noise with an author's name on it. The media is also pointer-events: none for the same reason: it is scenery, and nothing may pick it up or drag it out of the page.
A picture that is content wants a frame, in the flow, with a real description.
The same judgement grain makes: a decorative layer that costs ink or costs contrast is a decorative layer that goes. What is left is the section on its own surface, which is exactly the page this library drew before scenes existed.
--scene-clean and --scene-full are read inside the scene-foot and scene-lead rules, so they are substituted on the element carrying that class. Put them on the section. --scene-strength and --scene-focus are read on the picture and take either element.
--scene-focus is an object-position, and it is the one setting here with no theme half. Where the subject sits in a photograph is a fact about that photograph — a theme has no opinion about it, so it is written per instance and nowhere else.
The library ships no images at all — the same decision it made about fonts, for the same reason. Everything on this page is the book's own, and Pictures lists all sixteen with the credit each one is owed.