Continuous -2x..2x speed control for the resting altitude loop video
(#vid-loop); manual rAF reverse loop below 0x; reduced-motion a11y
behavior preserved invisibly via OS prefers-reduced-motion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unify #loading / #motion-warning / #run-sim into one #welcome overlay:
heads-up notice + four output controls (Video on, Reduce motion off,
Audio 2, English) + Loading Universe progress. Two states (welcome →
centered loading); right panel hidden until entry; Continue is the single
entry gesture. Forward note: extra welcome copy lands later.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reduced-motion freeze-to-stills, photosensitivity warning gate + flash
audit, keyboard/SR-operable Altitude dial, low-vision contrast, and a new
about.html (English-first). Targets WCAG 2.1 AA plus a motion/seizure layer
for the unattended public URL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Solution design for a no-origin public target at
benstull.art/human-experience-simulator (apex redirects): static frontend on
Pages, ~2GB served media on R2 behind static.benstull.art, dynamic logic baked
to JSON / moved client-side. Records the deliberate flotilla/PPE process
exception for a static art target.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Design for a language dropdown localizing the simulator UI controls and
the Left/Right brain annotations. This pass: en/es/fr/ja (Hebrew + Chinese
deferred — no RTL work in scope). English default, session-only (no
persistence), English fallback on missing keys. Annotations extend the
existing per-clip strings dict (no schema change); ~2,260 strings authored
via a one-shot idempotent translate_manifest tool.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Expanded-pools sky-scale work plus two experience tweaks:
- New `sky` altitude (airplane-window / low-flight layer) between orbit and
coast; RING_ORDER cosmos·orbit·sky·coast·reef·abyss. New clip pools across
all scales, re-baked the full adjacent-pair morph set (all-intra, LFS), and
removed the now-stale cosmos↔abyss transitions the old ring order produced.
- Auto-start: once the preload finishes the experience turns Video on and
raises the audio dial to 3/10 with no user gesture (app.js autoStart()).
- Dropped reef_hawaiian (text overlay — violates the text-free pool rule);
reef pool 7→6, manifest transitions 586→558.
Tests: rewrote tests/test_e2e_audio.py for the dial UI + auto-start; updated
the manifest morph-count assertions and the altitude-scrub target for the new
ring order. 302 pytest + 11 Playwright e2e + 9 node unit all green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Plan for the approved design at
docs/superpowers/specs/2026-06-27-scrub-driven-altitude-transitions-design.md.
Two phases: (1) scrub interaction against current morphs, (2) all-intra re-bake.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Approved design for the next increment: continuous knob position scrubs the morph
video + crossfades audio (hold-partway, reversible, re-roll-on-fresh-approach,
wheel auto-scrubs one altitude). Includes morph all-intra re-bake for smooth
seeking. To be planned + built in a separate session.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The curated clip bases, per-scale audio, and 154 baked altitude morphs are the
actual experience content, so they're committed via git-LFS (self-hosted Gitea
LFS store). coast_birdrock/base.mp4 was re-encoded 68MB->22MB (25Mbps->8Mbps,
1080p30 unchanged) to fit the git.benstull.org front-end nginx upload limit; its
16 morphs were re-baked. Stale right_variants stay gitignored. Adds .gitattributes
(LFS) and negates the used media back into git in .gitignore. Also records the
LFS media-graduation decision in the plan doc.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Choose the destination clip before transitioning, play the matching
member->member morph (154 clips, all adjacent video pairs, both
directions), chain through each crossed altitude, and lock the clip
until the altitude is changed (no secondary swap, no re-roll).
Session 0024 (writing-plans). Stops at the review gate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Operator follow-ups:
- Remove the tap-to-start wall; show a 'Loading Universe…' splash until all media
preloaded (main() awaits preloadAllMedia + a progress bar), then reveal the app.
- Both Video + Audio toggles default OFF (black + silent at start).
- FIX audio still silent on real Safari: the A/B-crossfade-after-gesture didn't
unlock on Safari (priming srcless elements doesn't unlock them). Use ONE <audio>
element played SYNCHRONOUSLY inside the toggle's click — the reliable Safari
unlock; later altitude swaps reuse the unlocked element.
- First time Video turns on, also turn Audio on (one flip = full experience), set+
played in the same gesture; Audio-on-first stays audio-only.
- Soundtrack follows Altitude via the single element (brief fade swap).
- Verified in headless Chromium AND WebKit: coupling works, soundtrack plays,
video-off blanks, zero JS errors. 290 tests + 5 Playwright E2E pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Operator-driven live-UI revision:
- Video + Audio are now Dev-Mode-style on/off toggles (Audio on = soundtrack);
white-noise deferred (removed from the live control; pure machinery kept).
- FIX video-off not blanking: the <video>/<canvas> are GPU-composited and could
paint above the auto-z #black on a real GPU — give #black z-index + its own
layer AND hide the video layers (opacity 0) on video-off.
- FIX no soundtrack on Safari/iOS: Safari unlocks <audio> only when play() runs
INSIDE the user gesture; the start gesture now primes both A/B elements
synchronously, so the async crossfades are allowed to play.
- Toggles wired on 'change' (matches the Dev Mode switch).
- player/audio.py AUDIO_SOURCES -> {off, soundtrack}; tests + E2E updated.
- Verified in headless Chromium AND WebKit: audio plays, video-off blanks both
layers, zero JS errors. 288 tests + 3 Playwright E2E pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Session 0020. Anchored on the audio-video-separated-controls Solution Design.
Scope: build into the current single-page simulator (simulator-first directive);
reframe the unbuilt control-surface spec on paper. 10 tasks, all testing tiers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sound for the experience, plus the design to control it.
Soundtrack layer (ambience), all license-clean (PD/CC0), recorded in
docs/audio-candidate-pool.md (media gitignored; re-sourceable):
- cosmos: Pillars of Creation sonification (NASA, PD)
- orbit: station room-tone hum (CC0)
- coast: sea waves + terns (CC0)
- reef: 6-layer NOAA soundscape + CC0 submerged bed (PD + CC0)
- abyss: blue-whale moan (NOAA, PD)
Solution Design (proposed): split the bundled Content selector into two
orthogonal dials, Visual (on/off) x Audio (off/soundtrack/white-noise),
unlocking white-noise+video. Soundtrack follows the single Altitude dial;
white noise is altitude-independent. Reframes the networked-control-surface
spec SS3/SS5 (still proposed/unbuilt -> clean pre-impl edit). Music layer deferred.
Dev panel: links to the clip + audio review galleries; sticky stage/panel layout.
gitignore: audio media, review_audio.html, .DS_Store.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v1 hardware step: split the simulator into a laptop RENDERER and a separate
touch CONTROLLER over wifi/LAN. Server-authoritative SessionState + SSE push;
one /api/control contract any "control source" speaks (iPad web twin now,
Arduino later). Live knobs (Left/Right/Mood) vs transitional controls
(Altitude, Content) with per-knob transition state + renderer settled-ack.
Reframes ROADMAP sub-project 4 and absorbs sub-project 3's serial-input slice.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Operator wanted more Cosmic Cliffs footage and a different-color rendering.
Keeps the NIRCam flythrough as the cosmos primary and adds ESA/Webb weic2205c
("Pan of the Carina Nebula, combined NIRCam + MIRI") as a new cosmos pool
member — the same Carina towers in the muted gray/teal/gold MIRI mid-infrared
palette, distinct from the iconic orange/blue flythrough.
- POOLS["cosmos"] grows 4 -> 5 (cosmos, cosmos_miri, galaxies, hudf, xdf);
primary unchanged.
- META + LABELS authored (nebula/star/distance, salience-gated); affect inherits
the cosmos scale vocabulary.
- manifest.json regenerated (19 -> 20 clips).
- Source: 4K master, text-free/human-free, trim 4-26s (clears the fade-from-
black), 1 s crossfade-loop (~21 s) -> 1080p base + 4K master (gitignored).
- docs/content-candidate-pool.md updated (cosmos pool of 5 + sourcing note).
271 passed, 2 skipped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The affect channel previously gated on BOTH knobs (strength = min(left, right)),
so the analytical Left brain co-controlled the emotion words. Per operator
direction, emotions are now driven by the Right (dreamlike) knob ALONE — Left no
longer gates them. This sharpens the split: Left = measurement (detections +
measurements), Right = the dream AND the feeling it evokes.
- player/alteration.py: `_affect_strength(right) = right` (was min(left,right));
`_affect_intensity` keyed off Right. AffectOverlay + is_identity docs updated
(is_identity still holds: right>0 ⇒ dream.strength>0).
- simulator/static/app.js: renderAffect comments (gating is Right via `strength`);
the client logic already keyed min_level/tier off the passed strength + right.
- Affect design spec: revision note + every min(left,right) → right.
- Tests rewritten: affect is Right-driven (full Right + Left 0 surfaces affect;
Right 0 + Left 4 surfaces none).
271 passed, 2 skipped. Live API verified: left=0/right=4 → strength 4; left=4/
right=0 → strength 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Operator found the Orion SVS 30957 flythrough merely good and asked for a more
dramatic nebula. Replaces the cosmos-scale primary with STScI's "Exploring the
Cosmic Cliffs in 3D" (Carina Nebula, Webb NIRCam — NASA SVS 31348), sourced from
its 4K master (Clifs-3d-STScI.mp4, 3840x2160) via the content pipeline:
trim 10-34s (clears the title card ~8s and end-credit card ~102s) + crossfade-loop
-> 4K master + supersampled 1080p base (5.5 Mbps, crisper than the old 2.9 Mbps
1080p-native Orion encode).
- build_pool_manifest META: cosmos -> SVS 31348 Cosmic Cliffs, new CCBY_WEBB
credit (NASA, ESA, CSA, STScI). Labels retuned for the Carina framing
(emission nebula / protostar; redshift -> distance ~7,500 ly).
- Regenerated manifest.json (also corrects stale JPL-Orion provenance left when
129bb23 updated META but not the manifest) + all ring-edge transitions from the
new base (cosmos-orbit / abyss-cosmos now zoom from the Cosmic Cliffs).
- docs/content-candidate-pool.md: record the swap + history.
269 passed, 2 skipped. New base verified text-free + full-frame by-eye across the
loop; final look to be confirmed by the operator (no Chrome on the box).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the JPL "Orion: Dust and Death" primary (captioned throughout — we'd
cropped it, losing framing) with STScI's "Flight Through the Orion Nebula"
(visible light, NASA SVS 30957) — a full-frame, text-free flythrough of the same
nebula. Sourced via the content pipeline (trim 10–34s + crossfade-loop → 1080p
master + base); cosmos-orbit / abyss-cosmos transitions regenerated from it.
- build_pool_manifest META: cosmos -> SVS 30957, license CC-BY-class (NASA/ESA/
STScI), new trim window.
- Remove the now-obsolete decaption_cosmos() crop helper (the new source needs
no caption removal).
- docs/content-candidate-pool.md: record the source swap; drop the crop note.
269 passed, 2 skipped. New clip verified text-free + full-frame by-eye;
final look to be confirmed by the operator.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The cosmos primary is NASA/JPL's "Orion: Dust and Death" — an annotated
visualization with lower-third captions ("DUST FILAMENT", "BLUE BUBBLE", …)
burned in throughout, so trimming can't avoid them (only ~4s of our window is
caption-free). The candidate-pool doc wrongly called it text-free.
- build_pool_manifest.decaption_cosmos(): crops the cosmos base/master to the
top 66% of frame height (16:9 preserved, center-x, ~1.5x tighter framing),
re-fit to 1920x1080 — the recorded, reproducible form of the fix (media is
gitignored). Applied in place; re-ran generate_media() so the cosmos-orbit /
abyss-cosmos transitions use the cropped base.
- docs/content-candidate-pool.md: correct the "text-free" note; document the crop.
269 passed, 2 skipped. De-caption verified by-eye on both caption moments;
final look to be confirmed by the operator.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a single "Dev Mode" switch at the bottom of the control panel (off by
default, persisted in localStorage). When on, a panel appears below it with all
dev controls and data; when off the default view is just the experience + the
three control fieldsets.
Dev panel:
- Pool picker: a <select> of the current altitude's pool members — choose any
clip to override the random landing pick; a "Re-roll random" button re-runs
the server-canonical pick. Rebuilds on each landing.
- Active clip metadata (id, title, source, license, base_file).
- Annotations & affect: keys with salience/window/tier counts (read-only;
editing stays in /author.html).
- RenderPlan JSON — relocated here from the always-visible panel.
- Cache & playback: preload status (N/total), memory-vs-network for the active
clip, live resolution/duration/loop position.
Frontend only — no API changes; everything is read from data the renderer
already has. Factored pickRandomMember() out of landScale() so the initial
landing, ring advances, and the re-roll button share one pick.
Design: docs/superpowers/specs/2026-06-25-simulator-dev-mode-design.md
269 passed, 2 skipped; node --check + server smoke clean. Frontend behavior
to be verified by-eye by the operator (no headless browser in repo yet).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Content-pipeline Increment 2, part 2 (the tooling). Implements design §11.5
(docs/superpowers/specs/2026-06-24-content-pipeline-design.md):
- tools/pipeline/track.py — the stage-5 geometry pass. Classical path: a
hand-seeded normalized box propagated by OpenCV Lucas-Kanade optical flow
(CSRT used instead when a contrib build provides it), sampled to a SPARSE
loop-normalized keyframed track + an appear/disappear window. Optional ML
detect+track path lazy-imports ultralytics (clear ImportError if absent;
base install needs only cv2). Pure helpers (normalize/denormalize, loop_t,
infer_window, sample_track, track_to_annotation) are unit-tested; the cv2
propagation is an opt-in integration test on real abyss_wow footage.
Semantics are never produced here — geometry only.
- Author mode — /author.html + author.js/.css reuse the preview stage: pick a
pool clip, scrub, drag a seed box, Run tracker (or Add as static box), author
the LEFT detail tiers (general -> scientific+fact) + salience, shift-click to
place affect anchors with RIGHT emotion tiers, and Save to manifest. Backend:
POST /api/author/track (runs track_seed on the clip's base) + POST
/api/author/clip (idempotent upsert via tools.pipeline.manifest — keeps media
+ provenance, replaces only authored content, reloads in place). The tracker
propagates box geometry; all strings/scientific names/facts are hand-typed.
- Repointed the pipeline integration test off the retired forest base to the
cosmos pool primary. USER_GUIDE simulator section brought current (pools,
coast, 3-knob Mood, real-time dream, progressive tiers, author mode).
267 passed / 2 skipped (+ track pure + opt-in real-footage + author endpoint
tests). Author UI by-eye review deferred to the operator (no Chrome on this box).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Content-pipeline Increment 2, part 1 (the experience). Implements design §11
(docs/superpowers/specs/2026-06-24-content-pipeline-design.md):
- Rotating pool (§11.1): each ring scale references a POOL of vetted clips
(docs/content-candidate-pool.md); the player picks a random member on landing.
player.ring.Scale gains `pool` + pure `pick_clip_id(scale, r)` (injected
randomness); the pick happens at the API boundary (random.random()), a delta=0
advance is the initial/re-roll pick. clips.py parses/exposes the pool; the
client lands on move.target_clip_id. Back-compat: a scale with only clip_id is
a pool of one.
- Rename ring scale forest -> coast (new land<->sea scale, orbit..reef); ring
order cosmos -> orbit -> coast -> reef -> abyss -> wrap. Cleanup: dropped the
leftover local media (cosmos_traverse, orbit_westcoast, old forest/reef, the
Increment-1 orbit/abyss single bases); new coast-edge transition placeholders.
- Time-windowed tracked labels (§11.2): annotations gain appear/disappear
(loop-normalized, wraps across the seam); a label shows only while on screen
and its box tracks the subject. abyss + reef pools authored as test material.
- Progressive LEFT detail tiers (§11.3): per-object `salience` (first shows at
Left 5-salience) + tiered strings (general -> specific -> scientific -> +fact)
escalating with the Left knob; replaces flat min_level gating. Strings may be a
tier list or a static string (back-compat). No engine change (client reads
overlay.level).
- Progressive RIGHT emotion tiers (§11.4): affect vocabulary escalates basic ->
compound with the Right knob (dream.strength); appearance still gated by
min(left,right). No engine change.
New simulator/build_pool_manifest.py holds the hand-authored content and emits
the 19-clip pool manifest (the reproducible baseline). setup_scales_media.py
marked superseded. 251 passed / 4 skipped (+ ring pool + API pool/window tests).
By-eye visual review deferred to the operator (no Chrome on this box).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Records the 5-scale rotating clip pools the operator selected + vetted from the
candidate gallery (19 clips: cosmos 4, orbit 3, coast 4, reef 5, abyss 3), each
strict-PD/CC-BY-class, word-free, human-free, with source URL + trim window so
they are re-sourceable (media stays gitignored). Captures: the rotating-pool model
(random clip per scale on ring landing), the forest→coast rename, the cosmos
#3-Orion vs #6-Traverse processing mix-up to fix, and the rejected/leftover clips
to clean up. Feeds the next session (Increment 2 expanded: pool wiring + tracked
progressive labels + progressive emotions).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bite-sized TDD plan for Increment 1 (real footage, no ML): the deterministic
tools/pipeline/ package (frame → crossfade-loop → master+proxy transcode →
manifest assembly, pure ffmpeg arg builders unit-tested + an opt-in integration
test on the real forest POC base), the backward-compatible keyframed annotation
track schema with client-side interpolation, and the 5-scale ring (orbit + reef).
9 tasks. Implements spec §3 (stages 1–4,6), §4, §5, §6, §7, and §8 Increment 1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Brainstormed + scoped the content pipeline that turns strict-PD source clips into
shippable, seamless-looping, labelled neutral bases for the scale ring.
Decisions settled this session:
- Scale set: lean 5 (cosmos · orbit · forest/land · reef · abyss; microscopic dropped)
- Loop: crossfade tail→head seam
- Labels: motion-tracked, hybrid (ML proposes where it can, hand-seed + classical
tracker elsewhere); label semantics always hand-authored
- Format: master + 1080p H.264 proxy
Anchor fact: the Right dream is real-time (no per-clip ML bake, session 0013), so
the pipeline is transcode + authoring — the one offline ML step is the chosen
motion-track pass. Six stages + an optional keyframed annotation-track schema
(backward compatible) + a 2-increment rollout (real footage no-ML first, then the
hybrid track pass + simulator author mode). i2v ring transitions + Pi/pano deferred.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the pre-baked SD restyle variants (too fluid — the painting re-rolled
every keyframe and the flow-warp melted frames) with a deterministic, real-time
dream that holds STILL across the loop; only the footage's own motion moves.
Design: docs/superpowers/specs/2026-06-22-right-axis-deterministic-dream-design.md
Engine (player/alteration.py): Restyle(variant) -> Dream(strength, intensity);
Calibration.right_variant_map -> dream_gain. player/state.py: a Right change is a
LIVE_UPDATE now, not a crossfade (only a clip swap crossfades). Plan dict
restyle -> dream. Tests migrated; 233 green. (No new Python behavior for the
client-render swap below.)
Renderer (simulator front-end): the Right dream is a WebGL2 Kuwahara shader on a
<canvas> over the live video — edge-preserving, so motion/structure stay crisp;
the dream is the same footage, just stylized (no blur). Ramped by the knob; max
goes "trippy" (vivid saturation + ~45deg hue drift + posterize, concentrated near
max via t=intensity^2). Phase-1 luminous-haze (CSS+bloom) was built then retired
by eye (blur read as out-of-focus video). Mood grade rides as a CSS filter on the
canvas; bloom layer removed.
Dev ergonomics that fell out of the iteration:
- /dev/version + a 1s client poll = live-reload (open tab never runs stale
renderer code; reloads on my edits AND server restarts).
- no-cache on the dev server; an on-screen error banner + crash-proof render so a
silent throw can't masquerade as "nothing is changing".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Left-brain HUD look-and-feel pass (judged by eye in the sim):
- corner-bracket targeting reticles (capped arms) replace plain boxes
- translucent label chips, legible over any frame
- two sensor channels: cyan detections (with deterministic confidence
scores) vs amber measurements (center crosshair)
- bbox-sized "ANALYSIS . L{n} . {k} OBJ" status tag, escalating with Left
Affect channel (emotions in the HUD), per
docs/superpowers/specs/2026-06-22-affect-channel-hud-design.md:
- surfaces only when BOTH knobs up; strength = min(left, right)
- stable per-scene palette, more words appear with combined strength
- soft glowing violet words on their own opacity layer (the dream
leaking into the machine's read); math in player/alteration.py
- forest/cosmos/abyss palettes in the manifest; 5 new unit tests
Simulator no-cache middleware so by-eye iteration never serves a stale
app.js / api response (fixes the latent "plan has affect but clip.affect
empty" stale-/api/clips bug).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ran the baker for the forest scale: real flow-stabilized painterly Right variants
1-4 now back the dreamlike axis on real Yosemite footage (was: 1 real + 3 ffmpeg
placeholders). By-eye finding this surfaced: sd-turbo's painterly transform is
sharply non-linear in img2img strength (barely registers <0.5, ramps hard through
~0.5-0.65), so the initial linear 0.28-0.58 ramp left levels 1-3 ~identical to
raw. Re-baked with a clustered 0.46/0.52/0.58/0.64 curve -> a real perceptual
ramp: gentle dream haze -> clearly impressionist -> strongest, each notch visibly
dreamier, temporally calm (flow-stabilized).
- manifest: forest right_variants 1-4 all model 'sd-turbo+farneback-flow'
- setup_sample_media.py: now only stages the neutral base; the baker owns the
Right variants, so re-running it never clobbers a real bake
- docs: USER_GUIDE setup steps + ROADMAP v2v vertical-slice-done note
Suite 228 passed / 2 skipped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A multi-detent encoder spin previously chained one full transition per scale
crossed (e.g. +5 ≈ 5 placeholder morphs ≈ 12-15s), which feels sluggish for a
fast spin. Design §3 anticipates this: "transitions chain, or past a speed
threshold a faster blended pass is used."
`player.ring.advance_ring` gains an opt-in `fast_spin_threshold` (canonical
default `DEFAULT_FAST_SPIN_THRESHOLD = 3`). A spin batches its detents into one
advance() call, so `abs(delta)` is the input layer's proxy for spin speed; at or
above the threshold the move collapses to a single blended pass — one
`TransitionStep` (the arrival edge, marked `blended`, landing straight on the
destination, `RingMove.fast=True`) instead of the full chain. Landing index,
seam-crossing (`wrapped`), and arrival edge/direction are exactly the full
chain's; only the in-between transitions are dropped.
The policy is opt-in (default off) because the pure function cannot observe
wall-clock spin speed — the simulator/firmware, which can, enables it. This keeps
all existing complete-chain behavior and tests intact. The simulator passes the
default threshold and plays the blended step at 2.5× (FAST_BLEND_RATE); a
dedicated fast-blend clip can replace the accelerated arrival-edge placeholder
when real transition media exists.
- player/ring.py: TransitionStep.blended, RingMove.fast, threshold param + policy
- simulator/clips.py: serialize fast/blended in ring_move_to_dict
- simulator/app.py: apply DEFAULT_FAST_SPIN_THRESHOLD at /api/ring/advance
- simulator/static/app.js: play a blended step at FAST_BLEND_RATE
- docs: scales design §3, USER_GUIDE, ROADMAP slice-3 note
Tests: +9 (ring policy, serializer, API). Suite 224 passed / 2 skipped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add scale-ring navigation to the simulator per the scales-library design §3:
an endless rotary-encoder control (relative, vs the absolute 0-4 experience
knobs) walks a closed ring of neutral "scales of nature" clips, with placeholder
AI zoom/warp transitions between adjacent scales and a small->large wrap (the
infinite-zoom payoff).
- player/ring.py (new, canonical pure logic): ScaleRing + advance_ring; one
transition clip per edge, played forward zooming inward / reversed outward;
modulo wrap both ways; chained steps for a multi-detent spin. Mirrors
player/content.py conventions (frozen dataclasses, pure functions).
- simulator: load_ring + ring_to_dict/ring_move_to_dict; GET /api/ring and
POST /api/ring/advance (Python owns step/wrap/transition math; the browser
only plays the returned transition(s) then settles on the target scale).
- frontend: endless-encoder control (zoom in/out buttons + stage scroll),
current-scale readout, multi-clip active-scale selection, transition playback.
- media: two cheap true-PD scales so the ring is demonstrable -- cosmos
(NASA/Hubble) + abyss (NOAA Ocean Exploration), provenance recorded in the
manifest, bytes generated as labelled placeholders by setup_scales_media.py.
The expensive multi-strength flow-stabilized Right re-bake is DEFERRED (new
scales carry a raw base only) until the ring is liked; Pi renderer +
serial/firmware remain deferred (simulator-first).
- docs: ROADMAP slice-3 done; USER_GUIDE scale-ring gesture; plan doc.
Verified: pytest 215 passed / 2 skipped (+22 new); sim boots, /api/ring +
/api/ring/advance correct incl. wrap, media served, and a headless-Chrome CDP
drive walked cosmos -> forest -> abyss -> (wrap) -> cosmos with the active clip
reloading correctly.
Spec: docs/superpowers/specs/2026-06-07-scales-library-and-right-axis-pipeline-design.md (§3)
Plan: docs/superpowers/plans/2026-06-07-scale-ring-navigation.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tuning the look by eye in the simulator (design §8) surfaced that the dark
mood pole rendered a full-frame hue-rotate(-200deg) — rock orange, trees
purple: the disorienting look rejected in session 0008, not the peaceful POC
dark_frame. Replace it with darken + slight desaturate on the video filter
plus a multiply-blended deep-blue wash (#tint, below the SVG HUD so the
overlay stays legible). Dark now reads cool/somber with natural greens, like
the approved POC look; light/left/right unchanged and confirmed peaceful.
With full tilt now tasteful on every axis, LOCK DEFAULT_CALIBRATION to unity
gains + linear variant map as a deliberate by-eye choice (not placeholders),
closing the open session-0006 knob->strength decision: knobs run 0=off..4=max,
equal Dark/Light = identity, the 5 notches map 1:1 to the 5 discrete Right
bakes. Guard the locked constants with test_default_calibration_is_locked.
Resolves design §8 open questions (calibration curve shape; grade-vs-overlay
ordering) and records the dark-grade fix. Full suite 193 passed / 2 skipped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bring the unmerged session-0007 simulator-alteration-preview design onto a
single thread and add the reconciliation design that resolves the load-bearing
Left-HUD conflict between it and the merged session-0008 scales-library /
right-axis design.
Decision (operator-approved): Left is a RUNTIME overlay (authored annotation
track + per-language string tables, shaped live — browser in the sim, Pango/
HarfBuzz on the Pi), not baked pixels. Consequently the pre-baked variant set is
1-D over Right strength, not 0007's 2-D 5x5 Left x Right grid; 0007's baked-HUD
position (its sec 4/5/8) is superseded. Engine change is surgical — the merged
slice-1 engine already keeps a runtime AnalyticalOverlay.
Scopes the first simulator-runnable slice: deterministic Dark/Light/Left +
discrete pre-baked flow-stabilized Right variants over ONE neutral clip, wired
into the simulator, with a parameterized Calibration tuned by eye.
Spec: docs/superpowers/specs/2026-06-07-reconciled-simulator-alteration-slice-design.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Design revision refining the machine-altered-perception design (2026-06-05):
- Right axis is a LOCAL offline restyle (SD img2img on MPS), not a cloud API
(refines §4.1/§4.3, §9). Per-frame restyle boils/flickers — disqualifying for
a peaceful piece — so temporal coherence is now a hard constraint, met by
optical-flow keyframe propagation (the EbSynth principle, OpenCV impl).
- Content = a small NEUTRAL "scales of nature" library (~4-6 clips, one per
scale), not a single stitched cosmic-zoom film; keeps the neutral-base thesis
and interactivity while retaining the awe-of-scale richness (refines §6/§8).
- NEW: the scales form a navigable closed RING joined by short AI zoom/warp
transitions, driven by an infinitely-turnable endless rotary encoder; diving
past the microscopic wraps around to the cosmos (refines §2 selector / §11).
- i18n sharpened (§1.2, sharpens §10): Left labels are a Pi-rendered runtime
graphics overlay (annotation-track + per-language string tables, shaped via
Pango/HarfBuzz + Noto) — NOT a baked per-language overlay video, which would
break i18n economics. Added Pi-resolution headroom to open questions.
- Strict-PD sourcing map (NASA/NOAA/NPS/USGS); non-US terrestrial is the CC-BY
soft spot. Economics: local authoring is ~free, not $300-3k of cloud API.
Grounded in a local POC this session (M4 Pro, sd-turbo, OpenCV flow): all four
axes validated on real footage; deterministic axes ~2.4s, Right flow-propagated
~2.7min/8s clip and calm.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Revise the Human Experience Filter design: the piece becomes about how
humans interact with machines and how that reshapes the nervous system.
Neutral public-domain nature footage in, machine-altered perception out —
soothing or disturbing, good and bad.
Supersedes the 2026-06-04 design's thesis (§1), selection model (§3 — now
"transform from neutral", not catalog lookup), tagging division (§5), and
sourcing (§8); expands the control panel and hardware (§2/§6). Coordinate
axes and the single-pano projector are preserved.
Captures: the per-axis alteration mapping (Left=analytical overlay,
Right=generative v2v dissolve, Dark/Light=color grade), the substrate-vs-
overlay composition rule, the Light=yellow/white → neutral grey →
Dark=blue/black mood ramp, the 6-way content dial + volume/brightness, the
tactile/braille/LED/read-aloud wooden panel, and the runtime-overlay
architecture that makes multilingual labels nearly free.
Per docs/ROADMAP.md (reshapes sub-projects 2/3/4 + adds an offline v2v
authoring pipeline). Discovery session 0005.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>