aax
無料Optional AAX support for Pulp, including developer-supplied Avid SDK setup, CMake enablement, DigiShell/AAX Validator workflows, and local AAX builds on macOS or Windows.
日本語の概要は準備中です。原文の説明を表示しています。
Generate and maintain browser demos of Pulp audio plugins (both web ABIs — WAM and WCLAP) from one declarative config, so every demo mounts the SAME shared player and the two ABIs stay in lockstep. Invoke it whenever you publish/update a browser demo of a Pulp plugin, add a plugin to a demo gallery, stand up a new gallery, or touch demo pages/hosting. It runs a deterministic generator (config → stamped WAM+WCLAP site + owned-files manifest) and a blocking validator (config schema, cross-origin-isolation coverage, OG metadata, regeneration ownership). Customization is declarative config in <repo>/.pulp-web-demo/config.json (schema bundled) plus at most two typed module seams; the shared player (pinned @danielraffel/web-player) holds all UX behavior and is never vendored. Works in Claude and Codex.
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
The way Pulp plugin web demos are built so the two web ABIs behave identically: WAM (Emscripten → AudioWorklet, single-thread, plain static hosting) and WCLAP (threaded CLAP-compiled-to-wasm hosted by a worklet-resident CLAP host, needs cross-origin isolation). Apply by default when creating/updating a demo, adding a plugin to a gallery, or touching hosting.
Both ABIs mount the SAME shared player. Every UX behavior — no-autoplay overlay,
iOS/mobile touch hygiene, keyboard/polyphony, scope/meter/safety-limiter, PLST state
round-trip, token theming — lives in @danielraffel/web-player (npm, pinned). The
generated pages import that pinned player; they never vendor a copy (vendoring is the
historical drift hazard). Fix any UX behavior once, in the player; both ABIs inherit it.
Customization is declarative data + at most two executable seams. The smarts are in the player; this skill is only the wiring + publish pipeline. Everything runs from the skill dir:
<repo-root>/.pulp-web-demo/config.json, validated against the bundled
config.schema.json (schemaVersion: 1, unknown keys rejected). Declares: the pinned
player, theme token/font hrefs, per-ABI deploy profiles, the plugin catalog, gallery
nav/cross-links, and OG/metadata policy. See examples/example.config.json and README.md.node generate.mjs --config <cfg> --out <siteDir>. Deterministic (no
network, no clock/random): identical config ⇒ byte-identical output. Stamps versioned
templates into a WAM+WCLAP site and writes a .pulp-web-demo.manifest.json of owned files
(with hashes) for upgrade safety. Use --check for a dry run.node validate.mjs --config <cfg> --site <siteDir> --check-isolation --check-metadata --check-ownership. Fails CI on: schema/invariant
violations, cross-origin-isolation not covering the deployed base path, missing OG
tags, or locally-modified owned files.Selected independently for WAM and WCLAP under deploy.wam / deploy.wclap:
github-pages — plain static. Correct for WAM (no isolation needed).cloudflare — server COOP/COEP/CORP via a generated _headers. Default for WCLAP.github-pages+coi — a coi-serviceworker isolation mirror. A labeled fallback
only — it enlarges the failure surface around isolation; prefer a header-capable host.Each profile carries a basePath (server path — isolation headers/scope MUST cover it)
and a publicUrl (the ABI's own absolute origin+base for canonical/OG urls). WAM and
WCLAP commonly live on different origins — keep both accurate.
.pulp-web-demo/hooks.mjs)Everything else is data. Reach for these only when a value can't express it:
artifactResolver — (plugin, abi) => { dspUrl, processorUrl, extraAssets[] }. Maps a
nonstandard build's outputs into the canonical site manifest. This is THE seam that stops
people forking when their build emits dist/web/<target>/… instead of the default layout.adapterModule — a non-default createAdapter (e.g. a custom WCLAP host). Omit to use
the player's bundled WAM/WCLAP adapters.Do not add general behavioral hooks or an "escape hatch" — they become places to recreate player behavior outside the package, which is the whole thing this skill prevents.
?v=<hash>),
never the worklet/dsp URLs (both sides must resolve one processor name)./my-plugins/), and
every worklet/wasm dependency must be isolation-compatible — validated, not assumed.continue-on-error). The generator emits the
og:image tag but does not render the image (rendering needs a browser; the generator
is offline + deterministic). So with ogImageStrategy: "screenshot" your pipeline MUST render
the images before validate.mjs --check-metadata runs — the validator fails if the tag points
at a file that isn't there, or isn't really a PNG. Do not settle for an HTTP 200: a static
host (Cloudflare Pages) will serve a missing asset as 200 and cheerfully confirm an image that
does not exist. Check the bytes. Use ogImageStrategy: "text" if you don't render images.If a plugin takes a user-supplied file (a convolver's impulse response, a sample, a preset),
declare it with the per-plugin fileUpload config (accept, label, hint). The demo must
then offer both a file-dialog button and a drop zone — people drag files onto anything
that looks like a target.
This is a PLAYER behavior, not a per-demo one. Like every other UX invariant, the drop-zone mechanics belong in the shared player so both ABIs inherit them. Re-implementing a drop zone in one demo page is exactly the drift this skill exists to prevent — its WCLAP twin would then need its own copy, and the two would diverge.
Put it INSIDE the plugin, directly under the controls. Placement is not cosmetics here. A loader parked below the plugin panel — in the page chrome, past the scope and the meter — reads as page furniture rather than part of the instrument, and people simply do not find it: it is the one control the demo is asking them to use, and it is the one sitting outside the box everything else lives in. It belongs in the panel, immediately under the last row of controls, with the gap between them tight enough that they read as one unit. The player exposes a slot for exactly this (chrome the plugin owns, rendered inside the panel); use it rather than appending to the page.
Any implementation MUST satisfy all six rules. Each one, skipped, makes the zone feel broken:
document. The browser's default action for a file dropped
anywhere on the page is to navigate to it, destroying the running demo — audio context,
loaded state, knob positions. Add document listeners for dragover and drop that call
preventDefault() and nothing else, so a ten-pixel miss is inert rather than session-ending.
That is a brutal punishment for a gesture you invited. Unbind them in destroy().dragenter/dragleave depth — do not toggle. dragleave bubbles from the zone's
own children, so dragging across a button inside the zone fires it and the highlight
strobes. Keep a depth counter; clear the highlight only at zero.dataTransfer.dropEffect = "copy" on dragover, so the cursor shows a copy badge
rather than a "no entry" sign.dataTransfer.files[0] can be undefined (dragged text, a URL).
Say so; don't throw.Two testing gotchas — both make a correct implementation look broken:
DragEvents and a real DataTransfer carrying a real File. The real
browser order when the pointer crosses into a child is dragenter on the new target, then
dragleave on the old — so a test that fires a bare dragleave will report a
highlight-flicker bug that does not exist.gallery.emit — "auto" (default): emit the gallery landing page only when the catalog
has more than one plugin (a gallery is pointless for a single plugin). true / false force
it; use false to keep a hand-curated landing page of your own.theme — omit it entirely and the player uses its own bundled skin. Only set
tokensHref / fontHref when you are actually supplying a token stylesheet.If a plugin takes a user-supplied file (a convolver's impulse response, a sample, a preset),
declare it with the per-plugin fileUpload config (accept, label, hint). The demo must
then offer both a file-dialog button and a drop zone — people drag files onto anything
that looks like a target.
This is a PLAYER behavior, not a per-demo one. Like every other UX invariant, the drop-zone mechanics belong in the shared player so both ABIs inherit them. Re-implementing a drop zone in one demo page is exactly the drift this skill exists to prevent — its WCLAP twin would then need its own copy, and the two would diverge.
Any implementation MUST satisfy all six rules. Each one, skipped, makes the zone feel broken:
document. The browser's default action for a file dropped
anywhere on the page is to navigate to it, destroying the running demo — audio context,
loaded state, knob positions. Add document listeners for dragover and drop that call
preventDefault() and nothing else, so a ten-pixel miss is inert rather than session-ending.
That is a brutal punishment for a gesture you invited. Unbind them in destroy().dragenter/dragleave depth — do not toggle. dragleave bubbles from the zone's
own children, so dragging across a button inside the zone fires it and the highlight
strobes. Keep a depth counter; clear the highlight only at zero.dataTransfer.dropEffect = "copy" on dragover, so the cursor shows a copy badge
rather than a "no entry" sign.dataTransfer.files[0] can be undefined (dragged text, a URL).
Say so; don't throw.Two testing gotchas — both make a correct implementation look broken:
DragEvents and a real DataTransfer carrying a real File. The real
browser order when the pointer crosses into a child is dragenter on the new target, then
dragleave on the old — so a test that fires a bare dragleave will report a
highlight-flicker bug that does not exist.dropEffect cannot be asserted from a synthetic drag. The spec honours it only during a
real user-initiated drag, so on a synthetic DataTransfer dropEffect = "copy" silently
stays "none" — a browser-driven test will "fail" a line that is perfectly correct. Pin rule 4
in a DOM shim (where the assignment is observable) and do not "fix" the code to satisfy a
synthetic drag.The player implements this (src/ui/file-upload.js in @danielraffel/web-player): declare
fileUpload and you get the zone, the button, and all six rules for free, on both ABIs. The
player owns the interaction; the encoding is yours — only the plugin knows how its bytes
want to look — so pass onFile(file, api) and use the api.writeBlob() you're handed, which
preserves the plugin's params (loading a file must never reset the knobs). With no onFile, the
player writes the file's raw bytes and lets the plugin decode them.
One related trap worth knowing: decodeAudioData resamples, so the decoded buffer never
carries the file's real sample rate. If you tell the user anything about their file, parse the
WAV/AIFF header instead of trusting the decoded buffer.
?query on the player's import specifier. An import map keys on the exact
bare specifier, so import ... from "<pkg>?v=<hash>" never matches the "<pkg>" key and the
module fails to resolve — the demo does not load at all. The cache-bust belongs on the
mapped URL. A versioned CDN pin is already its own cache key.midi-effect demo without synthUrls is SILENT. It renders fine and looks correct, but
a MIDI effect emits notes with nothing to play them. synthUrls chains it into a synth voice
pool. Always set it for mode: "midi-effect".wam-dsp.js, wam-processor.js, and
wam-runtime.mjs. The worklet imports the runtime relative to itself, so it must be
co-located with the processor. Miss it and audioWorklet.addModule() fails with a bare
AbortError: Unable to load a worklet's module.tokensHref. A made-up relative path just 404s and silently drops the skin.fileUpload against a version predating it yields a demo that silently
renders no zone. fileUpload needs >= 0.2.0. When the player gains a feature, bump the
pin in your config — the pin is what the generated page imports.examples/example.config.json is a copy-and-edit starting point: one plugin, WAM on GitHub
Pages, WCLAP on Cloudflare, with placeholder origins. Drop it at .pulp-web-demo/config.json
in your plugin repo and change the URLs, theme, and plugin catalog. The reader-facing
WAM-vs-WCLAP explainer that ships with the demo galleries is the companion doc.
templates/hosting/coi/coi-serviceworker.js is vendored MIT (Guido Zuidhof / coi-serviceworker).
Everything else here is part of the Pulp SDK. Follow pulp-feature-lifecycle for review/PR/merge
around any change to demos or this skill.
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Optional AAX support for Pulp, including developer-supplied Avid SDK setup, CMake enablement, DigiShell/AAX Validator workflows, and local AAX builds on macOS or Windows.
日本語の概要は準備中です。原文の説明を表示しています。
Configure, implement, and test Pulp's optional desktop Ableton Link tempo-sync adapter while preserving the developer-supplied SDK, licensing, realtime, latency-compensation, and no-install boundaries.
日本語の概要は準備中です。原文の説明を表示しています。
Maintain Pulp's installed design-time agent capability manifest and public-surface ledger. Use when adding, removing, renaming, or materially changing public audio, MIDI, signal, timebase, or sequence APIs; registering a new algorithm for generators; changing capability support or deprecation state; or repairing agent-capabilities freshness, schema, fingerprint, tombstone, or installed-SDK tests.
日本語の概要は準備中です。原文の説明を表示しています。
Android platform development for Pulp — NDK cross-compilation, Oboe audio, Dawn/Skia GPU rendering, JNI bridge, touch interaction, emulator workflows, and end-to-end smoke validation. Covers build, deploy, debug, and the gotchas discovered during bringup.
日本語の概要は準備中です。原文の説明を表示しています。
Optional ARA support for Pulp, including developer-supplied ARA SDK setup, CMake enablement, adapter companion APIs, validation, and ARA-aware plugin implementation guidance.
日本語の概要は準備中です。原文の説明を表示しています。
The measurement surface for ALL Pulp DSP and audio-pipeline work — read it BEFORE writing or gating DSP, not only when something already sounds wrong. Covers the C++ harness (signal generators, metrics, assertions, RenderScenario, contracts), the offline Audio Doctor (magnitude/frequency response, THD/THD+N, phase/group delay), and their Python sibling the Audio Quality Lab (tools/audio/quality-lab — null residual + alignment, LTAS log-spectral distance, spectral flux/centroid, HNR, Theil-Sen drift slope, Kaiser-sinc resampling, license-guarded corpus, regression-net ratchet). TRIGGER on AUTHORING work — "build/design an oscillator/filter/synth/effect", "add a DSP module", "what should the acceptance gate be", "how do I measure aliasing / anti-aliasing / alias floor", "null against a reference", "is this DSP correct", "choose a tolerance", "golden/regression corpus for audio", "measure drift or jitter", "A/B two renders" — AND on DEBUGGING work — "is there sound / no audio / I hear nothing", "does this filter/compressor/synth/delay produce the right signal", "prove the DSP / prove the contract", "measure the frequency response", "what's the THD / is it distorting", "what's the group delay / phase response / measured latency", "magnitude response curve", "render a test tone and assert", "audio regression", "64-frame works but 128 is silent", "sample-rate change pitch-shifted it", "describe what's in this buffer", "audio doctor", "compare before/after a DSP refactor". Reach for this BEFORE hand-rolling any FFT, null test, alias measurement, pitch tracker, or golden-render script — most of it already exists in one of the two lanes. Test/tool layer over HeadlessHost — deterministic, no audio device, no speakers. Off the realtime thread entirely.
日本語の概要は準備中です。原文の説明を表示しています。