Grounded on Blender renders
Ambient CSS calls itself physically based, and as of the Blender-grounded
rewrite that is literal: every coefficient in ambient.css is fitted from
measured Cycles renders of an equivalent physical scene — a millimetre-scale
plate on a reference ground under a calibrated key light and fill, viewed
flat-on (1 CSS px = 1 mm). The renders below are the committed ground truth
each effect is verified against; the left side is the live CSS running in
your browser right now. A comparison harness measures both sides with the
same extractors and gates every release.
The fitted models, residuals and R² values live in
ambient3d/derived/notes/
in the repository.
Surface
.amb-surface — a surface reflects albedo × exposure, and exposure is
what the two light intensities are linear in: irradiance adds up, sRGB
lightness does not. Fit in linear light, one two-parameter law
(0.6396·key + 0.5496·fill, no intercept — lights off is black) reproduces
every measured plate in the rig, at every albedo, to within 0.03 points of
lightness. That is why there is one surface class and a --amb-albedo
variable rather than a class per tone.

Chamfer
.amb-chamfer — both band alphas are affine: a 45° face keeps a residual
band even when key equals fill. Edge treatments imply thickness (material
to cut into).

Fillet
.amb-fillet — the round-over concentrates its highlight at 1.5px per
width unit, softer than the chamfer.

Elevation
.amb-elevation-1 on a paper-thin sheet — at rest the sheet sits embedded
in the surface like a decal (nothing renders); only elevation reveals it,
through the drop shadow cast by its top silhouette. Blur grows and alpha
washes out with height as light spills underneath.

Thickness
.amb-thickness-1 at rest — a button-scale slab. Its shadow is the
silhouette projection swept from the body's bottom to its top: a wedge
that hugs the two shadow-side edges, mitres the corner and fades outward,
not an offset square. Four stacked box-shadow layers sample the sweep at
quarter-heights up to the top silhouette (8px·elevation + 4.5px·thickness); their multiplicative overlap is the outward fade,
with each layer's blur erasing the steps. New corner and contact-hug
metrics gate the shape.

Groove
.amb-groove — negative space: a recessed slot whose depth reuses the
thickness vocabulary. The floor is the same material as the ground around
it under its own exposure, and that exposure runs slightly hot (the
studio's overhead fill reaches in, and the walls bounce light back); the lit-side
wall casts a crisp shadow band onto the floor, and the far wall catches
the key and bounces it back as a soft brightening — the physical origin
of the classic inset highlight. Component tracks compose this with the
lume material.

Curved surfaces
Cylindrical dishes and domes: the gradient stops ride the lit surface
tone — so a dish takes the panel's own --amb-albedo and only the shading
is painted — with the end-stop delta affine in light contrast.



Other materials
There is no class per tone. A plate of a different reflectance is the same
.amb-surface with a different --amb-albedo — and these four frames are
what makes that claim checkable: the rig rendered plates at five albedos,
and one two-parameter exposure law reproduces all 54 of those frames to
within 0.03 points of lightness. The CSS below is the same law, so the live
stage and the render are computing the same thing from the same number.
Headroom above the reference ground is physically narrow — a Lambertian plate caps out near albedo 1.0 — so the two lighter plates sit close together compared to the darker ladder.




Shiny
.amb-mat-shiny — grounded on a glossy dome referent under the white
studio environment every render is lit by: an overhead softbox easing to
neutral walls and a dimmer floor (a product-photography setup, normalized
so matte surfaces receive exactly the fill irradiance the flat world
gave). The specular has two physical features — a grazing Fresnel rim at
the lit edge and the key light's mirror band at 30% in from it (the sine
of half the light zenith) — plus the studio reflection: a softbox veil at
the top and a gentle floor grade at the bottom, riding the fill light and
never flipping with the key.

Brushed, spun and blasted metal
.amb-mat-brushed, .amb-mat-brushed-round (spun) and .amb-mat-blasted —
micro-relief materials, not gradients painted on: a Noise-Texture height
field bump-maps a Principled BSDF in the Blender rig (Object-space
coordinates, anisotropically stretched to the finish's grain — a hardcoded
tangent for brushed's straight belt-sanded lines, Blender's built-in radial
Tangent node for spun's lathe-turned circles), with an Anisotropic BSDF lobe
riding the same grain on the two directional finishes for their sheen. The CSS
mirrors that split: a raw-height-field SVG tile pair (screen + multiply,
offset opposite ways along the light so the pair evaluates the directional
derivative) for the relief, plus a separate gradient for the sheen.
Reference albedo is independently fit for each finish by solving the
already-grounded .amb-surface exposure law against the render's own mean
tone — brushed and spun land within 0.5% of each other (0.4819 vs 0.4795),
which is the "one reflectance, two finishes" claim confirmed rather than
just asserted. It now extends to three: blasted was regrounded as
bead-blasted aluminium at 0.4457, within 8% of the other two.
Blasted used to be described here as a dark, fully matte elastomer with no
anisotropic term. That was a fossil — the material was renamed from
.amb-mat-rubber and its grounding never followed, leaving it at an
albedo of 0.0594. It is now a conductor in the rig, and its grain target
rose an order of magnitude (1.27 → 11.74 RMS L*) because the glitter is
the material: a dielectric was tried first and saturates at 4.5, reaching
even that only by darkening the plate 19 L* below its measured tone. The
CSS side does not reach the new target — its overlay alpha hard-rails
at 1.0 where ~1.27 would be needed, and at the rail the tile reads as
sensor static rather than bead-blast. It ships at 0.666, ~52% of target.
That value was picked by eye for lower contrast and turns out to sit on an
exact edge: the overlay's opacity is a product that saturates at 1, and
0.666 is the highest alpha that never reaches it. At the earlier 0.85 the
material stopped brightening about 18% short of the top of its lighting
range, so asking for less contrast and restoring the light response were
the same move. The remaining shortfall is recorded in
ambient3d/derived/notes/blasted.md rather than tuned away. Its
--amb-mat-specular: 0 is kept deliberately: the reference crop's
low-frequency sweep is 3.4 against a grain of 11.9, so there is no
highlight band to paint.
A grounded number can also fail to reach the screen, which is its own kind
of ungrounding. Brushed's anisotropy — the ratio of across-grain to
along-grain pixel derivative, 7.50 on the rig — was matched on the CSS side
at 7.60 and shipped on that basis. Measured off an actual Chrome raster it
reads 1.55: near isotropic. The tile asked for 20 turbulence cycles per
CSS pixel, forty times the sampling rate, and feTurbulence rasterises at
device resolution — so what reached the screen was that grain's aliasing,
and aliasing has no direction. The finish read as a woven cross-hatch. The
tile has since been hand-retuned for long, fine streaks (a 512px tile, eight
cells across, a 1.1px across-grain period) at unchanged contrast, and now
measures 12.15 — an overshoot rather than a match, because the requested
look is finer than the fit, and one that is chosen rather than accidental.
The sharper form of the lesson is worth stating: the failure was not that the frequency was high but that it was an integer number of cycles per pixel. At that alignment the noise function's lattice coincides with the sampling grid and every sample lands on a lattice node, where gradient noise is zero by construction — so the tile renders far weaker and far less directional than it specifies. A closed-loop CSS fit therefore has to be measured in the regime it ships in, at more than one device pixel ratio, and the anisotropy figure is the one here that moves with it.
The sheen's amplitude is the one thing on this page the rig cannot
measure, and saying so is the honest result
(ambient3d/derived/notes/{brushed,spun}_sheen.md). The calibration camera
is orthographic, so every view ray is parallel and reflects off a flat
plate into a single point of the environment: a broad positional highlight
simply cannot form. 24 renders across roughness, anisotropy and bump
strength top out at a low-frequency sweep of 1.04 against a reference
photograph's 16.2, and with the bump removed the sweep is exactly 0.00 —
the relief was the only source of spatial variation in the frame. An
earlier pass measured that blindness and cut the sheen 4-5x on the
strength of it, to an alpha of ~0.029 at full key: effectively invisible.
That cut is reverted.
The reference photographs cannot supply a replacement number either, and that is a rejection rather than a miss: their sweep is dominated by scene-scale illumination falloff across a large sheet, which a small control has nothing to reproduce. A fully opaque white band on the CSS side reaches only 6.5 against the photograph's 16.2, and the exposure-invariant sweep/grain ratio fails the same way — so the target has no solution at any alpha, because it is not the same quantity. The shipped amplitude is therefore fit visually against the crops, keeping the original's floor-to-slope proportion so the sheen still survives a dim scene. Grounding is split by quantity on purpose: relief amplitude and anisotropy from the rig, sweep amplitude and grain shape by eye.
Brushed's band position is genuinely grounded — the rig resolves position fine, it is amplitude it is blind to — and confirmed to slide with the light the way the CSS assumed, just at a different rate. Its half-width, and spun's whole conic-lobe shape, stay hand-tuned. An earlier pass called spun's lack of directionality "a checked result" on the grounds that the same sweep recovered a clean peak for brushed; that claim is withdrawn, since the orthographic argument applies to both finishes and brushed's peak arrived through perturbed normals that spun's radial grain has no equivalent of. The shape is unmeasurable on this rig, not disconfirmed by it.



Glow
.amb-glow — halo radius from the emissive plate's measured bloom falloff.
The lume color's bright/dark switching is a design semantic layered on top.
