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.json,action-catalog.json(816 vendor descriptions),attested-tails.json(argument tails and shapes Atomix wrote),binary-vocabularies.json(argument enumerations as groups),vdjscript-corpus.json(vendor snippets from every mined source) andverb-arg-forms.json(probe results), plus theplugin-introspection*.jsoncaptures from the native channeltools/— extractors, sweeps, linters and thejustquery API; every artifact is regenerable and gated byjust check
| Goal | File |
|---|---|
| Answer anything about one verb | just verb <name> — the one-screen join: store record, vendor description, real usages, argument shapes with return evidence, every tail candidate by source, vocabulary groups, probe state, each labelled with its evidence tier. just get-verb <name> is the bare store record |
| Answer "how do I do X" | just topic <term> — the matching verbs, effects and XML elements, plus the real example files that use them, ranked by how much of the topic each demonstrates |
| 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 |
Action catalog |
The Button Editor's own description for a verb, shipped in languages.zip — the same prose the official appendix publishes, readable offline |
Vendor script |
A form Atomix wrote into a shipped Built-In pad page or skin — attested usage, no probe required |
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 reference used to document verb names well and their arguments barely. Three
independent sources now cover the tail of a statement, and just action-catalog --cross-check
prints them against each other:
tests/action-catalog.json— 816 vendor descriptions extracted from the app bundle (languages.zipcarries the official appendix's prose, so it is available offline). The only source that says what a parameter means.tests/attested-tails.json— 214 tails Atomix wrote into shipped skins, pad pages and the app's own compiled menu scripts, plus argument shapes (fadeout DUR DUR `BOOL`,param_bigger EXP:NUM EXP:NUM, thedeck SEL EXPwrapper) with the return type the vendor's attribute implies, for the verbs whose arguments are values rather than keywords. Attested without a probe, which reaches where no test state can.tests/binary-vocabularies.json— argument vocabularies as groups, recovered from the binary as structures (pointer tables, switch functions): 21 groups, 265 members, of which 189 are named by no per-verb source — the 26 colour names, the 19 settings pages, the 16 stem tokens. The only source that sees an enumeration matched in a shared helper rather than in the verb's own code. Leads, not confirmations.tests/verb-arg-forms.json— every candidate probed against two nonsense controls inside 10 named fixtures, because VirtualDJ silently ignores an argument it cannot parse, so a verb answering proves nothing on its own.
Agreement across all three is the strongest claim this project makes; 10 verbs have it today
(just action-catalog --cross-check).
- A misspelled argument usually makes the action do nothing, and on some verbs degrades to the bare action instead. Neither is reported as an error.
- Relative and multiplying arguments are execute-only.
loop 50%halves a loop rather than setting one, and asking a query for it errors. deck allbroadcasts on execute but collapses to deck 1 on query — the same line means two different things depending on position.timecode_cd_modelatches: script can set it and cannot unset it; only a restart clears.- The sampler's
allmeans the selected slot, not every slot.
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,032 records / 958 distinct verbs / 62 alias groups / 38 editor-hidden on build 18.0.9598 (arm64, extracted 2026-09-05; just verb-table-stamp). Membership proves; absence disproves on that build. just verb-table <name> is the live answer |
| What category is it in? | All of them mapped | Compiled Button Editor category tables, confirmed against the live UI |
| Can it execute / query / return text? | All of them | ACTION_ class RTTI — a checked 958↔958 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? | 433 verbs flagged, incl. 300 with optional args | E_INVALIDARG fingerprint in each class's own methods |
| Which keyword arguments? | 262 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 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. Headers are third-party with no license grant, so they are fetched to a gitignoredvendor/rather than committed. - The native introspection channel is open (2026-08-15). The read-only plugin builds, loads,
and has swept every verb-table name through both query callbacks (
just plugin-probe <name>, captures intests/plugin-introspection*.json). It is the boundary where VDJScript results are still typed —GetInfo→double,GetStringInfo→ text — which is why HTTP flattens them, and it settled things HTTP structurally cannot:master_beat_num's float-bits defect is in the core, not the transport; a definitive channel map (532 verbs on both callbacks, 67 text-only, 11 numeric-only, 418 on neither); and the HRESULT does discriminate a recognized keyword from an ignored one, which is now the method for the keyword queue because it needs no prepared state.
- Build the verb index from the artifacts, not from prose (TODO.md task 11) —
extract_verb_index.pystill parses the 6,300-lineVDJScript Verbs.mdto producevdjscript-verb-index.json, so where the prose and the extracted evidence disagree, the prose wins silently and nothing gates it. The reconciliation diff is the real prize: every discrepancy is either a documented claim the artifacts contradict, or a curated fact the store has no field for. - Confirm the documented-but-unprobed parameters (TODO.md task 13b). The
fixture harness and argument prober are built and have run:
just fixtureslists the named states,just checkreports the probe run's verb/form/recognized totals, andjust verb-arg-forms <name>shows one verb's. What is left is the state, not the tooling —just action-catalog --cross-checknames, underdocumented_but_not_probe_confirmed, every verb whose parameters the vendor documents and no probe has confirmed, each one a state the existing fixtures never build. Itsprobe_confirmed_but_undocumentedset is the mirror worklist. - Spend the native channel on what only it reaches (TODO.md task 10a). The
plugin is built and the verb sweep is done, so the remaining value is not throughput:
GetSongBufferandOnProcessSamplesgive the actual PCM behind every waveform element;OnKey(ch, vkey, modifiers, flag, scancode)is the first channel that may expose press/release, which HTTP structurally cannot;VDJINTERFACE_SKINturns skin testing from edit-and-restart into a loop. - Behavior for most verbs is still untested — 978 of 1,038 store records carry
Untested, against 40Pass(just verb-stats). 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.