Step-by-step guide for building a JUCE audio plugin from scratch. Use when the user asks "how do I create a JUCE plugin", "set up a JUCE project", "add parameters to my JUCE plugin", "package my VST3", or "how do I wire up APVTS". Trigger on phrases like "create a JUCE plugin", "JUCE CMake setup", "AudioProcessor skeleton", "add APVTS parameters", or "codesign my plugin on macOS".
Scanned 5/27/2026
Install via CLI
openskills install kunitoki/sonic-skills---
name: juce-guide
description: >
Step-by-step guide for building a JUCE audio plugin from scratch. Use when the user
asks "how do I create a JUCE plugin", "set up a JUCE project", "add parameters to my
JUCE plugin", "package my VST3", or "how do I wire up APVTS". Trigger on phrases like
"create a JUCE plugin", "JUCE CMake setup", "AudioProcessor skeleton", "add APVTS
parameters", or "codesign my plugin on macOS".
---
# JUCE Audio Plugin — Build Guide
Five steps from empty folder to distributable plugin. Do each step in order; skip none.
## Step 1 — Project setup (CMake + JUCE)
- Add JUCE as a git submodule or FetchContent target; call `add_subdirectory(JUCE)`.
- Use `juce_add_plugin(MyPlugin FORMATS VST3 AU Standalone ...)` to declare the plugin target.
- Set `PLUGIN_MANUFACTURER_CODE`, `PLUGIN_CODE`, `IS_SYNTH`, `NEEDS_MIDI_INPUT` in the same call.
- Link `juce::juce_audio_processors juce::juce_audio_utils juce::juce_dsp` to the target.
## Step 2 — AudioProcessor skeleton
- Subclass `juce::AudioProcessor`; override `prepareToPlay`, `releaseResources`, `processBlock`.
- In `prepareToPlay`: store `sampleRate` and `maximumBlockSize`, allocate internal buffers, reset all state (filters, envelopes, delay lines — unconditionally).
- In `processBlock`: read only pre-cached raw parameter pointers; never allocate, never call JUCE String ops or DBG().
- Implement `getStateInformation` / `setStateInformation` using `apvts.copyState()` and `apvts.replaceState()` with a `MemoryOutputStream` / `MemoryBlock`.
## Step 3 — Parameters via APVTS
- Declare a static `createParameterLayout()` method that returns `AudioProcessorValueTreeState::ParameterLayout`.
- Construct `apvts(*this, nullptr, "Parameters", createParameterLayout())` as a member.
- After constructing APVTS, cache raw pointers once: `gainParam = apvts.getRawParameterValue("Gain")`.
- In `processBlock`, dereference with `gainParam->load()` — no APVTS calls on the audio thread.
- Use `AudioProcessorValueTreeState::ParameterAttachment` (or `SliderAttachment`) in the editor, never in the processor.
## Step 4 — Editor and UI
- Subclass `juce::AudioProcessorEditor`; call `setSize(w, h)` in the constructor.
- Override `paint` for background / labels; override `resized` to lay out components with `setBounds`.
- Declare `juce::Slider` members; attach each via `juce::AudioProcessorValueTreeState::SliderAttachment`.
- Keep all UI state in the editor — the processor must function correctly with no editor open.
- The editor holds a reference to the processor (passed in constructor); never store a raw editor pointer in the processor.
## Step 5 — Build, test, package
- Configure: `cmake -B build -DCMAKE_BUILD_TYPE=Release`
- Build: `cmake --build build --config Release`
- Locate artefacts under `build/MyPlugin_artefacts/Release/`.
- macOS codesign: `codesign --deep --force --sign "Developer ID Application: ..." MyPlugin.vst3` then `spctl --assess --verbose MyPlugin.vst3`.
- Notarize for distribution: `xcrun notarytool submit MyPlugin.pkg --apple-id ... --wait`.
- Validate in a DAW host or use the JUCE `AudioPluginHost` utility (`extras/AudioPluginHost`).
## Common pitfalls
| Pitfall | Correct approach |
|---------|-----------------|
| Calling `apvts.getParameter()` in `processBlock` | Cache `getRawParameterValue()` once after APVTS construction |
| Allocating in `processBlock` | Allocate in `prepareToPlay` only |
| Not resetting state on `prepareToPlay` re-entry | Always reset unconditionally |
| Storing editor pointer in processor | Use `createEditor()` factory; processor owns no editor reference |
| Missing `JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR` | Add to every `AudioProcessor` and `AudioProcessorEditor` subclass |
Use the `juce-review` skill to audit finished processor code for thread-safety violations.
No comments yet. Be the first to comment!