//#region src/attributes.d.ts /** Maps `data-sound-*` attributes to the sound engine via event delegation. */ /** Configuration options for DOM event delegation. */ interface ObserveOptions { /** Element or Document to delegate listeners from. Defaults to `document`. */ root?: Document | Element; /** * Automatically calls `prime()` on the first click on a bound element. Hover and focus * don't count: they are not user gestures, so a browser would not unlock audio for them. * Defaults to `true`. */ primeOnFirstInteraction?: boolean; } /** * Initializes global event delegation for `data-sound` attributes. Returns a cleanup function. * * Calls are reference-counted per root: observing the same root twice (the auto script plus * a manual call, a remounted component) binds its listeners once, and they are removed only * when every returned cleanup has run. * * @example * ```html * * Next * ``` */ export declare function observe(options?: ObserveOptions): () => void; //#endregion //#region src/engine/theme-profiles.d.ts /** Theme profiles for global sound reshaping. */ /** Configurable parameters that a theme can override. */ interface ThemeOverrides { /** Overrides the oscillator waveform type. */ waveformOverride?: OscillatorType; /** Multiplier for filter cutoff frequencies. */ cutoffMultiplier?: number; /** Multiplier for reverb mix and impulse response decay length. */ reverbMultiplier?: number; /** Global volume multiplier. */ volumeMultiplier?: number; /** Multiplier for envelope attack durations. */ attackMultiplier?: number; /** Multiplier for envelope decay and release durations. */ durationMultiplier?: number; /** Multiplier for FM synthesis depth. */ fmMultiplier?: number; /** Exponent scaling filter sweep depth (0 to 1). */ filterEnvDepth?: number; /** Exponent scaling pitch sweep depth (0 to 1). */ pitchEnvMultiplier?: number; /** Gain multiplier for body oscillator layers. */ oscillatorMultiplier?: number; /** Gain multiplier for transient noise layers. */ noiseMultiplier?: number; /** Gain multiplier for sub sine layers. */ subMultiplier?: number; /** Master soft-saturation drive multiplier. */ saturationMultiplier?: number; /** Humanization micro-variation amount (0 to disable). */ humanize?: number; /** * Multiplier for every frequency in a sound, 0.25 to 4: pitches, filter cutoffs and noise * bands move together, so the whole sound changes size, not just its note. (`PlayOptions.pitch` * moves oscillator pitches only.) */ frequencyMultiplier?: number; /** Level of a short low thump added under each sound's first struck onset, 0 to 1 (0 to disable). */ bump?: number; /** Reverb send added to every sound on top of its own `reverb.mix`, 0 to 0.5 (0 to disable). */ room?: number; /** Shortest attack any layer gets, in seconds, 0 to 0.05: rounds hard onsets (0 to disable). */ attackFloor?: number; /** * Plays another theme's re-authored sounds (for example `"soft"`) wherever this theme * registers none of its own. Without it, those sounds come from the default palette. */ soundsFrom?: ThemeName; } /** Fields that are not numbers, copied as given. */ type FlagKey = "waveformOverride" | "soundsFrom"; /** Complete theme profile with all required multipliers resolved. */ type ThemeProfile = Required> & Pick; /** Names of the themes that ship with the library. */ type BuiltInThemeName = "default" | "soft" | "mechanical"; /** * Creates a ThemeProfile by applying overrides on top of the neutral profile. A value that is * omitted, `undefined` or not a finite number falls back to neutral, so a bad value can never * reach an AudioParam, and a value outside its documented range is clamped to it. */ export declare function defineTheme(overrides?: ThemeOverrides): ThemeProfile; /** Built-in theme profiles. Frozen: register a new theme instead of editing one. */ export declare const THEME_PROFILES: { /** Neutral: the palette exactly as authored, with no master saturation. */ default: Readonly; /** * Felt mallets on wood. Custom sounds become pure sines, rounder, a little longer and * roomier, with gentler clicks and pitch sweeps. */ soft: Readonly; /** * Switches, latches and ratchets. Custom sounds play through square waves with halved pitch * sweeps, a little saturation and extra humanization. */ mechanical: Readonly; }; /** * A theme name: one of the built-ins, or any name passed to `engine.registerTheme`. * The `string & {}` arm keeps editor autocomplete for the built-in names. */ type ThemeName = BuiltInThemeName | (string & {}); /** Default theme name. */ export declare const DEFAULT_THEME: BuiltInThemeName; //#endregion //#region src/engine/types.d.ts /** Biquad filter configuration for a sound layer. */ interface FilterDef { /** Web Audio filter type, e.g. `"lowpass"` or `"bandpass"`. */ type: BiquadFilterType; /** Cutoff (or centre, for bandpass) in Hz. */ frequency: number; /** Filter Q. Defaults to 1. For bandpass, higher is narrower: 8 and up rings with a pitch. */ resonance?: number; /** Cutoff sweep: from `frequency` to `peak` Hz over `attack` seconds, back over `decay`. */ envelope?: { attack?: number; peak: number; decay: number; }; } /** Frequency modulation configuration for a sound layer. */ interface FMDef { /** Modulator frequency as a multiple of the carrier. */ ratio: number; /** Modulation depth in Hz. */ depth: number; } /** Gain envelope of a struck sound. Times are in seconds. */ interface EnvelopeDef { /** Rise to full gain. Defaults to 0 (the engine still ramps over 1 ms, so it never clicks). */ attack?: number; /** Fall from full gain towards silence, as an RC curve: the gain is about -26 dB when it ends. */ decay: number; /** Extra time the layer is held after the decay, so a pitch sweep lands later. Filter sweeps keep their own timing. */ release?: number; } /** * Functional role of a sound layer, used for theme gain routing: * - `transient`: contact click or noise burst. * - `body`: pitched body/resonance. * - `sub`: low-frequency weight. * - `tone`: pitch-carrying core voice. */ type SoundLayerRole = "transient" | "body" | "sub" | "tone"; /** Configuration for a single sound synthesis layer. */ interface SoundLayer { /** Oscillator waveform type. Defaults to "sine". */ type?: OscillatorType; /** Overrides the inferred role used for theme gain routing. */ role?: SoundLayerRole; /** Carrier frequency in Hz, or a start/end sweep range. */ frequency?: number | { start: number; end: number; }; /** Noise source color instead of an oscillator. */ noise?: "white" | "pink"; /** Amplitude envelope. */ envelope?: EnvelopeDef; /** Layer gain (0 to 1). */ gain?: number; /** Delay in seconds relative to trigger time. */ delay?: number; /** Stereo pan (-1 left to +1 right). */ pan?: number; /** Filter configuration. */ filter?: FilterDef; /** FM synthesis configuration. */ fm?: FMDef; } /** Reverb send settings for a sound. */ interface ReverbDef { /** Reverb send level (0 to 1). */ mix: number; } /** Complete sound definition consisting of one or more synthesis layers. */ interface SoundDefinition { /** Layers played together, each from its own `delay`. */ layers: SoundLayer[]; /** Optional reverb send configuration. */ reverb?: ReverbDef; /** Minimum interval in milliseconds between triggers of this sound. Defaults to engine throttle. */ throttleMs?: number; } /** Runtime options for triggering a sound. */ interface PlayOptions { /** Arbitrary argument passed to dynamic sound factories. */ arg?: string; /** Pitch transposition multiplier (e.g. 1.25 for a major third up, 0.5 for an octave down). */ pitch?: number; /** Force / velocity multiplier (0.01 to 2). Scales every layer's gain. */ force?: number; /** Custom deduplication/gating bucket key. Disambiguates concurrent voices. */ key?: string; } /** Global engine configuration options. */ interface EngineConfig { /** Master volume (0 to 1). */ volume?: number; /** Global sound enabled state. */ enabled?: boolean; /** Active theme name: a built-in or one added with `engine.registerTheme`. */ theme?: ThemeName; /** Default throttle cooldown in milliseconds. */ defaultThrottleMs?: number; /** * Silences every sound while the user has `prefers-reduced-motion: reduce` set, * tracking changes to the preference live. Defaults to `true`. */ respectReducedMotion?: boolean; } /** Names of all default palette sounds. */ type DefaultSoundName = "tap" | "click" | "key-press" | "hover" | "toggle-on" | "toggle-off" | "checkbox" | "select" | "deselect" | "tab-switch" | "expand" | "collapse" | "page-enter" | "page-exit" | "turn" | "success" | "error" | "warning" | "notification" | "info" | "deny" | "copy" | "send" | "delete" | "erase" | "undo" | "pop" | "swoosh" | "slide"; //#endregion //#region src/engine/engine.d.ts /** Default interval in milliseconds between plays of the same sound. */ export declare const DEFAULT_THROTTLE_MS = 45; /** Factory function producing a sound definition based on a runtime argument. */ type SoundFactory = (arg?: string) => SoundDefinition; /** Unified audio engine and sound dispatcher. */ export declare const engine: { /** Returns the underlying AudioContext, initializing it if necessary. */ getContext(): AudioContext | null; /** Returns the final output gain node before destination. */ getOutputGain(): GainNode | null; /** * Unlocks audio playback. Call it from a user-gesture handler: it resumes a suspended * context (including one created earlier, outside a gesture) and plays a silent buffer, * which is what iOS Safari needs to route sound. */ prime(): void; /** Closes the AudioContext and resets internal state and caches. */ dispose(): void; /** Sets the master volume level (0 to 1). Non-finite values are ignored. */ setVolume(volume: number): void; /** Returns current user volume (0 to 1). */ getVolume(): number; /** Enables or disables sound playback. */ setEnabled(value: boolean): void; /** Returns whether sound playback is currently enabled. */ isEnabled(): boolean; /** Sets the active theme by name: a built-in or one added with `registerTheme`. Unknown names are ignored. */ setTheme(theme: ThemeName): void; /** * Registers (or replaces) a named theme. Omitted multipliers fall back to neutral, * as with `defineTheme`. Registering the active theme applies it immediately. */ registerTheme(name: string, profile: ThemeOverrides): void; /** Returns the currently active theme name. */ getTheme(): ThemeName; /** Returns the resolved theme profile for the active theme. */ getActiveProfile(): ThemeProfile; /** Returns the names of every built-in and registered theme. */ getAvailableThemes(): ThemeName[]; /** Configures global engine settings. Does not rely on `this`, so it is safe to destructure. */ configure(this: void, config: EngineConfig): void; /** Returns current global engine configuration. */ getConfig(): Required; /** Registers a sound definition or factory function. */ registerSound(name: string, def: SoundDefinition | SoundFactory): void; /** * Registers a theme's own version of a sound. Themes whose `soundsFrom` names this theme * play it too. */ registerThemeSound(theme: ThemeName, name: string, def: SoundDefinition | SoundFactory): void; /** * Resolves a sound definition by name, as `options.theme` (default: the active theme) would * play it, with `options.arg` passed to a sound factory. Returns a copy: mutating it does not * change the registered sound. */ getSound(name: DefaultSoundName | (string & {}), options?: { theme?: ThemeName; arg?: string; }): SoundDefinition | undefined; /** Plays a registered sound by name. Accepts an optional string argument or a PlayOptions object. */ play(name: DefaultSoundName | (string & {}), optionsOrArg?: PlayOptions | string): void; }; //#endregion //#region src/engine/feel.d.ts /** A theme described by feel. Every control is optional; 0 (or leaving it out) keeps the base. */ interface ThemeFeel { /** Built-in theme to start from: its sounds and its character. Defaults to `"default"`. */ base?: BuiltInThemeName; /** * -1 lighter and smaller to 1 deeper and bigger. Moves every pitch and band together, up to * 4 semitones up or 5 down; deeper sounds also ring a little longer. */ depth?: number; /** 0 to 1: a low thump under each sound's onset, for weight. */ bump?: number; /** -1 darker to 1 brighter: filters close or open, clicks get quieter or louder. */ brightness?: number; /** -1 shorter to 1 longer tails. */ length?: number; /** 0 dry to 1 roomy: every sound gets some room, and the room gets bigger. */ space?: number; /** -1 harder to 1 softer onsets: clicks get louder, or round off into felt. */ softness?: number; /** 0 clean to 1 driven: saturation and denser overtones. */ grit?: number; } /** A feel control's range and what its ends sound like, for building UIs. */ interface FeelControl { /** The `ThemeFeel` field it sets. */ key: Exclude; /** Display name. */ label: string; /** Lowest value; values below are clamped to it. */ min: number; /** Highest value; values above are clamped to it. */ max: number; /** What the low end sounds like. */ low: string; /** What the high end sounds like. */ high: string; } /** Every feel control, in the order a UI should show them. */ export declare const FEEL_CONTROLS: readonly FeelControl[]; /** * Builds theme overrides from a feel, on top of a built-in theme. Pass the result to * `engine.registerTheme`: * * ```ts * engine.registerTheme("deep", createTheme({ depth: 0.6, bump: 0.5, space: 0.3 })); * ``` */ export declare function createTheme(feel?: ThemeFeel): ThemeOverrides; //#endregion export type { BuiltInThemeName, DefaultSoundName, EngineConfig, EnvelopeDef, FMDef, FeelControl, FilterDef, ObserveOptions, PlayOptions, ReverbDef, SoundDefinition, SoundFactory, SoundLayer, SoundLayerRole, ThemeFeel, ThemeName, ThemeOverrides, ThemeProfile };