hayao 0.1.0 → 0.2.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.
Files changed (47) hide show
  1. package/README.md +29 -12
  2. package/dist/art/autotile.d.ts +77 -0
  3. package/dist/art/bitmapFont.d.ts +113 -0
  4. package/dist/art/font5.d.ts +11 -0
  5. package/dist/art/palette.d.ts +38 -0
  6. package/dist/art/texture.d.ts +78 -0
  7. package/dist/audio/audio.d.ts +7 -0
  8. package/dist/content/dsl.d.ts +61 -0
  9. package/dist/core/dmath.d.ts +20 -0
  10. package/dist/core/math.d.ts +2 -0
  11. package/dist/index.d.ts +37 -1
  12. package/dist/index.js +4549 -69
  13. package/dist/index.js.map +4 -4
  14. package/dist/logic/fsm.d.ts +85 -0
  15. package/dist/logic/graph.d.ts +88 -0
  16. package/dist/logic/history.d.ts +54 -0
  17. package/dist/logic/random.d.ts +32 -0
  18. package/dist/net/browser.d.ts +37 -0
  19. package/dist/net/inputBuffer.d.ts +27 -0
  20. package/dist/net/lockstep.d.ts +79 -0
  21. package/dist/net/players.d.ts +27 -0
  22. package/dist/net/protocol.d.ts +100 -0
  23. package/dist/net/rollback.d.ts +89 -0
  24. package/dist/net/room.d.ts +78 -0
  25. package/dist/net/transport.d.ts +78 -0
  26. package/dist/persist/codec.d.ts +4 -0
  27. package/dist/persist/save.d.ts +32 -0
  28. package/dist/persist/storage.d.ts +46 -0
  29. package/dist/physics/rigidBody.d.ts +104 -0
  30. package/dist/physics/rigidCollide.d.ts +16 -0
  31. package/dist/physics/rigidJoints.d.ts +65 -0
  32. package/dist/physics/rigidQueries.d.ts +15 -0
  33. package/dist/physics/rigidStep.d.ts +14 -0
  34. package/dist/procgen/cave.d.ts +21 -0
  35. package/dist/procgen/grid.d.ts +21 -0
  36. package/dist/procgen/rooms.d.ts +34 -0
  37. package/dist/procgen/scatter.d.ts +32 -0
  38. package/dist/procgen/terrain.d.ts +24 -0
  39. package/dist/render/nineSlice.d.ts +32 -0
  40. package/dist/scene/floatingText.d.ts +51 -0
  41. package/dist/scene/particles.d.ts +64 -0
  42. package/dist/scene/pool.d.ts +16 -0
  43. package/dist/scene/tween.d.ts +26 -0
  44. package/dist/ui/transition.d.ts +107 -0
  45. package/dist/verify/layout.d.ts +39 -0
  46. package/docs/API.md +247 -8
  47. package/package.json +31 -9
@@ -0,0 +1,51 @@
1
+ import type { Transform, Vec2 } from '../core/math';
2
+ import type { DrawCommand, TextAlign } from '../render/commands';
3
+ import { Node, type NodeConfig } from './node';
4
+ export interface FloatStyle {
5
+ /** Text colour. */
6
+ color: string;
7
+ /** Font size in px. */
8
+ size?: number;
9
+ font?: string;
10
+ weight?: number;
11
+ align?: TextAlign;
12
+ /** Upward speed in px/s (screen +y is down, so this is negated internally). */
13
+ rise?: number;
14
+ /** Gravity pulling the rise back down (px/s²) — arcs the pop. */
15
+ gravity?: number;
16
+ /** Lifetime in seconds. */
17
+ life?: number;
18
+ /** Random horizontal spread of the launch (px/s). */
19
+ jitter?: number;
20
+ /** Fraction of life spent fading out at the end (0..1, default 0.4). */
21
+ fade?: number;
22
+ }
23
+ /**
24
+ * A pooled floating-text emitter. Call `pop(text, at, style)` from game code in
25
+ * response to feel events. Always cosmetic; add it wherever the numbers should
26
+ * live in the tree (usually the world layer, so pops ride the camera).
27
+ */
28
+ export declare class FloatingText extends Node {
29
+ readonly type: string;
30
+ private pool;
31
+ private rng;
32
+ /** Cap on live popups (oldest recycled first). */
33
+ maxPopups: number;
34
+ constructor(config?: NodeConfig & {
35
+ seed?: number;
36
+ maxPopups?: number;
37
+ });
38
+ /** Spawn one popup at `at` (in this node's local space). */
39
+ pop(text: string, at: Vec2, style: FloatStyle): void;
40
+ private gravity;
41
+ protected onProcess(dt: number): void;
42
+ protected draw(out: DrawCommand[], world: Transform): void;
43
+ get liveCount(): number;
44
+ }
45
+ /** Ready-made popup looks for the common combat moments. */
46
+ export declare const FLOAT_PRESETS: {
47
+ readonly damage: (color?: string) => FloatStyle;
48
+ readonly crit: (color?: string) => FloatStyle;
49
+ readonly heal: (color?: string) => FloatStyle;
50
+ readonly label: (color?: string) => FloatStyle;
51
+ };
@@ -53,6 +53,70 @@ export declare const PARTICLE_PRESETS: {
53
53
  readonly hit: (colors?: string[]) => ParticleStyle;
54
54
  readonly sparkle: (colors?: string[]) => ParticleStyle;
55
55
  };
56
+ export interface AmbientStyle {
57
+ /** Colors drawn from at random per particle. */
58
+ colors: string[];
59
+ /** Particle radius range (px). */
60
+ sizeMin: number;
61
+ sizeMax: number;
62
+ /** Steady horizontal wind (px/s). */
63
+ windX?: number;
64
+ /** Fall speed (px/s, +y down). Snow ≈ 40, rain ≈ 600. */
65
+ fallY: number;
66
+ /** Horizontal sway amplitude (px) and frequency (Hz) — gives snow its wobble. */
67
+ swayAmp?: number;
68
+ swayFreq?: number;
69
+ /** Draw vertical streaks instead of dots (rain). */
70
+ streak?: boolean;
71
+ /** Streak length (px) in streak mode. Default = fallY * 0.03. */
72
+ streakLen?: number;
73
+ }
74
+ /** A single weather keyframe: `intensity` (0..1) reached at sim `time` (s). */
75
+ export interface WeatherKey {
76
+ time: number;
77
+ intensity: number;
78
+ }
79
+ /**
80
+ * Smoothstep-interpolated weather intensity at sim time `t` over an ordered list
81
+ * of keyframes. Before the first / after the last key it holds that key's value.
82
+ * Pure — drive it with `world.time`, never wall-clock.
83
+ */
84
+ export declare function weatherEnvelope(t: number, keys: readonly WeatherKey[]): number;
85
+ /**
86
+ * A screen-wrapping ambient field for snow, rain, dust, or ash. Seed once with a
87
+ * region size; it fills itself and drifts forever. Set `.envelope` to fade the
88
+ * weather in/out over sim time. Always cosmetic.
89
+ */
90
+ export declare class AmbientField extends Node {
91
+ readonly type: string;
92
+ private rng;
93
+ private field;
94
+ private time;
95
+ private style;
96
+ /** Field region (px). Particles wrap within [0,width] × [0,height]. */
97
+ width: number;
98
+ height: number;
99
+ /** Optional weather intensity schedule; scales count/opacity. */
100
+ envelope?: WeatherKey[];
101
+ constructor(config: NodeConfig & {
102
+ seed?: number;
103
+ count?: number;
104
+ width: number;
105
+ height: number;
106
+ style: AmbientStyle;
107
+ envelope?: WeatherKey[];
108
+ });
109
+ private intensity;
110
+ protected onProcess(dt: number): void;
111
+ protected draw(out: DrawCommand[], world: Transform): void;
112
+ get liveCount(): number;
113
+ }
114
+ /** Ready-made ambient weather styles (pair with `AmbientField`). */
115
+ export declare const AMBIENT_PRESETS: {
116
+ readonly snow: (colors?: string[]) => AmbientStyle;
117
+ readonly rain: (colors?: string[]) => AmbientStyle;
118
+ readonly ash: (colors?: string[]) => AmbientStyle;
119
+ };
56
120
  /**
57
121
  * Screen shake as a cosmetic camera offset with its own Rng and exponential
58
122
  * decay. Attach to whatever node the camera follows and read `offset` into the
@@ -0,0 +1,16 @@
1
+ import type { Node } from './node';
2
+ export declare class NodePool<T extends Node = Node> {
3
+ private parent;
4
+ private make;
5
+ private items;
6
+ private used;
7
+ constructor(parent: Node, make: () => T);
8
+ /** Start a frame: every pooled node is up for reuse. */
9
+ begin(): void;
10
+ /** Claim the next node (created and parented on first use), made visible. */
11
+ get(): T;
12
+ /** End a frame: hide every node not claimed since begin(). */
13
+ end(): void;
14
+ /** Nodes claimed this frame (call after the get() loop). */
15
+ get liveCount(): number;
16
+ }
@@ -1,5 +1,31 @@
1
1
  import { Node } from './node';
2
2
  export type Easing = (t: number) => number;
3
+ /**
4
+ * Exponentially damp `current` toward `target`, framerate-independent.
5
+ * `lambda` is the decay rate (1/s): larger = snappier. Reaches ~63% of the way
6
+ * to the target after 1/lambda seconds regardless of how dt is subdivided.
7
+ */
8
+ export declare const lerpDamp: (current: number, target: number, lambda: number, dt: number) => number;
9
+ /** A critically-damped spring value: rides toward a target with no overshoot. */
10
+ export interface SpringState {
11
+ value: number;
12
+ vel: number;
13
+ }
14
+ /** Make a spring at rest on `value`. */
15
+ export declare const spring: (value?: number) => SpringState;
16
+ /**
17
+ * Advance a critically-damped spring one fixed step toward `target`. `omega` is
18
+ * the angular frequency (rad/s) — higher snaps faster. Critical damping means it
19
+ * settles as fast as possible without oscillating. Mutates and returns the state.
20
+ * Uses the closed-form solution so it is stable at any dt (no stiffness blow-up).
21
+ */
22
+ export declare function springStep(s: SpringState, target: number, omega: number, dt: number): SpringState;
23
+ /**
24
+ * One-liner critically-damped follow that owns its own velocity in a closure —
25
+ * for camera/value chase where you don't want to thread a SpringState around.
26
+ * `settle` is the approximate time (s) to arrive. Returns a `(target, dt) → value`.
27
+ */
28
+ export declare function makeReach(start?: number, settle?: number): (target: number, dt: number) => number;
3
29
  export declare const EASINGS: Record<string, Easing>;
4
30
  /** A node that runs one or more property tweens and reports when they finish. */
5
31
  export declare class AnimationPlayer extends Node {
@@ -0,0 +1,107 @@
1
+ import { type Rect, type Transform } from '../core/math';
2
+ import type { DrawCommand } from '../render/commands';
3
+ import { Node, type NodeConfig } from '../scene/node';
4
+ export type WipeKind = 'fade' | 'circle' | 'dither';
5
+ export interface WipeOptions {
6
+ /** Seconds to cover the screen (default 0.4). */
7
+ cover?: number;
8
+ /** Seconds to hold fully covered before revealing (default 0). */
9
+ hold?: number;
10
+ /** Seconds to reveal the scene again (default = cover). */
11
+ reveal?: number;
12
+ /** Fired at full cover — swap the level/scene here. */
13
+ onMidpoint?: () => void;
14
+ /** Fired once the reveal finishes. */
15
+ onDone?: () => void;
16
+ }
17
+ export interface TransitionConfig extends NodeConfig {
18
+ kind?: WipeKind;
19
+ /** Overlay colour. */
20
+ color?: string;
21
+ /** Screen size in px (pass world.width / world.height). */
22
+ width?: number;
23
+ height?: number;
24
+ /** Dither cell size in px (default 28). */
25
+ cell?: number;
26
+ }
27
+ /**
28
+ * A full-screen wipe overlay. Add it to the tree (cosmetic), then drive it with
29
+ * `cover()` / `reveal()` / `wipe()`. `coverage` runs 0 (clear) → 1 (opaque).
30
+ */
31
+ export declare class ScreenTransition extends Node {
32
+ readonly type: string;
33
+ kind: WipeKind;
34
+ color: string;
35
+ screenW: number;
36
+ screenH: number;
37
+ cell: number;
38
+ /** 0 = fully clear, 1 = fully covering. */
39
+ coverage: number;
40
+ private queue;
41
+ constructor(config?: TransitionConfig);
42
+ /** True while a wipe is animating. */
43
+ get busy(): boolean;
44
+ private enqueue;
45
+ /** Animate the overlay to fully covering over `dur` seconds. */
46
+ cover(dur?: number, onEnd?: () => void): this;
47
+ /** Animate the overlay back to fully clear over `dur` seconds. */
48
+ reveal(dur?: number, onEnd?: () => void): this;
49
+ /** Hold the current coverage for `dur` seconds (chains after cover/reveal). */
50
+ hold(dur: number, onEnd?: () => void): this;
51
+ /** The classic cover → onMidpoint → reveal sequence. Returns this for chaining. */
52
+ wipe(opts?: WipeOptions): this;
53
+ /** Signal emitted at full cover (the midpoint). */
54
+ get covered(): import("..").Signal<void>;
55
+ /** Signal emitted when a wipe fully finishes revealing. */
56
+ get done(): import("..").Signal<void>;
57
+ protected onProcess(dt: number): void;
58
+ protected draw(out: DrawCommand[], _world: Transform): void;
59
+ }
60
+ export interface CinematicStep {
61
+ /** Optional label (handy for debugging/skip logic). */
62
+ name?: string;
63
+ /** Runs once when the step begins — aim the camera, set text, mutate state. */
64
+ enter?: () => void;
65
+ /** Minimum seconds to hold on this step before advancing (default 0). */
66
+ duration?: number;
67
+ /** Gate: advance only once this returns true (e.g. `() => !transition.busy`). */
68
+ until?: () => boolean;
69
+ }
70
+ /**
71
+ * Runs a list of pure-data cinematic steps on the fixed clock. Each step's
72
+ * `enter` fires once, then the player waits for both its `duration` and its
73
+ * `until` gate before moving on — the fade-gate pattern for scripted intros.
74
+ * Cosmetic: it only orchestrates view/state changes, holds no hashed state.
75
+ */
76
+ export declare class CinematicPlayer extends Node {
77
+ readonly type: string;
78
+ private steps;
79
+ private index;
80
+ private elapsed;
81
+ private running;
82
+ private onFinish?;
83
+ constructor(config?: NodeConfig);
84
+ /** Load and start a sequence. `onDone` fires after the last step advances. */
85
+ play(steps: CinematicStep[], onDone?: () => void): this;
86
+ /** True while a sequence is playing. */
87
+ get active(): boolean;
88
+ /** Index of the step currently on screen (−1 before play / after finish). */
89
+ get step(): number;
90
+ /** Signal emitted when the whole sequence finishes. */
91
+ get finished(): import("..").Signal<void>;
92
+ private advance;
93
+ /** Abort the sequence immediately (no further enters, no finish callback). */
94
+ stop(): void;
95
+ protected onProcess(dt: number): void;
96
+ }
97
+ /**
98
+ * Convenience: make a Transition sized to a world and add it to a parent (the
99
+ * scene root by default, so it paints over everything). Returns the node.
100
+ */
101
+ export declare function addTransition(parent: Node, config?: TransitionConfig): ScreenTransition;
102
+ /** A cinematic step that fires a wipe and gates advancement on its completion. */
103
+ export declare function wipeStep(transition: ScreenTransition, opts?: WipeOptions & {
104
+ name?: string;
105
+ }): CinematicStep;
106
+ /** Screen rect helper for wiring a Transition into other 9-slice/UI code. */
107
+ export declare const screenRect: (w: number, h: number) => Rect;
@@ -0,0 +1,39 @@
1
+ import type { DrawCommand, TextCommand } from '../render/commands';
2
+ import type { InputMap } from '../input/actions';
3
+ import type { World } from '../world';
4
+ export interface TextBox {
5
+ cmd: TextCommand;
6
+ x: number;
7
+ y: number;
8
+ w: number;
9
+ h: number;
10
+ }
11
+ /** Approximate a text command's on-screen box (serif ≈ 0.56em per char). */
12
+ export declare function textBox(cmd: TextCommand): TextBox;
13
+ /** Conservative bounds of a non-text command (local shape + translation). */
14
+ export declare function shapeBox(cmd: DrawCommand): {
15
+ x: number;
16
+ y: number;
17
+ w: number;
18
+ h: number;
19
+ } | null;
20
+ export interface LayoutOptions {
21
+ /** Shapes at or below this z are background lattice (tiles/felt) and may sit under text. */
22
+ backgroundZ?: number;
23
+ /** Extra pixels of breathing room demanded around text (default 0 = touch is allowed, overlap is not). */
24
+ margin?: number;
25
+ }
26
+ /**
27
+ * Lint a display list for text readability. Returns human-readable issues
28
+ * (empty = clean). Checks: text-vs-shape partial overlaps (rule 1) and
29
+ * text-vs-text overlaps.
30
+ */
31
+ export declare function layoutIssues(commands: DrawCommand[], opts?: LayoutOptions): string[];
32
+ /** Friendly names a hint text may use to reference a key code. */
33
+ export declare function keyMentions(code: string): string[];
34
+ /**
35
+ * First-contact check: which actions does no on-screen text explain? An
36
+ * action passes if any text mentions its name or one of its keys' friendly
37
+ * names. 'restart' is exempt (universal convention).
38
+ */
39
+ export declare function missingControlHints(world: World, inputMap: InputMap): string[];