#47 makes skyBackdrop the union of the skies the scenes draw: day 0.238-0.919, dusk
0.017-0.965, night 0.058-0.077. Only night text still clears 4.5:1 on bare sky (5.05);
day falls to 3.71 text / 2.56 link. Everything outside a bubble stays on the plate.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
They join the shared plate rule under the scene. The composer's own half-strength
blurred fill goes (its text fell below 4.5:1 in dusk and some auto themes); the
plate has the checked ink. skyTheme.test.ts pins which regions are on the plate.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
skyPlate.css.ts joins the room and page headers, the room list, list pages, the
typing and Following bars, non-bubble messages and the room intro to the sign-in
card's opaque --sky-bubble plate, with the plate's ink and link tokens, at all
widths. The estate title bar's own plate goes: the shared header rule covers it.
skyTheme.test.ts pins the link ratios on bare sky as well (day 5.25, night 2.36).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The menu is role=menu with menuitemradio items (aria-checked), the button carries
aria-expanded, focus goes to the checked item on open and back to the button on
close. Over the scene the estate title bar and any non-bubble message sit on the
sign-in card's plate (--sky-bubble) instead of bare sky. skyTheme.test.ts pins the
ink colours and WCAG ratios of the picked themes, measured with the ink clamped
into the sky range as skyState.test.ts does; the pass/fail set is unchanged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
One button beside Find a room opens Auto / Day / Dusk / Night (fits a 320 px bar).
Day and Dusk take Noonday Sky's dark ink, Night Midnight Sky's light ink, Auto
keeps the theme the page would have had; signed-out pages follow the state too.
skyTheme.test.ts checks contrast from the baked tokens: day and night ink clear
AA on bare sky, every container carries its text, links clear AA on the surface,
and dusk text on bare sky does not, so it stays on surfaces.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
index.ts compares the current state with the built one after subscribing and
rebuilds if they differ. skyBackdrop unions the ridge sky and the terrain sky
(skyColour sampled over the sphere, from chooseSky(terrainSkyFor(state))), so
terrain dusk's sun glow and terrain day's darker zenith are inside the range.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The door tells the host (onInactive/onActive) when a rebuild makes no scene or
makes one again. chooseSky takes an explicit sun or sky option before ?sun=,
?az= and ?sky=; only auto, which passes none, is steered by the URL.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The door (index.ts) reads getSkyState, subscribes on start and rebuilds the
scene on the same canvas when it changes; the returned scene's dispose
unsubscribes. skyForState.ts maps a state to the scene's sky option: auto
leaves it unset (today's behaviour), dusk is the ridge dusk, day and night
are the baked gradients skyBackdrop bounds.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
host.ts passes onContextLost to the scene; on loss it disposes the dead scene
and calls onInactive (BackgroundScene removes data-scene so the CSS ground
shows). A webglcontextrestored listener on the canvas starts a fresh scene;
it is removed on dispose, and a stale start is dropped by generation.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
getSkyState/setSkyState/subscribe over one localStorage key, default auto,
tolerant of missing, invalid and refused storage. skyBackdrop(state) returns
the darkest and lightest sky luminance the state can show. Tests measure
login text and link contrast against it per state and theme.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The scene sky is one fixed dusk for every theme, so a translucent card put
Midnight's link at 4.12/3.37 and Light's and Silver's at 2.49 (Libby). The card
is now the theme's bubble colour with no transparency and no backdrop-filter,
so text and link contrast no longer depend on the scene or a blur. Themes
without --sky-bubble (Light, Silver, Dark, Butter) get link #99c7ff on the card
(Dark and Butter already used that hue); Midnight and Noonday keep their own.
WCAG 2.x ratios, computed, text / Register link on the card:
Light, Silver, Dark, Butter #b7c7d9 / #99c7ff on #0d1a26 10.21 / 10.03
Midnight Sky #aeccff / #609385 on #0a090e 12.17 / 5.68
Noonday Sky #342d25 / #2a4f27 on #b9b6af 6.70 / 4.62
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Libby's read: at 54% fill Noonday text was 2.99:1 and the Register link 2.06:1
over shaded terrain. Dark text on a light bubble fails when a dark ground shows
through, so Noonday's card now takes the bubble colour with no transparency.
Midnight is unchanged (54%).
WCAG 2.x ratios, computed (relative luminance, sRGB):
Noonday, bubble #b9b6af, text #342d25, link #2a4f27, card over black / white:
54% fill: text 2.23 / 9.51, link 1.54 / 6.55 (fails over dark)
80% fill: text 4.36 / 7.86, link 3.00 / 5.42 (fails over dark)
90% fill: text 5.44 / 7.24, link 3.75 / 4.99 (link fails over dark)
100% fill: text 6.70, link 4.62, independent of backdrop and blur
Midnight, bubble #0a090e, text #aeccff, link #609385, 54% fill:
over black text 12.49, link 5.83; over white text 2.62, link 1.22
(white is not in the night scene; 4.5:1 over the horizon glow is an
estimate, not measured)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
One conflict, index.html's manifest link: this branch had %BASE_URL%manifest.json (4afd37e7), dev has ./manifest.json
(45aad35e). Both make the link base-relative for static previews; dev's form is kept, matching the file's other
relative links.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Phone shots of 'terrain · low' showed hard-edged facets on the near ground and stepped crests. Cause: the grid
(192 quads low, 256 full, 7 m wide at the nearest ground) was coarser than the 2.9 m height texels the fragment
shader reads its normals from, so gullies the polygons could not carry showed as hard shading edges. Measured by
rendering the low tier at 192..384 quads against a 768-quad reference: mean abs error 1.7 / 1.1 / 0.7 / 0.5 on
the day frame at 192 / 256 / 320 / 384; the warp's shape barely moved it.
- GRID: still 192, low 320, full 384; a test holds every tier to a quad of at most two texels at the nearest ground
the camera sees, and the tiers ordered by cost. The low triangle ceiling goes from 80k to 210k (205k used),
unmeasured on a phone.
- cavity: the shader read it from the nearest texel (blocks of one texel); it is now bilinear (hBil) at a continuous
position, with a CPU twin (bilinearHeight, curvatureAt, cavityAt, CAVITY) and a test that shading is continuous
across texel borders where the nearest-texel read jumps.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Soul: selected and hover shared one 80% value and the press state lost to hover on
specificity. Now hover 74%, selected 84%, pressed 92%.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
dev's settings default reads window.matchMedia at module load (composer-spellcheck merge);
soundscape.test.ts imports settings in a node environment, so "ships off, muted" threw
ReferenceError on dev itself. No window means no coarse-pointer query.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
With the background scene on, nav rows were fully clear and the ridges showed through
their text. Rows now carry the theme's own surface at 62% (80% on hover and selected).
An unjoined row (Commons) gets the same leading room icon as a joined one.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Anchored by its bottom edge 13px inside the bubble instead of its top edge 15px above it,
so a wrapped name and time never cover the first line of text.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The pill's child is the flex row holding name and time; flex-wrap on the pill itself
did nothing.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
At 320px the name shrank to a 37px column beside the time and broke mid-word.
The pill now wraps its children and breaks only where a single word is too long.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The pose-label test resolves fixture senders to known Minds; "@watch" was not one,
so server.test.ts failed on the long-name fixture. Same long display name, now @heimdall.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The name button wraps a truncate Text span; overriding only the button left the
span nowrap, so the long name overflowed the pill.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Username carries its own nowrap + ellipsis, which still clipped long names
("Heimdall o...") inside the widened pill. On phones the name now wraps.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The pill was capped at a percentage of the bubble column and clipped with an
ellipsis; a short bubble's column is narrower than its own name, so names read
as "E..." and "V...". It is now max-content up to a viewport-based cap and wraps.
Demo fixtures gain a long display name to keep this honest.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Haze was the Hillaire volume alone, ~40% opaque by 2 km and without the night glow
the sky adds, so the far ground sat well off the sky at the horizon (night: sky
73,79,99 vs far ground 20,24,31). Past SKY_FADE the surface is now skyColour flat
along the horizon in its ray's azimuth, in the CPU twin and the GLSL alike.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- before every attempt the picked file is read into memory (ArrayBuffer) and that copy is what
the SDK uploads; a file the browser cannot read fails there as "file unreadable before upload"
- while an attempt runs, XMLHttpRequest open/send are wrapped (reference-counted with the abort
probe, restored in finally, no behaviour change) so the failure line carries each upload XHR's
method, path (query dropped), readyState, status, the events it fired with timings, and our
signal.aborted
- the abort-call stacks stay as a minor extra
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>