Skip to content
⌂ Home

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 SDKLocal plug-ins
DistributionSteam Workshopplugins/ folder
RuntimeECHO sandbox by default; system:full needs separate subscriber approvalPlug-ins page in ECHO
TargetSteam ECHOECHO Next local plug-ins
Toolingecho-workshop-sdk CLIHand-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.

GuideBest for
Workshop Developer GuideCurrent SDK 1.17 source contract, new pages and lyric features, full build-to-publish flow
Themes: colors to CSSFirst skin or packaged stylesheet
Sandbox plug-ins: commands and catalogsHello plug-in, network catalog, permissions
JSON content: lyrics / visualizer / DSP / localeNon-code Workshop items
Runtime UI themesSandboxed HTML/CSS/JS replacement UI
Official examples and snippetshello / cinema / fragments / snippets
Local dev workflowdev / watch / quality / next / --json
Lyrics scene walkthroughCinema slots, transport, mini player
Locale packslocale.json, fallback, wenyan example
Visualizer and DSPbars/wave/radial + 31-band EQ
VST3 profileClassId mapping, no binaries
Catalog APIsearch / browse / resolve
Publish and updateShip after a clean local check
Author FAQBoundaries, 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.

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
KindYou editcontent/ entry
Themecontent/theme.json (+ optional theme.css / ui/)theme.json
Lyrics scenecontent/lyrics-style.jsonlyrics-style.json
Visualizercontent/visualizer.jsonvisualizer.json
DSPcontent/dsp.jsondsp.json
Locale packcontent/locale.jsonlocale.json
Sandbox plug-insrc/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.

ItemRequirement
Node.js20+ (init / check / dev need only Node, not ECHO)
EditorVS Code recommended; generated projects include JSON Schema and snippets
ECHOSteam build for publishing via Authoring Studio
SteamLaunch ECHO from Steam while online

These channels can differ in version. Check the actual files you download:

  1. Clone from GitHub
    Terminal window
    git clone https://github.com/Moekotori/echo-workshop-sdk.git
    cd echo-workshop-sdk
  2. Install from GitHub (pin a commit or release for CI)
    Terminal window
    npm install github:Moekotori/echo-workshop-sdk
    npx echo-workshop-sdk version
  3. Steam starter item — item 3784997717 is published separately.

The current D:\ECHO source package is 1.17.0, with manifest schema 1 and plug-in API 2. This does not imply the same version is already available as a Release or Steam download. Inspect your copy:

Terminal window
node .\bin\echo-workshop-sdk.mjs version --json

Walk through the local gate with the hello plug-in example.

  1. After cloning the SDK, copy the example into an empty folder:
    Terminal window
    node .\bin\echo-workshop-sdk.mjs example hello-plugin .\my-hello
    cd .\my-hello
  2. See what to do next:
    Terminal window
    npm run next
  3. Run the full local gate (sync, validate, quality, fixtures):
    Terminal window
    npm run check
  4. 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:

Terminal window
node .\bin\echo-workshop-sdk.mjs example minimal-theme .\my-theme
cd .\my-theme
npm run check
--kindPurposeTypical start
themeSkins, packaged CSS, custom UI--recipe css-theme or --preset skin
lyrics-styleLyrics scene layout--recipe cinema-lyrics
animation-libraryData-only reusable lyrics motion--kind animation-library
visualizer-presetSpectrum style (bars / wave / radial)--recipe radial-visualizer
dsp-preset31-band EQ preset--recipe vocal-eq
audio-plugin-profileLocal VST adapter notes--kind audio-plugin-profile
locale-packLanguage ECHO does not ship--recipe wenyan-locale
plugin-packageSandbox plug-in--recipe plugin-complete or hello-plugin
native-shellWindows system-shell protocol project; official Steam still rejects subscriber exe/dll--recipe native-shell-taskbar

Pick by outcome instead of memorizing kinds:

Terminal window
node .\bin\echo-workshop-sdk.mjs recipes
node .\bin\echo-workshop-sdk.mjs init .\harbor --recipe css-theme
--recipeKindYou get
colors-themeThemeLight/dark tones only
skin-themeThemeDeclarative chrome and atmosphere
css-themeThemePackaged CSS (stylesheet tier)
custom-uiThemeSandboxed HTML/CSS/JS UI
editorial-lyricsLyricsCover + lyrics grid (default stage)
cinema-lyricsLyricsCinema stage; often hides mini player
compact-lyricsLyricsCompact one-line header
cover-lyricsLyricsLarge cover column
bars-visualizerVisualizerMirrored bars
wave-visualizerVisualizerWaveform
radial-visualizerVisualizerRadial spectrum
flat / vocal-eq / bass-eqDSPFlat / vocal / bass 31-band presets
plugin-completePlug-inCommands, panel, agent, providers
source-catalogPlug-inAuthor-owned direct-link catalog
lyrics-sourcePlug-inLyrics provider + current-lyrics panel
wenyan-localeLocaleLiterary Chinese and similar
  1. Initialize — init or example; folder name becomes id/title.
  2. Edit — JSON under content/ for themes/lyrics/visualizer/DSP; src/plugin.js for plug-ins.
  3. Iterate — npm run next for fix-first items; add / set / scaffold for incremental changes.
  4. Verify — npm run check must pass before publish; use npm run check -- --warn-only while iterating.
  5. Preview — npm run dev opens the author console; several kinds also get fixture preview.
  6. Publish — validate and upload in ECHO → Workshop → Authoring Studio. SDK commands never upload.

Print the full checklist:

Terminal window
node .\bin\echo-workshop-sdk.mjs guide checklist
CommandPurpose
init ./dir --kind themeNew project
init ./dir --recipe cinema-lyricsNew project from a recipe
example hello-plugin ./dirCopy an official example
next .Fix-first items, then allowed slots/permissions
add . --permission library:readAppend a whitelisted permission
set . --title "Harbor Night"Update common fields
scaffold . --preset runtimeStack 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 troubleshootChinese cookbook and troubleshooting table
snippet listCopy-paste starters with required permissions
api echo.queue.moveItemMethod-to-permission lookup
api errorsWhich 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).

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 as snippet list)
  • Plug-in types — .echo-sdk/echo-workshop-plugin.d.ts completes the echo.* 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.

  1. After pushing to GitHub, read the gate summary on the PR — PASS means the local gate passed in CI.
  2. If CI fails with Generated files are committed: run npm run check && git add -A locally and commit synced manifests.
  3. Publishing still happens only in ECHO Authoring Studio; CI never uploads to Steam.

Upgrade without starting over:

PresetWhat you getMin ECHO
colorsLight/dark tones only26.8.15
skinDeclarative chrome (default)26.8.15
stylesheetPackaged CSS26.8.20
runtimeSandboxed HTML/CSS/JS UI26.8.20

Example:

Terminal window
node .\bin\echo-workshop-sdk.mjs scaffold .\my-theme --preset stylesheet
  • basePreset must be a public host preset such as classic. FINAL, nyanCat, and darkSideMoon are rejected.
  • Packaged CSS must live under html[data-workshop-theme-pack="<your-pack-id>"].
  • Inline scripts, remote @import, and non-raster url() values are blocked.
  • Declare minEchoVersion ≥ 26.8.20 for stylesheet and runtime themes.

Workshop plug-ins share ideas with local plug-in authoring but run in a narrower sandbox.

PresetBest for
basicOne command, minimal permissions
completeCommands, panel, agent, providers
catalogAuthor-owned direct HTTP(S) catalog — not official streaming
lyricsLyrics 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:

Terminal window
node .\bin\echo-workshop-sdk.mjs add . --permission network:request
node .\bin\echo-workshop-sdk.mjs api errors

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.

  1. Clean npm run check (decide whether warnings are acceptable).
  2. Replace placeholder preview.png (256×256); write README and listing copy (≥ 80 characters recommended).
  3. Align license, tags, and minEchoVersion with what you actually tested.
  4. Launch ECHO from Steam → Workshop → Authoring.
  5. Import or link the local project and run ECHO validation.
  6. Publish after validation passes. Keep public starter ID 3784997717 — do not create a new one when updating.

User-side subscribe/use flow → Steam Workshop.

Run npm run check and read the one-line gate summary at the end.

SymptomLikely causeFix
Manifest hash mismatchEdited content/ or src/ without syncRerun check (sync runs automatically)
capability-deniedUndeclared permissionadd . --permission <permission>
network-host-deniedRequest to undeclared hostDeclare networkHosts in outer manifest
Preview must be …Invalid preview imagenpm run fix
Port 41783 was busyDev port takenOmit --port to auto-pick the next free port

See TROUBLESHOOTING.md and CHEATSHEET.md in the SDK repo.

Terminal window
node .\bin\echo-workshop-sdk.mjs guide troubleshoot

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.