@signalsandsorcery/plugin-sdk 2.26.1 → 2.34.1

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.mts CHANGED
@@ -383,6 +383,19 @@ interface PluginHost {
383
383
  setRawPluginState(trackId: string, pluginIndex: number, stateBase64: string): Promise<void>;
384
384
  /** Get a plugin's RAW VST3/AU state (see setRawPluginState). @since SDK 2.15.0 */
385
385
  getRawPluginState(trackId: string, pluginIndex: number): Promise<string>;
386
+ /**
387
+ * Persist a preset as the track's durable sound identity (DB `preset_state`,
388
+ * the shape getTrackSound reads back). setPluginState/setRawPluginState are
389
+ * engine-only — a copied sound that is never persisted has no identity, so
390
+ * drift checks (e.g. the transition-designer preset re-sync) can never
391
+ * observe convergence. Call after applying a copied state to a layer track.
392
+ * @since SDK 2.34.0
393
+ */
394
+ persistTrackPresetState?(trackId: string, preset: {
395
+ state: string;
396
+ stateType: 'raw' | 'valuetree';
397
+ name?: string;
398
+ }): Promise<void>;
386
399
  /** List plugins currently loaded on a track. */
387
400
  getTrackPlugins(trackId: string): Promise<PluginSynthInfo[]>;
388
401
  /** Remove a plugin from a track. */
@@ -882,6 +895,30 @@ interface PluginHost {
882
895
  deleteSampleTrack(trackId: string): Promise<void>;
883
896
  /** Get all sample tracks in the active scene. Re-establishes ownership. */
884
897
  getPluginSampleTracks(): Promise<PluginSampleTrackInfo[]>;
898
+ /**
899
+ * Resolve a sample-track row id (as returned by `listSceneFamilyTracks`) back
900
+ * to its library `sampleId` + metadata, so a loop can be re-created in another
901
+ * scene (transition crossfade/fade). Returns null if not a sample track.
902
+ * @since SDK 2.31.0
903
+ */
904
+ getSampleTrackInfo?(dbId: string): Promise<{
905
+ sampleId: string;
906
+ fileName?: string;
907
+ bpm?: number;
908
+ key?: string;
909
+ } | null>;
910
+ /**
911
+ * Render an audio transition effect onto a sample (offline DSP via the audio
912
+ * tool), returning a NEW library sample to place. Used for stutter / chopped
913
+ * loop transitions. @since SDK 2.32.0
914
+ */
915
+ renderSampleEffect?(sampleId: string, spec: {
916
+ effect: 'stutter' | 'chopped';
917
+ bars: number;
918
+ bpm: number;
919
+ repeats?: number;
920
+ slices?: number;
921
+ }): Promise<PluginSampleInfo>;
885
922
  /** Time-stretch a sample to a target BPM. Returns the new sample info. */
886
923
  timeStretchSample(sampleId: string, targetBpm: number): Promise<PluginSampleInfo>;
887
924
  /**
@@ -1197,6 +1234,10 @@ interface SceneFamilyTrack {
1197
1234
  name: string;
1198
1235
  /** Musical role if set — used to enforce same-role crossfade pairing. */
1199
1236
  role?: string;
1237
+ /** Generation prompt, when the track was AI-generated. The crossfade picker
1238
+ * shows this as the primary label (users recognise tracks by prompt, not id).
1239
+ * @since SDK 2.27.0 */
1240
+ prompt?: string;
1200
1241
  }
1201
1242
  /**
1202
1243
  * One OTHER scene and its candidate tracks (already type-filtered). Scenes with
@@ -2573,6 +2614,16 @@ declare function TrackRow({ track, prompt, runtimeState, soloedOut, fxDetailStat
2573
2614
  *
2574
2615
  * @since SDK 2.23.0
2575
2616
  */
2617
+
2618
+ /**
2619
+ * Stable, state-aware identity for a track's sound — used to auto-detect when a
2620
+ * transition's SOURCE preset/sample has drifted from the copy on its layer. A
2621
+ * preset hashes its full STATE blob (so a same-name param tweak still differs); a
2622
+ * sample uses its path; an instrument uses its id + zones. Empty string = no sound.
2623
+ * @since SDK 2.32.0
2624
+ */
2625
+ declare function hashString(s: string): string;
2626
+ declare function soundIdentity(snap: TrackSoundSnapshot | null | undefined): string;
2576
2627
  /** Which half of the pair a per-layer control / member targets. */
2577
2628
  type CrossfadeSlot = 'origin' | 'target';
2578
2629
  /**
@@ -2772,6 +2823,224 @@ interface CrossfadeInpaintInput {
2772
2823
  */
2773
2824
  declare function buildCrossfadeInpaintPrompt(input: CrossfadeInpaintInput): string;
2774
2825
 
2826
+ /**
2827
+ * Fade metadata — family-agnostic types + parsing for transition orphan fades
2828
+ * (synth / drum / instrument panels).
2829
+ *
2830
+ * A fade is a CROSSFADE WITH ONE EMPTY ENDPOINT: a single generated track that
2831
+ * either fades IN (a target-only track entering — `morph(∅ → target)`) or fades
2832
+ * OUT (an origin-only track leaving — `morph(origin → ∅)`) across the transition
2833
+ * loop. It reuses the same generation pipeline (`buildCrossfadeInpaintPrompt`
2834
+ * with one empty endpoint) and the same volume-automation fader as crossfade.
2835
+ *
2836
+ * Stored in scene plugin_data under `track:<dbId>:fade` (ONE entry per track —
2837
+ * unlike crossfade there is no partner / groupId). Kept as a SEPARATE type from
2838
+ * crossfade so the load-bearing "drop a half-broken pair" guard in
2839
+ * `parseCrossfadePairs` stays intact.
2840
+ *
2841
+ * @since SDK 2.28.0
2842
+ */
2843
+
2844
+ /** Which way the lone track fades over the transition. */
2845
+ type FadeDirection = 'in' | 'out';
2846
+ /**
2847
+ * How the fade is shaped:
2848
+ * - `volume` — a one-sided level ramp does the work (DJ-style). Best for
2849
+ * textural/sustained material (pads, atmospheres).
2850
+ * - `build` — the MIDI carries the fade (the inpaint grows sparse→full on the way
2851
+ * in, or dissolves on the way out); the level stays flat. Best for articulated
2852
+ * material (lead, bass, drums, winds, vocals).
2853
+ */
2854
+ type FadeGesture = 'volume' | 'build';
2855
+ /** Per-track fade metadata (one scene-data value per fade track). */
2856
+ interface FadeMeta {
2857
+ direction: FadeDirection;
2858
+ gesture: FadeGesture;
2859
+ /**
2860
+ * Audio transition variant for one-sided LOOP transitions. `'fade'` (default,
2861
+ * and the only value MIDI panels write) is a plain level ramp; `stutter` /
2862
+ * `chopped` re-render the loop's audio, `delay` adds a delay-throw FX. Shown as
2863
+ * a badge on the row. @since SDK 2.32.0
2864
+ */
2865
+ effect?: 'fade' | 'stutter' | 'chopped' | 'delay';
2866
+ /** DB id of the SOURCE track this fade's preset/sample + pattern was seeded from. */
2867
+ sourceTrackDbId: string;
2868
+ /** DB id of the scene the source track lives in (the from/to scene). */
2869
+ sourceSceneId: string;
2870
+ /** Source track display name (shown in the caption). */
2871
+ sourceName: string;
2872
+ /** Copied preset/sample label (shown in the caption). */
2873
+ soundLabel: string;
2874
+ /** Fade position 0..1 — WHERE in time the fade midpoint sits. */
2875
+ sliderPos: number;
2876
+ }
2877
+ /** A fade entry resolved from scene data: the fade track's dbId + its metadata. */
2878
+ interface FadeEntry {
2879
+ dbId: string;
2880
+ meta: FadeMeta;
2881
+ }
2882
+ /** Narrow an unknown scene-data value to FadeMeta (defensive — survives partial blobs). */
2883
+ declare function asFadeMeta(val: unknown): FadeMeta | null;
2884
+ /**
2885
+ * Scan all `track:<dbId>:fade` keys in a scene's plugin_data and return one entry
2886
+ * per valid fade. Unlike crossfade there is no grouping or both-present gate — a
2887
+ * fade is intrinsically a single track.
2888
+ */
2889
+ declare function parseFades(sceneData: Record<string, unknown>): FadeEntry[];
2890
+ /**
2891
+ * Build a ONE-sided volume-automation curve for a fade over `bars` at `bpm`.
2892
+ *
2893
+ * - `gesture === 'build'` → flat at unity (0 dB). The compositional build in the
2894
+ * MIDI carries the fade; layering a volume ramp on top would double-fade.
2895
+ * - `gesture === 'volume'` → an equal-power ramp identical to ONE half of
2896
+ * `buildCrossfadeVolumeCurves`: fade-out ≡ its `origin` curve (unity→floor),
2897
+ * fade-in ≡ its `target` curve (floor→unity). `sliderPos` sets WHERE the −3 dB
2898
+ * midpoint sits in time.
2899
+ *
2900
+ * Points span [0, durationSeconds] so the engine re-reads them each loop. Returns
2901
+ * dB points for `host.setTrackVolumeAutomation`.
2902
+ *
2903
+ * @since SDK 2.28.0
2904
+ */
2905
+ declare function buildFadeVolumeCurve(bars: number, bpm: number, direction: FadeDirection, sliderPos: number, gesture: FadeGesture, steps?: number): VolumeAutomationPoint[];
2906
+ /**
2907
+ * Roles whose fades default to a `volume` (level) ramp — sustained/textural
2908
+ * material that enters/leaves by level in real productions. Everything else
2909
+ * defaults to `build` (the notes carry the fade).
2910
+ *
2911
+ * This is a UI default heuristic over role tokens, NOT the canonical role list
2912
+ * (that lives in the app's instrument-classification + `host.getValidRoles()`).
2913
+ * There is no textural↔articulated axis in the taxonomy, so this small curated
2914
+ * subset lives next to its consumer (the fade modal/panels).
2915
+ *
2916
+ * @since SDK 2.28.0
2917
+ */
2918
+ declare const TEXTURAL_ROLES: ReadonlySet<string>;
2919
+ /** Pick the default fade gesture for a track's role (textural → volume, else build). */
2920
+ declare function defaultFadeGesture(role: string | null | undefined): FadeGesture;
2921
+
2922
+ /**
2923
+ * FadeTrackRow — a transition "fade track": a single locked TrackRow with a
2924
+ * direction badge (Fade in / Fade out) and a one-sided fade slider.
2925
+ *
2926
+ * A fade is a crossfade with one empty endpoint — a lone generated track that
2927
+ * either enters (fade in, for a target-only track) or leaves (fade out, for an
2928
+ * origin-only track) across the transition loop. Like a crossfade layer, the
2929
+ * sound/generation controls are omitted (the SDK TrackRow is "controlled by
2930
+ * omission"): no shuffle / Create / preset-pick / FX / drawer / inner-delete.
2931
+ * What remains: per-track volume/pan/mute/solo and a single delete.
2932
+ *
2933
+ * The slider represents WHERE in the loop the fade sits (earlier ↔ later). Omit
2934
+ * `onSliderChange` to render it read-only.
2935
+ *
2936
+ * @since SDK 2.28.0
2937
+ */
2938
+
2939
+ /** The single (engine track) layer of a fade. */
2940
+ interface FadeLayer {
2941
+ /** Engine track id of this fade's track (also the meter key). */
2942
+ trackId: string;
2943
+ /** Display name of this fade's (newly created) track. */
2944
+ name: string;
2945
+ /** Musical role (drives the auto gesture). */
2946
+ role?: string;
2947
+ /** Name of the SOURCE track this fade was seeded from (origin/target scene). */
2948
+ sourceName?: string;
2949
+ /** Human label of the copied preset/sound, shown in the caption. */
2950
+ soundLabel?: string;
2951
+ /** Playback state for this track. */
2952
+ runtimeState: {
2953
+ muted: boolean;
2954
+ solo: boolean;
2955
+ volume: number;
2956
+ pan: number;
2957
+ };
2958
+ }
2959
+ interface FadeTrackRowProps {
2960
+ /** The lone fade track. */
2961
+ layer: FadeLayer;
2962
+ /** 'in' (enters across the loop) or 'out' (leaves across the loop). */
2963
+ direction: FadeDirection;
2964
+ /** How the fade is shaped — shown read-only (volume = level ramp, build = notes). */
2965
+ gesture: FadeGesture;
2966
+ /** Audio transition variant — relabels the badge (Stutter/Chopped/Delay). @since SDK 2.32.0 */
2967
+ effect?: 'fade' | 'stutter' | 'chopped' | 'delay';
2968
+ /** Fade position 0..1 — WHERE in time the fade sits. Defaults centered. */
2969
+ sliderPos?: number;
2970
+ /** Toggle mute. */
2971
+ onMuteToggle: () => void;
2972
+ /** Toggle solo. */
2973
+ onSoloToggle: () => void;
2974
+ /** Change the track's volume. */
2975
+ onVolumeChange: (volume: number) => void;
2976
+ /** Change the track's pan. */
2977
+ onPanChange: (pan: number) => void;
2978
+ /** Delete the fade. */
2979
+ onDelete: () => void;
2980
+ /** Move the fade point. Omit to render the slider read-only. */
2981
+ onSliderChange?: (pos: number) => void;
2982
+ /** Shared meter handle (welds a peak meter to the track). */
2983
+ levels?: TrackLevelsHandle;
2984
+ /** Left-border accent. Defaults to transition purple. */
2985
+ accentColor?: string;
2986
+ }
2987
+ declare function FadeTrackRow({ layer, direction, gesture, effect, sliderPos, onMuteToggle, onSoloToggle, onVolumeChange, onPanChange, onDelete, onSliderChange, levels, accentColor, }: FadeTrackRowProps): React.ReactElement;
2988
+
2989
+ /**
2990
+ * FadeModal — "add a fade" picker for a transition scene.
2991
+ *
2992
+ * Shown only inside a `scene_type='transition'` scene. It self-fetches the FROM
2993
+ * (origin) and TO (target) scenes' family tracks and diffs them by role to find
2994
+ * ORPHANS — tracks with no counterpart on the other side:
2995
+ * - origin-only surplus → "Fade out" candidates (the track leaves)
2996
+ * - target-only surplus → "Fade in" candidates (the track enters)
2997
+ * Tracks whose role is matched on both sides are crossfade territory and are NOT
2998
+ * shown here. A source already used in a crossfade or a fade is hidden (via
2999
+ * excludeSourceDbIds).
3000
+ *
3001
+ * The fade GESTURE (volume vs build) is auto-selected from the track's role and
3002
+ * shown read-only — the user does not choose it. On confirm the modal hands the
3003
+ * selection + direction + gesture to `onCreate`, which the panel implements
3004
+ * (create one track, generate a chord-conforming part, copy the sound, apply a
3005
+ * one-sided volume curve). `onCreate` should reject on failure so the modal can
3006
+ * show it and stay open.
3007
+ *
3008
+ * @since SDK 2.28.0
3009
+ */
3010
+
3011
+ /** A picked orphan track handed to `onCreate`. */
3012
+ interface FadeSelection {
3013
+ /** Source track DB id (selector for getTrackSound + seeding the part). */
3014
+ dbId: string;
3015
+ /** Display name (for the row caption). */
3016
+ name: string;
3017
+ /** Musical role of the source track (drives the auto gesture). */
3018
+ role?: string;
3019
+ }
3020
+ interface FadeModalProps {
3021
+ /** Scoped host — the modal calls listSceneFamilyTracks itself. */
3022
+ host: PluginHost;
3023
+ /** Controls visibility (the panel owns open/closed from its header button). */
3024
+ open: boolean;
3025
+ /** DB id of the transition's FROM (origin) scene. */
3026
+ fromSceneId: string;
3027
+ /** DB id of the transition's TO (target) scene. */
3028
+ toSceneId: string;
3029
+ /** Display name for the origin scene heading (optional). */
3030
+ fromSceneName?: string;
3031
+ /** Display name for the target scene heading (optional). */
3032
+ toSceneName?: string;
3033
+ /** Source-track DB ids already used in a crossfade OR a fade — hidden here. */
3034
+ excludeSourceDbIds?: readonly string[];
3035
+ /** Close handler (Escape, backdrop, Cancel, or after a successful create). */
3036
+ onClose: () => void;
3037
+ /** Build the fade. Should reject on failure so the modal shows it. */
3038
+ onCreate: (selection: FadeSelection, direction: FadeDirection, gesture: FadeGesture) => Promise<void>;
3039
+ /** data-testid prefix. */
3040
+ testIdPrefix?: string;
3041
+ }
3042
+ declare function FadeModal({ host, open, fromSceneId, toSceneId, fromSceneName, toSceneName, excludeSourceDbIds, onClose, onCreate, testIdPrefix, }: FadeModalProps): React.ReactElement | null;
3043
+
2775
3044
  /**
2776
3045
  * ImportTrackModal — "import a track from another scene" picker (SDK component).
2777
3046
  *
@@ -2886,6 +3155,181 @@ interface CrossfadeModalProps {
2886
3155
  }
2887
3156
  declare function CrossfadeModal({ host, open, fromSceneId, toSceneId, fromSceneName, toSceneName, excludeSourceDbIds, onClose, onCreate, testIdPrefix, }: CrossfadeModalProps): React.ReactElement | null;
2888
3157
 
3158
+ /**
3159
+ * TransitionDesigner — the per-panel transition staging board, rendered INLINE as
3160
+ * a toggled view inside a generator panel (NOT a modal).
3161
+ *
3162
+ * The multi-row, persistent successor to {@link CrossfadeModal} + {@link FadeModal}:
3163
+ * instead of opening a single-pair dialog ~20 times, the panel header gains a
3164
+ * Tracks ⇄ Transition toggle; flipping to Transition replaces the panel's track
3165
+ * list with this board. Playback is unaffected (the engine keeps playing the
3166
+ * scene's tracks — they're just not shown until you toggle back). Shown only
3167
+ * inside a `scene_type='transition'` scene and scoped to one panel family (a synth
3168
+ * board shows only synth tracks — "drums can't crossfade to synth" is enforced
3169
+ * structurally because each board asks its own family-scoped host).
3170
+ *
3171
+ * Two index-aligned, drag-reorderable columns: origin (scene A, left) and target
3172
+ * (scene B, right). Row i pairs origin[i] with target[i]; the pairing derives the
3173
+ * transition type (both → crossfade, origin-only → fade out, target-only → fade
3174
+ * in). Insert a "gap" above a cell to push a track so it fades instead of
3175
+ * crossfading with whatever sits opposite. The pool per column is the scene's
3176
+ * family tracks MINUS sources already consumed by a committed crossfade/fade
3177
+ * (`excludeSourceDbIds`).
3178
+ *
3179
+ * Per-row **Create** reuses the panel's EXISTING orchestration via `onCreateCrossfade`
3180
+ * / `onCreateFade`. Creates run CONCURRENTLY — fire several at once, or **Create all**
3181
+ * (a bounded pool). Each in-flight row shows its own progress bar and locks just its
3182
+ * own cells; the rest of the board stays editable. On success the source leaves the
3183
+ * pool (the panel updates `excludeSourceDbIds`) and the row collapses; deleting the
3184
+ * committed crossfade/fade on the deck returns the source here. The staged
3185
+ * arrangement persists to the transition scene's plugin_data so it survives toggles.
3186
+ *
3187
+ * @since SDK 2.29.0 (modal); inline toggle view + concurrent creation since 2.30.0.
3188
+ */
3189
+
3190
+ interface TransitionDesignerProps {
3191
+ /** Scoped host — the board calls listSceneFamilyTracks / getSceneName itself. */
3192
+ host: PluginHost;
3193
+ /** DB id of the transition's FROM (origin) scene. */
3194
+ fromSceneId: string;
3195
+ /** DB id of the transition's TO (target) scene. */
3196
+ toSceneId: string;
3197
+ /** DB id of the transition scene itself — the staged draft is persisted here. */
3198
+ transitionSceneId: string;
3199
+ /**
3200
+ * Source-track DB ids already consumed by a committed crossfade OR fade in this
3201
+ * panel. Hidden from both columns so each source is used at most once; when the
3202
+ * deck row is deleted the panel drops the id and the source reappears here.
3203
+ */
3204
+ excludeSourceDbIds?: readonly string[];
3205
+ /**
3206
+ * Build a crossfade pair — the panel's existing handler (create two tracks, one
3207
+ * morphed clip, copy each preset). Should reject on failure. Safe to call
3208
+ * concurrently.
3209
+ */
3210
+ onCreateCrossfade: (origin: CrossfadeSelection, target: CrossfadeSelection) => Promise<void>;
3211
+ /** Build a one-sided fade — the panel's existing handler. Should reject on failure. */
3212
+ onCreateFade: (selection: FadeSelection, direction: FadeDirection, gesture: FadeGesture) => Promise<void>;
3213
+ /**
3214
+ * Build an AUDIO-only one-sided transition (stutter / chopped / delay). When
3215
+ * provided, one-sided rows render an effect selector; absent (MIDI panels) →
3216
+ * one-sided rows stay plain fades. @since SDK 2.32.0
3217
+ */
3218
+ onCreateAudioTransition?: (selection: FadeSelection, direction: FadeDirection, effect: 'stutter' | 'chopped' | 'delay') => Promise<void>;
3219
+ /** Short family label for the heading, e.g. "Synths". */
3220
+ familyLabel?: string;
3221
+ /** data-testid prefix. */
3222
+ testIdPrefix?: string;
3223
+ }
3224
+ declare function TransitionDesigner({ host, fromSceneId, toSceneId, transitionSceneId, excludeSourceDbIds, onCreateCrossfade, onCreateFade, onCreateAudioTransition, familyLabel, testIdPrefix, }: TransitionDesignerProps): React.ReactElement;
3225
+
3226
+ /**
3227
+ * Transition Designer — pure helpers for the per-panel transition staging board.
3228
+ *
3229
+ * The designer is the multi-row, persistent successor to CrossfadeModal/FadeModal:
3230
+ * it lays out ONE panel-family's origin (scene A) and target (scene B) source
3231
+ * tracks as two index-aligned, drag-reorderable columns. Row i pairs the origin
3232
+ * slot at index i with the target slot at index i, and the pairing DERIVES the
3233
+ * transition type:
3234
+ * - both filled → crossfade (morph A→B)
3235
+ * - origin filled, target blank → fade out (the track leaves)
3236
+ * - target filled, origin blank → fade in (the track enters)
3237
+ * A slot may be a source-track dbId or `null` (a blank spacer). Blanks let the
3238
+ * user open a gap so a mid-list track becomes a fade instead of crossfading with
3239
+ * whatever happens to sit opposite it (the CSV-style layout).
3240
+ *
3241
+ * The "available pool" per column is the scene's family tracks MINUS the sources
3242
+ * already consumed by a committed crossfade/fade (excludeSourceDbIds). Creating a
3243
+ * row reuses the panel's existing crossfade/fade orchestration; deleting the
3244
+ * committed crossfade/fade on the deck returns its source to the pool.
3245
+ *
3246
+ * This module owns only the shape + the pure slot/row math so it can be unit
3247
+ * tested without a DOM and can't drift across the three panels. The component
3248
+ * (TransitionDesigner.tsx) owns the overlay, drag wiring, and persistence.
3249
+ *
3250
+ * @since SDK 2.29.0
3251
+ */
3252
+ /**
3253
+ * Persisted per-transition-scene draft: the two columns' slot orders. A slot is
3254
+ * a source-track dbId, or `null` for a blank spacer (an intentional gap). Stored
3255
+ * in the transition scene's plugin_data under {@link TRANSITION_DESIGNER_DRAFT_KEY};
3256
+ * because plugin_data is scoped by (plugin_id, sceneId), each panel family keeps
3257
+ * its own draft automatically.
3258
+ */
3259
+ interface TransitionDesignerDraft {
3260
+ /** Origin (scene A) column order — dbIds or `null` blanks. */
3261
+ originOrder: (string | null)[];
3262
+ /** Target (scene B) column order — dbIds or `null` blanks. */
3263
+ targetOrder: (string | null)[];
3264
+ /** Per one-sided-row audio effect, keyed by the source dbId. @since SDK 2.32.0 */
3265
+ rowEffects?: Record<string, AudioEffect>;
3266
+ }
3267
+ /** scene-data key (under the transition scene) holding the staged draft. */
3268
+ declare const TRANSITION_DESIGNER_DRAFT_KEY = "transitionDesigner:draft";
3269
+ /** The transition a single aligned row represents (derived from its two slots). */
3270
+ type TransitionRowType = 'crossfade' | 'fade-out' | 'fade-in';
3271
+ /**
3272
+ * Audio-only transition gesture for a ONE-SIDED (orphan) loop. `'fade'` is the
3273
+ * default level ramp (works for any family); `stutter`/`chopped`/`delay` are
3274
+ * audio panels only, surfaced via the row's effect selector when the panel
3275
+ * passes `onCreateAudioTransition`. @since SDK 2.32.0
3276
+ */
3277
+ type AudioEffect = 'fade' | 'stutter' | 'chopped' | 'delay';
3278
+ declare const AUDIO_EFFECTS: readonly AudioEffect[];
3279
+ declare const AUDIO_EFFECT_LABEL: Record<AudioEffect, string>;
3280
+ declare function asAudioEffect(v: unknown): AudioEffect | null;
3281
+ /** Derive a row's transition type from which slots are filled. `null` = empty row. */
3282
+ declare function rowType(hasOrigin: boolean, hasTarget: boolean): TransitionRowType | null;
3283
+ /** Narrow an unknown scene-data value to a TransitionDesignerDraft (defensive). */
3284
+ declare function asTransitionDesignerDraft(val: unknown): TransitionDesignerDraft | null;
3285
+ /**
3286
+ * Reconcile a saved slot order against the current pool of available source ids:
3287
+ * - keep saved ids still in the pool (in their saved position),
3288
+ * - keep `null` blanks,
3289
+ * - drop ids no longer in the pool (consumed by a created crossfade/fade, or the
3290
+ * source track was deleted) and any duplicates,
3291
+ * - append pool ids missing from the saved order (newly added tracks) at the end.
3292
+ *
3293
+ * Pure; exported for unit testing.
3294
+ */
3295
+ declare function reconcileSlots(saved: readonly (string | null)[] | undefined, poolIds: readonly string[]): (string | null)[];
3296
+ /** One assembled designer row: the two source dbIds (or `null`) + derived type. */
3297
+ interface DesignerRowSlots {
3298
+ originId: string | null;
3299
+ targetId: string | null;
3300
+ type: TransitionRowType | null;
3301
+ }
3302
+ /** Zip two slot columns into index-aligned rows with their derived type. */
3303
+ declare function buildRowSlots(originSlots: readonly (string | null)[], targetSlots: readonly (string | null)[]): DesignerRowSlots[];
3304
+ /**
3305
+ * Tidy the columns for persistence: drop rows where BOTH slots are blank (a
3306
+ * meaningless gap) and trim trailing blanks per column. Returns clean columns
3307
+ * suitable for {@link TransitionDesignerDraft}.
3308
+ */
3309
+ declare function normalizeSlots(originSlots: readonly (string | null)[], targetSlots: readonly (string | null)[]): TransitionDesignerDraft;
3310
+ /** Pad a column with trailing `null`s up to `n` (so both columns render aligned). */
3311
+ declare function padSlots(slots: readonly (string | null)[], n: number): (string | null)[];
3312
+ /** Pad both columns to equal length (= the longer column). */
3313
+ declare function padPair(originSlots: readonly (string | null)[], targetSlots: readonly (string | null)[]): [(string | null)[], (string | null)[]];
3314
+ /** Shallow element-wise equality for two slot columns. */
3315
+ declare function slotsEqual(a: readonly (string | null)[], b: readonly (string | null)[]): boolean;
3316
+ /**
3317
+ * Stable key identifying an in-flight create, derived from the row's SOURCE dbIds
3318
+ * (not its row index) — so reordering or inserting a gap mid-create still maps the
3319
+ * progress indicator to the right row, and concurrent creates never collide. dbIds
3320
+ * are UUIDs, so `|` is a safe origin/target separator. `null` for an empty row.
3321
+ *
3322
+ * @since SDK 2.30.0
3323
+ */
3324
+ declare function rowKey(row: DesignerRowSlots): string | null;
3325
+ /**
3326
+ * The set of source dbIds referenced by a collection of in-flight {@link rowKey}s —
3327
+ * used to lock those cells (no drag / gap edits) while their create runs.
3328
+ *
3329
+ * @since SDK 2.30.0
3330
+ */
3331
+ declare function dbIdsFromKeys(keys: Iterable<string>): Set<string>;
3332
+
2889
3333
  /**
2890
3334
  * ConfirmDialog — styled in-app confirmation modal (SDK component).
2891
3335
  *
@@ -3609,7 +4053,7 @@ declare function useSoundHistory(applySound: (trackId: string, descriptor: unkno
3609
4053
  * Registry checks semver.gte(PLUGIN_SDK_VERSION, manifest.minHostVersion)
3610
4054
  * during activation and marks incompatible plugins accordingly.
3611
4055
  */
3612
- declare const PLUGIN_SDK_VERSION = "2.26.0";
4056
+ declare const PLUGIN_SDK_VERSION = "2.34.0";
3613
4057
 
3614
4058
  /**
3615
4059
  * FX Preset Definitions
@@ -3757,4 +4201,4 @@ interface PickTopKOptions {
3757
4201
  */
3758
4202
  declare function pickTopKWeighted<T>(scored: ReadonlyArray<ScoredCandidate<T>>, options?: PickTopKOptions): T | null;
3759
4203
 
3760
- export { type AudioInputDevice, type BulkAddPlaceholderTrack, type ComposeProgressEvent, type ComposeProgressListener, type ComposeSceneOptions, type ComposeSceneResult, ConfirmDialog, type ConfirmDialogProps, type CreateTrackOptions, type CrossfadeInpaintInput, type CrossfadeLayer, type CrossfadeMeta, CrossfadeModal, type CrossfadeModalProps, type CrossfadePairMeta, type CrossfadeSelection, type CrossfadeSlot, CrossfadeTrackRow, type CrossfadeTrackRowProps, type CrossfadeVolumeCurves, DB_MAX, DB_MIN, DEFAULT_FX_CATEGORY_DETAIL, DEFAULT_FX_DRY_WET, DRAG_DEAD_ZONE, type DeckBoundaryEvent, type DeckBoundaryListener, DownloadPackButton, type DownloadPackButtonProps, type DownloadPackButtonVariant, type DrawerTab, type DrumKit, EMPTY_FX_DETAIL_STATE, EMPTY_FX_STATE, EQUAL_POWER_GAIN, type ExportMidiBundleOptions, type ExportMidiBundleResult, type ExportedPluginData, FX_CATEGORIES, FX_CHAIN_ORDER, FX_DISPLAY_LABELS, FX_ENGINE_PLUGIN_NAMES, FX_PRESET_CONFIGS, type FxCategory, type FxCategoryDetailState, type FxPreset, type FxPresetConfig, type FxPresetData, type FxPresetDataEntry, FxToggleBar, type FxToggleBarProps, GUTTER_W, type GeneratorPlugin, type GeneratorType, type ImportCandidateScene, type ImportCandidateTrack, ImportTrackModal, type ImportTrackModalProps, type InstrumentDescriptor, TrackDrawer as InstrumentDrawer, type TrackDrawerProps as InstrumentDrawerProps, type InstrumentSampler, type InstrumentZone, type LLMCandidate, type LLMContent, type LLMFunctionDeclaration, type LLMGenerationConfig, type LLMGenerationRequest, type LLMGenerationResult, type LLMPart, type LLMSystemInstruction, type LLMTool, type LLMToolUseRequest, type LLMToolUseResponse, type LLMUsageMetadata, LevelMeter, type LevelMeterProps, type ListAudioFilesOptions, type ListImportableTracksOptions, type MidiClipData, type MidiWriteResult, type MixInterpolation, Modal, type ModalProps, type MusicalContext, OffsetScrubber, type OffsetScrubberProps, PLUGIN_SDK_VERSION, PX_PER_BEAT, PanSlider, type PeakAnalysis, PianoRollEditor, type PianoRollEditorProps, type PickTopKOptions, type PluginAppTool, type PluginAppToolInputSchema, type PluginAppToolResult, type PluginAudioTextureRequest, type PluginAudioTextureResult, type PluginCapabilities, type PluginChordSegment, type PluginChordTiming, type PluginConcurrentTrackInfo, type PluginCuePoints, type PluginDownloadOptions, PluginError, type PluginErrorCode, type PluginFileDialogOptions, type PluginFxCategoryDetailState, type PluginGenerationContext, type PluginHost, type PluginHttpRequestOptions, type PluginHttpResponse, type PluginManifest, type PluginMidiNote, type PluginPresetData, type PluginPresetInfo, type PluginRegistration, type PluginSampleFilter, type PluginSampleImportResult, type PluginSampleInfo, type PluginSampleTrackInfo, type PluginSceneContext, type PluginSceneInfo, type PluginSettingsSchema, type PluginSettingsStore, type PluginSkill, type PluginSkillInputSchema, type PluginStatus, type PluginStemSplitResult, type PluginStemTrackInfo, type PluginSynthInfo, type PluginTrackFxDetailState, type PluginTrackHandle, type PluginTrackInfo, type PluginTrackLevel, type PluginTrackRuntimeState, type PluginTransportState, type PluginTrimWindow, type PluginUIProps, type PostProcessOptions, RESIZE_HANDLE_PX, ROW_HEIGHT, type ReadMidiClip, type ReadMidiResult, type RecordingChunkFinalizedEvent, type RecordingTargetInfo, type SDKTrackRowProps, SLIDER_UNITY, SamplePackCTACard, type SamplePackCTACardProps, type SamplePackCTACardStatus, type SamplePackCardInfo, type SavePluginPresetOptions, type SceneChangeListener, type SceneFamilyTrack, type ScoredCandidate, ScrollingWaveform, type ScrollingWaveformProps, type SettingDefinition, type ShufflePresetResult, SorceryProgressBar, type SoundHistoryEntry, type StemType, type SynthesizeCuePointsOptions, TrackDrawer, type TrackDrawerProps, type TrackFxDetailState, type TrackFxState, type TrackLevelsHandle, TrackMeterStrip, type TrackMeterStripProps, type TrackMeterView, TrackRow, type TrackRowDragProps, type TrackSoundHistory, type TrackSoundSnapshot, type TrackStateChangeListener, type TransportEvent, type TransportEventListener, type UnsubscribeFn, type UseSoundHistoryOptions, type UseSoundHistoryResult, type UseTrackReorderOptions, type UseTrackReorderResult, type VolumeAutomationPoint, VolumeSlider, type WaveformPeaks, WaveformView, type WaveformViewProps, analyzeWavPeak, asCrossfadeMeta, buildCrossfadeInpaintPrompt, buildCrossfadeVolumeCurves, calculateTimeBasedTarget, cellToPx, centerScrollTop, computePeaks, dbToSlider, drawWaveform, formatConcurrentTracks, moveItem, parseCrossfadePairs, pickTopKWeighted, pitchToName, pxToCell, resizeNoteDuration, scorePromptMatch, sliderToDb, synthesizeCuePoints, tokenizePrompt, transposeNotes, useAnySolo, useSceneState, useSoundHistory, useTrackLevel, useTrackLevels, useTrackMeter, useTrackReorder, useTransportPlaying };
4204
+ export { AUDIO_EFFECTS, AUDIO_EFFECT_LABEL, type AudioEffect, type AudioInputDevice, type BulkAddPlaceholderTrack, type ComposeProgressEvent, type ComposeProgressListener, type ComposeSceneOptions, type ComposeSceneResult, ConfirmDialog, type ConfirmDialogProps, type CreateTrackOptions, type CrossfadeInpaintInput, type CrossfadeLayer, type CrossfadeMeta, CrossfadeModal, type CrossfadeModalProps, type CrossfadePairMeta, type CrossfadeSelection, type CrossfadeSlot, CrossfadeTrackRow, type CrossfadeTrackRowProps, type CrossfadeVolumeCurves, DB_MAX, DB_MIN, DEFAULT_FX_CATEGORY_DETAIL, DEFAULT_FX_DRY_WET, DRAG_DEAD_ZONE, type DeckBoundaryEvent, type DeckBoundaryListener, type DesignerRowSlots, DownloadPackButton, type DownloadPackButtonProps, type DownloadPackButtonVariant, type DrawerTab, type DrumKit, EMPTY_FX_DETAIL_STATE, EMPTY_FX_STATE, EQUAL_POWER_GAIN, type ExportMidiBundleOptions, type ExportMidiBundleResult, type ExportedPluginData, FX_CATEGORIES, FX_CHAIN_ORDER, FX_DISPLAY_LABELS, FX_ENGINE_PLUGIN_NAMES, FX_PRESET_CONFIGS, type FadeDirection, type FadeEntry, type FadeGesture, type FadeLayer, type FadeMeta, FadeModal, type FadeModalProps, type FadeSelection, FadeTrackRow, type FadeTrackRowProps, type FxCategory, type FxCategoryDetailState, type FxPreset, type FxPresetConfig, type FxPresetData, type FxPresetDataEntry, FxToggleBar, type FxToggleBarProps, GUTTER_W, type GeneratorPlugin, type GeneratorType, type ImportCandidateScene, type ImportCandidateTrack, ImportTrackModal, type ImportTrackModalProps, type InstrumentDescriptor, TrackDrawer as InstrumentDrawer, type TrackDrawerProps as InstrumentDrawerProps, type InstrumentSampler, type InstrumentZone, type LLMCandidate, type LLMContent, type LLMFunctionDeclaration, type LLMGenerationConfig, type LLMGenerationRequest, type LLMGenerationResult, type LLMPart, type LLMSystemInstruction, type LLMTool, type LLMToolUseRequest, type LLMToolUseResponse, type LLMUsageMetadata, LevelMeter, type LevelMeterProps, type ListAudioFilesOptions, type ListImportableTracksOptions, type MidiClipData, type MidiWriteResult, type MixInterpolation, Modal, type ModalProps, type MusicalContext, OffsetScrubber, type OffsetScrubberProps, PLUGIN_SDK_VERSION, PX_PER_BEAT, PanSlider, type PeakAnalysis, PianoRollEditor, type PianoRollEditorProps, type PickTopKOptions, type PluginAppTool, type PluginAppToolInputSchema, type PluginAppToolResult, type PluginAudioTextureRequest, type PluginAudioTextureResult, type PluginCapabilities, type PluginChordSegment, type PluginChordTiming, type PluginConcurrentTrackInfo, type PluginCuePoints, type PluginDownloadOptions, PluginError, type PluginErrorCode, type PluginFileDialogOptions, type PluginFxCategoryDetailState, type PluginGenerationContext, type PluginHost, type PluginHttpRequestOptions, type PluginHttpResponse, type PluginManifest, type PluginMidiNote, type PluginPresetData, type PluginPresetInfo, type PluginRegistration, type PluginSampleFilter, type PluginSampleImportResult, type PluginSampleInfo, type PluginSampleTrackInfo, type PluginSceneContext, type PluginSceneInfo, type PluginSettingsSchema, type PluginSettingsStore, type PluginSkill, type PluginSkillInputSchema, type PluginStatus, type PluginStemSplitResult, type PluginStemTrackInfo, type PluginSynthInfo, type PluginTrackFxDetailState, type PluginTrackHandle, type PluginTrackInfo, type PluginTrackLevel, type PluginTrackRuntimeState, type PluginTransportState, type PluginTrimWindow, type PluginUIProps, type PostProcessOptions, RESIZE_HANDLE_PX, ROW_HEIGHT, type ReadMidiClip, type ReadMidiResult, type RecordingChunkFinalizedEvent, type RecordingTargetInfo, type SDKTrackRowProps, SLIDER_UNITY, SamplePackCTACard, type SamplePackCTACardProps, type SamplePackCTACardStatus, type SamplePackCardInfo, type SavePluginPresetOptions, type SceneChangeListener, type SceneFamilyTrack, type ScoredCandidate, ScrollingWaveform, type ScrollingWaveformProps, type SettingDefinition, type ShufflePresetResult, SorceryProgressBar, type SoundHistoryEntry, type StemType, type SynthesizeCuePointsOptions, TEXTURAL_ROLES, TRANSITION_DESIGNER_DRAFT_KEY, TrackDrawer, type TrackDrawerProps, type TrackFxDetailState, type TrackFxState, type TrackLevelsHandle, TrackMeterStrip, type TrackMeterStripProps, type TrackMeterView, TrackRow, type TrackRowDragProps, type TrackSoundHistory, type TrackSoundSnapshot, type TrackStateChangeListener, TransitionDesigner, type TransitionDesignerDraft, type TransitionDesignerProps, type TransitionRowType, type TransportEvent, type TransportEventListener, type UnsubscribeFn, type UseSoundHistoryOptions, type UseSoundHistoryResult, type UseTrackReorderOptions, type UseTrackReorderResult, type VolumeAutomationPoint, VolumeSlider, type WaveformPeaks, WaveformView, type WaveformViewProps, analyzeWavPeak, asAudioEffect, asCrossfadeMeta, asFadeMeta, asTransitionDesignerDraft, buildCrossfadeInpaintPrompt, buildCrossfadeVolumeCurves, buildFadeVolumeCurve, buildRowSlots, calculateTimeBasedTarget, cellToPx, centerScrollTop, computePeaks, dbIdsFromKeys, dbToSlider, defaultFadeGesture, drawWaveform, formatConcurrentTracks, hashString, moveItem, normalizeSlots, padPair, padSlots, parseCrossfadePairs, parseFades, pickTopKWeighted, pitchToName, pxToCell, reconcileSlots, resizeNoteDuration, rowKey, rowType, scorePromptMatch, sliderToDb, slotsEqual, soundIdentity, synthesizeCuePoints, tokenizePrompt, transposeNotes, useAnySolo, useSceneState, useSoundHistory, useTrackLevel, useTrackLevels, useTrackMeter, useTrackReorder, useTransportPlaying };