diff --git a/docs/superpowers/specs/2026-06-22-affect-channel-hud-design.md b/docs/superpowers/specs/2026-06-22-affect-channel-hud-design.md new file mode 100644 index 0000000..87ce6fe --- /dev/null +++ b/docs/superpowers/specs/2026-06-22-affect-channel-hud-design.md @@ -0,0 +1,85 @@ +# Affect channel — emotions in the Left-brain HUD + +**Status:** approved (session 0013, 2026-06-22) +**Surface:** simulator preview (`simulator/`, `player/alteration.py`) +**Builds on:** the machine-altered-perception design SPEC; the Left HUD look-and-feel +pass (same session). + +## Idea + +A third HUD channel beside the cyan *detections* and amber *measurements*: soft, +glowing **emotion-words** that surface the feelings the experience may invoke. +They appear only when *both* the analytical (Left) and dreamlike (Right) knobs are +up — the dream leaking into the machine's reading. This is the uncanny edge of the +thesis: the machine trying to quantify not just what is there, but how you are +meant to feel. + +## Behaviour + +- **Trigger / intensity.** Affect strength = `min(left, right)` (0–4). Either knob + at 0 → no emotions at all. Opacity scales with that strength × `overlay_gain`. +- **Escalation.** A **stable emotional palette per scene** — higher combined + strength reveals *more* words at higher opacity. Each word carries a `min_level` + (the same mechanic the detection channel uses), but compared against the + *combined* `min(left, right)` strength rather than Left alone. +- **Rendering.** Floating words at authored scene positions — **no boxes or + reticles**, lowercase, semi-transparent with a soft glow, in a distinct **violet** + register so they read as affective and clearly *softer* than the hard clinical + reticles. + +## Where the math lives + +Consistent with the existing split (alteration math in Python, label-selection in +the client): + +- `player/alteration.py` gains an `AffectOverlay(strength, intensity)` on the + `RenderPlan`. `strength = min(left, right)`; `intensity = clamp(overlay_gain * + min(left,right) / KNOB_MAX, 0, 1)`. Returned in `render_plan_to_dict` under + `"affect"`. Pure, unit-tested. +- The simulator client picks *which* words to show by comparing each affect + entry's `min_level` to `plan.affect.strength`, and renders them at + `plan.affect.intensity` opacity. + +`is_identity` is unaffected: `min(left,right) > 0` implies `left > 0`, which already +makes `overlay.level > 0`. + +## Data + +New optional per-clip `affect` list in the manifest, parallel to `annotations`: + +```json +"affect": [ + {"key": "feel.awe", "at": [0.5, 0.4], "min_level": 1}, + {"key": "feel.serenity", "at": [0.2, 0.62], "min_level": 2} +], +"strings": {"en": {"feel.awe": "awe", "feel.serenity": "serenity"}} +``` + +`at` is a normalized `[x, y]` anchor point (not a box — feelings are scene-level). +The words live in the existing `strings.en` map. `Clip` gains an `affect` field +(defaulting to `[]`) threaded through `_clip_from_dict` and `to_dict`. + +Starter palettes (words are art-direction, easily tuned): + +| scale | palette (min_level 1 → 4) | +|--------|-----------------------------------------------| +| forest | awe · serenity · reverence · stillness | +| cosmos | wonder · vastness · insignificance · longing | +| abyss | unease · fascination · isolation · dread | + +All three scales carry the data; forest is fully realized (it has the real Right +variants). + +## Testing + +- Python unit tests: affect `strength = min(left, right)` across knob combos; + intensity scaling and `overlay_gain`; `0` when either knob is 0; presence in the + serialized plan. +- By-eye in the live simulator (forest, Left & Right both up) — the established + judge-by-eye loop for this surface. + +## Out of scope + +- No drift-toward-unsettling arc (rejected in favour of a stable palette). +- No per-object emotion tags; no animated drift (words are statically placed for + v1; gentle motion can come later if wanted). diff --git a/docs/superpowers/specs/2026-06-22-right-axis-deterministic-dream-design.md b/docs/superpowers/specs/2026-06-22-right-axis-deterministic-dream-design.md new file mode 100644 index 0000000..2ac9a89 --- /dev/null +++ b/docs/superpowers/specs/2026-06-22-right-axis-deterministic-dream-design.md @@ -0,0 +1,109 @@ +# Right axis as a real-time deterministic dream + +**Status:** built (session 0013, 2026-06-22) — Phase 1 superseded by Phase 2 in the +same session after by-eye review (the haze "looked like blurred video, not stylized"). +The shipped Right dream is the **Phase 2 painterly** path. +**Surface:** simulator preview (`simulator/`, `player/alteration.py`) +**Supersedes:** the "discrete pre-baked, flow-stabilized restyle variant" definition +of the Right axis in the machine-altered-perception design SPEC §4.1 — a deliberate +change to a core decision (see Why). + +## Why + +The pre-baked SD img2img variants (`bake_right_variants.py`) are **too fluid**: the +painting re-rolls every keyframe (~2 s) and the optical-flow tween warps frames into +each other, so across the loop the dream churns and melts. The right brain should be +a **still altered state** — a calm, holistic counterpart to the busy, accreting +analytical Left — not a restless morph. + +## Concept + +The Right knob no longer selects a pre-baked variant. It drives a **deterministic, +real-time filter** applied live to the base footage, scaled 0→4. The same filter runs +every frame, so the look is **stable by construction** — locked to scene content, +moving only where the footage already moves. Bonus: no baked variant videos to ship, +which simplifies the eventual hardware (Pi) story. + +Staged delivery (both built this session; Phase 2 is what shipped): +- **Phase 1: luminous haze** — soft-focus, blooming highlights, pastel desaturation. + CSS + a bloom layer. Built, then **retired** by eye: blur reads as *out-of-focus + video*, not stylized, and softens the base's crisp motion. +- **Phase 2: painterly flatten (shipped)** — a WebGL2 **Kuwahara** shader on a + `` restyling the live video frames. Edge-preserving, so motion/structure + stay as crisp as the source — the dream is the same footage, just stylized. No blur. + +## Phase 2 — the shipped painterly dream + +- **Renderer:** `` over `