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.
- package/README.md +724 -580
- package/dist/animation.d.ts +149 -0
- package/dist/animation.d.ts.map +1 -0
- package/dist/animation.js +141 -0
- package/dist/animation.js.map +1 -0
- package/dist/ay.d.ts +89 -0
- package/dist/ay.d.ts.map +1 -0
- package/dist/ay.js +300 -0
- package/dist/ay.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
package/dist/ay.d.ts.map
ADDED
|
@@ -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"}
|