@viji-dev/core 0.5.2 → 0.5.4

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/dist/index.d.ts CHANGED
@@ -441,9 +441,14 @@ export declare class AudioSystem {
441
441
  */
442
442
  getChannelCount(): number;
443
443
  /**
444
- * Record a tap for the specified instrument onset
444
+ * Record a tap for the specified instrument onset.
445
+ * `options.skipRecognition` retains visual envelope + session timing but
446
+ * bypasses the recognition pipeline — used by host-side relay of forwarded
447
+ * tap messages where another core is doing the authoritative recognition.
445
448
  */
446
- tapOnset(instrument: InstrumentType): void;
449
+ tapOnset(instrument: InstrumentType, options?: {
450
+ skipRecognition?: boolean;
451
+ }): void;
447
452
  /**
448
453
  * Clear tap pattern for an instrument, restoring auto-detection
449
454
  */
@@ -467,7 +472,9 @@ export declare class AudioSystem {
467
472
  onOnsetModeChange(listener: (ev: OnsetModeChangeEvent) => void): Unsubscribe;
468
473
  onOnsetSessionEnd(listener: (ev: OnsetSessionEndEvent) => void): Unsubscribe;
469
474
  onOnsetMuteChange(listener: (ev: OnsetMuteChangeEvent) => void): Unsubscribe;
470
- exportOnsetSessionState(): SerializedOnsetState;
475
+ exportOnsetSessionState(options?: {
476
+ instruments?: ReadonlyArray<InstrumentType>;
477
+ }): SerializedOnsetState;
471
478
  importOnsetSessionState(state: SerializedOnsetState, clockOffset: number): void;
472
479
  exportAudioAnalysisState(): SerializedAudioAnalysisState;
473
480
  importAudioAnalysisState(state: SerializedAudioAnalysisState, clockOffset: number): void;
@@ -2244,7 +2251,7 @@ declare type TrackingState = 'TRACKING' | 'LOCKED' | 'BREAKDOWN' | 'LOST';
2244
2251
  /** Returned by `on*` listener registration calls; invoke to unsubscribe. */
2245
2252
  export declare type Unsubscribe = () => void;
2246
2253
 
2247
- export declare const VERSION = "0.5.2";
2254
+ export declare const VERSION = "0.5.4";
2248
2255
 
2249
2256
  /**
2250
2257
  * Real-time video API: drawable frame, dimensions, and the source-side
@@ -2884,8 +2891,12 @@ export declare class VijiCore {
2884
2891
  /**
2885
2892
  * Replace the audio analysis + onset state from a serialized payload.
2886
2893
  * `clockOffset` is added to all sender-clocked fields (`0` for same-process,
2887
- * NTP-derived for cross-device). Mutation is synchronous; no `onModeChange`
2888
- * or `onSessionEnd` events are emitted (state replacement is not a transition).
2894
+ * NTP-derived for cross-device). Mutation is synchronous.
2895
+ *
2896
+ * Field-level events (`onModeChange`, `onMuteChange`) fire when imported
2897
+ * values differ from current — consumer-visible state stays consistent
2898
+ * with what polling would have observed. Session-boundary events
2899
+ * (`onSessionEnd`) do NOT fire on import.
2889
2900
  *
2890
2901
  * Validates `version`; on mismatch, fires `onStateImportError` and leaves
2891
2902
  * existing state intact.
@@ -3011,8 +3022,21 @@ export declare class VijiCore {
3011
3022
  * Tap an onset for a specific instrument.
3012
3023
  * First tap switches the instrument from auto to tapping mode.
3013
3024
  * If a repeating pattern is recognized, it continues after tapping stops.
3025
+ *
3026
+ * `options.skipRecognition: true` keeps the visual envelope and session
3027
+ * timing but bypasses pattern recognition entirely (no IOI accumulation,
3028
+ * no mode transition, no `applyPattern`, no `handlePatternTap`). Use
3029
+ * this when relaying tap messages from another instance that owns the
3030
+ * authoritative recognition (e.g. host receiving forwarded controller
3031
+ * taps over WebRTC). The receiving core's mode is then driven only by
3032
+ * `importSessionState` from the authoritative sender.
3033
+ *
3034
+ * The `MIN_TAP_INTERVAL_MS` debounce still applies regardless of the
3035
+ * `skipRecognition` flag.
3014
3036
  */
3015
- tap: (instrument: "kick" | "snare" | "hat") => void;
3037
+ tap: (instrument: "kick" | "snare" | "hat", options?: {
3038
+ skipRecognition?: boolean;
3039
+ }) => void;
3016
3040
  /**
3017
3041
  * Clear the tap pattern for an instrument, restoring auto-detection
3018
3042
  */
@@ -3041,36 +3065,47 @@ export declare class VijiCore {
3041
3065
  isMuted: (instrument: "kick" | "snare" | "hat") => boolean;
3042
3066
  /**
3043
3067
  * Listen for instrument mode transitions (`'auto' | 'tapping' | 'pattern'`).
3044
- * Fires on every transition including the first tap (`'auto' → 'tapping'`)
3045
- * and pattern recognition (`'tapping' → 'pattern'`). Imported state does
3046
- * NOT fire mode-change events state replacement is not a transition.
3068
+ * Fires whenever the underlying mode field actually changes, regardless
3069
+ * of which code path triggered it — first tap (`'auto' → 'tapping'`),
3070
+ * pattern recognition (`'tapping' 'pattern'`), the 5s tap timeout
3071
+ * (`'tapping' → 'auto'`), explicit `clear()`, or `importSessionState`
3072
+ * landing a different mode value.
3073
+ *
3074
+ * Idempotent transitions (already in target mode) do not fire.
3047
3075
  *
3048
3076
  * @returns Unsubscribe function. Call to remove the listener.
3049
3077
  */
3050
3078
  onModeChange: (listener: (ev: OnsetModeChangeEvent) => void) => Unsubscribe;
3051
3079
  /**
3052
- * Listen for natural session-end events. Fires when:
3080
+ * Listen for natural session-end events. Fires only on natural session
3081
+ * boundaries:
3053
3082
  * - 500ms elapse since last tap with instrument in `'pattern'` mode
3054
3083
  * (outcome `'pattern'`), or
3055
3084
  * - 5s elapse in `'tapping'` mode without a recognized pattern
3056
3085
  * (outcome `'cleared'`; instrument transitions to `'auto'`).
3057
3086
  *
3058
- * Explicit `clear()` calls do NOT fire this event (caller-initiated;
3059
- * caller already knows). Imported state does NOT fire either.
3087
+ * Does NOT fire on:
3088
+ * - Explicit `clear()` calls (caller-initiated; not a natural boundary).
3089
+ * - `importSessionState` (state replacement; not a session boundary).
3090
+ *
3091
+ * Field-change events (`onModeChange`, `onMuteChange`) fire on imports
3092
+ * when fields differ; this event does not because session-end is a
3093
+ * different category — about session lifecycle, not field state.
3060
3094
  *
3061
3095
  * @returns Unsubscribe function. Call to remove the listener.
3062
3096
  */
3063
3097
  onSessionEnd: (listener: (ev: OnsetSessionEndEvent) => void) => Unsubscribe;
3064
3098
  /**
3065
3099
  * Listen for instrument mute-state transitions (`true ↔ false`). Fires
3066
- * whenever the underlying mute state actually changes, regardless of
3067
- * which method triggered it:
3068
- * - `setMuted(instrument, muted)` when `prev !== next`
3069
- * - `tap(instrument)` auto-unmute on first tap of a muted instrument
3070
- * - `clear(instrument)` when the instrument was muted
3100
+ * whenever the underlying mute field actually changes, regardless of
3101
+ * which code path triggered it:
3102
+ * - `setMuted(instrument, muted)` when `prev !== next`.
3103
+ * - `tap(instrument)` auto-unmute on first tap of a muted instrument.
3104
+ * - `clear(instrument)` when the instrument was muted at call time.
3105
+ * - `importSessionState` landing a different muted value.
3071
3106
  *
3072
3107
  * Idempotent calls (e.g. `setMuted(true)` on an already-muted instrument)
3073
- * do not fire. Imported state does NOT fire either.
3108
+ * do not fire.
3074
3109
  *
3075
3110
  * @returns Unsubscribe function. Call to remove the listener.
3076
3111
  */
@@ -3080,13 +3115,32 @@ export declare class VijiCore {
3080
3115
  * Cross-device-safe (no audio analysis state included). Pair with
3081
3116
  * `importSessionState` on a receiver. Wall-clock fields are in this
3082
3117
  * instance's `performance.now()` clock space.
3118
+ *
3119
+ * `options.instruments` scopes the snapshot to the listed instruments
3120
+ * only; omitted instruments are absent from the payload. The receiver
3121
+ * leaves its existing state for those instruments untouched (the
3122
+ * receiver's `applyInstrumentPayload` skips missing keys). Default =
3123
+ * all three.
3124
+ *
3125
+ * Cross-device commits should typically scope to the just-completed
3126
+ * instrument (e.g. `exportSessionState({ instruments: [ev.instrument] })`
3127
+ * inside an `onSessionEnd` handler) so the receiver's unrelated
3128
+ * instrument state isn't inadvertently overwritten by the sender's
3129
+ * default values.
3083
3130
  */
3084
- exportSessionState: () => SerializedOnsetState;
3131
+ exportSessionState: (options?: {
3132
+ instruments?: ReadonlyArray<"kick" | "snare" | "hat">;
3133
+ }) => SerializedOnsetState;
3085
3134
  /**
3086
3135
  * Replace per-instrument onset state from a serialized payload.
3087
3136
  * `clockOffset` is added to all sender-clocked fields during import
3088
3137
  * (use `0` for same-process transfer; NTP-derived offset for cross-device).
3089
- * Mutation is synchronous; no events are emitted.
3138
+ * Mutation is synchronous.
3139
+ *
3140
+ * Field-level events fire when imported values differ from current:
3141
+ * `onModeChange` if the imported mode is different, `onMuteChange` if
3142
+ * the imported muted state is different. Session-boundary events
3143
+ * (`onSessionEnd`) do NOT fire — imports aren't session boundaries.
3090
3144
  *
3091
3145
  * Patterns are rebased forward by whole pattern cycles to eliminate
3092
3146
  * the catch-up burst that would otherwise occur on stale payloads
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A, V, a, b } from "./index-B8LJ9m47.js";
1
+ import { A, V, a, b } from "./index-_PbbZgmh.js";
2
2
  export {
3
3
  A as AudioSystem,
4
4
  V as VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viji-dev/core",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Universal execution engine for Viji Creative scenes",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",