zx-kit 0.9.2 → 0.11.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.
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Time-based easing curve. Maps progress `t` (0..1) to eased value (typically 0..1).
3
+ * Pass to `createTween` via the `ease` option.
4
+ */
5
+ export type Easing = (t: number) => number;
6
+ /**
7
+ * Built-in easing curves for `Tween`. Pass to `createTween({ ease: Easings.easeOut })`.
8
+ * Roll your own by writing any `(t: number) => number` function.
9
+ */
10
+ export declare const Easings: {
11
+ /** Constant velocity. */
12
+ readonly linear: Easing;
13
+ /** Slow start, fast end (quadratic in). */
14
+ readonly easeIn: Easing;
15
+ /** Fast start, slow end (quadratic out). */
16
+ readonly easeOut: Easing;
17
+ };
18
+ /**
19
+ * A frame-index timer for sprite-strip animations.
20
+ * Holds no bitmaps — just counts time and reports which frame index should be shown.
21
+ * Use the index to look up your own sprite table (lets one timer drive multi-direction
22
+ * sprites: `SPRITES[playerDir][tickAnimation(walkAnim, dt)]`).
23
+ */
24
+ export interface Animation {
25
+ /** Number of frames in the cycle. */
26
+ frameCount: number;
27
+ /** Duration of each frame in milliseconds. */
28
+ frameMs: number;
29
+ /** When `true` the animation wraps; when `false` it stops on the last frame. */
30
+ loop: boolean;
31
+ /** Internal: accumulated time since last reset. */
32
+ elapsed: number;
33
+ /** `true` once a non-looping animation has reached its last frame. */
34
+ done: boolean;
35
+ /** Optional callback fired exactly once when a non-looping animation completes. */
36
+ onComplete?: () => void;
37
+ }
38
+ /**
39
+ * Creates an `Animation` frame timer at frame 0.
40
+ *
41
+ * @param frameCount - Number of distinct frames (e.g. `2` for a walk cycle, `4` for an explosion)
42
+ * @param frameMs - Milliseconds per frame
43
+ * @param opts.loop - When `true` (default) the animation wraps; when `false` it stops on the last frame
44
+ * @param opts.onComplete - Fired exactly once when a non-looping animation reaches its last frame
45
+ *
46
+ * @example
47
+ * const walkAnim = createAnimation(2, 60) // looping 2-frame cycle
48
+ * const explosion = createAnimation(4, 50, { loop: false,
49
+ * onComplete: () => state.phase = 'gameover' })
50
+ */
51
+ export declare function createAnimation(frameCount: number, frameMs: number, opts?: {
52
+ loop?: boolean;
53
+ onComplete?: () => void;
54
+ }): Animation;
55
+ /**
56
+ * Advances the animation by `dt` milliseconds and returns the current frame index (`0..frameCount-1`).
57
+ * Call once per frame. For non-looping animations, fires `onComplete` once on completion.
58
+ *
59
+ * @param anim - Animation to tick
60
+ * @param dt - Frame delta in milliseconds
61
+ * @returns Current frame index — use to look up your sprite bitmap
62
+ *
63
+ * @example
64
+ * const idx = tickAnimation(walkAnim, dt)
65
+ * const sprite = PLAYER_FRAMES[playerDir][idx]
66
+ * drawSprite(ctx, sprite, x, y, C.B_WHITE, C.BLACK)
67
+ */
68
+ export declare function tickAnimation(anim: Animation, dt: number): number;
69
+ /**
70
+ * Returns the current frame index without advancing time.
71
+ * Useful when reading the index outside the tick (e.g. inside a renderer).
72
+ */
73
+ export declare function getAnimationFrame(anim: Animation): number;
74
+ /**
75
+ * Resets the animation to frame 0 and clears `done`.
76
+ * Call before re-using a non-looping animation, or to restart a loop from the beginning.
77
+ */
78
+ export declare function resetAnimation(anim: Animation): void;
79
+ /**
80
+ * A time-based linear interpolation between two 2D points.
81
+ * Use to slide a sprite from one cell to another, drop a mine in an arc (with `easeIn`),
82
+ * or animate any pair of pixel coordinates.
83
+ *
84
+ * Read `tween.x` / `tween.y` after `tickTween` to draw at the current position.
85
+ */
86
+ export interface Tween {
87
+ /** Starting X in game pixels. */
88
+ fromX: number;
89
+ /** Starting Y in game pixels. */
90
+ fromY: number;
91
+ /** Ending X in game pixels. */
92
+ toX: number;
93
+ /** Ending Y in game pixels. */
94
+ toY: number;
95
+ /** Total duration in milliseconds. */
96
+ durationMs: number;
97
+ /** Internal: time elapsed since creation. */
98
+ elapsed: number;
99
+ /** Current interpolated X — updated each `tickTween`. */
100
+ x: number;
101
+ /** Current interpolated Y — updated each `tickTween`. */
102
+ y: number;
103
+ /** Easing curve mapping linear progress `t` to eased value. */
104
+ ease: Easing;
105
+ /** `true` once the tween has reached its end. */
106
+ done: boolean;
107
+ /** Optional callback fired exactly once on completion. */
108
+ onComplete?: () => void;
109
+ }
110
+ /**
111
+ * Creates a `Tween` from `(fromX, fromY)` to `(toX, toY)` over `durationMs`.
112
+ * Initial `x`/`y` are set to the starting point.
113
+ *
114
+ * @param fromX, fromY - Starting position in game pixels
115
+ * @param toX, toY - Ending position in game pixels
116
+ * @param durationMs - Total duration in milliseconds
117
+ * @param opts.ease - Easing curve (default `Easings.linear`)
118
+ * @param opts.onComplete - Fired exactly once when the tween reaches its end
119
+ *
120
+ * @example
121
+ * // Slide player from one cell to the next over 120ms
122
+ * state.walkTween = createTween(
123
+ * state.playerCol * 8, state.playerRow * 8,
124
+ * newCol * 8, newRow * 8,
125
+ * 120,
126
+ * { onComplete: () => commitMove(state) },
127
+ * )
128
+ */
129
+ export declare function createTween(fromX: number, fromY: number, toX: number, toY: number, durationMs: number, opts?: {
130
+ ease?: Easing;
131
+ onComplete?: () => void;
132
+ }): Tween;
133
+ /**
134
+ * Advances the tween by `dt` milliseconds and updates `tween.x` / `tween.y`.
135
+ * Returns `true` once the tween has finished (also fires `onComplete` exactly once).
136
+ * Subsequent calls after completion are no-ops and return `true`.
137
+ *
138
+ * @param tween - Tween to advance
139
+ * @param dt - Frame delta in milliseconds
140
+ * @returns `true` when the tween has reached its end this frame or earlier
141
+ *
142
+ * @example
143
+ * if (state.walkTween) {
144
+ * tickTween(state.walkTween, dt)
145
+ * // renderer reads state.walkTween.x / .y
146
+ * }
147
+ */
148
+ export declare function tickTween(tween: Tween, dt: number): boolean;
149
+ //# sourceMappingURL=animation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation.d.ts","sourceRoot":"","sources":["../src/animation.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;AAE1C;;;GAGG;AACH,eAAO,MAAM,OAAO;IAClB,yBAAyB;qBACH,MAAM;IAC5B,2CAA2C;qBACjB,MAAM;IAChC,4CAA4C;sBACD,MAAM;CACzC,CAAA;AAIV;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAA;IACf,gFAAgF;IAChF,IAAI,EAAE,OAAO,CAAA;IACb,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAA;IACf,sEAAsE;IACtE,IAAI,EAAE,OAAO,CAAA;IACb,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,GACrD,SAAS,CASX;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAWjE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAKzD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAGpD;AAID;;;;;;GAMG;AACH,MAAM,WAAW,KAAK;IACpB,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAA;IAClB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAA;IACf,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAA;IACT,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAA;IACT,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,IAAI,EAAE,OAAO,CAAA;IACb,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAC5B,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,GACpD,KAAK,CASP;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAc3D"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Built-in easing curves for `Tween`. Pass to `createTween({ ease: Easings.easeOut })`.
3
+ * Roll your own by writing any `(t: number) => number` function.
4
+ */
5
+ export const Easings = {
6
+ /** Constant velocity. */
7
+ linear: ((t) => t),
8
+ /** Slow start, fast end (quadratic in). */
9
+ easeIn: ((t) => t * t),
10
+ /** Fast start, slow end (quadratic out). */
11
+ easeOut: ((t) => 1 - (1 - t) * (1 - t)),
12
+ };
13
+ /**
14
+ * Creates an `Animation` frame timer at frame 0.
15
+ *
16
+ * @param frameCount - Number of distinct frames (e.g. `2` for a walk cycle, `4` for an explosion)
17
+ * @param frameMs - Milliseconds per frame
18
+ * @param opts.loop - When `true` (default) the animation wraps; when `false` it stops on the last frame
19
+ * @param opts.onComplete - Fired exactly once when a non-looping animation reaches its last frame
20
+ *
21
+ * @example
22
+ * const walkAnim = createAnimation(2, 60) // looping 2-frame cycle
23
+ * const explosion = createAnimation(4, 50, { loop: false,
24
+ * onComplete: () => state.phase = 'gameover' })
25
+ */
26
+ export function createAnimation(frameCount, frameMs, opts = {}) {
27
+ return {
28
+ frameCount,
29
+ frameMs,
30
+ loop: opts.loop ?? true,
31
+ elapsed: 0,
32
+ done: false,
33
+ onComplete: opts.onComplete,
34
+ };
35
+ }
36
+ /**
37
+ * Advances the animation by `dt` milliseconds and returns the current frame index (`0..frameCount-1`).
38
+ * Call once per frame. For non-looping animations, fires `onComplete` once on completion.
39
+ *
40
+ * @param anim - Animation to tick
41
+ * @param dt - Frame delta in milliseconds
42
+ * @returns Current frame index — use to look up your sprite bitmap
43
+ *
44
+ * @example
45
+ * const idx = tickAnimation(walkAnim, dt)
46
+ * const sprite = PLAYER_FRAMES[playerDir][idx]
47
+ * drawSprite(ctx, sprite, x, y, C.B_WHITE, C.BLACK)
48
+ */
49
+ export function tickAnimation(anim, dt) {
50
+ if (anim.done)
51
+ return anim.frameCount - 1;
52
+ anim.elapsed += dt;
53
+ const totalMs = anim.frameCount * anim.frameMs;
54
+ if (!anim.loop && anim.elapsed >= totalMs) {
55
+ anim.done = true;
56
+ anim.onComplete?.();
57
+ return anim.frameCount - 1;
58
+ }
59
+ const t = anim.loop ? anim.elapsed % totalMs : anim.elapsed;
60
+ return Math.min(anim.frameCount - 1, Math.floor(t / anim.frameMs));
61
+ }
62
+ /**
63
+ * Returns the current frame index without advancing time.
64
+ * Useful when reading the index outside the tick (e.g. inside a renderer).
65
+ */
66
+ export function getAnimationFrame(anim) {
67
+ if (anim.done)
68
+ return anim.frameCount - 1;
69
+ const totalMs = anim.frameCount * anim.frameMs;
70
+ const t = anim.loop ? anim.elapsed % totalMs : Math.min(anim.elapsed, totalMs);
71
+ return Math.min(anim.frameCount - 1, Math.floor(t / anim.frameMs));
72
+ }
73
+ /**
74
+ * Resets the animation to frame 0 and clears `done`.
75
+ * Call before re-using a non-looping animation, or to restart a loop from the beginning.
76
+ */
77
+ export function resetAnimation(anim) {
78
+ anim.elapsed = 0;
79
+ anim.done = false;
80
+ }
81
+ /**
82
+ * Creates a `Tween` from `(fromX, fromY)` to `(toX, toY)` over `durationMs`.
83
+ * Initial `x`/`y` are set to the starting point.
84
+ *
85
+ * @param fromX, fromY - Starting position in game pixels
86
+ * @param toX, toY - Ending position in game pixels
87
+ * @param durationMs - Total duration in milliseconds
88
+ * @param opts.ease - Easing curve (default `Easings.linear`)
89
+ * @param opts.onComplete - Fired exactly once when the tween reaches its end
90
+ *
91
+ * @example
92
+ * // Slide player from one cell to the next over 120ms
93
+ * state.walkTween = createTween(
94
+ * state.playerCol * 8, state.playerRow * 8,
95
+ * newCol * 8, newRow * 8,
96
+ * 120,
97
+ * { onComplete: () => commitMove(state) },
98
+ * )
99
+ */
100
+ export function createTween(fromX, fromY, toX, toY, durationMs, opts = {}) {
101
+ return {
102
+ fromX, fromY, toX, toY, durationMs,
103
+ elapsed: 0,
104
+ x: fromX, y: fromY,
105
+ ease: opts.ease ?? Easings.linear,
106
+ done: false,
107
+ onComplete: opts.onComplete,
108
+ };
109
+ }
110
+ /**
111
+ * Advances the tween by `dt` milliseconds and updates `tween.x` / `tween.y`.
112
+ * Returns `true` once the tween has finished (also fires `onComplete` exactly once).
113
+ * Subsequent calls after completion are no-ops and return `true`.
114
+ *
115
+ * @param tween - Tween to advance
116
+ * @param dt - Frame delta in milliseconds
117
+ * @returns `true` when the tween has reached its end this frame or earlier
118
+ *
119
+ * @example
120
+ * if (state.walkTween) {
121
+ * tickTween(state.walkTween, dt)
122
+ * // renderer reads state.walkTween.x / .y
123
+ * }
124
+ */
125
+ export function tickTween(tween, dt) {
126
+ if (tween.done)
127
+ return true;
128
+ tween.elapsed += dt;
129
+ const t = Math.min(1, tween.elapsed / tween.durationMs);
130
+ const eased = tween.ease(t);
131
+ tween.x = tween.fromX + (tween.toX - tween.fromX) * eased;
132
+ tween.y = tween.fromY + (tween.toY - tween.fromY) * eased;
133
+ if (t >= 1) {
134
+ tween.done = true;
135
+ tween.x = tween.toX;
136
+ tween.y = tween.toY;
137
+ tween.onComplete?.();
138
+ }
139
+ return tween.done;
140
+ }
141
+ //# sourceMappingURL=animation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation.js","sourceRoot":"","sources":["../src/animation.ts"],"names":[],"mappings":"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"}
package/dist/ay.d.ts ADDED
@@ -0,0 +1,89 @@
1
+ /** ZX Spectrum 128K / Melodik AY-3-8912 master clock. */
2
+ export declare const AY_CLOCK = 1773400;
3
+ /**
4
+ * Hardware-accurate logarithmic amplitude table.
5
+ * The real chip uses ≈ √2 steps per level (≈ 3 dB).
6
+ * Index 0 = silence, index 15 = full amplitude.
7
+ */
8
+ export declare const AY_VOL: readonly number[];
9
+ export type AYChannel = 'A' | 'B' | 'C';
10
+ /** One note in an AY sequencer pattern. */
11
+ export interface AYNote {
12
+ /** Frequency in Hz. 0 = rest (silence). */
13
+ freq: number;
14
+ /** Duration in milliseconds. */
15
+ dur: number;
16
+ /** Amplitude 0–15. Default 15. Ignored when envShape is set. */
17
+ vol?: number;
18
+ /** Mix LFSR noise alongside the tone. Default false. */
19
+ noise?: boolean;
20
+ /** Noise period 1–31 (maps to R6). Higher = darker texture. Default 8. */
21
+ noisePeriod?: number;
22
+ /** Envelope shape 0–15 (R13). When set, vol is ignored. */
23
+ envShape?: number;
24
+ /** Envelope cycle duration in ms (one ramp: 0→15 or 15→0). Default = note duration. */
25
+ envCycleDurMs?: number;
26
+ }
27
+ /** Real-time AY chip handle returned by `createAY()`. */
28
+ export interface AYChip {
29
+ /** Set channel tone + volume (vol 0–15). freq ≤ 0 silences the tone generator. */
30
+ tone(ch: AYChannel, freq: number, vol?: number): void;
31
+ /** Enable LFSR noise on a channel. period 1–31 (R6): higher = darker texture. */
32
+ enableNoise(ch: AYChannel, period?: number): void;
33
+ /** Disable noise on a channel. */
34
+ disableNoise(ch: AYChannel): void;
35
+ /**
36
+ * Apply an AY envelope to a channel's amplitude.
37
+ * shape 0–15 maps to the 16 AY-3-8912 envelope shapes (see `AY_ENVELOPE_SHAPES`).
38
+ * cycleDurMs: time in ms for one ramp (15→0 or 0→15).
39
+ * Repeating shapes are pre-scheduled for 32 cycles — call again to extend.
40
+ */
41
+ envelope(ch: AYChannel, shape: number, cycleDurMs: number): void;
42
+ /** Fade out a channel (tone + noise). */
43
+ mute(ch: AYChannel): void;
44
+ /** Fade out all three channels. */
45
+ muteAll(): void;
46
+ /** Stop all oscillators / sources and release Web Audio nodes. */
47
+ stop(): void;
48
+ }
49
+ /**
50
+ * Human-readable names for the 16 AY envelope shapes.
51
+ * Index = R13 value. Useful for documentation and tooling.
52
+ */
53
+ export declare const AY_ENVELOPE_SHAPES: readonly ["\\_ ", "\\_ ", "\\_ ", "\\_ ", "/_ ", "/_ ", "/_ ", "/_ ", "\\\\", "\\_", "\\/\\/", "\\‾", "//", "/‾", "/\\/\\", "/_"];
54
+ /**
55
+ * Creates three persistent AY channels wired to the zx-kit master gain.
56
+ * Each channel has independent tone (square wave), noise (LFSR), and envelope.
57
+ *
58
+ * Must be called inside a user-gesture handler due to browser autoplay policy.
59
+ *
60
+ * @example
61
+ * button.addEventListener('click', () => {
62
+ * const ay = createAY()
63
+ * ay.tone('A', 440, 12)
64
+ * ay.enableNoise('B', 16)
65
+ * ay.envelope('C', 10, 400) // shape 10 = \/\/ triangle
66
+ * ay.tone('C', 220, 0) // tone silent; only envelope-modulated noise
67
+ * })
68
+ */
69
+ export declare function createAY(): AYChip;
70
+ /**
71
+ * Pre-schedules up to three independent AY note arrays on the shared AudioContext.
72
+ * All channels start at the same wall-clock time; shorter channels finish earlier.
73
+ * Fire-and-forget — no handle returned.
74
+ *
75
+ * Each `AYNote` may optionally mix in LFSR noise and/or apply an envelope shape.
76
+ *
77
+ * @example
78
+ * playAY({
79
+ * a: [{ freq: 440, dur: 300 }, { freq: 523, dur: 300, envShape: 12, envCycleDurMs: 150 }],
80
+ * b: [{ freq: 110, dur: 200, noise: true, noisePeriod: 16 }],
81
+ * c: [{ freq: 0, dur: 600, noise: true, noisePeriod: 4, envShape: 8, envCycleDurMs: 100 }],
82
+ * })
83
+ */
84
+ export declare function playAY(pattern: {
85
+ a?: AYNote[];
86
+ b?: AYNote[];
87
+ c?: AYNote[];
88
+ }, startDelay?: number): void;
89
+ //# sourceMappingURL=ay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ay.d.ts","sourceRoot":"","sources":["../src/ay.ts"],"names":[],"mappings":"AAIA,yDAAyD;AACzD,eAAO,MAAM,QAAQ,UAAY,CAAA;AAEjC;;;;GAIG;AACH,eAAO,MAAM,MAAM,EAAE,SAAS,MAAM,EAGnC,CAAA;AAWD,MAAM,MAAM,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;AAEvC,2CAA2C;AAC3C,MAAM,WAAW,MAAM;IACrB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,wDAAwD;IACxD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,yDAAyD;AACzD,MAAM,WAAW,MAAM;IACrB,kFAAkF;IAClF,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrD,kFAAkF;IAClF,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjD,kCAAkC;IAClC,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAAA;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAChE,yCAAyC;IACzC,IAAI,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAAA;IACzB,mCAAmC;IACnC,OAAO,IAAI,IAAI,CAAA;IACf,kEAAkE;IAClE,IAAI,IAAI,IAAI,CAAA;CACb;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,mIAWrB,CAAA;AAwFV;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CA6GjC;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CACpB,OAAO,EAAE;IAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,EACrD,UAAU,SAAI,GACb,IAAI,CA+EN"}