vizcore 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,31 +1,34 @@
1
1
  # Vizcore [![Gem Version](https://badge.fury.io/rb/vizcore.svg)](https://badge.fury.io/rb/vizcore) [![CI](https://github.com/ydah/vizcore/actions/workflows/main.yml/badge.svg)](https://github.com/ydah/vizcore/actions/workflows/main.yml)
2
2
 
3
- Vizcore is a Ruby gem for building audio-reactive visuals with a Ruby DSL. Define scenes in pure Ruby, stream frames to the browser over WebSocket, and react to audio, beat, and MIDI in real time.
3
+ Vizcore is a Ruby gem for audio-reactive VJ visuals. Define scenes in Ruby, stream them to a browser renderer, and map audio analysis, beats, MIDI, OSC, and live controls to visual parameters.
4
4
 
5
- ## Installation
5
+ <p align="center">
6
+ <img src="docs/assets/vizcore-demo.gif" width="640" alt="Animated Vizcore demo where detected beats expand concentric rings" />
7
+ </p>
6
8
 
7
- ```bash
8
- gem install vizcore
9
- ```
9
+ ## Install
10
10
 
11
- Or add to your Gemfile:
11
+ Requirements:
12
12
 
13
- ```bash
14
- bundle add vizcore
15
- ```
16
-
17
- **System dependencies:**
13
+ - Ruby `>= 3.2`
14
+ - PortAudio for microphone input
15
+ - ffmpeg for MP3/FLAC input and MP4 output
16
+ - fftw3 optional for faster FFT analysis
18
17
 
19
- macOS:
20
18
  ```bash
21
- brew install portaudio ffmpeg # ffmpeg is needed for MP3/FLAC input and MP4 render output
22
- brew install fftw # optional: faster FFT
19
+ # macOS
20
+ brew install portaudio ffmpeg
21
+ brew install fftw # optional
22
+
23
+ # Ubuntu / Debian
24
+ sudo apt install -y libportaudio2 libportaudio-dev ffmpeg
25
+ sudo apt install -y libfftw3-dev # optional
23
26
  ```
24
27
 
25
- Ubuntu/Debian:
26
28
  ```bash
27
- sudo apt install -y libportaudio2 libportaudio-dev ffmpeg
28
- sudo apt install -y libfftw3-dev # optional: faster FFT
29
+ gem install vizcore
30
+ # or
31
+ bundle add vizcore
29
32
  ```
30
33
 
31
34
  ## Quick Start
@@ -33,673 +36,88 @@ sudo apt install -y libfftw3-dev # optional: faster FFT
33
36
  ```bash
34
37
  vizcore doctor
35
38
  vizcore demo
36
- vizcore start examples/basic.rb
37
- ```
38
-
39
- Then open `http://127.0.0.1:4567`.
40
-
41
- <p align="center">
42
- <img src="docs/assets/vizcore-demo.gif" width="640" alt="Animated Vizcore demo where detected beats expand concentric rings" />
43
- </p>
44
-
45
- This short preview is generated from `examples/readme_demo.rb` with the bundled
46
- demo audio: `beat_pulse -> ring radius`.
47
-
48
- ## Scene DSL
49
-
50
- Scenes are written in plain Ruby. Layers map audio analysis values to visual parameters:
51
-
52
- ```ruby
53
- Vizcore.define do
54
- scene :intro do
55
- layer :wireframe do
56
- type :wireframe_cube
57
- map amplitude => :rotation_speed
58
- map fft_spectrum => :deform
59
- map frequency_band(:high) => :color_shift
60
- end
61
- end
62
-
63
- scene :drop do
64
- layer :particles do
65
- type :particle_field
66
- count 3600
67
- map amplitude => :speed
68
- map frequency_band(:low) => :size
69
- end
70
-
71
- layer :waveform do
72
- type :waveform
73
- source :audio
74
- style :ribbon
75
- map amplitude, to: :height, range: 0.2..0.7
76
- end
77
-
78
- layer :spectrogram do
79
- type :spectrogram
80
- scroll :vertical
81
- map amplitude, to: :gain, range: 0.8..3.0
82
- end
83
-
84
- layer :mesh do
85
- type :mesh
86
- geometry :icosahedron
87
- material :wireframe
88
- map bass, to: :scale, range: 0.8..1.4
89
- map high, to: :deform
90
- end
91
-
92
- layer :rings do
93
- circle count: 8 do
94
- radius 100
95
- stroke 2
96
- map bass, to: :radius, range: 40..180
97
- end
98
- end
99
-
100
- layer :title do
101
- type :text
102
- content "DROP\nNOW"
103
- font "Inter Black"
104
- font_size 96
105
- letter_spacing 4
106
- align :center
107
- fill "#ffffff"
108
- stroke width: 2, color: "#111111"
109
- shadow color: "rgba(0, 0, 0, 0.45)", blur: 18
110
- map beat? => :flash
111
- end
112
-
113
- layer :logo do
114
- type :svg
115
- file "assets/logo.svg"
116
- scale 0.9
117
- map bass, to: :scale, range: 0.8..1.15
118
- end
119
-
120
- layer :photo do
121
- type :image
122
- file "assets/noise.png"
123
- fit :cover
124
- blend :screen
125
- map amplitude, to: :opacity, range: 0.25..0.85
126
- end
127
-
128
- layer :footage do
129
- type :video
130
- file "assets/loop.mp4"
131
- fit :cover
132
- map beat?, to: :invert
133
- end
134
- end
135
-
136
- transition from: :intro, to: :drop do
137
- on_bar 16
138
- effect :crossfade, duration: 1.4
139
- end
140
- end
141
- ```
142
-
143
- Mapping options can exaggerate small analysis values, clamp them into useful visual ranges, and smooth changes over time:
144
-
145
- ```ruby
146
- layer :liquid do
147
- shader :liquid_wobble
148
- wobble 0.25
149
- warp 0.45
150
-
151
- map amplitude, to: :wobble, gain: 3.5, range: 0.12..1.4, curve: :sqrt
152
- map frequency_band(:low), to: :warp, gain: 2.2, range: 0.25..2.4
153
- map onset(:high), to: :spark, range: 0.0..1.0
154
- map kick, to: :pulse, range: 0.0..1.0
155
- map beat_pulse, to: :effect_intensity, range: 0.08..0.35
156
- end
157
39
  ```
158
40
 
159
- Available transform options are `gain`, `range`, `min`, `max`, `curve`, `deadzone`, `attack`, and `release`. `curve` supports `:linear`, `:sqrt`, `:square`, and `:ease_out`. Existing mappings such as `map amplitude => :speed` continue to work.
160
- Use block syntax when shaping a mapping reads better:
41
+ Open `http://127.0.0.1:4567`.
161
42
 
162
- ```ruby
163
- map amplitude, to: :scale do
164
- gain 2.0
165
- range 0.8..1.6
166
- curve :ease_out
167
- smooth attack: 0.02, release: 0.18
168
- deadzone 0.05
169
- end
170
- ```
171
-
172
- Block syntax is additive and writes the same transform metadata as keyword
173
- syntax. `deadzone` suppresses tiny values before gain and curve are applied;
174
- `curve` also supports `:ease_out`.
175
-
176
- For tracks with very different levels, opt in to adaptive feature
177
- normalization at the top of the scene file:
178
-
179
- ```ruby
180
- audio_normalize mode: :adaptive, window: 3.0, target: 0.85, floor: 0.05
181
- ```
182
-
183
- This keeps `amplitude` and FFT-driven mappings in a repeatable range without
184
- changing the default analysis behavior.
185
-
186
- When the detected tempo should not drift during a prepared file or live set,
187
- lock BPM at the top of the scene file:
188
-
189
- ```ruby
190
- bpm 128
191
- bpm_lock true
192
- ```
193
-
194
- When you want to set tempo by ear from the browser during a live set, opt in to
195
- tap tempo and choose the keyboard key:
196
-
197
- ```ruby
198
- tap_tempo key: :space
199
- ```
200
-
201
- After two valid taps, Vizcore estimates BPM from recent intervals and applies it
202
- as a locked BPM so beat-driven visuals stop drifting.
203
-
204
- Browser keyboard shortcuts can also be declared in the scene file for operators
205
- who do not have a MIDI controller:
206
-
207
- ```ruby
208
- key "d" do
209
- switch_scene :drop
210
- end
211
-
212
- key "x" do
213
- blackout
214
- end
215
- ```
216
-
217
- For a more music-oriented style, `react_to` groups the same mappings by source:
218
-
219
- ```ruby
220
- layer :particles do
221
- type :particle_field
222
-
223
- react_to bass do
224
- change :size, gain: 4.0, range: 2.0..8.0, curve: :sqrt
225
- end
226
-
227
- react_to beat do
228
- trigger :burst
229
- end
230
- end
231
- ```
232
-
233
- `react_to` is additive syntax; it serializes to the same mapping model as `map`.
234
-
235
- Transitions can use explicit trigger blocks, or beat/bar helpers when that reads
236
- closer to the structure of a track:
237
-
238
- ```ruby
239
- transition from: :build, to: :drop do
240
- on_bar 8
241
- effect :flash, duration: 0.35
242
- end
243
- ```
244
-
245
- For simple song structure, `section` defines scenes in order and creates
246
- beat-counted transitions between adjacent sections:
247
-
248
- ```ruby
249
- section :intro, bars: 8 do
250
- layer :pulse do
251
- map amplitude => :scale
252
- end
253
- end
254
-
255
- section :drop, bars: 16 do
256
- layer :sparks do
257
- map beat? => :burst
258
- end
259
- end
260
- ```
261
-
262
- For file-backed shows or rehearsed sets, `timeline` can mark existing scenes at
263
- ordered beat or second positions and generate the transitions:
264
-
265
- ```ruby
266
- timeline do
267
- at beats(0), scene: :intro
268
- at bars(8), scene: :build
269
- at bars(16), scene: :drop
270
- end
271
- ```
272
-
273
- Layers can choose their compositing mode with `blend`. Supported modes are `:alpha` / `:normal`, `:add`, `:multiply`, `:screen`, and `:difference`:
274
-
275
- ```ruby
276
- layer :sparks do
277
- type :particle_field
278
- blend :screen
279
- map treble, to: :sparkle
280
- end
281
- ```
43
+ To run a scene file directly:
282
44
 
283
- Waveform layers draw the current audio features as browser line geometry. Use
284
- `style :line`, `:mirror`, or `:ribbon`; `source :audio` documents that the layer
285
- uses the active audio stream:
286
-
287
- ```ruby
288
- layer :scope do
289
- type :waveform
290
- source :audio
291
- style :ribbon
292
- map amplitude, to: :height, range: 0.2..0.7
293
- end
294
- ```
295
-
296
- Video layers embed MP4/WebM/OGV assets as muted looping textures. They share
297
- `fit`, `scale`, `rotation`, `blend`, and post-effect params with image layers:
298
-
299
- ```ruby
300
- layer :footage do
301
- type :video
302
- file "assets/loop.mp4"
303
- fit :cover
304
- map beat?, to: :invert
305
- end
306
- ```
307
-
308
- Spectrogram layers render a short scrolling FFT heatmap. Use `scroll :vertical`
309
- for a waterfall view or `scroll :horizontal` when time should move left to right:
310
-
311
- ```ruby
312
- layer :waterfall do
313
- type :spectrogram
314
- scroll :vertical
315
- bins 96
316
- history 128
317
- map amplitude, to: :gain, range: 0.8..3.0
318
- end
319
- ```
320
-
321
- Mesh layers render preset 3D wireframes without writing GLSL. Available
322
- geometry presets are `:cube`, `:tetrahedron`, `:octahedron`, and
323
- `:icosahedron`; use `material :wireframe`:
324
-
325
- ```ruby
326
- layer :mesh do
327
- type :mesh
328
- geometry :icosahedron
329
- material :wireframe
330
- map bass, to: :scale, range: 0.8..1.4
331
- map high, to: :deform
332
- end
333
- ```
334
-
335
- Shape layers provide declarative circles and lines for scenes that do not need
336
- custom GLSL. Shape-local mappings target the primitive inside the block:
337
-
338
- ```ruby
339
- layer :rings do
340
- circle count: 8 do
341
- radius 100
342
- stroke 2
343
- map bass, to: :radius, range: 40..180
344
- end
345
-
346
- draw do
347
- line x1: 0, y1: 360, x2: 1280, y2: 360
348
- end
349
- end
350
- ```
351
-
352
- Layers can also apply browser-side post effects. Supported effects are
353
- `:bloom`, `:glitch`, `:chromatic`, `:feedback`, `:motion_blur`, and `:crt`:
354
-
355
- ```ruby
356
- layer :tunnel do
357
- shader :bass_tunnel
358
- effect :motion_blur
359
- map bass, to: :effect_intensity, range: 0.1..0.7
360
- end
361
- ```
362
-
363
- Reusable layer styles keep repeated visual params in one place:
364
-
365
- ```ruby
366
- style :neon do
367
- palette "#00ffff", "#ff00aa", "#facc15"
368
- glow_strength 0.45
369
- blend :add
370
- end
371
-
372
- scene :drop do
373
- layer :title do
374
- type :text
375
- use_style :neon
376
- content "DROP"
377
- end
378
- end
379
- ```
380
-
381
- Themes provide scene-wide layer defaults:
382
-
383
- ```ruby
384
- theme :ruby_night do
385
- palette "#e11d48", "#f59e0b", "#38bdf8"
386
- glow_strength 0.5
387
- blend :screen
388
- end
389
-
390
- scene :drop do
391
- use_theme :ruby_night
392
-
393
- layer :title do
394
- type :text
395
- content "DROP"
396
- end
397
- end
398
- ```
399
-
400
- Layer groups apply shared params to a subset of adjacent layers while keeping the
401
- runtime payload as normal ordered layers:
402
-
403
- ```ruby
404
- scene :drop do
405
- group :foreground do
406
- use_style :neon
407
- blend :add
408
- opacity 0.9
409
-
410
- layer(:particles) { type :particle_field }
411
- layer(:title) { type :text }
412
- end
413
- end
414
- ```
415
-
416
- Scenes can inherit shared layers from an earlier scene:
417
-
418
- ```ruby
419
- scene :base do
420
- layer(:background) { shader :neon_grid }
421
- end
422
-
423
- scene :drop, extends: :base do
424
- layer(:particles) { type :particle_field }
425
- end
426
- ```
427
-
428
- Frequency bands can be written with musical aliases when that reads better in a scene:
429
-
430
- ```ruby
431
- map bass, to: :size # same as frequency_band(:low)
432
- map mid, to: :twist
433
- map treble, to: :sparkle # same as frequency_band(:high)
434
- map beat_confidence, to: :sync_strength
435
- ```
436
-
437
- ### Custom GLSL Shaders
438
-
439
- Built-in shader presets include `:gradient_pulse`, `:bass_tunnel`,
440
- `:neon_grid`, `:kaleidoscope`, `:spectrum_rings`, `:liquid_wobble`,
441
- `:audio_bars`, `:ruby_crystal`, `:starfield`, `:waveform_ribbon`,
442
- `:unyo_geometry`, and `:glitch_flash`.
443
-
444
- ```ruby
445
- layer :wave_shader do
446
- type :shader
447
- glsl "shaders/custom_wave.frag"
448
- param :intensity, default: 0.6, range: 0.0..2.0, step: 0.05
449
- map amplitude => :param_intensity
450
- map frequency_band(:low) => :param_bass
451
- map beat? => :param_flash
452
- end
453
- ```
454
-
455
- Path-style shader declarations are also accepted, so `shader "shaders/liquid.frag", reload: true` is equivalent to `glsl "shaders/liquid.frag"` for custom fragment shaders. When hot reload is enabled, Vizcore watches referenced GLSL files and pushes updated shader source to connected browsers.
456
-
457
- Use `vizcore shader new liquid` to create `shaders/liquid.frag` with a GLSL ES
458
- starter template.
459
-
460
- Custom fragment shaders must be GLSL ES 3.00. Run `vizcore shader-docs`
461
- to print the generated uniform reference. Common uniforms include:
462
-
463
- - `u_amplitude`
464
- - `u_bass` / `u_mid` / `u_high`
465
- - `u_beat`
466
- - `u_beat_pulse`
467
- - `u_onset` / `u_low_onset` / `u_mid_onset` / `u_high_onset`
468
- - `u_kick` / `u_snare` / `u_hihat`
469
- - `u_bpm`
470
- - `u_fft[32]`
471
- - `u_fft_size`
472
- - `u_param_<name>`
473
- - `u_global_<name>`
474
-
475
- For backward compatibility, a DSL target like `:param_intensity` is also exposed as `u_param_intensity`.
476
- Runtime globals set with `set :global_intensity, 0.75` are exposed as `u_global_intensity`.
477
- Use `param :name, default:, range:, step:` to attach numeric metadata for shader
478
- params that can be surfaced by tooling.
479
- The browser HUD turns this metadata into per-layer shader parameter sliders, so
480
- declared params can be adjusted during a live run without editing the scene file.
481
-
482
- ### Plugin Layer Capabilities
483
-
484
- Plugins can register layer capability metadata for validation, docs, and HUD
485
- tooling without patching Vizcore itself:
486
-
487
- ```ruby
488
- # in a plugin file loaded by Ruby
489
- Vizcore.register_layer_capability(
490
- type: :laser_grid,
491
- aliases: %i[laser_layer],
492
- params: { beam_count: "Integer", intensity: "Float" },
493
- mappable_params: %i[intensity opacity],
494
- description: "Plugin laser renderer."
495
- )
45
+ ```bash
46
+ vizcore start examples/basic.rb
47
+ vizcore start examples/vj_techno_warehouse.rb --audio-source file --audio-file examples/assets/complex_demo_loop.wav
496
48
  ```
497
49
 
498
- Load a plugin with `Vizcore.plugin "vizcore-laser-grid"` before defining
499
- scenes. A plugin-provided browser renderer or shader still needs to handle the
500
- custom layer type at runtime; the capability API keeps Ruby validation and docs
501
- aware of the extension.
50
+ ## Minimal Scene
502
51
 
503
- `vizcore plugin new laser-grid` creates a small plugin scaffold with a Ruby
504
- capability file, a browser renderer that registers with
505
- `globalThis.VizcorePlugins`, and an example scene. The browser plugin API exposes
506
- `apiVersion` and version 1 supports `registerLayerRenderer(type, renderer)` for
507
- line renderers and `registerShaderRenderer(type, renderer)` for shader
508
- renderers. Browser plugin renderers can return
509
- `{ kind: "lines", points: [...], color: [r, g, b] }`; shader renderers can return
510
- a GLSL fragment shader string or `{ kind: "shader", fragmentShader }`. Vizcore
511
- composites the result using the layer's normal `opacity`, `blend`, and palette
512
- behavior.
513
-
514
- ### MIDI Scene Switching
52
+ Scenes are plain Ruby files:
515
53
 
516
54
  ```ruby
517
55
  Vizcore.define do
518
- set :global_intensity, 0.65
519
-
520
- midi :controller, device: :default
521
-
522
- scene :warmup do
523
- layer :grid do
524
- shader :waveform_ribbon
525
- map frequency_band(:mid) => :intensity
56
+ scene :readme_demo do
57
+ layer :beat_rings do
58
+ palette "#24f6ff", "#ff2bbd", "#caff2e"
59
+
60
+ circle count: 4 do
61
+ radius 92
62
+ stroke 3
63
+ map beat_pulse,
64
+ to: :radius,
65
+ gain: 160.0,
66
+ min: 56,
67
+ max: 164,
68
+ attack: 1.0,
69
+ release: 0.2
70
+ end
526
71
  end
527
72
  end
528
-
529
- midi_map note: 36 do
530
- switch_scene :impact
531
- end
532
-
533
- midi_map cc: 1 do |value|
534
- set :global_intensity, value / 127.0
535
- end
536
73
  end
537
74
  ```
538
75
 
539
- ## CLI
76
+ Run it with:
540
77
 
541
78
  ```bash
542
- vizcore start [SCENE_FILE] [--manifest vizcore.yml] [--host 127.0.0.1] [--port 4567] [--audio-source mic|file|dummy] [--audio-file PATH] [--audio-device INDEX_OR_NAME] [--feature-file features.json] [--control-preset controls.json] [--osc-port 9000] [--noise-gate RMS] [--bpm BPM --bpm-lock] [--reload|--no-reload] [--projector]
543
- vizcore demo [--host 127.0.0.1] [--port 4567] [--control-preset controls.json] [--osc-port 9000] [--projector]
544
- vizcore doctor
545
- vizcore validate SCENE_FILE
546
- vizcore inspect SCENE_FILE
547
- vizcore snapshot SCENE_FILE [--audio-source dummy|file|mic] [--audio-file PATH] [--out screenshot.png]
548
- vizcore render SCENE_FILE [--audio-source dummy|file|mic] [--audio-file PATH] [--out frames|movie.mp4] [--frames 60] [--fps 30]
549
- vizcore capture SCENE_FILE [--audio-source dummy|file|mic] [--out browser-capture.png]
550
- vizcore browser-capture http://127.0.0.1:4567/projector [--out browser-capture.png]
551
- vizcore record-features AUDIO_FILE [--out features.json] [--frames 300] [--fps 30]
552
- vizcore gallery [--host 127.0.0.1] [--port 4568]
553
- vizcore layers
554
- vizcore dsl-docs
555
- vizcore shader new NAME [--out shaders/name.frag]
556
- vizcore shader-docs
557
- vizcore plugin new NAME [--out plugins/name]
558
- vizcore new PROJECT_NAME [--template standard|minimal|shader|midi|live-set|rubykaigi]
559
- vizcore devices [audio|midi]
79
+ vizcore start scene.rb
560
80
  ```
561
81
 
562
- ### Audio Sources
563
-
564
- | Source | Description |
565
- |--------|-------------|
566
- | `mic` | Live microphone input (default) |
567
- | `file` | File playback — `.wav` directly, `.mp3`/`.flac` via `ffmpeg` |
568
- | `dummy` | Silent source for layout testing |
82
+ ## Useful Commands
569
83
 
570
84
  ```bash
571
- # Microphone
572
- vizcore start examples/audio_inspector.rb --audio-source mic
573
-
574
- # Specific microphone device
85
+ vizcore start SCENE_FILE
86
+ vizcore start --manifest vizcore.yml
87
+ vizcore gallery
88
+ vizcore validate SCENE_FILE
575
89
  vizcore devices audio
576
- vizcore start examples/audio_inspector.rb --audio-source mic --audio-device 5
577
-
578
- # Lower this when the selected input is too quiet to move the visual
579
- vizcore start examples/audio_inspector.rb --audio-source mic --audio-device 5 --noise-gate 0.001
580
-
581
- # WAV file
582
- vizcore start scene.rb --audio-source file --audio-file track.wav
583
-
584
- # MP3/FLAC (requires ffmpeg)
585
- vizcore start scene.rb --audio-source file --audio-file set.mp3
586
-
587
- # Recorded analysis features
588
- vizcore record-features track.wav --out features.json --frames 300 --fps 30
589
- vizcore start scene.rb --feature-file features.json
90
+ vizcore devices midi
91
+ vizcore snapshot SCENE_FILE --out screenshot.png
590
92
  ```
591
93
 
592
- When using file source, the HUD exposes **Play Audio** / **Pause Audio** controls and shows BPM, Beat, and Beat Count.
94
+ Use `vizcore help` for the full CLI.
593
95
 
594
- The browser HUD also includes an Audio Inspector with amplitude, sub/low/mid/high meters, FFT preview bars, a performance monitor for FPS/frame/latency/drop/audio/shader/reconnect health, shader compile error overlay, emergency Blackout/Freeze controls, and Visual Gain, Bass Boost, Smoothing, Beat Hold, and Wobble controls for adapting visual response to different tracks and input levels. Reactivity controls can be saved, loaded, imported, and exported for repeatable HUD presets. When `--control-preset` or manifest `control_preset` is writable, the HUD also shows **Save Project** to write the current reactivity and MIDI Learn bindings back to that JSON file. MIDI Learn can bind Web MIDI note/CC/program messages to the current scene, Blackout/Freeze, or reactivity controls. Scene launcher entries can be selected with `1`-`9`, and scene-defined `key` mappings can switch scenes or toggle live controls. Use `--projector` or open `/projector` when the browser output should hide operator UI, and open `/control` for a separate operator panel.
595
-
596
- Project manifests keep show startup repeatable:
597
-
598
- ```yaml
599
- # vizcore.yml
600
- scene: scenes/show.rb
601
- audio:
602
- source: file
603
- file: audio/set.wav
604
- control_preset: controls/live.json
605
- sync:
606
- osc:
607
- port: 9000
608
- plugins:
609
- - require: vizcore-laser-grid
610
- frontend: frontend/laser-grid-renderer.js
611
- plugin_assets:
612
- - frontend/local-overlay.js
613
- profiles:
614
- rehearsal:
615
- audio:
616
- source: dummy
617
- control_preset: controls/rehearsal.json
618
- ```
96
+ Browser routes:
619
97
 
620
- Start it with `vizcore start --manifest vizcore.yml`, or
621
- `vizcore start --manifest vizcore.yml --profile rehearsal` for profile-specific
622
- overrides. Manifest plugin `frontend` entries and `plugin_assets` are served by
623
- RackApp and loaded before `/src/main.js`. A control preset JSON can include
624
- `visual_settings` and `midi_learn_bindings`; Vizcore sends it through `/runtime`
625
- and the browser applies it to HUD reactivity and MIDI Learn state.
626
- Set `--osc-port` or `sync.osc.port` to receive OSC controls:
627
- `/vizcore/scene` with a string scene name, `/vizcore/tap`,
628
- `/vizcore/bpm`, `/vizcore/bpm_unlock`, `/vizcore/global/<name>`,
629
- `/vizcore/live/blackout`, `/vizcore/live/freeze`, and
630
- `/vizcore/transport/play` or `/vizcore/transport/stop` for file transport.
98
+ - `/` visual output with operator controls
99
+ - `/projector` clean projection output
100
+ - `/control` separate operator panel
631
101
 
632
- `vizcore demo` starts a bundled scene with bundled audio, so it is the quickest way to verify a fresh installation.
102
+ ## Documentation
633
103
 
634
- `vizcore start scene.rb --reload` watches the scene file and pushes changes to connected browsers without restarting the server. Hot reload is enabled by default; use `--no-reload` when you want a fixed scene for a show.
635
-
636
- Use `vizcore snapshot scene.rb --audio-source dummy --out screenshot.png` to create a software-rendered PNG preview for README, social cards, or quick visual checks without starting the browser.
637
-
638
- Use `vizcore render scene.rb --audio-source file --audio-file track.wav --out frames --frames 120 --fps 30` to write a software-rendered PNG image sequence, or `--out movie.mp4` to encode the frames to MP4 with `ffmpeg`.
639
-
640
- Use `vizcore browser-capture http://127.0.0.1:4567/projector --out browser.png`
641
- when you need a PNG from an already-running browser/WebGL renderer. Use
642
- `vizcore capture scene.rb --out browser.png` to start a temporary projector
643
- server, capture it, and stop the server automatically. Both commands require
644
- Playwright in the local Node environment.
645
-
646
- Use `vizcore record-features track.wav --out features.json --frames 300 --fps 30` to capture the same audio analysis values as JSON for debugging mappings or comparing tracks. Replay the file with `vizcore start scene.rb --feature-file features.json` when you want deterministic visual behavior without live audio input.
647
-
648
- ## Requirements
649
-
650
- - Ruby `>= 3.2`
651
- - `portaudio` for microphone input
652
- - `ffmpeg` on `PATH` when using `.mp3` / `.flac` file input or `.mp4` render output
653
- - `fftw3` (optional) — Vizcore falls back to pure-Ruby FFT automatically when unavailable
654
-
655
- ## Examples
656
-
657
- Run `vizcore gallery` to open a browser gallery of bundled examples with scene counts, layer counts, audio-source hints, and launch commands.
658
-
659
- | File | Description |
660
- |------|-------------|
661
- | `examples/basic.rb` | Single wireframe cube layer |
662
- | `examples/intro_drop.rb` | Beat-triggered scene transition |
663
- | `examples/file_audio_demo.rb` | File audio source walkthrough |
664
- | `examples/complex_audio_showcase.rb` | Dense multi-layer showcase |
665
- | `examples/rhythm_geometry.rb` | Single large morphing geometric pattern scene with drum-reactive motion |
666
- | `examples/ruby_crystal_show.rb` | Ruby-themed crystal, particles, and title visual |
667
- | `examples/parser_visualizer.rb` | Parser-themed token, AST, and reduce visual sketch |
668
- | `examples/live_coding_minimal.rb` | Tiny scene for live-coding demos |
669
- | `examples/club_intro_drop.rb` | Intro, build, and drop flow for rhythmic file input |
670
- | `examples/shader_playground.rb` | Focused shader scene with declared params |
671
- | `examples/audio_inspector.rb` | Audio bars and blob for analysis visualization |
672
- | `examples/readme_demo.rb` | Minimal beat pulse to ring radius demo |
673
- | `examples/midi_scene_switch.rb` | MIDI-driven scene switching |
674
- | `examples/midi_controller_show.rb` | MIDI pads for scenes and knobs for global shader intensity/color |
675
- | `examples/kansai_rubykaigi_visual.rb` | Event showcase with ruby crystal, water ripple, and Kyoto-inspired pattern |
676
- | `examples/custom_shader.rb` | Custom GLSL shader with audio mapping |
677
- | `examples/unyo_liquid.rb` | Organic liquid wobble scene with FFT blob and particles |
678
-
679
- ### VJ Set Examples
680
-
681
- Ready-to-run scenes grouped by genre / mood. Each accepts live mic input or any
682
- audio file, including the bundled `examples/assets/complex_demo_loop.wav`.
683
-
684
- | File | Genre / Mood | BPM | Scenes | Notes |
685
- |------|--------------|-----|--------|-------|
686
- | `examples/vj_techno_warehouse.rb` | Techno / Warehouse | 128-140 | 4 | wireframe + particles |
687
- | `examples/vj_dnb_jungle.rb` | Drum & Bass / Jungle | 170-180 | 3 | kick/snare/hihat split |
688
- | `examples/vj_ambient_chill_room.rb` | Ambient / Chill | 60-90 | 2 | beatless, drone-friendly |
689
- | `examples/vj_hiphop_cipher.rb` | HipHop / Cipher | 85-100 | 3 | text-forward |
690
- | `examples/vj_jpop_idol_live.rb` | J-POP / Idol | 130-180 | 4 | color fields + tap tempo |
691
- | `examples/vj_synthwave_retro.rb` | Synthwave / Retro | 100-120 | 3 | circle and line primitives |
692
- | `examples/vj_glitch_industrial.rb` | Glitch / Industrial | n/a | 3 | feedback + difference blend |
693
- | `examples/vj_festival_mainstage.rb` | EDM / Mainstage | 124-132 | 5 | uses `extends:` and `group` |
104
+ - Project site: <https://ydah.github.io/vizcore/>
105
+ - Examples: [examples/README.md](examples/README.md)
106
+ - Changelog: [CHANGELOG.md](CHANGELOG.md)
107
+ - Runtime layer reference: `vizcore layers`
108
+ - Ruby DSL reference: `vizcore dsl-docs`
109
+ - Shader uniform reference: `vizcore shader-docs`
694
110
 
695
111
  ## Development
696
112
 
697
113
  ```bash
114
+ bundle install
115
+ npm install --prefix frontend
698
116
  bundle exec rspec
699
117
  npm --prefix frontend test
118
+ bundle exec rake release:verify
700
119
  ```
701
120
 
702
-
703
121
  ## License
704
122
 
705
123
  MIT