content(sim): rotating clip pools + progressive tracked labels & emotions
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>
This commit is contained in:
+30
-1
@@ -50,10 +50,25 @@ class RingError(ValueError):
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Scale:
|
||||
"""A node on the ring: a scale of nature and the base clip it plays."""
|
||||
"""A node on the ring: a scale of nature and the clip(s) it can play.
|
||||
|
||||
A scale carries a rotating POOL of vetted clips (content-pipeline design
|
||||
§11.1): when the viewer lands on the scale, the player picks one member at
|
||||
random (`pick_clip_id`). `clip_id` is the PRIMARY member (the deterministic
|
||||
default / pool[0]); `pool` is the full set. A scale written with only
|
||||
`clip_id` and no `pool` is a pool of one — exactly the Increment-1 behavior,
|
||||
so old manifests are unchanged.
|
||||
"""
|
||||
|
||||
id: str
|
||||
clip_id: str
|
||||
pool: tuple[str, ...] = ()
|
||||
|
||||
@property
|
||||
def members(self) -> tuple[str, ...]:
|
||||
"""The clip ids this scale can play — the pool, or just `clip_id` when
|
||||
no pool was authored (a pool of one)."""
|
||||
return self.pool if self.pool else (self.clip_id,)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -134,6 +149,20 @@ def scale_at(ring: ScaleRing, index: int) -> Scale:
|
||||
return ring.scales[index % len(ring)]
|
||||
|
||||
|
||||
def pick_clip_id(scale: Scale, r: float) -> str:
|
||||
"""Pick one clip id from a scale's rotating pool, given an injected uniform
|
||||
`r` in [0, 1) (content-pipeline design §11.1).
|
||||
|
||||
Randomness is INJECTED so this stays a pure function — testable and shared
|
||||
with the Pi player; the impure draw (`random.random()`) happens once at the
|
||||
API/runtime boundary. `r` is clamped into [0, 1) so an off-by-epsilon caller
|
||||
never indexes out of range; a pool of one always returns its single member.
|
||||
"""
|
||||
members = scale.members
|
||||
r = min(max(r, 0.0), 0.999999)
|
||||
return members[int(r * len(members))]
|
||||
|
||||
|
||||
def advance_ring(
|
||||
ring: ScaleRing,
|
||||
from_index: int,
|
||||
|
||||
Reference in New Issue
Block a user