Community-maintained reference for VirtualDJ skinning, pad pages, and VDJScript. VirtualDJ does not publish a comprehensive developer reference; this repo fills that gap.
docs/— Markdown documentation: VDJScript verb reference, skin SDK, waveform elements, pad-page schema, effects, options, filter syntax, mapper format, application internalsexamples/Pads/— focused pad page XML examples for ColorFX, samplers, cues, transport, reference patterns, and copied built-in pad pages; see examples/Pads/README.mdexamples/Skins/— skin examples, copied built-in skins, and build-system demos; GraveRaver is intentionally minimal and only demonstrates the XInclude workflowexamples/Mappers/— real working controller/keyboard mapper XML copied from a local install; ground truth for the mapper formatexamples/Samplerbanks/— sampler-bank XML copied from the app bundle (a third XML format alongside skins and pads)examples/VideoSkins/— built-in video skins (broadcast, karaoke, live) copied from the app bundle; same<skin>format as deck skins, rendered onto the video outputtests/— reproducible documentation test harnesses, pad-page XML fixtures, and the extracted data artifacts:verb-table.json(the authoritative verb set),action-contracts.json(per-verb implementation contract),verb-return-types.json(observed types and boolean truth),verb-existence-sweep.jsontools/— extractors, sweeps, linters and thejustquery API; every artifact is regenerable and gated byjust check
| Goal | File |
|---|---|
| Answer anything about one verb | just get-verb <name> — joins every artifact: existence, category, aliases, implementation class, capability, argument demands, keyword arguments, observed return type, boolean truth |
| Pick the next active maintenance task | TODO.md |
| Route a topic to the right docs and fixtures | INDEX.yml |
| Understand the repo structure and source labeling | docs/README.md |
| Pick the right VDJScript verb or pattern | docs/VirtualDJ Reference.md |
| Look up a specific verb | docs/VDJScript Verbs.md |
| Check official verb coverage | docs/Official VDJScript Coverage Audit.md |
| Choose the next completeness pass | docs/Completeness Roadmap.md |
| Choose or maintain a pad page | examples/Pads/README.md |
| Look up the pad-page XML format | docs/Pad Page XML.md |
| Build skin waveforms | docs/Skin Waveforms.md |
| Check skin/pad XML doc coverage | just find-xml-elements --undocumented (data: docs/skin-xml-inventory.json, refreshed by just inventory) |
| Look up verbs programmatically | docs/vdjscript-verb-index.json (generated; just verb-index) |
| Validate skin/mapper XML | just lint-skins [paths] · just lint-mappers [paths] · tools/README.md |
| Run or update a test harness | tests/README.md |
| Build or study a skin | docs/Skin SDK.md · docs/Skin Runtime Findings.md · examples/Skins/README.md · examples/Skins/ModularSkeleton/ |
| Work with effects | docs/Effects Usage.md · docs/Native Effects.md |
| Map a controller or keyboard | docs/Mapper XML.md |
| Write a native plugin, or understand where VDJScript results are still typed | docs/Plugin SDK.md |
| Understand macOS paths and databases | docs/Application Internals.md |
Inspect or create .vdjstems sidecars |
docs/Stem File Format.md |
AGENTS.md is intentionally retained for Claude, Codex, and other coding
agents that look for that filename. This README.md is the human-facing
overview; AGENTS.md keeps the operational shortcuts and repo-specific guardrails.
Every fact in the reference docs is labeled by source:
| Label | Meaning |
|---|---|
Official |
Current VirtualDJ manual or VDJPedia |
Official forum |
Post by VirtualDJ staff, CTO, or support |
Community |
Non-staff forum guidance |
Published skin |
Observed in a working public skin |
Built-in skin |
Observed in skin XML shipped inside the VirtualDJ app bundle |
Published pad page |
Observed in a working public pad page |
Built-in pad page |
Observed in pad-page XML shipped inside the VirtualDJ app bundle |
Built-in app resource |
Command name, description, or UI catalog entry observed in non-skin/non-pad app resources |
Verb table |
VirtualDJ's own serialised verb set, extracted from the binary — decides existence outright |
Binary compiled table |
Structured command metadata observed in compiled executable tables |
Binary symbol table |
Demangled implementation symbols observed in the VirtualDJ executable |
Binary string-table |
Command-looking string observed in the VirtualDJ executable; discovery only |
Local test |
Reproduced in VirtualDJ locally |
Inference |
Conclusion drawn from the above sources |
Unlabeled files are raw material not yet normalized to this standard. docs/Evidence Standards.md governs every claim: three tiers, what counts as a behavioral test, and why a channel's own return value is never a result.
The verb set, each verb's contract, and the grammar are now derived from VirtualDJ itself rather than assembled from documentation.
| Question | Answer | How |
|---|---|---|
Is x a verb? |
Decided, both ways | VirtualDJ's own verb table — 1,028 records, 955 distinct verbs, 61 alias groups, 37 editor-hidden. Membership proves; absence disproves. just verb-table <name> |
| What category is it in? | All 1,028 mapped | Compiled Button Editor category tables, confirmed against the live UI |
| Can it execute / query / return text? | All 955 | ACTION_ class RTTI — a checked 955↔955 bijection of verbs to implementation classes. just verb-contract <name> |
| What type does it return? | 623 of 652 query verbs | Live HTTP sweep. just verb-return-type <name> |
| Does it take arguments? | 436 verbs flagged, incl. 301 with optional args | E_INVALIDARG fingerprint in each class's own methods |
| Which keyword arguments? | 259 verbs | String-comparison fingerprint — recovered get_bpm absolute, browser_window sidelist, loaded opposite and 200+ more that no documentation lists |
- A verb's value is not its truth.
get_versionreports2026and is false as a condition. 171 of 652 query verbs are traps, and no slider verb is ever true. &&is not an operator. It never guards anything; it only changes which statement's value a query reports.- Chains stop after exactly 255 statements, partially, returning
false. - GET refuses scripts over ~2,650 characters at the transport layer — which looks exactly like a language failure and caused a documented rule to be wrong for months. Use POST.
- Chained ternaries are a genuine else-if ladder; each branch takes its whole
&chain.
- Skin SDK coverage is broad; the waveform element family is in
docs/Skin Waveforms.md, and remaining element gaps are tracked mechanically (just find-xml-elements --undocumented). - Controller mapper XML is rewritten around the real
<map value="">+ device-definition split, with working mappers inexamples/Mappers/Local/. Custom device-definition XML is official-doc-derived and still not load-tested. - The VirtualDJ Remote wire protocol is decoded and proven bidirectional (docs/Remote Protocol.md).
- The plugin SDK is now documented (docs/Plugin SDK.md): interface
hierarchy, the
VDJPARAM_*model and the[autoparams]manifest all 173 built-in plugins use, plugin UI models, and the interfaces present in the binary that the public headers never declare. It is the boundary where VDJScript results are still typed —GetInfo→double,GetStringInfo→ text — which is both why the HTTP channel flattens them and the basis of the next session's primary plan below. Headers are third-party with no license grant, so they are fetched to a gitignoredvendor/rather than committed.
- Build the read-only introspection plugin — this is the primary plan
(TODO.md task 10a, with the full build plan and constraints). Both existing
instruments are at their limits: the binary cannot yield argument types, and HTTP
flattens every result to text. The plugin SDK sits at the boundary where results are still
typed —
GetInfo→doubleandGetStringInfo→ text are separate calls — so a plugin reads native types and raw HRESULTs directly. It settles themaster_beat_numfloat-bits defect in one call, produces a definitive per-verb type-path map, makes the 301-verb optional-argument queue tractable at loop speed, and is a fifth Tier-1 channel needing neither the Network Control plugin nor a Pro license. Headers are fetched to a gitignoredvendor/, never committed — Atomix grants no redistribution license. - Probe the 217 verbs whose keyword arguments no documentation mentions. Note the constraint found the hard way: unknown arguments are silently ignored, so confirmation needs prepared state where forms would differ — never an error code.
- Behavior for ~940 verbs is still untested. Existence, kind, category, capability and return type are settled; what a verb does mostly is not.
- Audit the remaining
InferenceandCommunitylabels against docs/Evidence Standards.md, which does not permit either as a standing claim. - HTML export of the reference is parked in TODO.md and now worth doing — the per-verb pages finally have real content to show.
Contributions and corrections welcome. Corrections especially: several long-standing claims were overturned this session by re-testing them on a second channel, and the repo records retractions in place rather than deleting them.