Epic 5 Phase 0 — actors have bodies; the stage has depth
ActorGenerator is the cast with bodies: generateActor{mpl} takes
{summary,rng,archetype,personality,identity} and returns a serialisable
ActorSpec — same audio-tilts-centre / seed-picks-within rule as
Personality/Identity, forked rng so adding an actor never shifts later
decisions. Five archetypes (monolith/swarm/walker/vehicle/structure),
per-track actor set on look.actors, HUD helper included. Stage C will
grow as a library on this without infra changes.
Mesh twin of Identity.form: actors/meshes.js builds BufferGeometry from
the same assembly (cast SDF → Shape → ExtrudeGeometry, box/capsule/
torus/sphere primitives, symmetry folding radial/mirror/stack). Shared
with the shader impostor path — one character, two projectors.
Renderer depth targets: createDepthTarget / createTarget{depthTexture}
for WebGL DepthTexture plumbing.
Compositor shared rig: one PerspectiveCamera + DepthTexture so a ground
mesh can occlude a subject mesh from another layer. 4/scale dolly,
Personality.camera drift/sway/spin, framing shift — matches particles.js
and shader epilogue behaviour. ModelLayer (kind:model) with
build/update(actorSpec) and sharedCamera injection; createLayer dispatches
on model. Shader contract gains MODEL_PREAMBLE.
LookGenerator now derives actors before scenes; ArcDriver._actorFor +
_layerFor wires ActorSpec into ModelLayer; schema validates kind:model
and actor archetype; lint determinism gate covers actors/.
Gate: lint 107 files clean, 70 shader literals, 68 scenes green; vite
build 294 modules; ActorGenerator determinism + mesh smoke tests pass.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -221,20 +221,32 @@ export class ArcDriver {
|
||||
return stack[slot] || null;
|
||||
}
|
||||
|
||||
/** Resolve the ActorSpec for a layer, if the module requests one. */
|
||||
_actorFor(module) {
|
||||
const actors = this.look.actors;
|
||||
if (!actors || !module || !module.actor) return null;
|
||||
return actors[module.actor] || null;
|
||||
}
|
||||
|
||||
/** One Layer per (section, variant, layer slot), built lazily and kept. */
|
||||
_layerFor(sectionIndex, variant, slot = 0) {
|
||||
const key = `${sectionIndex}:${variant}:${slot}`;
|
||||
let layer = this.layerCache.get(key);
|
||||
if (!layer) {
|
||||
const spec = this._specFor(sectionIndex, variant, slot);
|
||||
const actorSpec = this._actorFor(spec.module);
|
||||
layer = createLayer(spec.module, {
|
||||
params: spec.params,
|
||||
seed: spec.seed,
|
||||
opacity: spec.opacity,
|
||||
blend: spec.blend,
|
||||
actorSpec,
|
||||
});
|
||||
layer.setPalette(this.look.palette);
|
||||
layer.setPersonality(this.look.personality);
|
||||
// ModelLayers can have their actor swapped without being rebuilt — the
|
||||
// mesh is imposter-free so the geometry can be re-bound live.
|
||||
if (actorSpec && layer.setActor) layer.setActor(actorSpec);
|
||||
this.layerCache.set(key, layer);
|
||||
}
|
||||
return layer;
|
||||
|
||||
@@ -25,6 +25,7 @@ import { derivePaletteArc, describePaletteArc } from './paletteArc.js';
|
||||
import { deriveFramingStyle, describeFraming } from './framing.js';
|
||||
import { deriveCamera, describeCamera } from './Camera.js';
|
||||
import { deriveStory, storyForSection, NEUTRAL_STATE } from './Story.js';
|
||||
import { generateActorSet, describeActorSet } from '../actors/ActorGenerator.js';
|
||||
|
||||
// Which families suit which section kind now comes from the track's DIRECTOR
|
||||
// (look/directors.js) rather than from a constant here. The coupling it
|
||||
@@ -816,6 +817,10 @@ export function generateLook(track, {
|
||||
// toward one camera the way it leans toward one family per kind, and the
|
||||
// seed decides — see look/Camera.js.
|
||||
const camera = deriveCamera(director, summary, rng.fork('camera'));
|
||||
// The cast with bodies — one ActorSpec per archetype, seeded so a later
|
||||
// library of actors (Stage C) grows without changing the infra. See
|
||||
// src/actors/ActorGenerator.js — audio tilts the centre, seed picks within.
|
||||
const actors = generateActorSet(summary, rng.fork('actors'), personality, personality.identity);
|
||||
const { post, feedback } = derivePost(summary, rng.fork('post'), grain);
|
||||
|
||||
// Scenes eligible to be composited OVER a background. Same casting rule as
|
||||
@@ -887,6 +892,7 @@ export function generateLook(track, {
|
||||
paletteArc,
|
||||
framing,
|
||||
camera,
|
||||
actors,
|
||||
grain,
|
||||
post,
|
||||
feedback,
|
||||
|
||||
Reference in New Issue
Block a user