Skip to content

feat(smplr): add sampler instruments#212

Open
heypoom wants to merge 17 commits into
mainfrom
add-smplr-objects
Open

feat(smplr): add sampler instruments#212
heypoom wants to merge 17 commits into
mainfrom
add-smplr-objects

Conversation

@heypoom

@heypoom heypoom commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Add sampler instruments from the smplr library

Summary by CodeRabbit

  • New Features

    • Added sampled-instrument objects: piano~, epiano~, drums~, mallet~, mellotron~, versilian~, smolken~, plus soundfont~, soundfont2~, and multi-channel gm~.
    • Enabled Patchies/MIDI-style triggering (note on/off, bang, programChange, controlChange, gain/detune/reverse) and descriptor-driven playback with improved sampled-instrument settings UI, including searchable comboboxes and conditional field visibility.
  • Bug Fixes

    • Improved async sampled-instrument load/reload handling and trigger semantics (including noteOn velocity 0 acting as noteOff).
  • Documentation

    • Added new object pages for gm~, all sampled instruments, and SoundFont objects, plus updated MIDI-file messaging notes.
  • Tests

    • Added unit/integration tests covering message normalization, program mapping, settings option helpers, and sampled-instrument runtime behavior.

@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@heypoom, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 25 minutes and 25 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b562c6cf-11c2-49df-b560-5b59c2b851cf

📥 Commits

Reviewing files that changed from the base of the PR and between 644dc0b and 6abed9e.

📒 Files selected for processing (17)
  • docs/superpowers/plans/2026-06-27-smplr-sampled-instruments.md
  • docs/superpowers/plans/2026-06-28-gm-smplr-multichannel.md
  • ui/src/lib/components/nodes/ScopeNode.svelte
  • ui/src/lib/objects/builtin-shorthands.test.ts
  • ui/src/lib/settings/types.ts
  • ui/src/lib/settings/visibility.test.ts
  • ui/src/lib/settings/visibility.ts
  • ui/src/objects/midi.file/midi-file-player.test.ts
  • ui/src/objects/midi.file/midi-file-player.ts
  • ui/src/objects/smplr/GmAudioNode.test.ts
  • ui/src/objects/smplr/GmAudioNode.ts
  • ui/src/objects/smplr/GmNode.svelte
  • ui/src/objects/smplr/SmplrNodeLayout.svelte
  • ui/src/objects/smplr/descriptors.test.ts
  • ui/src/objects/smplr/gm-settings.ts
  • ui/src/objects/smplr/messages.test.ts
  • ui/src/objects/smplr/messages.ts
📝 Walkthrough

Walkthrough

Adds sampled-instrument support across settings, message/program normalization, descriptors, runtime nodes, GM multi-channel behavior, registry wiring, and object docs.

Changes

Smplr Sampled Instruments

Layer / File(s) Summary
Spec and rollout docs
docs/design-docs/specs/165-smplr-sampled-instruments.md, docs/superpowers/plans/2026-06-27-smplr-sampled-instruments.md, docs/superpowers/plans/2026-06-28-gm-smplr-multichannel.md
Design spec and implementation plans covering the descriptor/runtime split, lazy-loading, message surface, GM multi-channel behavior, and verification steps.
Settings option model and visibility
ui/src/lib/settings/types.ts, ui/src/lib/settings/options.ts, ui/src/lib/settings/options.test.ts, ui/src/lib/settings/visibility.ts, ui/src/lib/settings/visibility.test.ts, ui/src/lib/settings/index.ts, ui/src/lib/components/settings/ObjectSettings.svelte
Adds SettingsOption, combobox support, option normalization/filtering, field visibility helpers, tests, and the updated settings UI rendering path.
Message and program primitives
ui/src/objects/smplr/messages.ts, ui/src/objects/smplr/messages.test.ts, ui/src/objects/smplr/programs.ts, ui/src/objects/smplr/gm-channel-state.ts, ui/src/objects/smplr/gm-channel-state.test.ts, ui/src/objects/smplr/gm-settings.ts, ui/src/objects/midi.file/midi-file-player.ts, ui/src/objects/midi.file/midi-file-player.test.ts, ui/src/objects/midi.file/schema.ts
Defines Smplr command shapes, message normalization, program lookup helpers, GM channel state/settings, and MIDI-file program metadata with tests.
Descriptor catalog and metadata
ui/src/objects/smplr/descriptors.ts, ui/src/objects/smplr/descriptors.test.ts, ui/src/objects/smplr/schema.ts, ui/src/objects/smplr/prompt.ts, ui/package.json, ui/src/lib/data/license-data.ts, ui/src/lib/ai/object-descriptions-types.ts, ui/src/lib/ai/object-prompts/index.ts, ui/src/lib/extensions/object-packs.ts, ui/src/lib/objects/schemas/index.ts, ui/static/content/objects/soundfont~.md, ui/static/content/objects/soundfont2~.md
Defines the sampled-instrument descriptor registry, schemas, prompt text, dependency/license metadata, AI object lists, object-pack entries, schema re-exports, descriptor tests, and base object docs.
Shared audio runtime
ui/src/objects/smplr/SmplrInstrumentAudioNode.ts, ui/src/objects/smplr/SmplrInstrumentAudioNode.test.ts, ui/src/objects/smplr/SmplrNodeLayout.svelte
Implements the shared audio node runtime, status flow, settings persistence, message forwarding, and runtime tests.
GM multi-channel feature
ui/src/objects/smplr/GmAudioNode.ts, ui/src/objects/smplr/GmAudioNode.test.ts, ui/src/objects/smplr/GmNode.svelte, ui/src/lib/migration/migrations/015-gm-to-ui-node.ts, ui/src/lib/migration/migrations/015-gm-to-ui-node.test.ts, ui/src/lib/migration/migrate-patch.ts, ui/src/lib/objects/builtin-shorthands.ts, ui/src/lib/objects/builtin-shorthands.test.ts, ui/src/lib/nodes/defaultNodeData.ts, ui/src/lib/nodes/node-types.ts, ui/src/lib/audio/v2/nodes/index.ts, ui/src/objects/smplr/audio-nodes.ts, ui/src/objects/smplr/*Node.svelte, ui/src/lib/objects/schemas/index.ts, ui/static/content/objects/gm~.md, ui/static/content/objects/midi.file.md
Adds the GM runtime, node UI, migration, shorthand, default data, registry wiring, and GM-specific docs plus MIDI-file preload metadata usage.
Instrument wrappers and docs
ui/src/objects/smplr/ElectricPianoNode.svelte, ui/src/objects/smplr/PianoNode.svelte, ui/src/objects/smplr/DrumMachineNode.svelte, ui/src/objects/smplr/MalletNode.svelte, ui/src/objects/smplr/MellotronNode.svelte, ui/src/objects/smplr/VersilianNode.svelte, ui/src/objects/smplr/SmolkenNode.svelte, ui/static/content/objects/epiano~.md, ui/static/content/objects/piano~.md, ui/static/content/objects/drums~.md, ui/static/content/objects/mallet~.md, ui/static/content/objects/mellotron~.md, ui/static/content/objects/versilian~.md, ui/static/content/objects/smolken~.md
Adds thin Svelte wrappers and per-object documentation pages for the sampled instruments.
Settings metadata for UI/runtime wiring
ui/src/lib/settings/types.ts, ui/src/lib/settings/index.ts, ui/src/lib/components/settings/ObjectSettings.svelte, ui/src/objects/smplr/schema.ts, ui/src/objects/smplr/descriptors.ts, ui/src/objects/smplr/gm-settings.ts
Connects the settings types, schema-driven rendering, and descriptor-backed settings definitions used by the sampled instruments.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • heypoom/patchies#204: Extends ui/src/objects/midi.file/midi-file-player.ts with programs/preloadPrograms, which this PR uses for GM instrument preloading.
  • heypoom/patchies#185: Similar registry and prompt wiring updates for newly added object types.
  • heypoom/patchies#80: Related built-in pack and object catalog updates in the same extension system.

Poem

🐰 I hop through notes, both bright and deep,
With GM drums and pianos that leap.
Lazy loads rustle, soft and low,
While sample gardens bloom and grow.
My whiskers twitch at bang and play
Smplr sings the rabbit way!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding smplr-based sampler instruments and related support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add-smplr-objects

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 27, 2026

Copy link
Copy Markdown

Deploying patchies with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6abed9e
Status: ✅  Deploy successful!
Preview URL: https://92aa8ae8.patchies.pages.dev
Branch Preview URL: https://add-smplr-objects.patchies.pages.dev

View logs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
ui/src/objects/smplr/SmplrInstrumentAudioNode.ts (1)

165-175: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Avoid floating promise in applyProgramChange.

void this.applySettings(...) creates an unawaited promise; if applyLiveSettings or reload throws, it becomes an unhandled rejection. Since applyProgramChange is only called from the synchronous applyCommand, you can safely mark it async and await the call, or catch and route errors to onStatusChange.

-  private applyProgramChange(program: number): void {
+  private async applyProgramChange(program: number): Promise<void> {
     const patch = this.descriptor.handleProgramChange?.(program, {
       ...this.settings,
       instrumentNames: this.instrument?.instrumentNames
     });

     if (!patch) return;

     this.onSettingsPatch?.(patch);
-    void this.applySettings({ ...this.settings, ...patch });
+    await this.applySettings({ ...this.settings, ...patch });
   }

Then update the call site in applyCommand:

       case 'program':
-        this.applyProgramChange(command.program);
+        await this.applyProgramChange(command.program);
         break;

And mark applyCommand as async (or handle the promise in send).

-  private applyCommand(command: ReturnType<typeof normalizeSmplrMessage>): void {
+  private async applyCommand(command: ReturnType<typeof normalizeSmplrMessage>): Promise<void> {

Or, minimally, keep it synchronous but surface the error:

-    void this.applySettings({ ...this.settings, ...patch });
+    this.applySettings({ ...this.settings, ...patch }).catch((err) => {
+      this.onStatusChange?.({ state: 'error', message: String(err) });
+    });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/objects/smplr/SmplrInstrumentAudioNode.ts` around lines 165 - 175, The
`applyProgramChange` flow in `SmplrInstrumentAudioNode` is creating a floating
promise by calling `applySettings` with `void`, which can surface as an
unhandled rejection. Make `applyProgramChange` async and await the
`applySettings` call, then update the synchronous `applyCommand` path (and any
direct caller like `send`) to await or otherwise handle the returned promise; if
you keep it sync, catch errors from `applySettings` and route them through
`onStatusChange` instead of dropping them.
ui/src/objects/smplr/descriptors.test.ts (1)

42-46: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

This test only asserts a declaration shape, not behavior.

Checking typeof descriptor.loadInstrument === 'function' inspects an implementation detail rather than an observable outcome. Either drop it or convert it into a behavioral assertion (e.g., that invoking a descriptor's loader stays lazy / doesn't eagerly import heavy modules). As per coding guidelines: "Do NOT create tests that only inspect source text, declarations, prompts, imports, or implementation details."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/objects/smplr/descriptors.test.ts` around lines 42 - 46, The current
test in smplrDescriptors only checks the declaration shape of loadInstrument
instead of observable behavior. Update the descriptors test to either remove
this assertion or replace it with a behavioral test against smplrDescriptors
that verifies the loader stays lazy (for example, invoking a descriptor’s loader
does not eagerly import heavy modules). Focus the change in the descriptors test
suite and the loadInstrument-related descriptor entries.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/design-docs/specs/165-smplr-sampled-instruments.md`:
- Around line 277-292: The spec for the Soundfont2 parser currently shows a
direct constructor call, but the implementation uses a closure-based adapter via
createSoundfont passed into module.Soundfont2(). Update the spec to describe the
local adapter pattern used by the Soundfont2 integration, making clear that
parser construction is wrapped in an indirection layer. Reference the soundfont2
parser section and the createSoundfont adapter so the documented contract
matches the actual API-evolution-resistant implementation.
- Around line 81-103: The SmplrInstrumentDescriptor spec is out of sync with the
real descriptor contract, so update the interface to match the implementation
used by SmplrInstrumentDescriptor and loadInstrument: include the missing
destination and onLoadProgress parameters, the getDisplayName(settings) shape,
and defaultVelocity, and remove updateLiveSetting if it is not part of the
canonical type. If this doc is meant to stay simplified, add an explicit note
that it is non-canonical and point readers to the shared descriptor definition
in smplr/descriptors for the authoritative interface.

In `@ui/src/lib/components/settings/ObjectSettings.svelte`:
- Around line 405-413: The trigger markup in ObjectSettings.svelte nests a
<button> inside Popover.Trigger, which already renders a button and creates
invalid interactive content. Update the Popover.Trigger usage around
getSelectedOptionLabel(field) and ChevronsUpDown to use the child snippet
pattern or apply the button styling directly to Popover.Trigger so there is only
one interactive element.

In `@ui/src/lib/nodes/defaultNodeData.ts`:
- Around line 395-397: The node defaults mapping in defaultNodeData should not
return the shared descriptor object from smplrDescriptors[type].defaultSettings.
Update the logic around the settings/settingsSchema creation so each node gets a
fresh deep copy of defaultSettings before it is assigned, using the existing
descriptor lookup in the mapping callback. Preserve settingsSchema as-is, but
ensure the returned settings value is cloned per node to avoid shared nested
state like soundfont2~ instrumentNames leaking across instances.

In `@ui/src/objects/smplr/descriptors.ts`:
- Around line 240-256: The SF2 loader in loadInstrument is dropping progress
updates because it omits onLoadProgress and passes a no-op into commonOptions,
so the status UI never advances during SoundFont2 loading. Update the
soundfont2~ descriptor to accept onLoadProgress from the loader args and forward
that real callback through commonOptions (and any Soundfont2 progress hook
exposed by smplr) instead of using an empty function, keeping behavior
consistent with the other descriptor loaders.

---

Nitpick comments:
In `@ui/src/objects/smplr/descriptors.test.ts`:
- Around line 42-46: The current test in smplrDescriptors only checks the
declaration shape of loadInstrument instead of observable behavior. Update the
descriptors test to either remove this assertion or replace it with a behavioral
test against smplrDescriptors that verifies the loader stays lazy (for example,
invoking a descriptor’s loader does not eagerly import heavy modules). Focus the
change in the descriptors test suite and the loadInstrument-related descriptor
entries.

In `@ui/src/objects/smplr/SmplrInstrumentAudioNode.ts`:
- Around line 165-175: The `applyProgramChange` flow in
`SmplrInstrumentAudioNode` is creating a floating promise by calling
`applySettings` with `void`, which can surface as an unhandled rejection. Make
`applyProgramChange` async and await the `applySettings` call, then update the
synchronous `applyCommand` path (and any direct caller like `send`) to await or
otherwise handle the returned promise; if you keep it sync, catch errors from
`applySettings` and route them through `onStatusChange` instead of dropping
them.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 64c51042-ec03-4000-bc2c-ba9d139fbe3c

📥 Commits

Reviewing files that changed from the base of the PR and between 09f6ae8 and 22e8555.

⛔ Files ignored due to path filters (2)
  • ui/bun.lock is excluded by !**/*.lock
  • ui/src/lib/generated/object-schemas.generated.ts is excluded by !**/generated/**
📒 Files selected for processing (45)
  • docs/design-docs/specs/165-smplr-sampled-instruments.md
  • docs/superpowers/plans/2026-06-27-smplr-sampled-instruments.md
  • ui/package.json
  • ui/src/lib/ai/object-descriptions-types.ts
  • ui/src/lib/ai/object-prompts/index.ts
  • ui/src/lib/audio/v2/nodes/index.ts
  • ui/src/lib/components/settings/ObjectSettings.svelte
  • ui/src/lib/data/license-data.ts
  • ui/src/lib/extensions/object-packs.ts
  • ui/src/lib/nodes/defaultNodeData.ts
  • ui/src/lib/nodes/node-types.ts
  • ui/src/lib/objects/schemas/index.ts
  • ui/src/lib/settings/index.ts
  • ui/src/lib/settings/options.test.ts
  • ui/src/lib/settings/options.ts
  • ui/src/lib/settings/types.ts
  • ui/src/objects/smplr/DrumMachineNode.svelte
  • ui/src/objects/smplr/ElectricPianoNode.svelte
  • ui/src/objects/smplr/MalletNode.svelte
  • ui/src/objects/smplr/MellotronNode.svelte
  • ui/src/objects/smplr/PianoNode.svelte
  • ui/src/objects/smplr/SmolkenNode.svelte
  • ui/src/objects/smplr/SmplrInstrumentAudioNode.test.ts
  • ui/src/objects/smplr/SmplrInstrumentAudioNode.ts
  • ui/src/objects/smplr/SmplrNodeLayout.svelte
  • ui/src/objects/smplr/Soundfont2Node.svelte
  • ui/src/objects/smplr/SoundfontNode.svelte
  • ui/src/objects/smplr/VersilianNode.svelte
  • ui/src/objects/smplr/audio-nodes.ts
  • ui/src/objects/smplr/descriptors.test.ts
  • ui/src/objects/smplr/descriptors.ts
  • ui/src/objects/smplr/messages.test.ts
  • ui/src/objects/smplr/messages.ts
  • ui/src/objects/smplr/programs.ts
  • ui/src/objects/smplr/prompt.ts
  • ui/src/objects/smplr/schema.ts
  • ui/static/content/objects/drum-machine~.md
  • ui/static/content/objects/epiano~.md
  • ui/static/content/objects/mallet~.md
  • ui/static/content/objects/mellotron~.md
  • ui/static/content/objects/piano~.md
  • ui/static/content/objects/smolken~.md
  • ui/static/content/objects/soundfont2~.md
  • ui/static/content/objects/soundfont~.md
  • ui/static/content/objects/versilian~.md

Comment thread docs/design-docs/specs/165-smplr-sampled-instruments.md
Comment thread docs/design-docs/specs/165-smplr-sampled-instruments.md
Comment thread ui/src/lib/components/settings/ObjectSettings.svelte Outdated
Comment thread ui/src/lib/nodes/defaultNodeData.ts
Comment thread ui/src/objects/smplr/descriptors.ts Outdated
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 4 file(s) based on 5 unresolved review comments.

Files modified:

  • docs/design-docs/specs/165-smplr-sampled-instruments.md
  • ui/src/lib/components/settings/ObjectSettings.svelte
  • ui/src/lib/nodes/defaultNodeData.ts
  • ui/src/objects/smplr/descriptors.ts

Commit: 0b20154cc7434129c24627ca55d39f1d260cddcc

The changes have been pushed to the add-smplr-objects branch.

Time taken: 3m 45s

heypoom and others added 2 commits June 27, 2026 23:16
Fixed 4 file(s) based on 5 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
@heypoom heypoom force-pushed the add-smplr-objects branch from 0b20154 to e22da58 Compare June 27, 2026 16:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/superpowers/plans/2026-06-27-smplr-sampled-instruments.md (1)

13-13: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix heading level for Task 1.

### Task 1 should be ## Task 1 (or add a ## Tasks h2 before it) to comply with standard Markdown heading increment rules. This keeps the document structure consistent with markdownlint expectations.

-### Task 1: Dependencies And Spec Baseline
+## Task 1: Dependencies And Spec Baseline

(Apply the same change to all Task headings if they remain h3.)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/superpowers/plans/2026-06-27-smplr-sampled-instruments.md` at line 13,
The Task headings in this plan are using an h3 level where the document
structure expects an h2-level section or a preceding Tasks section. Update the
heading for Task 1, and any other Task headings in this document, to use
consistent Markdown hierarchy by either promoting them to ## or inserting a ##
Tasks parent heading before the task list.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ui/src/objects/smplr/messages.ts`:
- Around line 139-140: The controlChange mapping in messages.ts only clamps
msg.value, so invalid CC numbers can still pass through unchanged. Update the
controlChange branch to normalize msg.control to a valid MIDI byte as well,
alongside msg.value, before returning the cc object. Use the existing
isFiniteNumber, clampMidi, and the controlChange handling logic in this module
to keep the fix localized and consistent.

---

Nitpick comments:
In `@docs/superpowers/plans/2026-06-27-smplr-sampled-instruments.md`:
- Line 13: The Task headings in this plan are using an h3 level where the
document structure expects an h2-level section or a preceding Tasks section.
Update the heading for Task 1, and any other Task headings in this document, to
use consistent Markdown hierarchy by either promoting them to ## or inserting a
## Tasks parent heading before the task list.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 65d80ab4-ac24-48b9-b3de-6d2902d9c734

📥 Commits

Reviewing files that changed from the base of the PR and between 0b20154 and e22da58.

⛔ Files ignored due to path filters (2)
  • ui/bun.lock is excluded by !**/*.lock
  • ui/src/lib/generated/object-schemas.generated.ts is excluded by !**/generated/**
📒 Files selected for processing (45)
  • docs/design-docs/specs/165-smplr-sampled-instruments.md
  • docs/superpowers/plans/2026-06-27-smplr-sampled-instruments.md
  • ui/package.json
  • ui/src/lib/ai/object-descriptions-types.ts
  • ui/src/lib/ai/object-prompts/index.ts
  • ui/src/lib/audio/v2/nodes/index.ts
  • ui/src/lib/components/settings/ObjectSettings.svelte
  • ui/src/lib/data/license-data.ts
  • ui/src/lib/extensions/object-packs.ts
  • ui/src/lib/nodes/defaultNodeData.ts
  • ui/src/lib/nodes/node-types.ts
  • ui/src/lib/objects/schemas/index.ts
  • ui/src/lib/settings/index.ts
  • ui/src/lib/settings/options.test.ts
  • ui/src/lib/settings/options.ts
  • ui/src/lib/settings/types.ts
  • ui/src/objects/smplr/DrumMachineNode.svelte
  • ui/src/objects/smplr/ElectricPianoNode.svelte
  • ui/src/objects/smplr/MalletNode.svelte
  • ui/src/objects/smplr/MellotronNode.svelte
  • ui/src/objects/smplr/PianoNode.svelte
  • ui/src/objects/smplr/SmolkenNode.svelte
  • ui/src/objects/smplr/SmplrInstrumentAudioNode.test.ts
  • ui/src/objects/smplr/SmplrInstrumentAudioNode.ts
  • ui/src/objects/smplr/SmplrNodeLayout.svelte
  • ui/src/objects/smplr/Soundfont2Node.svelte
  • ui/src/objects/smplr/SoundfontNode.svelte
  • ui/src/objects/smplr/VersilianNode.svelte
  • ui/src/objects/smplr/audio-nodes.ts
  • ui/src/objects/smplr/descriptors.test.ts
  • ui/src/objects/smplr/descriptors.ts
  • ui/src/objects/smplr/messages.test.ts
  • ui/src/objects/smplr/messages.ts
  • ui/src/objects/smplr/programs.ts
  • ui/src/objects/smplr/prompt.ts
  • ui/src/objects/smplr/schema.ts
  • ui/static/content/objects/drum-machine~.md
  • ui/static/content/objects/epiano~.md
  • ui/static/content/objects/mallet~.md
  • ui/static/content/objects/mellotron~.md
  • ui/static/content/objects/piano~.md
  • ui/static/content/objects/smolken~.md
  • ui/static/content/objects/soundfont2~.md
  • ui/static/content/objects/soundfont~.md
  • ui/static/content/objects/versilian~.md
✅ Files skipped from review due to trivial changes (14)
  • ui/src/objects/smplr/VersilianNode.svelte
  • ui/src/objects/smplr/Soundfont2Node.svelte
  • ui/static/content/objects/mellotron~.md
  • ui/src/objects/smplr/SmolkenNode.svelte
  • ui/static/content/objects/epiano~.md
  • ui/static/content/objects/drum-machine~.md
  • ui/static/content/objects/versilian~.md
  • ui/src/objects/smplr/ElectricPianoNode.svelte
  • ui/static/content/objects/mallet~.md
  • ui/static/content/objects/piano~.md
  • ui/static/content/objects/soundfont2~.md
  • ui/static/content/objects/smolken~.md
  • ui/package.json
  • ui/static/content/objects/soundfont~.md
🚧 Files skipped from review as they are similar to previous changes (28)
  • ui/src/lib/settings/options.test.ts
  • ui/src/objects/smplr/prompt.ts
  • ui/src/objects/smplr/messages.test.ts
  • ui/src/lib/ai/object-prompts/index.ts
  • ui/src/objects/smplr/PianoNode.svelte
  • ui/src/lib/nodes/defaultNodeData.ts
  • ui/src/objects/smplr/programs.ts
  • ui/src/objects/smplr/descriptors.test.ts
  • ui/src/objects/smplr/audio-nodes.ts
  • ui/src/objects/smplr/SoundfontNode.svelte
  • ui/src/objects/smplr/DrumMachineNode.svelte
  • ui/src/objects/smplr/MalletNode.svelte
  • ui/src/lib/extensions/object-packs.ts
  • ui/src/lib/settings/index.ts
  • ui/src/objects/smplr/MellotronNode.svelte
  • ui/src/lib/audio/v2/nodes/index.ts
  • ui/src/lib/ai/object-descriptions-types.ts
  • ui/src/lib/data/license-data.ts
  • ui/src/lib/nodes/node-types.ts
  • ui/src/lib/objects/schemas/index.ts
  • ui/src/objects/smplr/SmplrInstrumentAudioNode.test.ts
  • ui/src/lib/settings/options.ts
  • ui/src/objects/smplr/descriptors.ts
  • ui/src/lib/settings/types.ts
  • ui/src/objects/smplr/schema.ts
  • ui/src/objects/smplr/SmplrNodeLayout.svelte
  • ui/src/lib/components/settings/ObjectSettings.svelte
  • ui/src/objects/smplr/SmplrInstrumentAudioNode.ts

Comment thread ui/src/objects/smplr/messages.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ui/src/lib/components/settings/ObjectSettings.svelte (1)

163-170: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear the combobox filter on every close path.

comboboxQuery[field.key] is only reset after selectComboboxOption(). If the popover closes via outside click, Escape, or blur, reopening it keeps the stale filter and can hide most options immediately.

Also applies to: 414-454

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/lib/components/settings/ObjectSettings.svelte` around lines 163 - 170,
The combobox filter state in ObjectSettings.svelte is only cleared in
selectComboboxOption(), so closing the popover through other paths leaves
comboboxQuery[field.key] stale. Update the combobox close handling in
ObjectSettings.svelte so every close path (outside click, Escape, blur, and
option selection) also resets comboboxQuery for the affected field, using the
existing comboboxOpen/comboboxQuery state and the combobox-related handlers in
the same component.
🧹 Nitpick comments (1)
ui/src/objects/smplr/descriptors.test.ts (1)

1-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid locking descriptor order in this test.

These assertions are order-sensitive and mostly pin declaration shape, so a harmless reorder of SMPLR_OBJECT_TYPES or smplrDescriptors will fail the suite without changing behavior. Prefer asserting membership/coverage and resolving each supported type through getSmplrDescriptor(...) instead of checking exact key order.

As per coding guidelines, **/*.test.{ts,tsx}: "Do NOT add 'guardrail' tests that lock wording or code shape unless that wording is itself a user-visible product contract."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/objects/smplr/descriptors.test.ts` around lines 1 - 22, The smplr
descriptors test is over-constraining declaration order by asserting exact array
and object key ordering in the smplrDescriptors/SMPLR_OBJECT_TYPES checks.
Update the test to verify the supported descriptor set by membership/coverage
instead of exact order, and use getSmplrDescriptor(...) to confirm each object
type resolves correctly rather than comparing Object.keys(...) to
SMPLR_OBJECT_TYPES.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@ui/src/lib/components/settings/ObjectSettings.svelte`:
- Around line 163-170: The combobox filter state in ObjectSettings.svelte is
only cleared in selectComboboxOption(), so closing the popover through other
paths leaves comboboxQuery[field.key] stale. Update the combobox close handling
in ObjectSettings.svelte so every close path (outside click, Escape, blur, and
option selection) also resets comboboxQuery for the affected field, using the
existing comboboxOpen/comboboxQuery state and the combobox-related handlers in
the same component.

---

Nitpick comments:
In `@ui/src/objects/smplr/descriptors.test.ts`:
- Around line 1-22: The smplr descriptors test is over-constraining declaration
order by asserting exact array and object key ordering in the
smplrDescriptors/SMPLR_OBJECT_TYPES checks. Update the test to verify the
supported descriptor set by membership/coverage instead of exact order, and use
getSmplrDescriptor(...) to confirm each object type resolves correctly rather
than comparing Object.keys(...) to SMPLR_OBJECT_TYPES.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9b8b0175-7de3-43bf-a05c-61b59dc33879

📥 Commits

Reviewing files that changed from the base of the PR and between 2f0b325 and 6bec09f.

📒 Files selected for processing (10)
  • docs/design-docs/specs/165-smplr-sampled-instruments.md
  • ui/src/lib/components/settings/ObjectSettings.svelte
  • ui/src/lib/extensions/object-packs.ts
  • ui/src/lib/settings/types.ts
  • ui/src/lib/settings/visibility.test.ts
  • ui/src/lib/settings/visibility.ts
  • ui/src/objects/smplr/descriptors.test.ts
  • ui/src/objects/smplr/descriptors.ts
  • ui/src/objects/smplr/prompt.ts
  • ui/static/content/objects/soundfont~.md
✅ Files skipped from review due to trivial changes (4)
  • ui/src/lib/settings/visibility.test.ts
  • ui/src/objects/smplr/prompt.ts
  • ui/static/content/objects/soundfont~.md
  • docs/design-docs/specs/165-smplr-sampled-instruments.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • ui/src/objects/smplr/descriptors.ts

@heypoom heypoom force-pushed the add-smplr-objects branch from 9021dcb to 644dc0b Compare June 28, 2026 05:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (3)
docs/superpowers/plans/2026-06-28-gm-smplr-multichannel.md (1)

9-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix tech stack reference: "SvelteKit 5" → "Svelte 5".

SvelteKit versioning is independent of Svelte. The current major Svelte version is 5, but SvelteKit is at v2. This should read "Svelte 5" or "SvelteKit + Svelte 5".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/superpowers/plans/2026-06-28-gm-smplr-multichannel.md` at line 9, Update
the tech stack line to use the correct framework version reference: replace
“SvelteKit 5” with “Svelte 5” or “SvelteKit + Svelte 5”. Adjust the “Tech Stack”
entry in the markdown so it reflects that SvelteKit and Svelte versioning are
separate, and keep the rest of the stack list unchanged.
ui/src/objects/smplr/GmAudioNode.ts (1)

180-241: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prefer ts-pattern for SmplrCommand dispatch.

This is discriminated-union branching on command.type, so the current switch loses the exhaustiveness guarantee the repo standard expects here. As per coding guidelines, **/*.{ts,tsx}: "Use ts-pattern for exhaustive branching on discriminated unions, enums, or mode/state values..."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/objects/smplr/GmAudioNode.ts` around lines 180 - 241, The SmplrCommand
dispatch in applyCommand is using a switch on command.type, which should be
rewritten to the repo’s ts-pattern style for exhaustive discriminated-union
handling. Update GmAudioNode.applyCommand to use ts-pattern matching over
SmplrCommand so every command variant is covered explicitly and future variants
are checked exhaustively, while preserving the current start, stop, stopAll, cc,
program, volume, ignored, detune, and reverse behaviors.

Source: Coding guidelines

ui/src/lib/objects/builtin-shorthands.test.ts (1)

47-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise the registry path instead of the backing array.

This only proves the array entry exists and that its inline transform() returns the expected literal. Please assert ObjectShorthandRegistry.getInstance().tryTransform('gm~') instead. As per coding guidelines, **/*.test.{ts,tsx}: Test observable behavior through public APIs, rendered UI, store state, emitted events, tool results, or user-visible outcomes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ui/src/lib/objects/builtin-shorthands.test.ts` around lines 47 - 58, The test
is asserting the shorthand entry directly from the backing array instead of
exercising the public registry API. Update the gm~ test in
builtin-shorthands.test.ts to use
ObjectShorthandRegistry.getInstance().tryTransform('gm~') and assert on that
returned result, so the test covers observable behavior through the registry
path rather than the inline transform function.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/superpowers/plans/2026-06-28-gm-smplr-multichannel.md`:
- Around line 107-111: The focused test command for Task 5 Step 1 includes
unrelated settings tests, which should be removed from this verification step.
Update the test command in the plan so it only runs the SMPLR-focused paths
under src/objects/smplr, and leave out src/lib/settings/options.test.ts and
src/lib/settings/visibility.test.ts.
- Line 13: The task headings are using too deep a level after the top-level
heading, so update `Task 1: Channel Routing Helpers` and the other similar task
headings to the next appropriate markdown level. Adjust the heading markup in
the plan document so the section titles follow the document hierarchy correctly
and satisfy the markdown lint rule.

In `@ui/src/objects/midi.file/midi-file-player.ts`:
- Around line 312-340: The preload metadata helpers are skipping channels that
never emit a programChange, so channels using the GM default program 0 are not
warmed ahead of playback. Update getProgramStateAt and getUniqueProgramStates in
midi-file-player.ts to seed each used channel with program 0 when no prior
programChange exists, so the arrays consumed by
GmAudioNode.applyLoadedProgramMetadata() still include those channels. Keep the
existing sorting/shape of MidiFileProgramState output unchanged.

In `@ui/src/objects/smplr/gm-settings.ts`:
- Around line 48-56: The `drumInstrument` setting in `GM_SETTINGS` is shown too
broadly because `visibleWhen` only checks `source === 'soundfont'`, while
`createSoundfontInstrument()` only uses it when the kit is not `Custom`. Update
the visibility condition for the `drumInstrument` field to also exclude custom
kits so the UI matches the runtime behavior and only shows it when it can affect
Soundfont playback.

In `@ui/src/objects/smplr/GmAudioNode.ts`:
- Around line 373-381: `loadProgramInstrument()` is emitting the `ready` status
before the new channel has been added to `this.channels`, so `activeChannels` is
one behind. Update the status emission in `GmAudioNode.loadProgramInstrument()`
/ `ensureChannelInstrument()` flow so the channel is registered before calling
`onStatusChange`, or compute `activeChannels` from the pending channel count,
and keep the `updateMonitorChannel`/`onStatusChange` state in sync.
- Around line 676-678: Clamp loaded program values to the MIDI range 0..127 in
normalizeProgram so state stays aligned with program lookup behavior. Update the
GmAudioNode helper normalizeProgram to bound values above 127 as well as
negatives before writing into preloadRequests and channelState, matching the
normalization used by the program resolution helpers in programs.ts.

In `@ui/src/objects/smplr/GmNode.svelte`:
- Around line 68-71: The revert flow in revertSettings() is not handling the
audioService.send() result the same way as the normal settings write, so a
failed revert can leave persisted defaults out of sync with the runtime. Update
revertSettings() to await or otherwise handle the audioService.send(node.id,
'settings', GM_DEFAULT_SETTINGS) promise with the same success/error path used
for the regular settings save, and only commit the reverted state when the
runtime update succeeds.
- Around line 84-112: The async mount flow in onMount is not guarded against
teardown, so if the component unmounts while audioService.createNode() or the
initial audioService.send() is still pending, the continuation can still attach
runtimeNode callbacks and persist settings after onDestroy() has already cleaned
up. Add a mounted/aborted guard around the GmNode.svelte onMount sequence using
the existing node/messageContext/runtimeNode flow, and bail out before
installing onStatusChange/onMonitorChange or calling send() if onDestroy() has
run. Ensure onDestroy() marks the instance as disposed and that any
late-resolving createNode() path removes or ignores the orphaned node.

---

Nitpick comments:
In `@docs/superpowers/plans/2026-06-28-gm-smplr-multichannel.md`:
- Line 9: Update the tech stack line to use the correct framework version
reference: replace “SvelteKit 5” with “Svelte 5” or “SvelteKit + Svelte 5”.
Adjust the “Tech Stack” entry in the markdown so it reflects that SvelteKit and
Svelte versioning are separate, and keep the rest of the stack list unchanged.

In `@ui/src/lib/objects/builtin-shorthands.test.ts`:
- Around line 47-58: The test is asserting the shorthand entry directly from the
backing array instead of exercising the public registry API. Update the gm~ test
in builtin-shorthands.test.ts to use
ObjectShorthandRegistry.getInstance().tryTransform('gm~') and assert on that
returned result, so the test covers observable behavior through the registry
path rather than the inline transform function.

In `@ui/src/objects/smplr/GmAudioNode.ts`:
- Around line 180-241: The SmplrCommand dispatch in applyCommand is using a
switch on command.type, which should be rewritten to the repo’s ts-pattern style
for exhaustive discriminated-union handling. Update GmAudioNode.applyCommand to
use ts-pattern matching over SmplrCommand so every command variant is covered
explicitly and future variants are checked exhaustively, while preserving the
current start, stop, stopAll, cc, program, volume, ignored, detune, and reverse
behaviors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8f8ea5fe-7a67-4eef-9466-9432f80f340a

📥 Commits

Reviewing files that changed from the base of the PR and between 2f0b325 and 644dc0b.

⛔ Files ignored due to path filters (1)
  • ui/src/lib/generated/object-schemas.generated.ts is excluded by !**/generated/**
📒 Files selected for processing (38)
  • docs/design-docs/specs/165-smplr-sampled-instruments.md
  • docs/superpowers/plans/2026-06-28-gm-smplr-multichannel.md
  • ui/src/lib/ai/object-descriptions-types.ts
  • ui/src/lib/ai/object-prompts/index.ts
  • ui/src/lib/components/settings/ObjectSettings.svelte
  • ui/src/lib/extensions/object-packs.ts
  • ui/src/lib/migration/migrate-patch.ts
  • ui/src/lib/migration/migrations/015-gm-to-ui-node.test.ts
  • ui/src/lib/migration/migrations/015-gm-to-ui-node.ts
  • ui/src/lib/nodes/defaultNodeData.ts
  • ui/src/lib/nodes/node-types.ts
  • ui/src/lib/objects/builtin-shorthands.test.ts
  • ui/src/lib/objects/builtin-shorthands.ts
  • ui/src/lib/objects/schemas/index.ts
  • ui/src/lib/services/NodeOperationsService.test.ts
  • ui/src/lib/settings/types.ts
  • ui/src/lib/settings/visibility.test.ts
  • ui/src/lib/settings/visibility.ts
  • ui/src/objects/midi.file/midi-file-player.test.ts
  • ui/src/objects/midi.file/midi-file-player.ts
  • ui/src/objects/midi.file/schema.ts
  • ui/src/objects/smplr/GmAudioNode.test.ts
  • ui/src/objects/smplr/GmAudioNode.ts
  • ui/src/objects/smplr/GmNode.svelte
  • ui/src/objects/smplr/SmplrNodeLayout.svelte
  • ui/src/objects/smplr/audio-nodes.ts
  • ui/src/objects/smplr/descriptors.test.ts
  • ui/src/objects/smplr/descriptors.ts
  • ui/src/objects/smplr/gm-channel-state.test.ts
  • ui/src/objects/smplr/gm-channel-state.ts
  • ui/src/objects/smplr/gm-settings.ts
  • ui/src/objects/smplr/programs.ts
  • ui/src/objects/smplr/prompt.ts
  • ui/src/objects/smplr/schema.ts
  • ui/static/content/objects/gm~.md
  • ui/static/content/objects/midi.file.md
  • ui/static/content/objects/soundfont2~.md
  • ui/static/content/objects/soundfont~.md
✅ Files skipped from review due to trivial changes (5)
  • ui/src/objects/smplr/gm-channel-state.test.ts
  • ui/src/lib/migration/migrations/015-gm-to-ui-node.test.ts
  • ui/static/content/objects/soundfont2~.md
  • ui/static/content/objects/midi.file.md
  • ui/src/lib/ai/object-descriptions-types.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • ui/src/lib/extensions/object-packs.ts
  • ui/src/objects/smplr/audio-nodes.ts
  • ui/src/lib/settings/visibility.test.ts
  • ui/src/lib/nodes/defaultNodeData.ts
  • ui/src/lib/ai/object-prompts/index.ts
  • ui/src/lib/objects/schemas/index.ts
  • ui/src/objects/smplr/prompt.ts
  • ui/src/objects/smplr/schema.ts
  • ui/src/lib/nodes/node-types.ts
  • ui/src/objects/smplr/descriptors.test.ts
  • ui/src/lib/components/settings/ObjectSettings.svelte
  • docs/design-docs/specs/165-smplr-sampled-instruments.md
  • ui/src/objects/smplr/descriptors.ts
  • ui/src/objects/smplr/SmplrNodeLayout.svelte

Comment thread docs/superpowers/plans/2026-06-28-gm-smplr-multichannel.md Outdated
Comment thread docs/superpowers/plans/2026-06-28-gm-smplr-multichannel.md
Comment thread ui/src/objects/midi.file/midi-file-player.ts
Comment thread ui/src/objects/smplr/gm-settings.ts
Comment thread ui/src/objects/smplr/GmAudioNode.ts
Comment thread ui/src/objects/smplr/GmAudioNode.ts
Comment thread ui/src/objects/smplr/GmNode.svelte Outdated
Comment thread ui/src/objects/smplr/GmNode.svelte
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant