hayao 0.4.0 → 0.4.1
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/dist/anim/blend.d.ts +68 -0
- package/dist/anim/clip.d.ts +87 -0
- package/dist/anim/ik.d.ts +40 -0
- package/dist/anim/skeleton.d.ts +64 -0
- package/dist/hayao.global.js +12 -12
- package/dist/index.d.ts +11 -1
- package/dist/index.js +1683 -516
- package/dist/index.js.map +4 -4
- package/dist/index.min.js +12 -12
- package/dist/render/canvas2d-core.d.ts +4 -0
- package/dist/render/commands.d.ts +19 -0
- package/dist/render/lightRun.d.ts +35 -0
- package/dist/render/svgString.d.ts +8 -3
- package/dist/scene/clipPlayer.d.ts +58 -0
- package/dist/scene/ikTarget.d.ts +25 -0
- package/dist/scene/light.d.ts +80 -0
- package/dist/scene/shadow2d.d.ts +25 -0
- package/dist/scene/skeletonDebug.d.ts +28 -0
- package/dist/verify/gates.d.ts +25 -0
- package/docs/API.md +66 -8
- package/docs/CONVENTIONS.md +56 -0
- package/package.json +1 -1
package/docs/API.md
CHANGED
|
@@ -3,19 +3,23 @@
|
|
|
3
3
|
> Auto-generated by `npm run api`. Everything importable from `@hayao`.
|
|
4
4
|
> Grep here for the real surface — never guess an API from memory.
|
|
5
5
|
|
|
6
|
-
**
|
|
6
|
+
**775 exports.**
|
|
7
7
|
|
|
8
|
-
## classs (
|
|
8
|
+
## classs (68)
|
|
9
9
|
|
|
10
10
|
- `AmbientField`
|
|
11
11
|
- `AnimationPlayer`
|
|
12
12
|
- `AudioBus`
|
|
13
13
|
- `BitmapText`
|
|
14
|
+
- `Blend1D`
|
|
15
|
+
- `Blend2D`
|
|
16
|
+
- `Bone2D`
|
|
14
17
|
- `BroadcastChannelTransport`
|
|
15
18
|
- `Camera2D`
|
|
16
19
|
- `CameraController`
|
|
17
20
|
- `Canvas2DRenderer`
|
|
18
21
|
- `CinematicPlayer`
|
|
22
|
+
- `ClipPlayer`
|
|
19
23
|
- `Clock`
|
|
20
24
|
- `Coroutines`
|
|
21
25
|
- `DepthSort`
|
|
@@ -24,11 +28,13 @@
|
|
|
24
28
|
- `Fsm`
|
|
25
29
|
- `GamepadSource`
|
|
26
30
|
- `HeadlessRenderer`
|
|
31
|
+
- `IkTarget`
|
|
27
32
|
- `InputBuffer`
|
|
28
33
|
- `InputRecorder`
|
|
29
34
|
- `InputState`
|
|
30
35
|
- `IsoPrism`
|
|
31
36
|
- `KeyboardSource`
|
|
37
|
+
- `LightLayer`
|
|
32
38
|
- `LocalStorageAdapter`
|
|
33
39
|
- `LockstepSession`
|
|
34
40
|
- `LoopbackHub`
|
|
@@ -44,6 +50,7 @@
|
|
|
44
50
|
- `PixelBuffer`
|
|
45
51
|
- `PlayerInput`
|
|
46
52
|
- `PointerSource`
|
|
53
|
+
- `PointLight`
|
|
47
54
|
- `RingBuffer`
|
|
48
55
|
- `Rng`
|
|
49
56
|
- `RollbackSession`
|
|
@@ -54,6 +61,8 @@
|
|
|
54
61
|
- `Shaker`
|
|
55
62
|
- `Shell`
|
|
56
63
|
- `Signal`
|
|
64
|
+
- `Skeleton`
|
|
65
|
+
- `SkeletonDebug`
|
|
57
66
|
- `SnapshotRing`
|
|
58
67
|
- `SpatialHash`
|
|
59
68
|
- `Sprite`
|
|
@@ -67,7 +76,7 @@
|
|
|
67
76
|
- `WebGL2Renderer`
|
|
68
77
|
- `World`
|
|
69
78
|
|
|
70
|
-
## functions (
|
|
79
|
+
## functions (330)
|
|
71
80
|
|
|
72
81
|
- `abilitiesOf`: (world: WorldGraphDef, taken: readonly string[]) => Set<string>
|
|
73
82
|
- `addBody`: (rw: RigidWorld, def: RigidBodyDef) => number
|
|
@@ -77,6 +86,7 @@
|
|
|
77
86
|
- `albumTrack`: (id: string) => AlbumTrack | undefined
|
|
78
87
|
- `all`: (...waits: Wait[]) => Wait
|
|
79
88
|
- `analyzePlaytest`: (def: GameDefinition<Record<string, unknown>>, session: PlaytestSession, opts?: AnalyzeOptions) => PlaytestReport
|
|
89
|
+
- `applyChannel`: (node: Node, channel: ClipChannel, value: number) => void
|
|
80
90
|
- `applyImpulse`: (rw: RigidWorld, id: number, ix: number, iy: number, px?: number | undefined, py?: number | undefined) => void
|
|
81
91
|
- `applyReverb`: (buf: StereoBuffer, opts?: ReverbOptions) => void
|
|
82
92
|
- `applyTransform`: (m: Transform, p: Vec2) => Vec2
|
|
@@ -93,10 +103,12 @@
|
|
|
93
103
|
- `availableUpgrades`: (defs: readonly UpgradeDef[], owned: readonly string[]) => UpgradeDef[]
|
|
94
104
|
- `bandBalance`: (sig: Samples, sampleRate?: number) => BandBalance
|
|
95
105
|
- `bfs`: <N>(start: N, neighbours: Neighbours<N>, key: NodeKey<N>, opts?: { goal?: ((n: N) => boolean) | undefined; maxNodes?: number | undefined; }) => BfsResult<N>
|
|
106
|
+
- `blendIssues`: (samples: BlendSample[], dims?: 2 | 1) => string[]
|
|
96
107
|
- `blobPath`: (rng: Rng, radius: number, wobble?: number, lobes?: number) => string
|
|
97
108
|
- `bodyAABB`: (b: RigidBody) => Rect
|
|
98
109
|
- `bodyContains`: (b: RigidBody, x: number, y: number) => boolean
|
|
99
110
|
- `bootDom`: (def: GameDefinition<Record<string, unknown>>, mount?: HTMLElement | undefined) => DomHarness
|
|
111
|
+
- `buildSkeleton`: (root: Node) => Skeleton
|
|
100
112
|
- `cadenceResolves`: (romans: string[]) => boolean
|
|
101
113
|
- `cameraIssues`: (samples: readonly Vec2[], opts?: CameraOptions) => string[]
|
|
102
114
|
- `canvasGradient`: (ctx: { createLinearGradient(x0: number, y0: number, x1: number, y1: number): CanvasGradient; createRadialGradient(x0: number, y0: number, r0: number, x1: nu…
|
|
@@ -108,8 +120,12 @@
|
|
|
108
120
|
- `chordChanges`: (symbols: string[], octave?: number) => number[][]
|
|
109
121
|
- `chordNotes`: (symbol: string, octave?: number) => number[]
|
|
110
122
|
- `clientToDesign`: (rect: { left: number; top: number; width: number; height: number; }, width: number, height: number, clientX: number, clientY: number) => Vec2
|
|
123
|
+
- `clipEvents`: (def: ClipDef, prev: number, next: number) => string[]
|
|
124
|
+
- `clipFinished`: (def: ClipDef, elapsed: number) => boolean
|
|
125
|
+
- `clipIssues`: (def: ClipDef, knownTargets?: readonly string[] | undefined) => string[]
|
|
126
|
+
- `clipTime`: (def: ClipDef, elapsed: number) => number
|
|
111
127
|
- `collide`: (a: RigidBody, b: RigidBody) => Manifold | null
|
|
112
|
-
- `commandsToSVGInner`: (commands: DrawCommand[], idPrefix?: string) => string
|
|
128
|
+
- `commandsToSVGInner`: (commands: DrawCommand[], idPrefix?: string, viewW?: number, viewH?: number) => string
|
|
113
129
|
- `composeCampaign`: <State, Move>(spec: CampaignSpec<State, Move>) => Campaign<State, Move>
|
|
114
130
|
- `composeTransform`: (m: Transform, n: Transform) => Transform
|
|
115
131
|
- `connectedComponents`: (cols: number, rows: number, passable: Passable, diagonal?: boolean) => Components
|
|
@@ -122,6 +138,7 @@
|
|
|
122
138
|
- `createStereo`: (durationSec: number, sampleRate?: number) => StereoBuffer
|
|
123
139
|
- `createWorld`: <TState extends Record<string, unknown> = Record<string, unknown>>(def: GameDefinition<TState>, opts?: number | CreateWorldOptions | undefined) => World<...>
|
|
124
140
|
- `crestFactorDb`: (sig: Samples) => number
|
|
141
|
+
- `cullSegments`: (light: Vec2, radius: number, segs: readonly ContourSegment[]) => ContourSegment[]
|
|
125
142
|
- `dashJumpDistance`: (cfg?: PlatformerConfig) => number
|
|
126
143
|
- `datan`: (x: number) => number
|
|
127
144
|
- `datan2`: (y: number, x: number) => number
|
|
@@ -215,6 +232,7 @@
|
|
|
215
232
|
- `levelIssues`: (data: LevelData) => string[]
|
|
216
233
|
- `levelReachable`: (data: LevelData, opts?: { passable?: Passable | undefined; diagonal?: boolean | undefined; }) => ReachReport
|
|
217
234
|
- `levelToTilemap`: (data: LevelData) => TilemapData
|
|
235
|
+
- `lightingIssues`: (commands: DrawCommand[], avatarFill: string, avatarWorld: Vec2, opts?: LightingOptions) => string[]
|
|
218
236
|
- `linearGradient`: (stops: readonly StopInput[], angleDeg?: number) => LinearGradient
|
|
219
237
|
- `lineOfSight`: (map: TilemapData, ax: number, ay: number, bx: number, by: number) => boolean
|
|
220
238
|
- `lintSong`: (song: Song, opts?: LintOptions) => MusicLintResult
|
|
@@ -238,6 +256,7 @@
|
|
|
238
256
|
- `mix`: (a: string, b: string, t: number) => string
|
|
239
257
|
- `mixLinear`: (a: string, b: string, t: number) => string
|
|
240
258
|
- `mixMono`: (bus: StereoBuffer, sig: Samples, startSample: number, gain?: number, pan?: number) => void
|
|
259
|
+
- `mixPose`: (a: Pose, b: Pose, t: number, out?: Pose) => Pose
|
|
241
260
|
- `moveRect`: (map: TilemapData, rect: Rect, dx: number, dy: number, opts?: MoveOpts) => MoveResult
|
|
242
261
|
- `mutateColor`: (rng: Rng, hex: string, amounts?: DriftAmounts) => string
|
|
243
262
|
- `netMessage`: <T extends Omit<NetMessage, "v">>(msg: T) => T & { v: number; }
|
|
@@ -245,11 +264,13 @@
|
|
|
245
264
|
- `nineSlice`: (rect: Rect, style: NineSliceStyle, z?: number, transform?: Transform) => DrawCommand[]
|
|
246
265
|
- `normalize`: (buf: StereoBuffer, target?: number) => void
|
|
247
266
|
- `noteToMidi`: (name: string) => number
|
|
267
|
+
- `occludersFromTilemap`: (map: TilemapData) => ContourSegment[]
|
|
248
268
|
- `onsetDensity`: (sig: Samples, sampleRate?: number) => number
|
|
249
269
|
- `openVoicing`: (chord: number[]) => number[]
|
|
250
270
|
- `packVarints`: (nums: readonly number[]) => string
|
|
251
271
|
- `panFromOffset`: (dx: number, spread?: number) => number
|
|
252
272
|
- `panGains`: (pan: number) => { l: number; r: number; }
|
|
273
|
+
- `parseLightRun`: (run: DrawCommand[]) => ParsedLightRun | null
|
|
253
274
|
- `parseRich`: (markup: string, colorMap?: Record<string, string>) => RichChar[]
|
|
254
275
|
- `parseSnapshot`: (text: string | null) => WorldSnapshot | null
|
|
255
276
|
- `passableFromTilemap`: (map: TilemapData) => Passable
|
|
@@ -296,6 +317,7 @@
|
|
|
296
317
|
- `replaySession`: (def: GameDefinition<Record<string, unknown>>, session: PlaytestSession, opts?: number | ReplayOptions | undefined) => World<...>
|
|
297
318
|
- `resetNodeIds`: (start?: number) => void
|
|
298
319
|
- `resetZzfxWarnings`: () => void
|
|
320
|
+
- `resolveTracks`: (def: ClipDef, skeleton: Skeleton) => BoundTrack[]
|
|
299
321
|
- `resolveTuning`: (spec: TuningSpec | undefined, overrides?: TuningValues | undefined) => TuningValues
|
|
300
322
|
- `rigidStep`: (rw: RigidWorld, dt: number) => ContactEvent[]
|
|
301
323
|
- `rleDecode`: (input: string) => string
|
|
@@ -309,7 +331,10 @@
|
|
|
309
331
|
- `runHeadless`: <TState extends Record<string, unknown> = Record<string, unknown>>(def: GameDefinition<TState>, inputLog?: InputLog | undefined) => HeadlessResult<TState>
|
|
310
332
|
- `runStudio`: (baseDef: GameDefinition<Record<string, unknown>>, mount: HTMLElement, opts?: StudioOptions) => StudioHandle
|
|
311
333
|
- `salienceIssues`: (commands: DrawCommand[], avatarFill: string, background: string, opts?: SalienceOptions) => string[]
|
|
334
|
+
- `sampleClip`: (def: ClipDef, elapsed: number) => SampledChannel[]
|
|
312
335
|
- `sampleGradient`: (stops: readonly string[], t: number) => string
|
|
336
|
+
- `samplePose`: (def: ClipDef, phase: number) => Pose
|
|
337
|
+
- `sampleTrack`: (keys: Keyframe[], t: number) => number
|
|
313
338
|
- `scaleMidis`: (tonic: number, mode?: "major" | "minor" | "harmonicMinor" | "melodicMinor" | "dorian" | "phrygian" | "lydian" | "mixolydian" | "locrian" | "majorPentatonic"…
|
|
314
339
|
- `scalePitchClasses`: (tonic: number, mode?: "major" | "minor" | "harmonicMinor" | "melodicMinor" | "dorian" | "phrygian" | "lydian" | "mixolydian" | "locrian" | "majorPentatonic"…
|
|
315
340
|
- `scatter`: (x: number, y: number, probability: number, seed?: number) => boolean
|
|
@@ -324,6 +349,7 @@
|
|
|
324
349
|
- `setScreenObserver`: (cb: ((kind: "show" | "hide", title?: string | undefined) => void) | null) => void
|
|
325
350
|
- `shadeHex`: (hex: string, f: number) => string
|
|
326
351
|
- `shadowDef`: (s: Shadow, id: string) => string
|
|
352
|
+
- `shadowQuads`: (light: Vec2, radius: number, segs: readonly ContourSegment[]) => number[][]
|
|
327
353
|
- `shapeBBox`: (c: DrawCommand) => BBox | null
|
|
328
354
|
- `shapeBox`: (cmd: DrawCommand) => { x: number; y: number; w: number; h: number; } | null
|
|
329
355
|
- `showScreen`: (spec: ScreenSpec) => ScreenHandle
|
|
@@ -336,13 +362,16 @@
|
|
|
336
362
|
- `softClipInPlace`: (buf: StereoBuffer) => void
|
|
337
363
|
- `solidNeighbours`: (g: Grid, x: number, y: number) => number
|
|
338
364
|
- `solve`: <State, Move>(puzzle: Puzzle<State, Move>, options?: SolveOptions) => SolveResult<Move>
|
|
365
|
+
- `solveFabrik`: (root: Vec2, lengths: number[], target: Vec2, opts?: { maxIter?: number | undefined; tolerance?: number | undefined; initial?: Vec2[] | undefined; }) => Fabr…
|
|
339
366
|
- `solveJoint`: (j: Joint, A: RigidBody, B: RigidBody, dt: number, scratch: JointScratch) => void
|
|
367
|
+
- `solveTwoBoneIK`: (root: Vec2, l0: number, l1: number, target: Vec2, bendDir?: 1 | -1) => TwoBoneResult
|
|
340
368
|
- `songBeats`: (song: Song) => number
|
|
341
369
|
- `songDuration`: (song: Song) => number
|
|
342
370
|
- `sortCommands`: (cmds: DrawCommand[]) => DrawCommand[]
|
|
343
371
|
- `spatialMix`: (dx: number, dy: number, hearing?: number, rolloff?: number) => SpatialMix
|
|
344
372
|
- `specFromZzfx`: (p: readonly (number | undefined)[]) => SoundSpec
|
|
345
373
|
- `spectralCentroid`: (sig: Samples, sampleRate?: number) => number
|
|
374
|
+
- `splitByLightLayer`: (sorted: DrawCommand[]) => LightRunSplit
|
|
346
375
|
- `springStep`: (s: SpringState, target: number, omega: number, dt: number) => SpringState
|
|
347
376
|
- `star`: (points: number, outer: number, inner: number, rotation?: number) => number[]
|
|
348
377
|
- `steer2D`: (px: number, py: number, tx: number, ty: number, out: string[], dead?: number) => void
|
|
@@ -380,7 +409,7 @@
|
|
|
380
409
|
- `worldPoints`: (b: RigidBody) => number[]
|
|
381
410
|
- `zcr`: (sig: Samples, sampleRate?: number) => number
|
|
382
411
|
|
|
383
|
-
## interfaces (
|
|
412
|
+
## interfaces (259)
|
|
384
413
|
|
|
385
414
|
- `AcceptedProof`
|
|
386
415
|
- `ActBounds`
|
|
@@ -402,7 +431,10 @@
|
|
|
402
431
|
- `BfsResult`
|
|
403
432
|
- `BitmapFont`
|
|
404
433
|
- `BitmapTextConfig`
|
|
434
|
+
- `BlendSample`
|
|
435
|
+
- `Bone2DConfig`
|
|
405
436
|
- `BotCtx`
|
|
437
|
+
- `BoundTrack`
|
|
406
438
|
- `Breakpoint`
|
|
407
439
|
- `CameraBounds`
|
|
408
440
|
- `CameraConfig`
|
|
@@ -416,6 +448,9 @@
|
|
|
416
448
|
- `Cell`
|
|
417
449
|
- `CinematicStep`
|
|
418
450
|
- `CircleCommand`
|
|
451
|
+
- `ClipDef`
|
|
452
|
+
- `ClipEvent`
|
|
453
|
+
- `ClipPlayerConfig`
|
|
419
454
|
- `ClockConfig`
|
|
420
455
|
- `Components`
|
|
421
456
|
- `ContactEvent`
|
|
@@ -439,6 +474,7 @@
|
|
|
439
474
|
- `Dungeon`
|
|
440
475
|
- `DungeonOptions`
|
|
441
476
|
- `EllipseCommand`
|
|
477
|
+
- `FabrikResult`
|
|
442
478
|
- `FeatureDelta`
|
|
443
479
|
- `FeedbackOptions`
|
|
444
480
|
- `FeedbackResponse`
|
|
@@ -466,6 +502,7 @@
|
|
|
466
502
|
- `HesitationSpan`
|
|
467
503
|
- `HotContext`
|
|
468
504
|
- `HSL`
|
|
505
|
+
- `IkTargetConfig`
|
|
469
506
|
- `ImageCommand`
|
|
470
507
|
- `InputLog`
|
|
471
508
|
- `InputSource`
|
|
@@ -473,12 +510,16 @@
|
|
|
473
510
|
- `IsoPrismConfig`
|
|
474
511
|
- `IsoProjection`
|
|
475
512
|
- `JointScratch`
|
|
513
|
+
- `Keyframe`
|
|
476
514
|
- `KnobEvent`
|
|
477
515
|
- `LayoutOptions`
|
|
478
516
|
- `LevelChange`
|
|
479
517
|
- `LevelData`
|
|
480
518
|
- `LevelEntity`
|
|
481
519
|
- `LevelSpec`
|
|
520
|
+
- `LightingOptions`
|
|
521
|
+
- `LightLayerConfig`
|
|
522
|
+
- `LightRunSplit`
|
|
482
523
|
- `LinearGradient`
|
|
483
524
|
- `LintOptions`
|
|
484
525
|
- `LockstepOptions`
|
|
@@ -501,6 +542,8 @@
|
|
|
501
542
|
- `Paint`
|
|
502
543
|
- `Palette`
|
|
503
544
|
- `ParallaxLayerConfig`
|
|
545
|
+
- `ParsedLight`
|
|
546
|
+
- `ParsedLightRun`
|
|
504
547
|
- `ParticleStyle`
|
|
505
548
|
- `PathCommand`
|
|
506
549
|
- `PhaseDef`
|
|
@@ -518,6 +561,7 @@
|
|
|
518
561
|
- `PointerReadout`
|
|
519
562
|
- `PointerSourceOptions`
|
|
520
563
|
- `PointerTarget`
|
|
564
|
+
- `PointLightConfig`
|
|
521
565
|
- `PolyCommand`
|
|
522
566
|
- `PostProcessPass`
|
|
523
567
|
- `ProgressState`
|
|
@@ -552,6 +596,7 @@
|
|
|
552
596
|
- `RoomHostOptions`
|
|
553
597
|
- `RunOptions`
|
|
554
598
|
- `SalienceOptions`
|
|
599
|
+
- `SampledChannel`
|
|
555
600
|
- `ScreenEvent`
|
|
556
601
|
- `ScreenHandle`
|
|
557
602
|
- `ScreenSpec`
|
|
@@ -561,6 +606,7 @@
|
|
|
561
606
|
- `Settings`
|
|
562
607
|
- `Shadow`
|
|
563
608
|
- `ShellOptions`
|
|
609
|
+
- `SkeletonDebugConfig`
|
|
564
610
|
- `SoftlockReport`
|
|
565
611
|
- `SolidRect`
|
|
566
612
|
- `SolveOptions`
|
|
@@ -594,12 +640,14 @@
|
|
|
594
640
|
- `TouchControlsLayout`
|
|
595
641
|
- `TouchStick`
|
|
596
642
|
- `Track`
|
|
643
|
+
- `TrackDef`
|
|
597
644
|
- `Transform`
|
|
598
645
|
- `Transition`
|
|
599
646
|
- `TransitionConfig`
|
|
600
647
|
- `Transport`
|
|
601
648
|
- `TuningKnob`
|
|
602
649
|
- `TuningSpec`
|
|
650
|
+
- `TwoBoneResult`
|
|
603
651
|
- `UpgradeDef`
|
|
604
652
|
- `Variant`
|
|
605
653
|
- `VariantRef`
|
|
@@ -623,11 +671,13 @@
|
|
|
623
671
|
- `WorldRegion`
|
|
624
672
|
- `WorldSnapshot`
|
|
625
673
|
|
|
626
|
-
## types (
|
|
674
|
+
## types (50)
|
|
627
675
|
|
|
628
676
|
- `AxisFrame`
|
|
629
677
|
- `BodyKind`
|
|
630
678
|
- `BoolGrid`
|
|
679
|
+
- `ClipChannel`
|
|
680
|
+
- `ClipLoop`
|
|
631
681
|
- `CompletionMode`
|
|
632
682
|
- `DistanceModel`
|
|
633
683
|
- `DrawCommand`
|
|
@@ -648,10 +698,12 @@
|
|
|
648
698
|
- `NetMessage`
|
|
649
699
|
- `NodeFactory`
|
|
650
700
|
- `NodeKey`
|
|
701
|
+
- `Occluder`
|
|
651
702
|
- `Passable`
|
|
652
703
|
- `PauseMode`
|
|
653
704
|
- `Pitch`
|
|
654
705
|
- `PlayerId`
|
|
706
|
+
- `Pose`
|
|
655
707
|
- `ProbeFrame`
|
|
656
708
|
- `ProgressMove`
|
|
657
709
|
- `RigidShape`
|
|
@@ -672,13 +724,14 @@
|
|
|
672
724
|
- `WipeKind`
|
|
673
725
|
- `WorldFactory`
|
|
674
726
|
|
|
675
|
-
## consts (
|
|
727
|
+
## consts (67)
|
|
676
728
|
|
|
677
729
|
- `ALBUM`: { title: string; subtitle: string; concept: string; tracks: AlbumTrack[]; }
|
|
678
730
|
- `AMBIENT_PRESETS`: { readonly snow: (colors?: string[]) => AmbientStyle; readonly rain: (colors?: string[]) => AmbientStyle; readonly ash: (colors?: string[]) => AmbientStyle; }
|
|
679
731
|
- `audio`: AudioBus
|
|
680
732
|
- `BLOOM_PIPELINE`: PostProcessPass[]
|
|
681
733
|
- `clamp`: (v: number, lo: number, hi: number) => number
|
|
734
|
+
- `CLIP_CHANNELS`: readonly ClipChannel[]
|
|
682
735
|
- `DEFAULT_GAMEPAD_MAP`: GamepadMap
|
|
683
736
|
- `DEFAULT_INPUT_MAP`: Readonly<Record<string, readonly string[]>>
|
|
684
737
|
- `DEFAULT_PLATFORMER`: PlatformerConfig
|
|
@@ -696,8 +749,12 @@
|
|
|
696
749
|
- `IDENTITY`: Transform
|
|
697
750
|
- `INSTRUMENTS`: Record<string, Instrument>
|
|
698
751
|
- `invLerp`: (a: number, b: number, v: number) => number
|
|
752
|
+
- `isLightCommand`: (c: DrawCommand) => boolean
|
|
699
753
|
- `KENTO`: { readonly gofun: "#f7f1e2"; readonly washi: "#efe7d3"; readonly kinu: "#e4d8bd"; readonly line: "#d8cbac"; readonly kinako: "#b9a882"; readonly stone: "#6c6…
|
|
700
754
|
- `knob`: { num(key: string, opts: { default: number; min?: number | undefined; max?: number | undefined; step?: number | undefined; label?: string | undefined; group?…
|
|
755
|
+
- `LAYER_HUD`: 1
|
|
756
|
+
- `LAYER_LIGHT`: 0.5
|
|
757
|
+
- `LAYER_WORLD`: 0
|
|
701
758
|
- `lerp`: (a: number, b: number, t: number) => number
|
|
702
759
|
- `lerpDamp`: (current: number, target: number, lambda: number, dt: number) => number
|
|
703
760
|
- `mapHeight`: (map: TilemapData) => number
|
|
@@ -714,6 +771,7 @@
|
|
|
714
771
|
- `PARTICLE_PRESETS`: { readonly dust: (colors?: string[]) => ParticleStyle; readonly burst: (colors?: string[]) => ParticleStyle; readonly hit: (colors?: string[]) => ParticleSty…
|
|
715
772
|
- `playerAction`: (player: string, action: string) => string
|
|
716
773
|
- `playerInput`: (world: World<Record<string, unknown>>, player: string) => PlayerInput
|
|
774
|
+
- `poseKey`: (target: string, channel: string) => string
|
|
717
775
|
- `rad2deg`: (r: number) => number
|
|
718
776
|
- `remap`: (v: number, a0: number, a1: number, b0: number, b1: number) => number
|
|
719
777
|
- `SAMPLE_RATE`: 44100
|
|
@@ -730,7 +788,7 @@
|
|
|
730
788
|
- `vdist`: (a: Vec2, b: Vec2) => number
|
|
731
789
|
- `vdot`: (a: Vec2, b: Vec2) => number
|
|
732
790
|
- `vec2`: (x?: number, y?: number) => Vec2
|
|
733
|
-
- `VERSION`: "0.4.
|
|
791
|
+
- `VERSION`: "0.4.1"
|
|
734
792
|
- `vlen`: (a: Vec2) => number
|
|
735
793
|
- `vscale`: (a: Vec2, s: number) => Vec2
|
|
736
794
|
- `vsub`: (a: Vec2, b: Vec2) => Vec2
|
package/docs/CONVENTIONS.md
CHANGED
|
@@ -342,6 +342,62 @@ broken by tree order. For any game where sprites overlap (top-down, iso), derive
|
|
|
342
342
|
- **`diamond` / `regularPoly` shapes** — sugar over `poly` so an iso tile or hex
|
|
343
343
|
reads as intent, not four re-typed corners.
|
|
344
344
|
|
|
345
|
+
## The animation & lighting seam
|
|
346
|
+
|
|
347
|
+
Two subsystems landed in 0.4.1 — authored **animation** (clips, blend spaces, IK,
|
|
348
|
+
skeletons) and 2D **lighting** (a light layer, point lights, occluder shadows).
|
|
349
|
+
They look unrelated, but they ride the SAME rule, and it is the one rule that
|
|
350
|
+
keeps them from rotting the sim: **deterministic data lives in the sim; the
|
|
351
|
+
motion and the light are observer-side presentation.**
|
|
352
|
+
|
|
353
|
+
Concretely, on the LOGICAL side (`world.state`, hashed, rolled back, replayed):
|
|
354
|
+
the pose a game *reasons about* is an `Fsm.current` / `PhaseClock` / committed
|
|
355
|
+
anchors + hitboxes in `world.state`, all advanced through `dmath`. Light state
|
|
356
|
+
that *drives gameplay* (is the torch lit? how alarmed is the sentry?) is a value
|
|
357
|
+
in `world.state` too. On the OBSERVER side: `ClipPlayer`, `IkTarget`,
|
|
358
|
+
`SkeletonDebug`, `LightLayer`, and `PointLight` are all `cosmetic = true` by
|
|
359
|
+
construction — they render state that lives elsewhere and are **excluded from
|
|
360
|
+
`serialize()` / `hash()` / `snapshot()`**. State flows LOGICAL → view, never the
|
|
361
|
+
reverse.
|
|
362
|
+
|
|
363
|
+
What that forbids, in order of how often it bites:
|
|
364
|
+
|
|
365
|
+
- **Never read a visual pose back into the sim.** A gameplay anchor — a muzzle,
|
|
366
|
+
a hand, a foot-plant — is computed on the LOGICAL side with `dmath`, NEVER read
|
|
367
|
+
from a posed `bone.worldTransform()`. The clip/IK result is one frame of eased,
|
|
368
|
+
crossfaded, observer-only motion; sampling it into the sim couples the hash to
|
|
369
|
+
the animation and the replay diverges. **The committed-anchor recipe** is the
|
|
370
|
+
lead pattern: the sim owns the muzzle point as a `dmath` offset from the
|
|
371
|
+
logical body (in `world.state`); the ClipPlayer poses the visible gun to *point
|
|
372
|
+
at* it; a shot spawns from the committed anchor, not from the barrel sprite's
|
|
373
|
+
world transform. The picture follows the truth; the truth never asks the
|
|
374
|
+
picture where it landed.
|
|
375
|
+
- **Blend weights, IK reach, and light intensity never gate gameplay.** A
|
|
376
|
+
`Blend1D` weight, an `IkTarget.reached` flag, a `PointLight.litIntensity` after
|
|
377
|
+
flicker — these are view outputs. Branch gameplay on the logical parameter that
|
|
378
|
+
*fed* them (the `world.state` speed, the logical "is the target in range"
|
|
379
|
+
distance, the `world.state` lit boolean), not on the interpolated result.
|
|
380
|
+
- **Secondary-motion and flicker RNG is observer-seeded — never `world.rng`.**
|
|
381
|
+
A `PointLight`'s flicker uses a private `Rng` seeded at construction (the
|
|
382
|
+
Particles precedent), advanced in `onProcess`, never in `draw` (which may run
|
|
383
|
+
0..n times per step). Same for any spring/wobble jitter on the rig. Pulling
|
|
384
|
+
those numbers from `world.rng` would race the gameplay stream and desync every
|
|
385
|
+
replay.
|
|
386
|
+
|
|
387
|
+
**The proof pattern to copy** is the stripped-rig hash-equality test in
|
|
388
|
+
`src/scene/clipPlayer.test.ts`: build a world whose logic advances every frame
|
|
389
|
+
*with* the full cosmetic rig, build the same world *without* it, and assert
|
|
390
|
+
`withRig.hash() === without.hash()` at every frame (plus `assertSnapshotStable`
|
|
391
|
+
with warmup landing mid-clip and mid-crossfade). If stripping the animation
|
|
392
|
+
changes the hash, a visual write has leaked into the sim — the test names the
|
|
393
|
+
frame. Lighting has the same proof: `examples/duskveil/` was relit with a
|
|
394
|
+
`LightLayer` + two cosmetic `PointLight`s over the existing fight, and its golden
|
|
395
|
+
hash is **unchanged** — the lights are pure view, so the pinned replay survives
|
|
396
|
+
the relight. Both sandboxes wire the seam the idiomatic way end to end
|
|
397
|
+
(`sandboxes/anim-lab/` for the rig, `sandboxes/light-lab/` for the lights):
|
|
398
|
+
canonical knob state is hashed, the whole rig/light apparatus is cosmetic and
|
|
399
|
+
excluded.
|
|
400
|
+
|
|
345
401
|
## The human-contact layer
|
|
346
402
|
|
|
347
403
|
The first real playtest of the campaign found every defect in the one layer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hayao",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An AI-first game engine: a deterministic, headless-native simulation kernel with a Godot-style scene tree, pluggable renderers (SVG/Canvas/headless), and a built-in verification harness — designed so an LLM can author, test, and prove correct a whole game without ever opening a browser.",
|
|
6
6
|
"keywords": [
|