diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..48898c9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,20 @@ +version: 2 + +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + commit-message: + prefix: chore + reviewers: + - steady41 + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + commit-message: + prefix: ci + reviewers: + - steady41 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1c6434..7f02d87 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,12 +2,16 @@ name: CI on: push: - branches: [main] + branches: ['**'] pull_request: permissions: contents: read +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + jobs: check: runs-on: ubuntu-latest @@ -30,9 +34,31 @@ jobs: - name: Build run: npm run build + - name: Unit tests (node:test, headless engine + wav) + run: npm test + + - name: Syntax-check every compiled module + run: | + fail=0 + for f in $(find dist -name '*.js' -type f); do + node --check "$f" || fail=1 + done + exit $fail + - name: Verify build output run: | test -f dist/main.js test -f dist/audio/engine.js test -d dist/ui - echo "dist/ sanity check passed" \ No newline at end of file + echo "dist/ sanity check passed" + + - name: Verify index.html asset links resolve + run: | + missing=0 + for ref in $(grep -oE '(src|href)="[^"]+"' index.html | sed -E 's/(src|href)="([^"]+)"/\2/' | grep -v '^https\?:'); do + if [ ! -f "$ref" ]; then + echo "::error::index.html references missing file: $ref" + missing=1 + fi + done + exit $missing diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index fc78941..b455cf7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -41,7 +41,7 @@ jobs: - name: Prepare dist for Pages run: | cp index.html dist/ - sed -i 's|src/styles/|styles/|g; s|src/main.js|main.js|' dist/index.html + sed -i 's|src/styles/|styles/|g; s|dist/main.js|main.js|' dist/index.html cp -r src/styles dist/ - name: Upload artifact diff --git a/README.md b/README.md index dcad518..2dfa543 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # VOIDSTATION [](LICENSE) +[](https://github.com/steady41/voidstation/actions/workflows/ci.yml) An analog-hardware-styled web DAW built with TypeScript and the Web Audio API. No backend, no dependencies: patterns, samples, effects, the playlist @@ -10,8 +11,10 @@ The interface is a canvas-style studio room — drag hardware modules (step sequencer, piano roll, playlist, mixer, transport) around a 3400×2800 wall, zoom with `Ctrl`+wheel, and arrange a full track: 16-step sequencing, piano-roll notes, per-track reverb/delay/EQ, a synth editor (waveform + -ADSR), sample trimming, loop regions, swing/groove, a master bus with -limiter, WAV export, and gesture-based undo/redo. +ADSR), sample trimming and pitch, loop regions, swing/groove, a master bus +with limiter, WAV + stem export, computer-keyboard / Web MIDI live input, +a MODULES dock for arranging the studio wall, sample trim/reverse/pitch, +and gesture-based undo/redo. The old UI is archived in git tag `legacy-vscode-ui`. @@ -34,6 +37,13 @@ The main interface is a canvas-style "studio room": a large world their brushed-metal headers. Pan with native scroll, zoom with `Ctrl`+wheel (or the HUD `— / % / + / ⌂` buttons). +Every module is also listed in the **MODULES dock** — a slide-out sidebar on +the left edge (`MODULES` tab or the HUD `▤` button). Drag a chip onto the +wall to place its module, drag an on-wall chip to relocate it, click a chip +to auto-pan to it, and use the `⏏` button in a header to put a unit away. +Double-clicking a header collapses/expands the body; docked/collapsed state +persists with the wall layout (`voidstation-wall-v1`). + Modules (one feature = one file in `src/ui/`): | Module | Description | @@ -45,6 +55,7 @@ Modules (one feature = one file in `src/ui/`): | Mixer | 5 analog channels: pan knob, LED meter, mute/solo, volume fader, channel click selects the piano-roll track | | Synth editor | per-track waveform (sine/tri/sqr/saw/noise) + ADSR envelope sliders with note preview | | Master section | master volume, brickwall limiter (toggle + threshold), real-time output LED meter | +| Live controller | play the selected track from the computer keyboard (`Z S X D C V G B H N J M…`, `-`/`=` octave) or a Web MIDI device, with held-note voices | Module positions persist across reloads (`voidstation-wall-v1`). @@ -57,7 +68,8 @@ Module positions persist across reloads (`voidstation-wall-v1`). delay (feedback loop), 3-band EQ (lowshelf 250 Hz / peaking 1 kHz / highshelf 4 kHz) — per-track, live and in export. - **Samples**: load a sample per track, canvas waveform with draggable - start/end trim handles, preview by clicking the wave. + start/end trim handles, preview by clicking the wave, tape-style pitch + (-24..+12 semitones) and a REVERSE toggle. - **Velocity accents**: each sequencer step carries a velocity (1.0 / 0.7 / 0.45). Right-click (or `Shift`+click) an active pad to cycle its accent; dimmer pads play softer. Applied to both sample triggers and synth notes, @@ -72,6 +84,17 @@ Module positions persist across reloads (`voidstation-wall-v1`). (`DynamicsCompressor`, toggle + threshold). A real-time output LED meter is fed by an `AnalyserNode` tapped after the limiter. All audible live and in the WAV export. +- **Live controller**: held-note synth voices (attack → decay → sustain until + release) from the computer keyboard or any Web MIDI input device; octave + shift, on-screen keys, device hot-plug. +- **Pattern copy/paste**: COPY grabs every track of the current pattern into + an in-memory clipboard, PASTE overwrites the active pattern (single undo + entry). +- **Sample pitch**: per-track tape-style playback rate in semitones + (-24..+12), applied live and in exports; a fresh sample load resets it. +- **Stem export**: `EXPORT STEMS` renders every track that plays anything in + the export region to its own WAV file (`voidstation-stem-01-kick.wav`, …), + fx chains and master bus included. - **Piano roll**: draw / resize / erase notes, real-time playback preview. - **Playlist**: patterns, clip drag & drop (move/swap), loop region rendered into the WAV export. @@ -105,8 +128,11 @@ src/ui/fx.ts — per-track reverb/delay/EQ rack src/ui/sampler.ts — sample load/trim/preview src/ui/instrument.ts — per-track synth editor (waveform + ADSR) src/ui/master.ts — master bus: volume, limiter, output meter +src/ui/keys.ts — live controller: computer keyboard + Web MIDI src/ui/app.ts — assembly: engine + wall + modules + wiring -src/styles/ — theme/base/racks/topbar/transport/drawer/sequencer/pianoroll/playlist/mixer/fx/sampler/instrument/master +tests/ — node:test suites (headless engine + WAV encoder) + run via `npm test` against the compiled dist/ +src/styles/ — theme/base/racks/topbar/transport/drawer/sequencer/pianoroll/playlist/mixer/fx/sampler/instrument/master/keys/dock ``` `dist/` (compiled JS) and `node_modules/` are git-ignored; the engine diff --git a/index.html b/index.html index 951cacb..9051749 100644 --- a/index.html +++ b/index.html @@ -19,9 +19,11 @@ + +
- +