createTerrainScene returned null without WebGL2, leaving plain dark ground. The door now mounts
terrain/TerrainSky2D.ts on the same canvas: skyColour (the CPU twin of SKY_FRAG) painted once, the star
layer on top when dark, same ?sky= ?sun= ?az= choice. chooseSky moves from Terrain.ts to terrainSky.ts
so both scenes share one owner.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Drops the vendored terrain/skyData.ts and the computed azimuth. terrainSky.ts reads src/sky/baked.ts:
sun {elevation_deg, azimuth_deg, color_linear}, ambient_linear, horizon_hex. terrainScatter.ts decodes
baked.scatter and uploads sky_view as an RGB16F 3D texture; SKY_FRAG and GRID_FRAG sample it (README
sampler), the sky for the view ray, the haze for the horizon in the fragment's azimuth.
- Sky: 1 - exp(-exposure * radiance) + night glow (midnight horizon colour, off as the sun nears the
horizon) + sun disc; +-0.5/255 dither on the 8-bit output.
- Stars fade by sun elevation (starGain: 1 below -12, 0 above -6) instead of a dark-sky gate; the
field is placed against the midnight gradient.
- ?sun=<deg>&az=<deg> (or the sun option) lights between the two bakes for dusk (skyAtSun).
- Changed numbers, noted in scene/README.md: haze colour is the scattered sky (was the gradient's
horizon stop), ambient is ambient_linear as baked (was gradient zenith x 0.25 x night lift up to 4),
HAZE_K unchanged at 0.0004.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Terrain overlay draws the ridge field at 2.4x alpha (capped at 1) and 1.3x
radius; the dark-sky gate is unchanged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
scatter.js ray-marches a single-scattering Rayleigh+Mie atmosphere whose vertical optical depth is
sun.js's TAU, and bakes two tables into baked.scatter: transmittance to space by view elevation
(32x1) and sky radiance by azimuth from the sun x view elevation x sun elevation (7x32x12), RGB
half floats, little-endian base64, value x 64. Layout, exact decode and a GLSL sampler are in
src/sky/README.md. Tests pin layout, encoding, checksums and physical anchors (zenith transmittance
equals exp(-TAU); blue noon, red low sun toward the sun, black below the planet-shadow limit).
The per-sky sun {elevation_deg, azimuth_deg, color_linear}, ambient_linear and horizon_hex were
already baked in 7216456a; sun.js now exports TAU.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reuses ridge/stars.ts (placement, tint, rolling 32-star twinkle) projected with the terrain camera
onto an overlay cut to the sky; stops with the terrain loop.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Bands moved so snow caps only the peaks and soil/scree/rock read; haze
0.0007 -> 0.0004 so the albedo is not washed out; ambient x4 at night so a
moonlit face is readable on a phone.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Rock on steep faces, soil to scree to snow by height, snow only on gentle
faces; no texture reads. Pure albedoAt()/albedoPalette() mirror the grid
fragment shader; the palette is read from the baked sky (snow line and tint
by sun elevation: cool haze at night, warm sun by day).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The noise is evaluated at vec3(xz * f, c), so .z is the slope along the held
constant axis. Confirmed numerically (harness/scene/gradAxis.cjs): analytic
.xy matches central differences for fbm and phacelle, .z does not. Only the
ray-march scene's normals were affected; the grid tier already used .xy.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed in, the shell is clear over the ridge scene (html[data-scene]): Background and Surface
container tokens are redefined on #root only, so menus, dialogs and tooltips in #portalContainer
keep their fills. Bubbles and the composer are the filled surfaces: their colour at 50% over a
12px blur. Avatar initials read the surface colour through a variable captured above the override.
On phones the message content (a flex column) formed its own block formatting context and sat
beside the floated portrait for the bubble's whole height, so text stayed as narrow as the gap
beside the portrait. It is a plain block there now: lines wrap around the silhouette and then
run the bubble's full width.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The demo pose thumbnails were 160px wide palette PNGs, about 4 KB, shown at up to 210 CSS px
on phones: 195 CSS px x DPR 3 = 585 device px from 160, a 3.6x upscale. They are now 480px
wide (about 2.5x the phone portrait at DPR 3, still 25-70 KB each), generated from
/opt/commons/cast-art/poses by scripts/make-pose-thumbs.mjs, and cover every pose the
catalogue lists for the three demo Minds.
The Ratatoskr demo room gains three long Mind posts with paragraphs, lists and code,
sent with formatted_body like the real Minds' Markdown.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Found driving Chrome: the pose setting was seeded after settings.ts had already read defaults;
the Connecting bar stayed until the first 15 s long poll returned.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The host CSP sandbox lacks allow-forms; Chrome drops native submission before the submit
event fires, so the login button did nothing in a real browser (found driving Chrome).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
src/preview-demo answers a demo.invalid homeserver from fixtures through a guarded fetch;
own-origin requests pass, every other origin is refused (fetch, WebSocket, XHR, beacon).
Built in only with VITE_PREVIEW_DEMO=1 and switched on by previewDemo in config.json
(scripts/preview-config.js --demo, run by the dev workflow). Login prefills 'demo'.
Pose art: 24 downscaled thumbnails in preview-demo/poses, copied into dist by the workflow.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Preview on Starfire showed one flat normal per height-map texel (blocky ground)
and a hard step in the sky gradient at the geometric horizon. Normals now blend
the four surrounding texels; the sky's elevation mapping eases through the
horizon; haze k 0.0012 -> 0.0007 so relief reads.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
style 'terrain' (WebGL2, tier-gated, dynamic import): height map baked once on the
GPU into RGBA8 (promoted from the terrain-tier-spike), a displaced grid, the baked
gradient as sky, baked sun/ambient/haze. Sky from option, ?sky=, or the stars'
night notion. Cadence guard, pauses, context loss and compile failure follow the
ridge scene. preview-config.js takes an optional style argument.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Vendors the small set the terrain needs from Void's baked sky (PR #22, 7b4aa2f):
sun elevation, the 7-stop gradient, sun.js light().direct, plus a sun azimuth
computed from the same series (not in the bake). Lambert from the sun, ambient
from the gradient zenith, exp(-k d) haze toward the gradient's horizon stop;
a sun below the horizon lights nothing. Pure functions, no GL.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Every star is seeded, placed toward the zenith, faded by the local sky
luma, and baked once into the sky canvas. A night sky is one whose
zenith luma is below 110; the ridge scene has no theme flag, so the
dusk default qualifies faintly and a day sky gets no stars and no
overlay.
32 slots twinkle at a time on a small overlay canvas under the ridges:
each slot runs back-to-back one-cycle twinkles (own 2-7 s period and
offset) of one star from its own partition, shuffled per epoch, never
repeating across the seam. Gain is a pure function of (slot, t), 0.35x
to 1.15x, exactly 1 at start and end. Dimming paints the sky's own
colour over the baked star; brightening adds a star. The pass is
clear + at most 32 arcs at 20 fps, stopped under reduced motion (live),
while hidden, in tier 'still', and after the slow-frame fallback.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The blur flattens the sky and ridges behind the text, so the fill can be
half as opaque and let the scene show through. Text over the unblurred
horizon glow is 4.15:1 (4.5 needs 54%); measured over the real blurred
backdrop at 390x844 it is >= 4.94:1.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Under html[data-scene] the card is a blurred 85% pane in the sky bubble colour
(--sky-bubble, fallback #0d1a26), message-bubble radius, no visible border, and
shorter padding/gaps so more scene shows on a phone. Tier off is unchanged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
BackgroundScene hosts the scene behind the app (fixed, z-index -1, tier off
renders nothing); mountBackgroundScene owns the async start/dispose race and
calls login() when a session already exists. Signed-out screens go transparent
while a scene runs. build:preview sets backgroundScene.tier low in dist.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Heimdall's ruling: type org.gamecult.notice, state_key '', content {version, scope}.
version is a positive integer, scope exactly show, study or train; absent or
malformed means no train line. ROOM_NOTICE_CONTENT_KEY becomes
ROOM_NOTICE_EVENT_TYPE; RoomTrainingLine reads the state event through useStateEvent.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The collector reads the notice version from the room's pinned notice and takes
the member's first reply as the acceptance (Heimdall answer-collector-consent.md),
so a localStorage record at registration was a second, unread copy. Deleted it
and its unused re-ask helpers. RoomTrainingLine now reads the room's own pinned
notice and shows the train sentence only where that notice declares train; no
notice, no line (DMs included). The pinned event's encoding is not fixed by the
doc; the key is provisional and isolated in trainingNotice.ts.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Two themes replace the navy GameCult theme. Every colour is a bark, leaf, soil
or pigment albedo times the irradiance sun.js gives for a fixed moment (equinox
noon and midnight, 45N). scripts/bake-sky.mjs writes src/sky/baked.ts: the
terrain-free sky gradient used as the fallback background, folds tokens for
panels and buttons, chat bubble colours, link and name colours.
skyTokens.test.ts holds every text pairing to WCAG AA and fails if baked.ts is
stale.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Per-layer Beer-Lambert transmittance exp(-k d) mixes each layer toward the haze colour, with
desaturation, 0-2 px edge softening (2D canvas filter, where supported) and an optional faint
warm sun-side in-scatter growing with distance. All at bake time; no per-frame work. Sky colours
still come only from skyColours() (gains optional sunAzimuth).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Login no longer shows the notice. Registration shows the ruled sentence with a
plain tick, and records {noticeVersion, acceptedAt} on submit (newcomers only;
a changed TRAINING_NOTICE_VERSION is a fresh acceptance). Each room carries one
line above the composer. The Discord sentence and "on this server" are gone.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Four ridge layers generated once on the CPU from CultMath value-noise fbm, each painted
once to an integer-size 2D canvas over a baked sky; CSS translate3d drift only. Pauses
hidden / reduced motion; falls back to a still image if rAF p95 > 33 ms over 2 s;
?probe=1 shows median/p95. Same createScene contract, tier flag still defaults off.
Ray-march scene stays behind backgroundScene.style = 'raymarch'.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Dependency-free ES module: light({time,lat,lon,cloud_cover,precipitation})
-> {elevation, direct, diffuse, wetness}, linear RGB. Constants that were
tuned by eye are labelled EYEBALLED. Fixed-moment tests in
sun.node-test.js (plain node, not collected by vitest).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
One TrainingNotice component above the submit button on both screens. Login
shows the notice only; registration adds a ticked checkbox that gates the
Register button.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Pose portrait beside the bubble on wide screens and floating inside it on phones with
shape-outside; asymmetric bubble corner; own messages right-aligned in the accent colour;
first-appearance pop and rise, staggered, off under prefers-reduced-motion; Nunito in the
GameCult theme; package name and README move to Ratatoskr, Cinny credit and AGPL notice kept.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>