@arcane-engine/runtime 0.1.0 → 0.2.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.
Files changed (47) hide show
  1. package/package.json +4 -2
  2. package/src/agent/protocol.ts +35 -1
  3. package/src/agent/types.ts +98 -13
  4. package/src/particles/emitter.test.ts +323 -0
  5. package/src/particles/emitter.ts +409 -0
  6. package/src/particles/index.ts +25 -0
  7. package/src/particles/types.ts +236 -0
  8. package/src/pathfinding/astar.ts +27 -0
  9. package/src/pathfinding/types.ts +39 -0
  10. package/src/physics/aabb.ts +55 -8
  11. package/src/rendering/animation.ts +73 -0
  12. package/src/rendering/audio.ts +29 -9
  13. package/src/rendering/camera.ts +28 -4
  14. package/src/rendering/input.ts +45 -9
  15. package/src/rendering/lighting.ts +29 -3
  16. package/src/rendering/loop.ts +16 -3
  17. package/src/rendering/sprites.ts +24 -1
  18. package/src/rendering/text.ts +52 -6
  19. package/src/rendering/texture.ts +22 -4
  20. package/src/rendering/tilemap.ts +36 -4
  21. package/src/rendering/types.ts +37 -19
  22. package/src/rendering/validate.ts +48 -3
  23. package/src/state/error.ts +21 -2
  24. package/src/state/observe.ts +40 -9
  25. package/src/state/prng.ts +88 -10
  26. package/src/state/query.ts +115 -15
  27. package/src/state/store.ts +42 -11
  28. package/src/state/transaction.ts +116 -12
  29. package/src/state/types.ts +31 -5
  30. package/src/systems/system.ts +77 -5
  31. package/src/systems/types.ts +52 -6
  32. package/src/testing/harness.ts +103 -5
  33. package/src/testing/mock-renderer.test.ts +16 -20
  34. package/src/tweening/chain.test.ts +191 -0
  35. package/src/tweening/chain.ts +103 -0
  36. package/src/tweening/easing.test.ts +134 -0
  37. package/src/tweening/easing.ts +288 -0
  38. package/src/tweening/helpers.test.ts +185 -0
  39. package/src/tweening/helpers.ts +166 -0
  40. package/src/tweening/index.ts +76 -0
  41. package/src/tweening/tween.test.ts +322 -0
  42. package/src/tweening/tween.ts +296 -0
  43. package/src/tweening/types.ts +134 -0
  44. package/src/ui/colors.ts +129 -0
  45. package/src/ui/index.ts +1 -0
  46. package/src/ui/primitives.ts +44 -5
  47. package/src/ui/types.ts +41 -2
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Core tweening implementation.
3
+ *
4
+ * Manages a global list of active tweens. Call {@link updateTweens} once per
5
+ * frame (typically inside your `onFrame` callback) to advance all tweens.
6
+ */
7
+
8
+ import type {
9
+ Tween,
10
+ TweenOptions,
11
+ TweenProps,
12
+ EasingFunction,
13
+ } from "./types.ts";
14
+ import { TweenState } from "./types.ts";
15
+
16
+ /** Active tweens being updated */
17
+ const activeTweens: Tween[] = [];
18
+
19
+ /** Counter for generating unique tween IDs */
20
+ let tweenIdCounter = 0;
21
+
22
+ /**
23
+ * Linear easing function (identity). Used as the default when no easing is specified.
24
+ * @param t - Progress from 0 to 1.
25
+ * @returns The same value `t`, unchanged.
26
+ */
27
+ export function linear(t: number): number {
28
+ return t;
29
+ }
30
+
31
+ /**
32
+ * Create and start a tween that interpolates numeric properties on `target`
33
+ * from their current values to the values specified in `props`.
34
+ *
35
+ * The tween is automatically added to the global update list. Call
36
+ * {@link updateTweens} each frame to advance it.
37
+ *
38
+ * @param target - Object whose numeric properties will be interpolated.
39
+ * @param props - Map of property names to their target (end) values.
40
+ * @param duration - Animation duration in seconds. Use 0 for instant.
41
+ * @param options - Optional easing, delay, repeat, yoyo, and lifecycle callbacks.
42
+ * @returns The created {@link Tween} instance for further control.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const sprite = { x: 0, y: 0, alpha: 1 };
47
+ * // Move sprite to (100, 50) over 0.5 seconds with ease-out
48
+ * const t = tween(sprite, { x: 100, y: 50 }, 0.5, {
49
+ * easing: easeOutQuad,
50
+ * onComplete: () => console.log("done!"),
51
+ * });
52
+ * ```
53
+ */
54
+ export function tween(
55
+ target: any,
56
+ props: TweenProps,
57
+ duration: number,
58
+ options: TweenOptions = {},
59
+ ): Tween {
60
+ const tweenInstance: Tween = {
61
+ id: `tween_${tweenIdCounter++}`,
62
+ state: options.delay && options.delay > 0 ? TweenState.PENDING : TweenState.ACTIVE,
63
+ target,
64
+ props,
65
+ startValues: {}, // Will be captured when tween starts
66
+ duration,
67
+ options: {
68
+ easing: options.easing ?? linear,
69
+ delay: options.delay ?? 0,
70
+ repeat: options.repeat ?? 0,
71
+ yoyo: options.yoyo ?? false,
72
+ onStart: options.onStart,
73
+ onUpdate: options.onUpdate,
74
+ onComplete: options.onComplete,
75
+ onRepeat: options.onRepeat,
76
+ },
77
+ elapsed: 0,
78
+ delayElapsed: 0,
79
+ currentRepeat: 0,
80
+ isReversed: false,
81
+ };
82
+
83
+ // If no delay, capture start values and call onStart immediately
84
+ if (tweenInstance.options.delay === 0) {
85
+ captureStartValues(tweenInstance);
86
+ if (tweenInstance.options.onStart) {
87
+ tweenInstance.options.onStart();
88
+ }
89
+ }
90
+
91
+ activeTweens.push(tweenInstance);
92
+ return tweenInstance;
93
+ }
94
+
95
+ /**
96
+ * Advance all active tweens by the given delta time.
97
+ *
98
+ * Call this once per frame in your game loop. Handles delay, easing,
99
+ * property interpolation, repeat/yoyo, and lifecycle callbacks.
100
+ * Completed and stopped tweens are automatically removed from the list.
101
+ *
102
+ * @param dt - Elapsed time since last frame, in seconds. Must be >= 0.
103
+ */
104
+ export function updateTweens(dt: number): void {
105
+ for (let i = activeTweens.length - 1; i >= 0; i--) {
106
+ const t = activeTweens[i];
107
+
108
+ if (t.state === TweenState.PAUSED) {
109
+ continue;
110
+ }
111
+
112
+ if (t.state === TweenState.PENDING) {
113
+ // Handle delay
114
+ t.delayElapsed += dt;
115
+ if (t.delayElapsed >= t.options.delay) {
116
+ t.state = TweenState.ACTIVE;
117
+ captureStartValues(t);
118
+ if (t.options.onStart) {
119
+ t.options.onStart();
120
+ }
121
+ }
122
+ continue;
123
+ }
124
+
125
+ if (t.state !== TweenState.ACTIVE) {
126
+ continue;
127
+ }
128
+
129
+ // Update elapsed time
130
+ t.elapsed += dt;
131
+
132
+ // Calculate progress (0 to 1)
133
+ // Handle zero duration specially
134
+ let progress = t.duration === 0 ? 1.0 : Math.min(t.elapsed / t.duration, 1.0);
135
+
136
+ // Apply easing
137
+ const easedProgress = t.options.easing(progress);
138
+
139
+ // Update target properties
140
+ updateTargetProps(t, easedProgress);
141
+
142
+ // Call onUpdate callback
143
+ if (t.options.onUpdate) {
144
+ t.options.onUpdate(progress);
145
+ }
146
+
147
+ // Check if tween is complete
148
+ if (progress >= 1.0) {
149
+ handleTweenComplete(t, i);
150
+ }
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Capture start values from target
156
+ */
157
+ function captureStartValues(t: Tween): void {
158
+ for (const key in t.props) {
159
+ t.startValues[key] = t.target[key] ?? 0;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Update target properties based on progress
165
+ */
166
+ function updateTargetProps(t: Tween, easedProgress: number): void {
167
+ for (const key in t.props) {
168
+ const start = t.startValues[key];
169
+ const end = t.props[key];
170
+ const delta = end - start;
171
+ t.target[key] = start + delta * easedProgress;
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Handle tween completion
177
+ */
178
+ function handleTweenComplete(t: Tween, index: number): void {
179
+ // Check for repeat
180
+ if (t.options.repeat === -1 || t.currentRepeat < t.options.repeat) {
181
+ t.currentRepeat++;
182
+ t.elapsed = 0;
183
+
184
+ // Handle yoyo
185
+ if (t.options.yoyo) {
186
+ // Swap start and target values to reverse direction
187
+ const temp = { ...t.startValues };
188
+ t.startValues = { ...t.props };
189
+ t.props = temp;
190
+ } else {
191
+ // Reset to original start values
192
+ captureStartValues(t);
193
+ }
194
+
195
+ if (t.options.onRepeat) {
196
+ t.options.onRepeat();
197
+ }
198
+ } else {
199
+ // Tween complete
200
+ t.state = TweenState.COMPLETED;
201
+
202
+ if (t.options.onComplete) {
203
+ t.options.onComplete();
204
+ }
205
+
206
+ // Remove from active tweens
207
+ activeTweens.splice(index, 1);
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Stop a tween immediately and remove it from the update list.
213
+ * Sets state to {@link TweenState.STOPPED}. The `onComplete` callback is NOT called.
214
+ *
215
+ * @param t - The tween to stop.
216
+ */
217
+ export function stopTween(t: Tween): void {
218
+ t.state = TweenState.STOPPED;
219
+ const index = activeTweens.indexOf(t);
220
+ if (index !== -1) {
221
+ activeTweens.splice(index, 1);
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Pause a tween, freezing it at its current progress.
227
+ * Only affects tweens in "active" or "pending" state. Use {@link resumeTween} to continue.
228
+ *
229
+ * @param t - The tween to pause.
230
+ */
231
+ export function pauseTween(t: Tween): void {
232
+ if (t.state === TweenState.ACTIVE || t.state === TweenState.PENDING) {
233
+ t.state = TweenState.PAUSED;
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Resume a paused tween from where it left off.
239
+ * Restores the tween to "active" or "pending" state depending on whether the delay had elapsed.
240
+ * No-op if the tween is not paused.
241
+ *
242
+ * @param t - The tween to resume.
243
+ */
244
+ export function resumeTween(t: Tween): void {
245
+ if (t.state === TweenState.PAUSED) {
246
+ t.state = t.delayElapsed < t.options.delay ? TweenState.PENDING : TweenState.ACTIVE;
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Stop all active tweens and clear the update list.
252
+ * Sets every tween's state to {@link TweenState.STOPPED}. No `onComplete` callbacks are called.
253
+ */
254
+ export function stopAllTweens(): void {
255
+ for (const t of activeTweens) {
256
+ t.state = TweenState.STOPPED;
257
+ }
258
+ activeTweens.length = 0;
259
+ }
260
+
261
+ /**
262
+ * Reverse a tween's direction mid-flight.
263
+ *
264
+ * Captures the target's current property values as the new start,
265
+ * and sets the original start values as the new target. Resets elapsed
266
+ * time so the tween animates back from the current position.
267
+ *
268
+ * @param t - The tween to reverse.
269
+ */
270
+ export function reverseTween(t: Tween): void {
271
+ // Capture current values as the new start
272
+ const currentValues: Record<string, number> = {};
273
+ for (const key in t.props) {
274
+ currentValues[key] = t.target[key];
275
+ }
276
+
277
+ // New target is the old start
278
+ const newTarget = { ...t.startValues };
279
+
280
+ // Update tween
281
+ t.startValues = currentValues;
282
+ t.props = newTarget;
283
+
284
+ // Reset elapsed to animate from current position
285
+ t.elapsed = 0;
286
+ }
287
+
288
+ /**
289
+ * Get the number of tweens currently in the update list (active, pending, or paused).
290
+ * Useful for debugging and testing.
291
+ *
292
+ * @returns Count of tweens that have not yet completed or been stopped.
293
+ */
294
+ export function getActiveTweenCount(): number {
295
+ return activeTweens.length;
296
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Tweening system type definitions.
3
+ *
4
+ * Tweens smoothly interpolate numeric properties on any object over time.
5
+ * Used for animations, UI transitions, camera effects, and game juice.
6
+ */
7
+
8
+ /**
9
+ * A function that maps linear progress to eased progress.
10
+ * See `runtime/tweening/easing.ts` for 30 built-in easing functions.
11
+ *
12
+ * @param t - Linear progress, clamped to 0..1 by the tween system.
13
+ * @returns Eased value. Usually 0..1, but may overshoot for back/elastic easings.
14
+ */
15
+ export type EasingFunction = (t: number) => number;
16
+
17
+ /**
18
+ * Callback invoked at tween lifecycle events (start, complete, repeat).
19
+ */
20
+ export type TweenCallback = () => void;
21
+
22
+ /**
23
+ * Callback invoked every frame while a tween is active.
24
+ * @param progress - Linear progress from 0 to 1 (before easing).
25
+ */
26
+ export type TweenUpdateCallback = (progress: number) => void;
27
+
28
+ /**
29
+ * Options for creating a tween via {@link tween}.
30
+ *
31
+ * All fields are optional; sensible defaults are applied (linear easing, no delay, no repeat).
32
+ */
33
+ export interface TweenOptions {
34
+ /** Easing function applied to progress. Default: linear (no easing). */
35
+ easing?: EasingFunction;
36
+ /** Delay in seconds before the tween starts animating. Default: 0. Must be >= 0. */
37
+ delay?: number;
38
+ /** Number of additional times to repeat after the first play. 0 = play once, -1 = infinite. Default: 0. */
39
+ repeat?: number;
40
+ /** When true, alternates direction on each repeat (ping-pong). Default: false. */
41
+ yoyo?: boolean;
42
+ /** Called once when the tween transitions from pending to active (after delay elapses). */
43
+ onStart?: TweenCallback;
44
+ /** Called every frame while the tween is active. Receives linear progress (0..1). */
45
+ onUpdate?: TweenUpdateCallback;
46
+ /** Called once when the tween finishes all iterations. Not called if stopped manually. */
47
+ onComplete?: TweenCallback;
48
+ /** Called each time the tween starts a new repeat iteration. */
49
+ onRepeat?: TweenCallback;
50
+ }
51
+
52
+ /**
53
+ * A map of property names to their target numeric values.
54
+ * Each key must correspond to a numeric property on the tween target object.
55
+ */
56
+ export type TweenProps = Record<string, number>;
57
+
58
+ /**
59
+ * Lifecycle state of a tween instance.
60
+ *
61
+ * Transitions: pending -> active -> completed (normal flow),
62
+ * active <-> paused (via pauseTween/resumeTween),
63
+ * any -> stopped (via stopTween).
64
+ */
65
+ export type TweenState = "pending" | "active" | "paused" | "completed" | "stopped";
66
+
67
+ /**
68
+ * Tween state constants for comparing against {@link Tween.state}.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * if (myTween.state === TweenState.ACTIVE) { ... }
73
+ * ```
74
+ */
75
+ export const TweenState = {
76
+ /** Waiting for delay to elapse before starting. */
77
+ PENDING: "pending" as const,
78
+ /** Currently animating properties each frame. */
79
+ ACTIVE: "active" as const,
80
+ /** Temporarily paused; resumes from current progress via resumeTween(). */
81
+ PAUSED: "paused" as const,
82
+ /** All iterations complete. The tween has been removed from the update list. */
83
+ COMPLETED: "completed" as const,
84
+ /** Manually stopped via stopTween(). The tween has been removed from the update list. */
85
+ STOPPED: "stopped" as const,
86
+ };
87
+
88
+ /**
89
+ * A tween instance returned by {@link tween}.
90
+ *
91
+ * Inspect `state` to check lifecycle. Use `stopTween()`, `pauseTween()`,
92
+ * `resumeTween()`, or `reverseTween()` to control playback.
93
+ */
94
+ export interface Tween {
95
+ /** Unique identifier, auto-generated as "tween_0", "tween_1", etc. */
96
+ id: string;
97
+ /** Current lifecycle state. See {@link TweenState}. */
98
+ state: TweenState;
99
+ /** The object whose properties are being interpolated. */
100
+ target: any;
101
+ /** Target values for each property being tweened. */
102
+ props: TweenProps;
103
+ /** Start values captured when the tween becomes active (after delay). */
104
+ startValues: TweenProps;
105
+ /** Total animation duration in seconds (excluding delay). Must be >= 0. */
106
+ duration: number;
107
+ /** Resolved options with defaults applied. */
108
+ options: {
109
+ /** Easing function applied to progress. */
110
+ easing: EasingFunction;
111
+ /** Delay in seconds before animation starts. */
112
+ delay: number;
113
+ /** Number of additional repeat iterations. -1 = infinite. */
114
+ repeat: number;
115
+ /** Whether direction alternates on repeat. */
116
+ yoyo: boolean;
117
+ /** Called when tween transitions to active. */
118
+ onStart?: TweenCallback;
119
+ /** Called every frame with linear progress (0..1). */
120
+ onUpdate?: TweenUpdateCallback;
121
+ /** Called when all iterations complete. */
122
+ onComplete?: TweenCallback;
123
+ /** Called at the start of each repeat iteration. */
124
+ onRepeat?: TweenCallback;
125
+ };
126
+ /** Seconds elapsed since the tween became active (resets on repeat). */
127
+ elapsed: number;
128
+ /** Seconds elapsed during the delay phase. */
129
+ delayElapsed: number;
130
+ /** Zero-based index of the current repeat iteration. */
131
+ currentRepeat: number;
132
+ /** True when playing in reverse direction (yoyo mode). */
133
+ isReversed: boolean;
134
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Standard color palette and layout helpers for consistent UI styling.
3
+ */
4
+
5
+ import type { Color } from "./types.ts";
6
+
7
+ /**
8
+ * Arcane UI Color Palette.
9
+ * Pre-defined colors (0.0-1.0 RGBA) for consistent visual style across all demos.
10
+ */
11
+ export const Colors = {
12
+ // Primary UI Colors
13
+ /** Bright blue. */
14
+ PRIMARY: { r: 0.2, g: 0.6, b: 1.0, a: 1.0 },
15
+ /** Green (success state). */
16
+ SUCCESS: { r: 0.2, g: 0.8, b: 0.3, a: 1.0 },
17
+ /** Orange/Yellow (warning state). */
18
+ WARNING: { r: 1.0, g: 0.7, b: 0.0, a: 1.0 },
19
+ /** Red (danger/error state). */
20
+ DANGER: { r: 1.0, g: 0.3, b: 0.3, a: 1.0 },
21
+ /** Cyan (informational). */
22
+ INFO: { r: 0.4, g: 0.8, b: 0.9, a: 1.0 },
23
+
24
+ // Grayscale
25
+ /** Pure white. */
26
+ WHITE: { r: 1.0, g: 1.0, b: 1.0, a: 1.0 },
27
+ /** Light gray. */
28
+ LIGHT_GRAY: { r: 0.8, g: 0.8, b: 0.8, a: 1.0 },
29
+ /** Medium gray. */
30
+ GRAY: { r: 0.5, g: 0.5, b: 0.5, a: 1.0 },
31
+ /** Dark gray. */
32
+ DARK_GRAY: { r: 0.3, g: 0.3, b: 0.3, a: 1.0 },
33
+ /** Pure black. */
34
+ BLACK: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
35
+
36
+ // HUD backgrounds (semi-transparent)
37
+ /** Dark semi-transparent background for HUD panels. */
38
+ HUD_BG: { r: 0.1, g: 0.1, b: 0.15, a: 0.85 },
39
+ /** Lighter semi-transparent background for HUD panels. */
40
+ HUD_BG_LIGHT: { r: 0.2, g: 0.2, b: 0.25, a: 0.75 },
41
+
42
+ // Common game colors
43
+ /** Gold color for scores, coins, rewards. */
44
+ GOLD: { r: 1.0, g: 0.84, b: 0.0, a: 1.0 },
45
+ /** Silver color for secondary rewards. */
46
+ SILVER: { r: 0.75, g: 0.75, b: 0.75, a: 1.0 },
47
+ /** Bronze color for tertiary rewards. */
48
+ BRONZE: { r: 0.8, g: 0.5, b: 0.2, a: 1.0 },
49
+
50
+ // Game state colors
51
+ /** Bright green for victory/win state. */
52
+ WIN: { r: 0.2, g: 1.0, b: 0.4, a: 1.0 },
53
+ /** Bright red for defeat/lose state. */
54
+ LOSE: { r: 1.0, g: 0.2, b: 0.2, a: 1.0 },
55
+ /** Yellow for paused state. */
56
+ PAUSED: { r: 0.9, g: 0.9, b: 0.2, a: 1.0 },
57
+ } as const;
58
+
59
+ /**
60
+ * Standard HUD layout positions and spacing for an 800x600 viewport.
61
+ * Provides consistent anchor points for common HUD element placement.
62
+ */
63
+ export const HUDLayout = {
64
+ /** Standard padding from screen edges in pixels. */
65
+ PADDING: 10,
66
+ /** Vertical spacing between HUD lines in pixels. */
67
+ LINE_HEIGHT: 25,
68
+ /** Default text scale for main HUD text. */
69
+ TEXT_SCALE: 2,
70
+ /** Smaller text scale for secondary HUD text. */
71
+ SMALL_TEXT_SCALE: 1.5,
72
+
73
+ // Standard positions (screen-space pixel coordinates)
74
+ /** Top-left corner position. */
75
+ TOP_LEFT: { x: 10, y: 10 },
76
+ /** Top-right corner position. */
77
+ TOP_RIGHT: { x: 700, y: 10 },
78
+ /** Bottom-left corner position. */
79
+ BOTTOM_LEFT: { x: 10, y: 560 },
80
+ /** Bottom-right corner position. */
81
+ BOTTOM_RIGHT: { x: 700, y: 560 },
82
+ /** Screen center position. */
83
+ CENTER: { x: 400, y: 300 },
84
+ } as const;
85
+
86
+ /**
87
+ * Create a semi-transparent version of a color.
88
+ *
89
+ * @param color - Source color.
90
+ * @param alpha - New alpha value, 0.0 (transparent) to 1.0 (opaque).
91
+ * @returns New Color with the same RGB but the specified alpha.
92
+ */
93
+ export function withAlpha(color: Color, alpha: number): Color {
94
+ return { ...color, a: alpha };
95
+ }
96
+
97
+ /**
98
+ * Lighten a color by adding a fixed amount to each RGB channel (clamped to 1.0).
99
+ * Useful for hover effects and highlights.
100
+ *
101
+ * @param color - Source color.
102
+ * @param amount - Amount to add to each RGB channel, 0.0-1.0. Default: 0.2.
103
+ * @returns New lightened Color (alpha unchanged).
104
+ */
105
+ export function lighten(color: Color, amount: number = 0.2): Color {
106
+ return {
107
+ r: Math.min(1.0, color.r + amount),
108
+ g: Math.min(1.0, color.g + amount),
109
+ b: Math.min(1.0, color.b + amount),
110
+ a: color.a,
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Darken a color by subtracting a fixed amount from each RGB channel (clamped to 0.0).
116
+ * Useful for pressed states and shadows.
117
+ *
118
+ * @param color - Source color.
119
+ * @param amount - Amount to subtract from each RGB channel, 0.0-1.0. Default: 0.2.
120
+ * @returns New darkened Color (alpha unchanged).
121
+ */
122
+ export function darken(color: Color, amount: number = 0.2): Color {
123
+ return {
124
+ r: Math.max(0.0, color.r - amount),
125
+ g: Math.max(0.0, color.g - amount),
126
+ b: Math.max(0.0, color.b - amount),
127
+ a: color.a,
128
+ };
129
+ }
package/src/ui/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export type { Color, RectOptions, PanelOptions, BarOptions, LabelOptions } from "./types.ts";
2
2
  export { rgb } from "./types.ts";
3
3
  export { drawRect, drawPanel, drawBar, drawLabel } from "./primitives.ts";
4
+ export { Colors, HUDLayout, withAlpha, lighten, darken } from "./colors.ts";
@@ -63,6 +63,19 @@ function toWorld(
63
63
  /**
64
64
  * Draw a filled rectangle.
65
65
  * No-op in headless mode.
66
+ *
67
+ * @param x - X position (screen pixels if screenSpace, world units otherwise).
68
+ * @param y - Y position (screen pixels if screenSpace, world units otherwise).
69
+ * @param w - Width in pixels (screenSpace) or world units.
70
+ * @param h - Height in pixels (screenSpace) or world units.
71
+ * @param options - Color, layer, and screenSpace options.
72
+ *
73
+ * @example
74
+ * // Draw a red rectangle in screen space (HUD)
75
+ * drawRect(10, 10, 200, 30, {
76
+ * color: { r: 1, g: 0, b: 0, a: 0.8 },
77
+ * screenSpace: true,
78
+ * });
66
79
  */
67
80
  export function drawRect(
68
81
  x: number,
@@ -85,9 +98,23 @@ export function drawRect(
85
98
  }
86
99
 
87
100
  /**
88
- * Draw a panel with border and fill.
89
- * Uses 5 sprites: 4 border edges + 1 fill.
101
+ * Draw a panel with border and fill (5 sprites: 4 border edges + 1 fill).
90
102
  * No-op in headless mode.
103
+ *
104
+ * @param x - X position (screen pixels if screenSpace, world units otherwise).
105
+ * @param y - Y position (screen pixels if screenSpace, world units otherwise).
106
+ * @param w - Total width including border.
107
+ * @param h - Total height including border.
108
+ * @param options - Fill color, border color, border width, layer, and screenSpace options.
109
+ *
110
+ * @example
111
+ * // Draw a HUD panel
112
+ * drawPanel(10, 10, 200, 100, {
113
+ * fillColor: { r: 0.1, g: 0.1, b: 0.2, a: 0.9 },
114
+ * borderColor: { r: 0.5, g: 0.5, b: 0.5, a: 1 },
115
+ * borderWidth: 2,
116
+ * screenSpace: true,
117
+ * });
91
118
  */
92
119
  export function drawPanel(
93
120
  x: number,
@@ -148,9 +175,15 @@ export function drawPanel(
148
175
  }
149
176
 
150
177
  /**
151
- * Draw a progress/health bar.
152
- * fillRatio is 0.0 to 1.0 (clamped).
178
+ * Draw a progress/health bar with background, fill, and optional border.
153
179
  * No-op in headless mode.
180
+ *
181
+ * @param x - X position (screen pixels if screenSpace, world units otherwise).
182
+ * @param y - Y position (screen pixels if screenSpace, world units otherwise).
183
+ * @param w - Total width.
184
+ * @param h - Total height.
185
+ * @param fillRatio - Fill amount, 0.0 (empty) to 1.0 (full). Clamped to this range.
186
+ * @param options - Colors, border, layer, and screenSpace options.
154
187
  */
155
188
  export function drawBar(
156
189
  x: number,
@@ -222,8 +255,14 @@ export function drawBar(
222
255
  }
223
256
 
224
257
  /**
225
- * Draw a text label with optional background panel.
258
+ * Draw a text label with an automatic background panel.
259
+ * Panel size is computed from the text measurement + padding.
226
260
  * No-op in headless mode.
261
+ *
262
+ * @param text - The text string to display.
263
+ * @param x - X position (screen pixels if screenSpace, world units otherwise).
264
+ * @param y - Y position (screen pixels if screenSpace, world units otherwise).
265
+ * @param options - Text color, background, border, padding, scale, layer, and screenSpace.
227
266
  */
228
267
  export function drawLabel(
229
268
  text: string,