Workshop SDK Tutorial
For authors who publish Steam Workshop themes, lyrics scenes, visualizers, EQ presets, locale packs, or sandbox plug-ins.
SDK repository: github.com/Moekotori/echo-workshop-sdk
| Workshop SDK | Local plug-ins | |
|---|---|---|
| Distribution | Steam Workshop | plugins/ folder |
| Runtime | ECHO sandbox | Plug-ins page in ECHO |
| Target | Steam ECHO | ECHO Next local plug-ins |
| Tooling | echo-workshop-sdk CLI | Hand-written echo.plugin.json |
After users subscribe, they must click Use inside ECHO — see Steam Workshop. These SDK commands never upload to Steam. Publishing happens only in ECHO → Workshop → Authoring Studio.
Step-by-step guides
Section titled “Step-by-step guides”| Guide | Best for |
|---|---|
| Themes: colors to CSS | First skin or packaged stylesheet |
| Sandbox plug-ins: commands and catalogs | Hello plug-in, network catalog, permissions |
| JSON content: lyrics / visualizer / DSP / locale | Non-code Workshop items |
| Runtime UI themes | Sandboxed HTML/CSS/JS replacement UI |
| Official examples and snippets | hello / cinema / fragments / snippets |
| Local dev workflow | dev / watch / quality / next / --json |
| Lyrics scene walkthrough | Cinema slots, transport, mini player |
| Locale packs | locale.json, fallback, wenyan example |
| Visualizer and DSP | bars/wave/radial + 31-band EQ |
| VST3 profile | ClassId mapping, no binaries |
| Catalog API | search / browse / resolve |
| Publish and update | Ship after a clean local check |
| Author FAQ | Boundaries, choices, versions, AI help |
- Subscribers → Steam Workshop — no SDK required.
- Authors → this series; after
check, follow publish.
A passing local check does not replace Steam download, Use, or production host policy. Test subscribe flow with a real Steam account before and after publish.
What a project contains
Section titled “What a project contains”A workspace from init or example looks like this:
my-project/├── echo.workshop.project.json # Authoring project: tags, description, visibility, preview path├── preview.png # 256×256 listing image (replace placeholder before publish)├── package.json # npm run check / dev / watch├── content/ # Shipped Workshop payload│ ├── echo.workshop.json # Outer manifest: id, version, file hashes, compatibility│ └── theme.json etc. # Depends on kind (see table)├── src/ # Plug-in sources (synced into content/community.echo on check)│ └── plugin.js├── .echo-sdk/ # Portable SDK copy + TypeScript declarations└── .vscode/ # JSON Schema, tasks, echo- snippets| Kind | You edit | content/ entry |
|---|---|---|
| Theme | content/theme.json (+ optional theme.css / ui/) | theme.json |
| Lyrics scene | content/lyrics-style.json | lyrics-style.json |
| Visualizer | content/visualizer.json | visualizer.json |
| DSP | content/dsp.json | dsp.json |
| Locale pack | content/locale.json | locale.json |
| Sandbox plug-in | src/plugin.js (+ panels) | community.echo (generated) |
After changing content/ or src/, run npm run check. The SDK syncs and recomputes files[].sha256 in echo.workshop.json.
ECHO does not ship Netease, Spotify, YouTube, or other streaming platforms. Plug-ins may expose an author-owned HTTP(S) direct-link catalog; playback starts only after the user confirms. Legal boundary → Download and plug-in source policy.
Prerequisites
Section titled “Prerequisites”| Item | Requirement |
|---|---|
| Node.js | 20+ (init / check / dev need only Node, not ECHO) |
| Editor | VS Code recommended; generated projects include JSON Schema and snippets |
| ECHO | Steam build for publishing via Authoring Studio |
| Steam | Launch ECHO from Steam while online |
Get the SDK
Section titled “Get the SDK”All three paths ship the same package:
- Clone from GitHub
Terminal window git clone https://github.com/Moekotori/echo-workshop-sdk.gitcd echo-workshop-sdk - Install via npm
Terminal window npm install github:Moekotori/echo-workshop-sdknpx echo-workshop-sdk version - Steam starter item — subscribe to Workshop item
3784997717.
Current package version 1.11.0, manifest schema 1, sandbox plug-in API 2:
node .\bin\echo-workshop-sdk.mjs version --json30-second first project
Section titled “30-second first project”Walk through the local gate with the hello plug-in example.
- After cloning the SDK, copy the example into an empty folder:
Terminal window node .\bin\echo-workshop-sdk.mjs example hello-plugin .\my-hellocd .\my-hello - See what to do next:
Terminal window npm run next - Run the full local gate (sync, validate, quality, fixtures):
Terminal window npm run check - Open the author console:
Terminal window npm run dev
hello-plugin ships one command and a single playback:read permission. Edit src/plugin.js; check syncs into content/community.echo.
Prefer a theme first:
node .\bin\echo-workshop-sdk.mjs example minimal-theme .\my-themecd .\my-themenpm run checkSeven content kinds
Section titled “Seven content kinds”--kind | Purpose | Typical start |
|---|---|---|
theme | Skins, packaged CSS, custom UI | --recipe css-theme or --preset skin |
lyrics-style | Lyrics scene layout | --recipe cinema-lyrics |
visualizer-preset | Spectrum style (bars / wave / radial) | --recipe radial-visualizer |
dsp-preset | 31-band EQ preset | --recipe vocal-eq |
audio-plugin-profile | Local VST adapter notes | --kind audio-plugin-profile |
locale-pack | Language ECHO does not ship | --recipe wenyan-locale |
plugin-package | Sandbox plug-in | --recipe plugin-complete or hello-plugin |
Pick by outcome instead of memorizing kinds:
node .\bin\echo-workshop-sdk.mjs recipesnode .\bin\echo-workshop-sdk.mjs init .\harbor --recipe css-themeRecipe reference
Section titled “Recipe reference”--recipe | Kind | You get |
|---|---|---|
colors-theme | Theme | Light/dark tones only |
skin-theme | Theme | Declarative chrome and atmosphere |
css-theme | Theme | Packaged CSS (stylesheet tier) |
custom-ui | Theme | Sandboxed HTML/CSS/JS UI |
editorial-lyrics | Lyrics | Cover + lyrics grid (default stage) |
cinema-lyrics | Lyrics | Cinema stage; often hides mini player |
compact-lyrics | Lyrics | Compact one-line header |
cover-lyrics | Lyrics | Large cover column |
bars-visualizer | Visualizer | Mirrored bars |
wave-visualizer | Visualizer | Waveform |
radial-visualizer | Visualizer | Radial spectrum |
flat / vocal-eq / bass-eq | DSP | Flat / vocal / bass 31-band presets |
plugin-complete | Plug-in | Commands, panel, agent, providers |
source-catalog | Plug-in | Author-owned direct-link catalog |
lyrics-source | Plug-in | Lyrics provider + current-lyrics panel |
wenyan-locale | Locale | Literary Chinese and similar |
Recommended workflow
Section titled “Recommended workflow”- Initialize —
initorexample; folder name becomes id/title. - Edit — JSON under
content/for themes/lyrics/visualizer/DSP;src/plugin.jsfor plug-ins. - Iterate —
npm run nextfor fix-first items;add/set/scaffoldfor incremental changes. - Verify —
npm run checkmust pass before publish; usenpm run check -- --warn-onlywhile iterating. - Preview —
npm run devopens the author console; several kinds also get fixture preview. - Publish — validate and upload in ECHO → Workshop → Authoring Studio. SDK commands never upload.
Print the full checklist:
node .\bin\echo-workshop-sdk.mjs guide checklistCommand reference
Section titled “Command reference”| Command | Purpose |
|---|---|
init ./dir --kind theme | New project |
init ./dir --recipe cinema-lyrics | New project from a recipe |
example hello-plugin ./dir | Copy an official example |
next . | Fix-first items, then allowed slots/permissions |
add . --permission library:read | Append a whitelisted permission |
set . --title "Harbor Night" | Update common fields |
scaffold . --preset runtime | Stack theme tiers without restarting |
check . | Complete local gate |
dev . | Author console (port 41783, auto-fallback) |
watch . | Rerun check on save |
fix . | Repair preview.png, README, minEchoVersion |
guide / guide troubleshoot | Chinese cookbook and troubleshooting table |
snippet list | Copy-paste starters with required permissions |
api echo.queue.moveItem | Method-to-permission lookup |
api errors | Which errors may be retried |
Generated projects expose npm run check and npm run dev. VS Code default build task: ECHO Workshop: Check (Ctrl+Shift+B).
VS Code and CI
Section titled “VS Code and CI”Generated projects include:
- JSON Schema — invalid fields in
echo.workshop.json,theme.json, etc. are underlined while editing - Snippets — type an
echo-prefix in.js/.json(same set assnippet list) - Plug-in types —
.echo-sdk/echo-workshop-plugin.d.tscompletes theecho.*global
The bundled .github/workflows/validate-workshop.yml runs the same check gate on every push and pull request and mirrors the summary into the GitHub Actions job summary. The template uses Node 22; local Node 20+ is fine.
- After pushing to GitHub, read the gate summary on the PR — PASS means the local gate passed in CI.
- If CI fails with
Generated files are committed: runnpm run check && git add -Alocally and commit synced manifests. - Publishing still happens only in ECHO Authoring Studio; CI never uploads to Steam.
Theme tiers
Section titled “Theme tiers”Upgrade without starting over:
| Preset | What you get | Min ECHO |
|---|---|---|
colors | Light/dark tones only | 26.8.15 |
skin | Declarative chrome (default) | 26.8.15 |
stylesheet | Packaged CSS | 26.8.20 |
runtime | Sandboxed HTML/CSS/JS UI | 26.8.20 |
Example:
node .\bin\echo-workshop-sdk.mjs scaffold .\my-theme --preset stylesheetbasePresetmust be a public host preset such asclassic.FINAL,nyanCat, anddarkSideMoonare rejected.- Packaged CSS must live under
html[data-workshop-theme-pack="<your-pack-id>"]. - Inline scripts, remote
@import, and non-rasterurl()values are blocked. - Declare
minEchoVersion≥ 26.8.20 for stylesheet and runtime themes.
Sandbox plug-ins
Section titled “Sandbox plug-ins”Workshop plug-ins share ideas with local plug-in authoring but run in a narrower sandbox.
| Preset | Best for |
|---|---|
basic | One command, minimal permissions |
complete | Commands, panel, agent, providers |
catalog | Author-owned direct HTTP(S) catalog — not official streaming |
lyrics | Lyrics provider plus current-lyrics panel |
Projects reference .echo-sdk/echo-workshop-plugin.d.ts for API 2 completion on the echo global.
At most 32 files, 512 KiB per UTF-8 file, 2 MiB serialized package. Allowed extensions: .css, .html, .js, .mjs, .json. Inner plug-in apiVersion must exactly match outer compatibility.pluginApiVersion.
Network plug-ins must declare networkHosts (bare domain or public IPv4, no protocol/port) and request network:request. The mock host rejects undeclared destinations locally:
node .\bin\echo-workshop-sdk.mjs add . --permission network:requestnode .\bin\echo-workshop-sdk.mjs api errorsLyrics, visualizer, DSP
Section titled “Lyrics, visualizer, DSP”Lyrics scenes — the host owns all slots; you place whitelisted styles. Slots include cover, title, lyrics, current-line, spectrum, play-toggle, and more. If you hide the mini transport bar, you must ship play-toggle.
Visualizer — host styles are bars, wave, and radial only — no particles. Palette: 1–8 unique #rrggbb colors; barCount 8–128.
DSP / EQ — official 31-band layout; gain -12..12, Q 0.1..12, preamp -12..6. JSON is a preset; Audio Core executes at playback time.
From zero to publish
Section titled “From zero to publish”- Clean
npm run check(decide whether warnings are acceptable). - Replace placeholder
preview.png(256×256); write README and listing copy (≥ 80 characters recommended). - Align
license,tags, andminEchoVersionwith what you actually tested. - Launch ECHO from Steam → Workshop → Authoring.
- Import or link the local project and run ECHO validation.
- Publish after validation passes. Keep public starter ID
3784997717— do not create a new one when updating.
User-side subscribe/use flow → Steam Workshop.
Troubleshooting
Section titled “Troubleshooting”Run npm run check and read the one-line gate summary at the end.
| Symptom | Likely cause | Fix |
|---|---|---|
| Manifest hash mismatch | Edited content/ or src/ without sync | Rerun check (sync runs automatically) |
| capability-denied | Undeclared permission | add . --permission <permission> |
| network-host-denied | Request to undeclared host | Declare networkHosts in outer manifest |
| Preview must be … | Invalid preview image | npm run fix |
| Port 41783 was busy | Dev port taken | Omit --port to auto-pick the next free port |
See TROUBLESHOOTING.md and CHEATSHEET.md in the SDK repo.
node .\bin\echo-workshop-sdk.mjs guide troubleshootLicense and contributions
Section titled “License and contributions”SDK types, schemas, CLI, templates, and examples are MIT licensed. Your original Workshop content stays yours; declare a license with --license on init / set (default All-Rights-Reserved).
To change the SDK itself, open issues or PRs at echo-workshop-sdk — see CONTRIBUTING.md.
Related docs
Section titled “Related docs”- Theme tutorial: colors to CSS
- Sandbox plug-in tutorial
- JSON content: lyrics / visualizer / DSP / locale
- Steam Workshop — subscribe, enable, troubleshooting
- Plug-in authoring — local
plugins/plug-ins (not Workshop sandbox) - AI theme guide — importable custom theme JSON (not a Workshop pack)