first commit
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
# NullSpritePlaybackAdapter
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`NullSpritePlaybackAdapter` is the recording adapter that conforms to the `SpritePlaybackAdapter` contract without producing any audio. It is the fixture every test in this package uses, and it is exported so downstream engine adapters can use it as the contract-conformance baseline before plugging in real audio output.
|
||||
|
||||
Every method on the adapter appends a typed entry to a public read-only `calls` array. Every `play` returns a `SpritePlayHandle` whose `stop`, `setVolume`, and `isPlaying` invocations are also recorded. The timestamps come from an injectable `Clock`, so tests using `FakeClock` (or any deterministic clock) produce identical traces on every run.
|
||||
|
||||
## Features
|
||||
|
||||
- Implements the full `SpritePlaybackAdapter` interface: `init`, `play`, `dispose`.
|
||||
- Records every method call with `{ kind, at, payload }` where `at` is the clock reading and `payload` carries the relevant arguments.
|
||||
- Records every handle lifecycle event (`stop` with `fadeOutMs`, `setVolume` with value).
|
||||
- Honours `AbortSignal`: throws an `aborted` error when invoked with an already-aborted signal.
|
||||
- Pure — no platform globals, no side effects beyond the in-memory `calls` array.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { NullSpritePlaybackAdapter, createSpritePlayer } from "@suaveplan/audio-sprite-player";
|
||||
|
||||
const adapter = new NullSpritePlaybackAdapter();
|
||||
const player = createSpritePlayer({ adapter });
|
||||
await player.load(sprite);
|
||||
await player.play("hit");
|
||||
console.log(adapter.calls.map((c) => c.kind));
|
||||
// → ["init", "play"]
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
createNullSpritePlaybackAdapter,
|
||||
createSpritePlayer,
|
||||
} from "@suaveplan/audio-sprite-player";
|
||||
import { FakeClock } from "@suaveplan/testing";
|
||||
|
||||
const fakeClock = new FakeClock({ startTime: 1_000_000 });
|
||||
const adapter = createNullSpritePlaybackAdapter({
|
||||
clock: () => fakeClock.now(),
|
||||
});
|
||||
const player = createSpritePlayer({
|
||||
adapter,
|
||||
clock: () => fakeClock.now(),
|
||||
idGenerator: (() => {
|
||||
let i = 0;
|
||||
return () => `id-${++i}`;
|
||||
})(),
|
||||
});
|
||||
|
||||
await player.load(sprite);
|
||||
await player.play("hit");
|
||||
fakeClock.advance(100);
|
||||
await player.play("hit");
|
||||
const playRecords = adapter.calls.filter((c) => c.kind === "play");
|
||||
console.log(playRecords.length); // 2
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `new NullSpritePlaybackAdapter(options?)`
|
||||
|
||||
`options.clock?: Clock` — defaults to `() => Date.now()`.
|
||||
|
||||
### `calls: ReadonlyArray<NullCall>`
|
||||
|
||||
Append-only log. `NullCall` is `{ kind: "init" | "play" | "dispose" | "stop" | "setVolume"; at: number; payload?: unknown }`.
|
||||
|
||||
### `init(sprite, signal?)`
|
||||
|
||||
Records `{ kind: "init" }`. Throws if `signal.aborted`.
|
||||
|
||||
### `play(entry, opts, signal?)`
|
||||
|
||||
Records `{ kind: "play", payload: { entryName, id, opts } }`. Returns a handle. Throws if `signal.aborted`.
|
||||
|
||||
### `dispose()`
|
||||
|
||||
Records `{ kind: "dispose" }`.
|
||||
|
||||
### `createNullSpritePlaybackAdapter(options?)`
|
||||
|
||||
Functional alias for `new NullSpritePlaybackAdapter(options)`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The adapter is exported from the package root and from the `./adapter/null/null` subpath so consumers can import it without pulling the rest of the surface.
|
||||
- It is a valid implementation of `SpritePlaybackAdapter` from the type level, so the `adapter contract compiles from type-only imports` smoke test in `null.test.ts` confirms a downstream engine could ship an adapter using nothing but `import type` from this package.
|
||||
- The handle returned by `play` carries the same `id` recorded in the `play` call's payload, so consumers can correlate handle lifecycle calls back to their originating `play` deterministically.
|
||||
Reference in New Issue
Block a user