@sadhaka/loom-engine 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +344 -0
- package/dist/animation/animation-clip.d.ts +12 -0
- package/dist/animation/animation-clip.d.ts.map +1 -0
- package/dist/animation/animation-clip.js +85 -0
- package/dist/animation/animation-clip.js.map +1 -0
- package/dist/animation/animation-state-pool.d.ts +25 -0
- package/dist/animation/animation-state-pool.d.ts.map +1 -0
- package/dist/animation/animation-state-pool.js +113 -0
- package/dist/animation/animation-state-pool.js.map +1 -0
- package/dist/asset/sprite-sheet-loader.d.ts +41 -0
- package/dist/asset/sprite-sheet-loader.d.ts.map +1 -0
- package/dist/asset/sprite-sheet-loader.js +313 -0
- package/dist/asset/sprite-sheet-loader.js.map +1 -0
- package/dist/audio/audio-bus.d.ts +43 -0
- package/dist/audio/audio-bus.d.ts.map +1 -0
- package/dist/audio/audio-bus.js +258 -0
- package/dist/audio/audio-bus.js.map +1 -0
- package/dist/combat/mob-catalog.d.ts +29 -0
- package/dist/combat/mob-catalog.d.ts.map +1 -0
- package/dist/combat/mob-catalog.js +104 -0
- package/dist/combat/mob-catalog.js.map +1 -0
- package/dist/components/health.d.ts +28 -0
- package/dist/components/health.d.ts.map +1 -0
- package/dist/components/health.js +150 -0
- package/dist/components/health.js.map +1 -0
- package/dist/components/interactable.d.ts +30 -0
- package/dist/components/interactable.d.ts.map +1 -0
- package/dist/components/interactable.js +94 -0
- package/dist/components/interactable.js.map +1 -0
- package/dist/components/particle-emitter.d.ts +62 -0
- package/dist/components/particle-emitter.d.ts.map +1 -0
- package/dist/components/particle-emitter.js +193 -0
- package/dist/components/particle-emitter.js.map +1 -0
- package/dist/components/pursue.d.ts +23 -0
- package/dist/components/pursue.d.ts.map +1 -0
- package/dist/components/pursue.js +96 -0
- package/dist/components/pursue.js.map +1 -0
- package/dist/components/ranged-attack.d.ts +44 -0
- package/dist/components/ranged-attack.d.ts.map +1 -0
- package/dist/components/ranged-attack.js +120 -0
- package/dist/components/ranged-attack.js.map +1 -0
- package/dist/components/sprite.d.ts +27 -0
- package/dist/components/sprite.d.ts.map +1 -0
- package/dist/components/sprite.js +122 -0
- package/dist/components/sprite.js.map +1 -0
- package/dist/components/transform.d.ts +30 -0
- package/dist/components/transform.d.ts.map +1 -0
- package/dist/components/transform.js +150 -0
- package/dist/components/transform.js.map +1 -0
- package/dist/director/director-bridge.d.ts +22 -0
- package/dist/director/director-bridge.d.ts.map +1 -0
- package/dist/director/director-bridge.js +23 -0
- package/dist/director/director-bridge.js.map +1 -0
- package/dist/director/director-encounter-system.d.ts +21 -0
- package/dist/director/director-encounter-system.d.ts.map +1 -0
- package/dist/director/director-encounter-system.js +128 -0
- package/dist/director/director-encounter-system.js.map +1 -0
- package/dist/director/director-system.d.ts +19 -0
- package/dist/director/director-system.d.ts.map +1 -0
- package/dist/director/director-system.js +179 -0
- package/dist/director/director-system.js.map +1 -0
- package/dist/director/event-envelope.d.ts +144 -0
- package/dist/director/event-envelope.d.ts.map +1 -0
- package/dist/director/event-envelope.js +108 -0
- package/dist/director/event-envelope.js.map +1 -0
- package/dist/director/knot-context-resource.d.ts +25 -0
- package/dist/director/knot-context-resource.d.ts.map +1 -0
- package/dist/director/knot-context-resource.js +152 -0
- package/dist/director/knot-context-resource.js.map +1 -0
- package/dist/director/mock-director-bridge.d.ts +18 -0
- package/dist/director/mock-director-bridge.d.ts.map +1 -0
- package/dist/director/mock-director-bridge.js +75 -0
- package/dist/director/mock-director-bridge.js.map +1 -0
- package/dist/director/snapshot-recovery.d.ts +37 -0
- package/dist/director/snapshot-recovery.d.ts.map +1 -0
- package/dist/director/snapshot-recovery.js +180 -0
- package/dist/director/snapshot-recovery.js.map +1 -0
- package/dist/director/sse-director-bridge.d.ts +42 -0
- package/dist/director/sse-director-bridge.d.ts.map +1 -0
- package/dist/director/sse-director-bridge.js +280 -0
- package/dist/director/sse-director-bridge.js.map +1 -0
- package/dist/engine.d.ts +25 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +166 -0
- package/dist/engine.js.map +1 -0
- package/dist/entity.d.ts +17 -0
- package/dist/entity.d.ts.map +1 -0
- package/dist/entity.js +77 -0
- package/dist/entity.js.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/input/input-manager.d.ts +91 -0
- package/dist/input/input-manager.d.ts.map +1 -0
- package/dist/input/input-manager.js +349 -0
- package/dist/input/input-manager.js.map +1 -0
- package/dist/input/tap-to-walk.d.ts +27 -0
- package/dist/input/tap-to-walk.d.ts.map +1 -0
- package/dist/input/tap-to-walk.js +118 -0
- package/dist/input/tap-to-walk.js.map +1 -0
- package/dist/input/virtual-dpad.d.ts +34 -0
- package/dist/input/virtual-dpad.d.ts.map +1 -0
- package/dist/input/virtual-dpad.js +267 -0
- package/dist/input/virtual-dpad.js.map +1 -0
- package/dist/renderer/camera.d.ts +26 -0
- package/dist/renderer/camera.d.ts.map +1 -0
- package/dist/renderer/camera.js +39 -0
- package/dist/renderer/camera.js.map +1 -0
- package/dist/renderer/canvas2d-device.d.ts +26 -0
- package/dist/renderer/canvas2d-device.d.ts.map +1 -0
- package/dist/renderer/canvas2d-device.js +252 -0
- package/dist/renderer/canvas2d-device.js.map +1 -0
- package/dist/renderer/graphics-device.d.ts +36 -0
- package/dist/renderer/graphics-device.d.ts.map +1 -0
- package/dist/renderer/graphics-device.js +12 -0
- package/dist/renderer/graphics-device.js.map +1 -0
- package/dist/renderer/iso-projection.d.ts +11 -0
- package/dist/renderer/iso-projection.d.ts.map +1 -0
- package/dist/renderer/iso-projection.js +59 -0
- package/dist/renderer/iso-projection.js.map +1 -0
- package/dist/resources.d.ts +28 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +53 -0
- package/dist/resources.js.map +1 -0
- package/dist/system.d.ts +14 -0
- package/dist/system.d.ts.map +1 -0
- package/dist/system.js +25 -0
- package/dist/system.js.map +1 -0
- package/dist/systems/animation-system.d.ts +8 -0
- package/dist/systems/animation-system.d.ts.map +1 -0
- package/dist/systems/animation-system.js +77 -0
- package/dist/systems/animation-system.js.map +1 -0
- package/dist/systems/attack-system.d.ts +17 -0
- package/dist/systems/attack-system.d.ts.map +1 -0
- package/dist/systems/attack-system.js +94 -0
- package/dist/systems/attack-system.js.map +1 -0
- package/dist/systems/damage-system.d.ts +18 -0
- package/dist/systems/damage-system.d.ts.map +1 -0
- package/dist/systems/damage-system.js +77 -0
- package/dist/systems/damage-system.js.map +1 -0
- package/dist/systems/input-system.d.ts +7 -0
- package/dist/systems/input-system.d.ts.map +1 -0
- package/dist/systems/input-system.js +27 -0
- package/dist/systems/input-system.js.map +1 -0
- package/dist/systems/interaction-system.d.ts +23 -0
- package/dist/systems/interaction-system.d.ts.map +1 -0
- package/dist/systems/interaction-system.js +120 -0
- package/dist/systems/interaction-system.js.map +1 -0
- package/dist/systems/particle-emitter-system.d.ts +8 -0
- package/dist/systems/particle-emitter-system.d.ts.map +1 -0
- package/dist/systems/particle-emitter-system.js +161 -0
- package/dist/systems/particle-emitter-system.js.map +1 -0
- package/dist/systems/particle-render-system.d.ts +7 -0
- package/dist/systems/particle-render-system.d.ts.map +1 -0
- package/dist/systems/particle-render-system.js +53 -0
- package/dist/systems/particle-render-system.js.map +1 -0
- package/dist/systems/particle-simulation-system.d.ts +8 -0
- package/dist/systems/particle-simulation-system.d.ts.map +1 -0
- package/dist/systems/particle-simulation-system.js +45 -0
- package/dist/systems/particle-simulation-system.js.map +1 -0
- package/dist/systems/projectile-render-system.d.ts +7 -0
- package/dist/systems/projectile-render-system.d.ts.map +1 -0
- package/dist/systems/projectile-render-system.js +35 -0
- package/dist/systems/projectile-render-system.js.map +1 -0
- package/dist/systems/projectile-system.d.ts +7 -0
- package/dist/systems/projectile-system.d.ts.map +1 -0
- package/dist/systems/projectile-system.js +114 -0
- package/dist/systems/projectile-system.js.map +1 -0
- package/dist/systems/pursue-system.d.ts +7 -0
- package/dist/systems/pursue-system.d.ts.map +1 -0
- package/dist/systems/pursue-system.js +83 -0
- package/dist/systems/pursue-system.js.map +1 -0
- package/dist/systems/ranged-attack-system.d.ts +7 -0
- package/dist/systems/ranged-attack-system.d.ts.map +1 -0
- package/dist/systems/ranged-attack-system.js +98 -0
- package/dist/systems/ranged-attack-system.js.map +1 -0
- package/dist/systems/sprite-render-system.d.ts +9 -0
- package/dist/systems/sprite-render-system.d.ts.map +1 -0
- package/dist/systems/sprite-render-system.js +108 -0
- package/dist/systems/sprite-render-system.js.map +1 -0
- package/dist/systems/veil-budget-system.d.ts +7 -0
- package/dist/systems/veil-budget-system.d.ts.map +1 -0
- package/dist/systems/veil-budget-system.js +37 -0
- package/dist/systems/veil-budget-system.js.map +1 -0
- package/dist/util/color.d.ts +19 -0
- package/dist/util/color.d.ts.map +1 -0
- package/dist/util/color.js +45 -0
- package/dist/util/color.js.map +1 -0
- package/dist/util/math.d.ts +26 -0
- package/dist/util/math.d.ts.map +1 -0
- package/dist/util/math.js +47 -0
- package/dist/util/math.js.map +1 -0
- package/dist/util/typed-arrays.d.ts +7 -0
- package/dist/util/typed-arrays.d.ts.map +1 -0
- package/dist/util/typed-arrays.js +42 -0
- package/dist/util/typed-arrays.js.map +1 -0
- package/dist/vfx/particle-pool.d.ts +61 -0
- package/dist/vfx/particle-pool.d.ts.map +1 -0
- package/dist/vfx/particle-pool.js +204 -0
- package/dist/vfx/particle-pool.js.map +1 -0
- package/dist/vfx/projectile-pool.d.ts +56 -0
- package/dist/vfx/projectile-pool.d.ts.map +1 -0
- package/dist/vfx/projectile-pool.js +157 -0
- package/dist/vfx/projectile-pool.js.map +1 -0
- package/dist/world.d.ts +23 -0
- package/dist/world.d.ts.map +1 -0
- package/dist/world.js +101 -0
- package/dist/world.js.map +1 -0
- package/dist/zone/zone-catalog.d.ts +17 -0
- package/dist/zone/zone-catalog.d.ts.map +1 -0
- package/dist/zone/zone-catalog.js +116 -0
- package/dist/zone/zone-catalog.js.map +1 -0
- package/dist/zone/zone-state.d.ts +18 -0
- package/dist/zone/zone-state.d.ts.map +1 -0
- package/dist/zone/zone-state.js +52 -0
- package/dist/zone/zone-state.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// DirectorSystem - drains the IDirectorBridge each tick, applies
|
|
2
|
+
// each event to the world's resources, and ticks the knot palette
|
|
3
|
+
// crossfade.
|
|
4
|
+
//
|
|
5
|
+
// Runs in PHASE_INPUT, AFTER InputSystem and VeilBudgetSystem so:
|
|
6
|
+
// 1. Input snapshot is fresh first
|
|
7
|
+
// 2. Any prior frame's VeilBudget propagation has already applied
|
|
8
|
+
// 3. THIS system overlays Director events on top, mutating
|
|
9
|
+
// VeilBudget + KnotContext + others as the events stream in
|
|
10
|
+
// 4. VeilBudgetSystem next frame picks up the new budget and
|
|
11
|
+
// pushes it to AudioBus + ParticlePool
|
|
12
|
+
//
|
|
13
|
+
// Per spec invariants:
|
|
14
|
+
// - Section 5.1: renderer never decides palette logic. We just
|
|
15
|
+
// apply what the Director sends.
|
|
16
|
+
// - Section 6.5: renderer never computes VE tier. Just receives.
|
|
17
|
+
// - Section 4.2: gap detection is the bridge's job, not ours.
|
|
18
|
+
// This system trusts the bridge has already reordered / dropped.
|
|
19
|
+
//
|
|
20
|
+
// What this system does for each event type:
|
|
21
|
+
//
|
|
22
|
+
// knot.context -> KnotContextResource.beginFade(palette,
|
|
23
|
+
// fade_ms, now)
|
|
24
|
+
// ve.budget.update -> mutate VeilBudgetResource (ve fields, tier)
|
|
25
|
+
// into engine-internal scalar (audioBudget,
|
|
26
|
+
// particleBudget) per Section 6.2 tier table.
|
|
27
|
+
// VeilBudgetSystem picks up next frame.
|
|
28
|
+
// encounter.spawn -> log + push narrator-line to a new
|
|
29
|
+
// NarratorEvent queue (consumer-defined; v1
|
|
30
|
+
// just exposes the latest event)
|
|
31
|
+
// encounter.tick -> log; v1 doesn't react to mid-fight ticks
|
|
32
|
+
// encounter.end -> log + clear current encounter state
|
|
33
|
+
// encounter.loot -> log + push loot data
|
|
34
|
+
// scene.transition -> log + emit scene change marker
|
|
35
|
+
// narrator.line -> push to narrator queue
|
|
36
|
+
// system.heartbeat -> stats only; bridge already extracted drops
|
|
37
|
+
// system.replay.* -> log only
|
|
38
|
+
// system.snapshot.* -> log + bridge has already closed; consumer
|
|
39
|
+
// must reconnect
|
|
40
|
+
//
|
|
41
|
+
// Lightweight-by-design: most events are just logged + appended to
|
|
42
|
+
// a recent-events ring buffer that gameplay code can read. Heavy
|
|
43
|
+
// state mutation (combat state machines, world graph, NPC dialog
|
|
44
|
+
// queues) lives in higher-level systems that read from this resource.
|
|
45
|
+
import { RESOURCE_DIRECTOR_BRIDGE, RESOURCE_KNOT_CONTEXT, } from './director-bridge.js';
|
|
46
|
+
import { RESOURCE_VEIL_BUDGET, RESOURCE_TIME, } from '../resources.js';
|
|
47
|
+
export const RESOURCE_DIRECTOR_LOG = 'director_log';
|
|
48
|
+
const RING_SIZE = 32;
|
|
49
|
+
export function createDirectorEventLog() {
|
|
50
|
+
return {
|
|
51
|
+
recent: [],
|
|
52
|
+
lastNarratorLine: null,
|
|
53
|
+
lastNarratorTtlMs: 0,
|
|
54
|
+
lastKnot: null,
|
|
55
|
+
activeEncounterId: null,
|
|
56
|
+
lastTier: 'green',
|
|
57
|
+
eventsApplied: 0,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// Section 6.2 tier-to-multiplier table. Renderer-internal scalars
|
|
61
|
+
// that tune the engine subsystems each tick.
|
|
62
|
+
//
|
|
63
|
+
// particleBudget: max simultaneous particles (was 4096 default; we
|
|
64
|
+
// multiply by tier scalar)
|
|
65
|
+
// audioBudget: [0, 1] passed to AudioBus.setAudioBudget (Section 6.2
|
|
66
|
+
// amber drops ambient stages, red minimal)
|
|
67
|
+
// shaderBudget: passes through; downstream VFX gates on this when
|
|
68
|
+
// Phase 6+ shader effects land
|
|
69
|
+
//
|
|
70
|
+
// These scalars are applied multiplicatively to the engine's standalone
|
|
71
|
+
// defaults so demos / standalone runs (no Director) keep their generous
|
|
72
|
+
// settings, while connected runs scale down under load.
|
|
73
|
+
const TIER_SCALARS = {
|
|
74
|
+
green: { particle: 1.0, audio: 1.0, shader: 1.0 },
|
|
75
|
+
amber: { particle: 0.5, audio: 0.7, shader: 0.5 },
|
|
76
|
+
red: { particle: 0.05, audio: 0.4, shader: 0.0 },
|
|
77
|
+
};
|
|
78
|
+
const PARTICLE_BUDGET_BASE = 4096;
|
|
79
|
+
const SHADER_BUDGET_BASE = 8;
|
|
80
|
+
export class DirectorSystem {
|
|
81
|
+
name = 'director';
|
|
82
|
+
update(world, _dt) {
|
|
83
|
+
const bridge = world.resources.get(RESOURCE_DIRECTOR_BRIDGE);
|
|
84
|
+
const knotCtx = world.resources.get(RESOURCE_KNOT_CONTEXT);
|
|
85
|
+
const log = world.resources.get(RESOURCE_DIRECTOR_LOG);
|
|
86
|
+
const time = world.resources.get(RESOURCE_TIME);
|
|
87
|
+
if (!bridge || !knotCtx || !log)
|
|
88
|
+
return;
|
|
89
|
+
const nowMs = (time ? time.elapsed * 1000 : 0) + (typeof performance !== 'undefined' ? performance.now() : 0);
|
|
90
|
+
// 1. Drain queued events.
|
|
91
|
+
const events = bridge.pollEvents();
|
|
92
|
+
if (events.length > 0) {
|
|
93
|
+
const budget = world.resources.get(RESOURCE_VEIL_BUDGET);
|
|
94
|
+
const frameNow = time ? time.frame : -1;
|
|
95
|
+
for (let i = 0; i < events.length; i++) {
|
|
96
|
+
const ev = events[i];
|
|
97
|
+
if (!ev)
|
|
98
|
+
continue;
|
|
99
|
+
applyEvent(ev, knotCtx, log, budget ?? null, nowMs, frameNow);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// 2. Tick the palette crossfade (idempotent if no fade active).
|
|
103
|
+
knotCtx.tickFade(nowMs);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// applyEvent mutates KnotContextResource + DirectorEventLog +
|
|
107
|
+
// optionally VeilBudgetResource. Pure: no I/O, no allocation beyond
|
|
108
|
+
// the ring buffer push.
|
|
109
|
+
function applyEvent(ev, knotCtx, log, budget, nowMs, frameNow) {
|
|
110
|
+
// Append to ring buffer (newest first).
|
|
111
|
+
log.recent.unshift(ev);
|
|
112
|
+
if (log.recent.length > RING_SIZE) {
|
|
113
|
+
log.recent.length = RING_SIZE;
|
|
114
|
+
}
|
|
115
|
+
log.eventsApplied++;
|
|
116
|
+
switch (ev.type) {
|
|
117
|
+
case 'knot.context': {
|
|
118
|
+
const d = ev.data;
|
|
119
|
+
knotCtx.knot = d.knot;
|
|
120
|
+
knotCtx.mood = d.mood;
|
|
121
|
+
knotCtx.beginFade(d.palette, d.fade_ms, nowMs);
|
|
122
|
+
log.lastKnot = d.knot;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case 've.budget.update': {
|
|
126
|
+
const d = ev.data;
|
|
127
|
+
log.lastTier = d.tier;
|
|
128
|
+
if (budget) {
|
|
129
|
+
const scalars = TIER_SCALARS[d.tier];
|
|
130
|
+
budget.particleBudget = Math.round(PARTICLE_BUDGET_BASE * scalars.particle);
|
|
131
|
+
budget.audioBudget = scalars.audio;
|
|
132
|
+
budget.shaderBudget = Math.round(SHADER_BUDGET_BASE * scalars.shader);
|
|
133
|
+
budget.eventBudget = d.encounter_budget_ve;
|
|
134
|
+
if (frameNow >= 0)
|
|
135
|
+
budget.lastUpdatedFrame = frameNow;
|
|
136
|
+
}
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case 'encounter.spawn': {
|
|
140
|
+
log.activeEncounterId = ev.data.encounter_id;
|
|
141
|
+
if (ev.data.narrator_line) {
|
|
142
|
+
log.lastNarratorLine = ev.data.narrator_line;
|
|
143
|
+
log.lastNarratorTtlMs = 0;
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case 'encounter.tick': {
|
|
148
|
+
if (ev.data.narrator_line) {
|
|
149
|
+
log.lastNarratorLine = ev.data.narrator_line;
|
|
150
|
+
log.lastNarratorTtlMs = 0;
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case 'encounter.end': {
|
|
155
|
+
log.activeEncounterId = null;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case 'encounter.loot': {
|
|
159
|
+
if (ev.data.narrator_line) {
|
|
160
|
+
log.lastNarratorLine = ev.data.narrator_line;
|
|
161
|
+
log.lastNarratorTtlMs = 0;
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case 'narrator.line': {
|
|
166
|
+
log.lastNarratorLine = ev.data.line;
|
|
167
|
+
log.lastNarratorTtlMs = ev.data.ttl_ms;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case 'scene.transition':
|
|
171
|
+
case 'system.heartbeat':
|
|
172
|
+
case 'system.replay.complete':
|
|
173
|
+
case 'system.snapshot.required':
|
|
174
|
+
// Logged only via the ring buffer above. Specialized systems
|
|
175
|
+
// (scene loader, telemetry) read from log.recent.
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=director-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"director-system.js","sourceRoot":"","sources":["../../src/director/director-system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
export interface EventEnvelope<T extends DirectorEventType = DirectorEventType> {
|
|
2
|
+
id: number;
|
|
3
|
+
ts: number;
|
|
4
|
+
type: T;
|
|
5
|
+
character_id: string;
|
|
6
|
+
encounter_id: string | null;
|
|
7
|
+
priority?: EventPriority;
|
|
8
|
+
data: DirectorEventDataMap[T];
|
|
9
|
+
}
|
|
10
|
+
export interface MobSpec {
|
|
11
|
+
type: string;
|
|
12
|
+
name: string;
|
|
13
|
+
hp: number;
|
|
14
|
+
dmg: number;
|
|
15
|
+
count: number;
|
|
16
|
+
position_hint: {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
};
|
|
20
|
+
knot_flavor: string;
|
|
21
|
+
}
|
|
22
|
+
export interface BossSpec {
|
|
23
|
+
type: string;
|
|
24
|
+
name: string;
|
|
25
|
+
hp: number;
|
|
26
|
+
dmg: number;
|
|
27
|
+
position_hint: {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
};
|
|
31
|
+
knot_flavor: string;
|
|
32
|
+
}
|
|
33
|
+
export interface DropSpec {
|
|
34
|
+
item_id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
slot: string;
|
|
37
|
+
knot_affinity: string;
|
|
38
|
+
stats: Record<string, number>;
|
|
39
|
+
}
|
|
40
|
+
export interface EncounterSpawnData {
|
|
41
|
+
encounter_id: string;
|
|
42
|
+
zone_id: string;
|
|
43
|
+
level: number;
|
|
44
|
+
knot: string;
|
|
45
|
+
mobs: ReadonlyArray<MobSpec>;
|
|
46
|
+
boss: BossSpec | null;
|
|
47
|
+
narrator_line: string | null;
|
|
48
|
+
difficulty_score: number;
|
|
49
|
+
}
|
|
50
|
+
export interface EncounterTickData {
|
|
51
|
+
encounter_id: string;
|
|
52
|
+
elapsed_ms: number;
|
|
53
|
+
difficulty_delta: number;
|
|
54
|
+
narrator_line: string | null;
|
|
55
|
+
vfx_prompt: string | null;
|
|
56
|
+
}
|
|
57
|
+
export interface EncounterEndData {
|
|
58
|
+
encounter_id: string;
|
|
59
|
+
outcome: 'victory' | 'death' | 'flee';
|
|
60
|
+
duration_ms: number;
|
|
61
|
+
mob_killed: ReadonlyArray<string>;
|
|
62
|
+
next_step: 'loot' | 'respawn' | 'transition' | 'idle';
|
|
63
|
+
}
|
|
64
|
+
export interface EncounterLootData {
|
|
65
|
+
encounter_id: string;
|
|
66
|
+
drops: ReadonlyArray<DropSpec>;
|
|
67
|
+
ve_bonus: number;
|
|
68
|
+
narrator_line: string | null;
|
|
69
|
+
}
|
|
70
|
+
export interface KnotPaletteHex {
|
|
71
|
+
primary: string;
|
|
72
|
+
secondary: string;
|
|
73
|
+
accent: string;
|
|
74
|
+
}
|
|
75
|
+
export type KnotMood = 'calm' | 'tense' | 'climactic';
|
|
76
|
+
export interface KnotContextData {
|
|
77
|
+
knot: string;
|
|
78
|
+
palette: KnotPaletteHex;
|
|
79
|
+
mood: KnotMood;
|
|
80
|
+
fade_ms: number;
|
|
81
|
+
}
|
|
82
|
+
export type VeilTier = 'green' | 'amber' | 'red';
|
|
83
|
+
export interface VeBudgetUpdateData {
|
|
84
|
+
ve_remaining_month: number;
|
|
85
|
+
ve_ceiling_month: number;
|
|
86
|
+
tier: VeilTier;
|
|
87
|
+
tier_prev: VeilTier;
|
|
88
|
+
encounter_budget_ve: number;
|
|
89
|
+
encounter_budget_usd: number;
|
|
90
|
+
}
|
|
91
|
+
export type SceneTransitionKind = 'walk' | 'portal' | 'cinematic' | 'instant';
|
|
92
|
+
export interface SceneTransitionData {
|
|
93
|
+
from_zone: string;
|
|
94
|
+
to_zone: string;
|
|
95
|
+
transition_kind: SceneTransitionKind;
|
|
96
|
+
duration_ms: number;
|
|
97
|
+
}
|
|
98
|
+
export type NarratorVoice = 'ambient' | 'urgent' | 'whisper';
|
|
99
|
+
export interface NarratorLineData {
|
|
100
|
+
line: string;
|
|
101
|
+
voice: NarratorVoice;
|
|
102
|
+
ttl_ms: number;
|
|
103
|
+
}
|
|
104
|
+
export interface SystemHeartbeatData {
|
|
105
|
+
tail_id: number;
|
|
106
|
+
drops_p2: number;
|
|
107
|
+
drops_p1: number;
|
|
108
|
+
}
|
|
109
|
+
export interface SystemReplayCompleteData {
|
|
110
|
+
from_id: number;
|
|
111
|
+
to_id: number;
|
|
112
|
+
events_sent: number;
|
|
113
|
+
}
|
|
114
|
+
export interface SystemSnapshotRequiredData {
|
|
115
|
+
last_known_id: number;
|
|
116
|
+
current_tail_id: number;
|
|
117
|
+
retention_window: number;
|
|
118
|
+
}
|
|
119
|
+
export type DirectorEventType = 'encounter.spawn' | 'encounter.tick' | 'encounter.end' | 'encounter.loot' | 'knot.context' | 've.budget.update' | 'scene.transition' | 'narrator.line' | 'system.heartbeat' | 'system.replay.complete' | 'system.snapshot.required';
|
|
120
|
+
export interface DirectorEventDataMap {
|
|
121
|
+
'encounter.spawn': EncounterSpawnData;
|
|
122
|
+
'encounter.tick': EncounterTickData;
|
|
123
|
+
'encounter.end': EncounterEndData;
|
|
124
|
+
'encounter.loot': EncounterLootData;
|
|
125
|
+
'knot.context': KnotContextData;
|
|
126
|
+
've.budget.update': VeBudgetUpdateData;
|
|
127
|
+
'scene.transition': SceneTransitionData;
|
|
128
|
+
'narrator.line': NarratorLineData;
|
|
129
|
+
'system.heartbeat': SystemHeartbeatData;
|
|
130
|
+
'system.replay.complete': SystemReplayCompleteData;
|
|
131
|
+
'system.snapshot.required': SystemSnapshotRequiredData;
|
|
132
|
+
}
|
|
133
|
+
export type DirectorEvent = {
|
|
134
|
+
[K in DirectorEventType]: EventEnvelope<K>;
|
|
135
|
+
}[DirectorEventType];
|
|
136
|
+
export type EventPriority = 'P0' | 'P1' | 'P2';
|
|
137
|
+
export declare function priorityFor(type: DirectorEventType): EventPriority;
|
|
138
|
+
export declare class EventEnvelopeParseError extends Error {
|
|
139
|
+
readonly raw: unknown;
|
|
140
|
+
constructor(message: string, raw: unknown);
|
|
141
|
+
}
|
|
142
|
+
export declare function parseEnvelope(raw: unknown): DirectorEvent;
|
|
143
|
+
export declare function parseEnvelopeJson(json: string): DirectorEvent | null;
|
|
144
|
+
//# sourceMappingURL=event-envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-envelope.d.ts","sourceRoot":"","sources":["../../src/director/event-envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Director event envelope + typed event payloads.
|
|
2
|
+
//
|
|
3
|
+
// Per LOOM-DIRECTOR-PROTOCOL.md Section 3: every event shares an
|
|
4
|
+
// envelope of {id, ts, type, character_id, encounter_id, data} where
|
|
5
|
+
// `data` is type-specific. This file defines all 11 event types and
|
|
6
|
+
// the discriminated-union DirectorEvent that callers parse against.
|
|
7
|
+
//
|
|
8
|
+
// Spec invariants preserved:
|
|
9
|
+
// - id is monotonic positive integer per (user, character)
|
|
10
|
+
// - encounter_id is null for non-encounter-scoped events
|
|
11
|
+
// - all hex palette values in knot.context come straight from
|
|
12
|
+
// LOOM-CLASS-SYSTEM-SPEC Section 4 (Director sources them at
|
|
13
|
+
// emit time; renderer trusts and applies)
|
|
14
|
+
// - mood is one of 'calm' | 'tense' | 'climactic'
|
|
15
|
+
// - tier is one of 'green' | 'amber' | 'red'
|
|
16
|
+
const PRIORITY_BY_TYPE = {
|
|
17
|
+
'encounter.spawn': 'P0',
|
|
18
|
+
'encounter.end': 'P0',
|
|
19
|
+
'encounter.loot': 'P0',
|
|
20
|
+
'system.replay.complete': 'P0',
|
|
21
|
+
'system.snapshot.required': 'P0',
|
|
22
|
+
'knot.context': 'P1',
|
|
23
|
+
'scene.transition': 'P1',
|
|
24
|
+
'narrator.line': 'P1',
|
|
25
|
+
've.budget.update': 'P1',
|
|
26
|
+
'encounter.tick': 'P2',
|
|
27
|
+
'system.heartbeat': 'P2',
|
|
28
|
+
};
|
|
29
|
+
export function priorityFor(type) {
|
|
30
|
+
return PRIORITY_BY_TYPE[type];
|
|
31
|
+
}
|
|
32
|
+
// ----- Parsers -----
|
|
33
|
+
export class EventEnvelopeParseError extends Error {
|
|
34
|
+
raw;
|
|
35
|
+
constructor(message, raw) {
|
|
36
|
+
super('EventEnvelopeParseError: ' + message);
|
|
37
|
+
this.raw = raw;
|
|
38
|
+
this.name = 'EventEnvelopeParseError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const KNOWN_EVENT_TYPES = new Set([
|
|
42
|
+
'encounter.spawn',
|
|
43
|
+
'encounter.tick',
|
|
44
|
+
'encounter.end',
|
|
45
|
+
'encounter.loot',
|
|
46
|
+
'knot.context',
|
|
47
|
+
've.budget.update',
|
|
48
|
+
'scene.transition',
|
|
49
|
+
'narrator.line',
|
|
50
|
+
'system.heartbeat',
|
|
51
|
+
'system.replay.complete',
|
|
52
|
+
'system.snapshot.required',
|
|
53
|
+
]);
|
|
54
|
+
// Validate the envelope shape only - data payload validation is the
|
|
55
|
+
// caller's responsibility (downstream type narrowing on `event.type`
|
|
56
|
+
// gives full payload typing). Throws on shape errors so the bridge
|
|
57
|
+
// can decide to drop / log / reconnect.
|
|
58
|
+
export function parseEnvelope(raw) {
|
|
59
|
+
if (!raw || typeof raw !== 'object') {
|
|
60
|
+
throw new EventEnvelopeParseError('envelope is not an object', raw);
|
|
61
|
+
}
|
|
62
|
+
const e = raw;
|
|
63
|
+
if (typeof e['id'] !== 'number' || e['id'] < 0 || !Number.isFinite(e['id'])) {
|
|
64
|
+
throw new EventEnvelopeParseError('id must be a non-negative number', raw);
|
|
65
|
+
}
|
|
66
|
+
if (typeof e['ts'] !== 'number') {
|
|
67
|
+
throw new EventEnvelopeParseError('ts must be a number', raw);
|
|
68
|
+
}
|
|
69
|
+
if (typeof e['type'] !== 'string' || !KNOWN_EVENT_TYPES.has(e['type'])) {
|
|
70
|
+
throw new EventEnvelopeParseError('unknown event type: ' + String(e['type']), raw);
|
|
71
|
+
}
|
|
72
|
+
if (typeof e['character_id'] !== 'string') {
|
|
73
|
+
throw new EventEnvelopeParseError('character_id must be a string', raw);
|
|
74
|
+
}
|
|
75
|
+
if (e['encounter_id'] !== null && typeof e['encounter_id'] !== 'string') {
|
|
76
|
+
throw new EventEnvelopeParseError('encounter_id must be string or null', raw);
|
|
77
|
+
}
|
|
78
|
+
// Priority field is optional (Phase 6.4 backend addition; pre-6.4
|
|
79
|
+
// events on disk lack it). When present, must be a known class.
|
|
80
|
+
if (e['priority'] !== undefined) {
|
|
81
|
+
if (e['priority'] !== 'P0' && e['priority'] !== 'P1' && e['priority'] !== 'P2') {
|
|
82
|
+
throw new EventEnvelopeParseError('priority must be P0 / P1 / P2 when present, got: ' + String(e['priority']), raw);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (!e['data'] || typeof e['data'] !== 'object') {
|
|
86
|
+
throw new EventEnvelopeParseError('data must be an object', raw);
|
|
87
|
+
}
|
|
88
|
+
return e;
|
|
89
|
+
}
|
|
90
|
+
// Convenience: parse a string (typically an SSE 'data:' line) into
|
|
91
|
+
// an envelope. Returns null on JSON parse error so the caller can
|
|
92
|
+
// decide whether to log or re-throw.
|
|
93
|
+
export function parseEnvelopeJson(json) {
|
|
94
|
+
let parsed;
|
|
95
|
+
try {
|
|
96
|
+
parsed = JSON.parse(json);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
return parseEnvelope(parsed);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=event-envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-envelope.js","sourceRoot":"","sources":["../../src/director/event-envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ColorRGBA } from '../util/color.js';
|
|
2
|
+
import type { KnotMood, KnotPaletteHex } from './event-envelope.js';
|
|
3
|
+
export interface KnotPaletteRgba {
|
|
4
|
+
primary: ColorRGBA;
|
|
5
|
+
secondary: ColorRGBA;
|
|
6
|
+
accent: ColorRGBA;
|
|
7
|
+
}
|
|
8
|
+
export declare class KnotContextResource {
|
|
9
|
+
current: KnotPaletteRgba;
|
|
10
|
+
target: KnotPaletteRgba;
|
|
11
|
+
knot: string;
|
|
12
|
+
mood: KnotMood;
|
|
13
|
+
fadeStartMs: number;
|
|
14
|
+
fadeDurationMs: number;
|
|
15
|
+
fadeFromPalette: KnotPaletteRgba;
|
|
16
|
+
constructor();
|
|
17
|
+
beginFade(targetHex: KnotPaletteHex, fadeMs: number, nowMs: number): void;
|
|
18
|
+
tickFade(nowMs: number): void;
|
|
19
|
+
isFading(): boolean;
|
|
20
|
+
getBloomMultiplier(): number;
|
|
21
|
+
getShakeMultiplier(): number;
|
|
22
|
+
getMusicIntensity(): number;
|
|
23
|
+
hexSnapshot(): KnotPaletteHex;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=knot-context-resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knot-context-resource.d.ts","sourceRoot":"","sources":["../../src/director/knot-context-resource.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,SAAS,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,SAAS,CAAC;CACnB;AAUD,qBAAa,mBAAmB;IAG9B,OAAO,EAAE,eAAe,CAAC;IAGzB,MAAM,EAAE,eAAe,CAAC;IAGxB,IAAI,EAAE,MAAM,CAAS;IAGrB,IAAI,EAAE,QAAQ,CAAW;IAIzB,WAAW,EAAE,MAAM,CAAM;IACzB,cAAc,EAAE,MAAM,CAAK;IAG3B,eAAe,EAAE,eAAe,CAAC;;IAWjC,SAAS,CAAC,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAUzE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAU7B,QAAQ,IAAI,OAAO;IAKnB,kBAAkB,IAAI,MAAM;IAI5B,kBAAkB,IAAI,MAAM;IAI5B,iBAAiB,IAAI,MAAM;IAK3B,WAAW,IAAI,cAAc;CAO9B"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// KnotContextResource - the renderer's current palette + mood state.
|
|
2
|
+
//
|
|
3
|
+
// Per LOOM-DIRECTOR-PROTOCOL.md Section 5: Director picks the active
|
|
4
|
+
// knot, the renderer applies the palette it is told to apply. This
|
|
5
|
+
// resource holds:
|
|
6
|
+
// - current palette + mood (what's rendered right now)
|
|
7
|
+
// - target palette + mood (what we're crossfading toward)
|
|
8
|
+
// - fade timing for the active transition
|
|
9
|
+
//
|
|
10
|
+
// DirectorSystem mutates `target` and `fadeStartMs` on knot.context
|
|
11
|
+
// events. A small per-tick interpolation (also inside DirectorSystem)
|
|
12
|
+
// advances `current` toward `target` over fade_ms. A fade_ms of 0 is
|
|
13
|
+
// rendered as a 1-frame fade so animation systems do not skip a beat
|
|
14
|
+
// (Section 5.3).
|
|
15
|
+
//
|
|
16
|
+
// Mood multipliers (Section 5.4) are exposed as derived getters on
|
|
17
|
+
// the resource. Render systems read them when computing bloom + shake
|
|
18
|
+
// + music intensity.
|
|
19
|
+
import { hexToRgba, rgbaToHexString } from '../util/color.js';
|
|
20
|
+
// Default palette - Strknot per LOOM-CLASS-SYSTEM-SPEC Section 4.
|
|
21
|
+
// Used until the first knot.context event lands.
|
|
22
|
+
const DEFAULT_PALETTE_HEX = {
|
|
23
|
+
primary: '#b04a24',
|
|
24
|
+
secondary: '#5ac9d6',
|
|
25
|
+
accent: '#ffd86a',
|
|
26
|
+
};
|
|
27
|
+
export class KnotContextResource {
|
|
28
|
+
// Active palette currently in use by render systems. Interpolates
|
|
29
|
+
// toward `target` over the fade window.
|
|
30
|
+
current;
|
|
31
|
+
// Target palette the active fade is moving toward. Equals `current`
|
|
32
|
+
// when no fade is active.
|
|
33
|
+
target;
|
|
34
|
+
// Currently displayed knot id (e.g. 'str', 'dex', 'int', 'center').
|
|
35
|
+
knot = 'str';
|
|
36
|
+
// Currently active mood. Updated immediately on knot.context (no
|
|
37
|
+
// mood crossfade in v1; mood is a hint, not a continuous param).
|
|
38
|
+
mood = 'tense';
|
|
39
|
+
// Crossfade timing (ms-based; uses performance.now() coordinates).
|
|
40
|
+
// -1 means no fade is in progress.
|
|
41
|
+
fadeStartMs = -1;
|
|
42
|
+
fadeDurationMs = 0;
|
|
43
|
+
// Snapshot of `current` at the moment the fade started, so each
|
|
44
|
+
// tick can interpolate from a stable origin.
|
|
45
|
+
fadeFromPalette;
|
|
46
|
+
constructor() {
|
|
47
|
+
this.current = paletteFromHex(DEFAULT_PALETTE_HEX);
|
|
48
|
+
this.target = paletteFromHex(DEFAULT_PALETTE_HEX);
|
|
49
|
+
this.fadeFromPalette = paletteFromHex(DEFAULT_PALETTE_HEX);
|
|
50
|
+
}
|
|
51
|
+
// Begin a crossfade to a new palette. Called by DirectorSystem on
|
|
52
|
+
// knot.context. fade_ms = 0 is treated as 16ms (one frame at 60fps)
|
|
53
|
+
// so animation systems always observe at least one frame of fade.
|
|
54
|
+
beginFade(targetHex, fadeMs, nowMs) {
|
|
55
|
+
this.fadeFromPalette = clonePalette(this.current);
|
|
56
|
+
this.target = paletteFromHex(targetHex);
|
|
57
|
+
this.fadeStartMs = nowMs;
|
|
58
|
+
this.fadeDurationMs = fadeMs <= 0 ? 16 : fadeMs;
|
|
59
|
+
}
|
|
60
|
+
// Per-tick interpolation. Call from DirectorSystem.update each tick
|
|
61
|
+
// with performance.now(). Updates `current` toward `target` based
|
|
62
|
+
// on elapsed fade time. Idempotent if no fade is active.
|
|
63
|
+
tickFade(nowMs) {
|
|
64
|
+
if (this.fadeStartMs < 0)
|
|
65
|
+
return;
|
|
66
|
+
const elapsed = nowMs - this.fadeStartMs;
|
|
67
|
+
const t = Math.min(1, Math.max(0, elapsed / this.fadeDurationMs));
|
|
68
|
+
interpolatePaletteInto(this.fadeFromPalette, this.target, t, this.current);
|
|
69
|
+
if (t >= 1) {
|
|
70
|
+
this.fadeStartMs = -1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
isFading() {
|
|
74
|
+
return this.fadeStartMs >= 0;
|
|
75
|
+
}
|
|
76
|
+
// Mood multipliers per Section 5.4.
|
|
77
|
+
getBloomMultiplier() {
|
|
78
|
+
return moodBloomMult(this.mood);
|
|
79
|
+
}
|
|
80
|
+
getShakeMultiplier() {
|
|
81
|
+
return moodShakeMult(this.mood);
|
|
82
|
+
}
|
|
83
|
+
getMusicIntensity() {
|
|
84
|
+
return moodMusicMult(this.mood);
|
|
85
|
+
}
|
|
86
|
+
// Snapshot in hex form. Useful for debug HUD / serialization.
|
|
87
|
+
hexSnapshot() {
|
|
88
|
+
return {
|
|
89
|
+
primary: rgbaToHexString(this.current.primary),
|
|
90
|
+
secondary: rgbaToHexString(this.current.secondary),
|
|
91
|
+
accent: rgbaToHexString(this.current.accent),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// ----- Helpers -----
|
|
96
|
+
function paletteFromHex(p) {
|
|
97
|
+
return {
|
|
98
|
+
primary: hexToRgba(parseHex(p.primary)),
|
|
99
|
+
secondary: hexToRgba(parseHex(p.secondary)),
|
|
100
|
+
accent: hexToRgba(parseHex(p.accent)),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function clonePalette(p) {
|
|
104
|
+
return {
|
|
105
|
+
primary: { ...p.primary },
|
|
106
|
+
secondary: { ...p.secondary },
|
|
107
|
+
accent: { ...p.accent },
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function interpolatePaletteInto(from, to, t, out) {
|
|
111
|
+
out.primary.r = from.primary.r + (to.primary.r - from.primary.r) * t;
|
|
112
|
+
out.primary.g = from.primary.g + (to.primary.g - from.primary.g) * t;
|
|
113
|
+
out.primary.b = from.primary.b + (to.primary.b - from.primary.b) * t;
|
|
114
|
+
out.primary.a = from.primary.a + (to.primary.a - from.primary.a) * t;
|
|
115
|
+
out.secondary.r = from.secondary.r + (to.secondary.r - from.secondary.r) * t;
|
|
116
|
+
out.secondary.g = from.secondary.g + (to.secondary.g - from.secondary.g) * t;
|
|
117
|
+
out.secondary.b = from.secondary.b + (to.secondary.b - from.secondary.b) * t;
|
|
118
|
+
out.secondary.a = from.secondary.a + (to.secondary.a - from.secondary.a) * t;
|
|
119
|
+
out.accent.r = from.accent.r + (to.accent.r - from.accent.r) * t;
|
|
120
|
+
out.accent.g = from.accent.g + (to.accent.g - from.accent.g) * t;
|
|
121
|
+
out.accent.b = from.accent.b + (to.accent.b - from.accent.b) * t;
|
|
122
|
+
out.accent.a = from.accent.a + (to.accent.a - from.accent.a) * t;
|
|
123
|
+
}
|
|
124
|
+
function parseHex(hex) {
|
|
125
|
+
if (!hex || typeof hex !== 'string')
|
|
126
|
+
return 0xffffff;
|
|
127
|
+
const trimmed = hex.startsWith('#') ? hex.slice(1) : hex;
|
|
128
|
+
const n = parseInt(trimmed, 16);
|
|
129
|
+
return Number.isFinite(n) ? n : 0xffffff;
|
|
130
|
+
}
|
|
131
|
+
function moodBloomMult(mood) {
|
|
132
|
+
if (mood === 'calm')
|
|
133
|
+
return 0.6;
|
|
134
|
+
if (mood === 'climactic')
|
|
135
|
+
return 1.4;
|
|
136
|
+
return 1.0; // tense or unknown
|
|
137
|
+
}
|
|
138
|
+
function moodShakeMult(mood) {
|
|
139
|
+
if (mood === 'calm')
|
|
140
|
+
return 0.5;
|
|
141
|
+
if (mood === 'climactic')
|
|
142
|
+
return 1.5;
|
|
143
|
+
return 1.0;
|
|
144
|
+
}
|
|
145
|
+
function moodMusicMult(mood) {
|
|
146
|
+
if (mood === 'calm')
|
|
147
|
+
return 0.5;
|
|
148
|
+
if (mood === 'climactic')
|
|
149
|
+
return 1.4;
|
|
150
|
+
return 1.0;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=knot-context-resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knot-context-resource.js","sourceRoot":"","sources":["../../src/director/knot-context-resource.ts"],"names":[],"mappings":"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"}
|