vizcore 0.1.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.
- checksums.yaml +4 -4
- data/README.md +70 -117
- data/docs/.nojekyll +0 -0
- data/docs/assets/playground-worker.js +373 -0
- data/docs/assets/playground.css +440 -0
- data/docs/assets/playground.js +652 -0
- data/docs/assets/site.css +744 -0
- data/docs/assets/vizcore-demo.gif +0 -0
- data/docs/assets/vizcore-poster.png +0 -0
- data/docs/assets/vj-tunnel.js +159 -0
- data/docs/index.html +225 -0
- data/docs/playground.html +81 -0
- data/docs/shape_dsl.md +269 -0
- data/examples/README.md +59 -0
- data/examples/assets/README.md +19 -0
- data/examples/audio_inspector.rb +34 -0
- data/examples/club_intro_drop.rb +78 -0
- data/examples/kansai_rubykaigi_visual.rb +70 -0
- data/examples/live_coding_minimal.rb +22 -0
- data/examples/midi_controller_show.rb +78 -0
- data/examples/midi_scene_switch.rb +3 -1
- data/examples/parser_visualizer.rb +48 -0
- data/examples/readme_demo.rb +17 -0
- data/examples/rhythm_geometry.rb +34 -0
- data/examples/ruby_crystal_show.rb +35 -0
- data/examples/shader_playground.rb +18 -0
- data/examples/unyo_liquid.rb +59 -0
- data/examples/vj_ambient_chill_room.rb +124 -0
- data/examples/vj_dnb_jungle.rb +170 -0
- data/examples/vj_festival_mainstage.rb +245 -0
- data/examples/vj_festival_mainstage.yml +17 -0
- data/examples/vj_glitch_industrial.rb +164 -0
- data/examples/vj_hiphop_cipher.rb +167 -0
- data/examples/vj_jpop_idol_live.rb +210 -0
- data/examples/vj_synthwave_retro.rb +173 -0
- data/examples/vj_techno_warehouse.rb +195 -0
- data/frontend/index.html +494 -2
- data/frontend/src/audio-inspector.js +40 -0
- data/frontend/src/custom-shape-param-controls.js +106 -0
- data/frontend/src/live-controls.js +131 -0
- data/frontend/src/main.js +1060 -16
- data/frontend/src/mapping-target-selector.js +109 -0
- data/frontend/src/midi-learn.js +194 -0
- data/frontend/src/performance-monitor.js +183 -0
- data/frontend/src/plugin-runtime.js +130 -0
- data/frontend/src/projector-mode.js +56 -0
- data/frontend/src/renderer/engine.js +157 -3
- data/frontend/src/renderer/layer-manager.js +442 -30
- data/frontend/src/renderer/shader-manager.js +26 -0
- data/frontend/src/runtime-control-preset.js +11 -0
- data/frontend/src/shader-error-overlay.js +29 -0
- data/frontend/src/shader-param-controls.js +93 -0
- data/frontend/src/shaders/builtins.js +380 -2
- data/frontend/src/shaders/post-effects.js +52 -0
- data/frontend/src/shape-editor-controls.js +157 -0
- data/frontend/src/visual-regression.js +67 -0
- data/frontend/src/visual-settings-preset.js +103 -0
- data/frontend/src/visuals/geometry.js +666 -0
- data/frontend/src/visuals/image-renderer.js +291 -0
- data/frontend/src/visuals/particle-system.js +56 -10
- data/frontend/src/visuals/shape-renderer.js +475 -0
- data/frontend/src/visuals/spectrogram-renderer.js +226 -0
- data/frontend/src/visuals/svg-arc.js +104 -0
- data/frontend/src/visuals/text-renderer.js +112 -11
- data/frontend/src/websocket-client.js +12 -1
- data/lib/vizcore/analysis/adaptive_normalizer.rb +70 -0
- data/lib/vizcore/analysis/beat_detector.rb +4 -2
- data/lib/vizcore/analysis/bpm_estimator.rb +8 -0
- data/lib/vizcore/analysis/feature_recorder.rb +159 -0
- data/lib/vizcore/analysis/feature_replay.rb +84 -0
- data/lib/vizcore/analysis/pipeline.rb +235 -11
- data/lib/vizcore/analysis/tap_tempo.rb +74 -0
- data/lib/vizcore/analysis.rb +4 -0
- data/lib/vizcore/audio/dummy_sine_input.rb +1 -1
- data/lib/vizcore/audio/fixture_input.rb +65 -0
- data/lib/vizcore/audio/input_manager.rb +4 -2
- data/lib/vizcore/audio/mic_input.rb +24 -8
- data/lib/vizcore/audio/portaudio_ffi.rb +106 -1
- data/lib/vizcore/audio.rb +1 -0
- data/lib/vizcore/cli/doctor.rb +159 -0
- data/lib/vizcore/cli/dsl_reference.rb +99 -0
- data/lib/vizcore/cli/layer_docs.rb +46 -0
- data/lib/vizcore/cli/scene_diagnostics.rb +23 -0
- data/lib/vizcore/cli/scene_inspector.rb +136 -0
- data/lib/vizcore/cli/scene_validator.rb +337 -0
- data/lib/vizcore/cli/shader_template.rb +68 -0
- data/lib/vizcore/cli/shader_uniform_docs.rb +54 -0
- data/lib/vizcore/cli.rb +689 -18
- data/lib/vizcore/config.rb +103 -2
- data/lib/vizcore/control_preset.rb +68 -0
- data/lib/vizcore/dsl/engine.rb +277 -5
- data/lib/vizcore/dsl/layer_builder.rb +1280 -23
- data/lib/vizcore/dsl/layer_group_builder.rb +112 -0
- data/lib/vizcore/dsl/mapping_resolver.rb +290 -7
- data/lib/vizcore/dsl/mapping_transform_builder.rb +71 -0
- data/lib/vizcore/dsl/reaction_builder.rb +44 -0
- data/lib/vizcore/dsl/scene_builder.rb +61 -5
- data/lib/vizcore/dsl/shader_source_resolver.rb +67 -6
- data/lib/vizcore/dsl/style_builder.rb +68 -0
- data/lib/vizcore/dsl/timeline_builder.rb +138 -0
- data/lib/vizcore/dsl/transition_controller.rb +77 -0
- data/lib/vizcore/dsl.rb +5 -1
- data/lib/vizcore/layer_catalog.rb +275 -0
- data/lib/vizcore/project_manifest.rb +152 -0
- data/lib/vizcore/renderer/png_writer.rb +57 -0
- data/lib/vizcore/renderer/render_sequence.rb +153 -0
- data/lib/vizcore/renderer/scene_frame_source.rb +132 -0
- data/lib/vizcore/renderer/scene_serializer.rb +36 -3
- data/lib/vizcore/renderer/snapshot.rb +38 -0
- data/lib/vizcore/renderer/snapshot_renderer.rb +938 -0
- data/lib/vizcore/renderer.rb +5 -0
- data/lib/vizcore/server/frame_broadcaster.rb +143 -8
- data/lib/vizcore/server/gallery_app.rb +155 -0
- data/lib/vizcore/server/gallery_page.rb +100 -0
- data/lib/vizcore/server/gallery_runner.rb +48 -0
- data/lib/vizcore/server/rack_app.rb +203 -4
- data/lib/vizcore/server/runner.rb +391 -22
- data/lib/vizcore/server/scene_dependency_watcher.rb +79 -0
- data/lib/vizcore/server/websocket_handler.rb +60 -10
- data/lib/vizcore/server.rb +4 -0
- data/lib/vizcore/shape.rb +719 -0
- data/lib/vizcore/sync/osc_message.rb +103 -0
- data/lib/vizcore/sync/osc_receiver.rb +68 -0
- data/lib/vizcore/sync.rb +4 -0
- data/lib/vizcore/templates/midi_control_scene.rb +3 -1
- data/lib/vizcore/templates/plugin_layer.rb +20 -0
- data/lib/vizcore/templates/plugin_readme.md +23 -0
- data/lib/vizcore/templates/plugin_renderer.js +43 -0
- data/lib/vizcore/templates/plugin_scene.rb +14 -0
- data/lib/vizcore/templates/project_readme.md +7 -23
- data/lib/vizcore/templates/rubykaigi_scene.rb +30 -0
- data/lib/vizcore/version.rb +1 -1
- data/lib/vizcore.rb +28 -0
- data/scripts/browser_capture.mjs +75 -0
- data/sig/vizcore.rbs +461 -0
- metadata +94 -3
- data/docs/GETTING_STARTED.md +0 -105
data/docs/shape_dsl.md
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Vizcore Shape DSL
|
|
2
|
+
|
|
3
|
+
Vizcore shape layers can declare 2D vector primitives directly in Ruby. Calling a
|
|
4
|
+
shape primitive inside a layer automatically marks that layer as `type: :shape`.
|
|
5
|
+
|
|
6
|
+
```ruby
|
|
7
|
+
Vizcore.define do
|
|
8
|
+
scene :logo do
|
|
9
|
+
layer :badge do
|
|
10
|
+
rect :panel, width: 360, height: 160, radius: 24 do
|
|
11
|
+
fill "#111827"
|
|
12
|
+
stroke width: 2, color: "#38bdf8"
|
|
13
|
+
opacity 0.8
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
star :spark, points: 5, radius: 72, inner_radius: 28 do
|
|
17
|
+
translate x: 180, y: 0
|
|
18
|
+
map beat_pulse, to: :scale, range: 0.8..1.4
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Primitives
|
|
26
|
+
|
|
27
|
+
Supported primitives:
|
|
28
|
+
|
|
29
|
+
- `circle id = nil, x: 0, y: 0, radius: 100, count: 1, segments: 96`
|
|
30
|
+
- `line id = nil, x1: -100, y1: 0, x2: 100, y2: 0`
|
|
31
|
+
- `rect id = nil, x: 0, y: 0, width:, height:, radius: 0`
|
|
32
|
+
- `polygon id = nil, points: [[x, y], ...], closed: true`
|
|
33
|
+
- `polyline id = nil, points: [[x, y], ...]`
|
|
34
|
+
- `path id = nil, detail: 32, tolerance: nil, max_segments: 4096 do ... end`
|
|
35
|
+
- `bezier id = nil, from:, control:, to:` for quadratic curves
|
|
36
|
+
- `bezier id = nil, from:, c1:, c2:, to:` for cubic curves
|
|
37
|
+
- `star id = nil, points: 5, radius: 100, inner_radius: 50`
|
|
38
|
+
- `custom_shape name_or_class, **params`
|
|
39
|
+
|
|
40
|
+
`draw do ... end` may be used to group declarations for readability.
|
|
41
|
+
`group do ... end` applies shared style and transform to child primitives.
|
|
42
|
+
|
|
43
|
+
## Path Commands
|
|
44
|
+
|
|
45
|
+
Path blocks support an SVG-like command subset:
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
path :blob, detail: 48 do
|
|
49
|
+
move_to 0, 120
|
|
50
|
+
line_to 120, 0
|
|
51
|
+
quad_to 80, -100, 0, -120
|
|
52
|
+
cubic_to -80, -100, -120, 80, 0, 120
|
|
53
|
+
close
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Commands are serialized as `M`, `L`, `Q`, `C`, `H`, `V`, `A`, and `Z`. The
|
|
58
|
+
Canvas2D renderer draws `arc_to` as an SVG-style elliptical arc, and the line
|
|
59
|
+
fallback/snapshot renderer flattens curves and arcs to line segments.
|
|
60
|
+
`detail` controls the default curve/arc subdivision count. When `tolerance` is
|
|
61
|
+
provided, quadratic and cubic curves use adaptive flattening instead. `max_segments`
|
|
62
|
+
caps the number of flattened line segments per path; the DSL raises when the
|
|
63
|
+
estimated flattened path would exceed that budget.
|
|
64
|
+
|
|
65
|
+
## Style And Transform
|
|
66
|
+
|
|
67
|
+
Inside a shape block, these methods target the shape rather than the layer:
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
fill "#f472b6"
|
|
71
|
+
stroke 2
|
|
72
|
+
stroke width: 3, color: "#ffffff"
|
|
73
|
+
blend :add
|
|
74
|
+
opacity 0.75
|
|
75
|
+
|
|
76
|
+
translate x: 100, y: 40
|
|
77
|
+
translate 100, 40
|
|
78
|
+
rotate 30
|
|
79
|
+
scale 1.2
|
|
80
|
+
scale x: 1.4, y: 0.8
|
|
81
|
+
origin x: 0, y: 0
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The transform order is origin adjustment, scale, rotate, then translate.
|
|
85
|
+
|
|
86
|
+
## Groups
|
|
87
|
+
|
|
88
|
+
Groups are flattened into child primitives during DSL evaluation. Child shapes
|
|
89
|
+
inherit style values they do not set themselves, and group opacity is multiplied
|
|
90
|
+
with child opacity.
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
group :spinner do
|
|
94
|
+
translate x: 0, y: 80
|
|
95
|
+
rotate 15
|
|
96
|
+
scale 1.2
|
|
97
|
+
opacity 0.75
|
|
98
|
+
stroke width: 2, color: "#38bdf8"
|
|
99
|
+
|
|
100
|
+
12.times do |index|
|
|
101
|
+
rect width: 12, height: 80 do
|
|
102
|
+
translate x: 0, y: 160
|
|
103
|
+
rotate index * 30
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Mapping
|
|
110
|
+
|
|
111
|
+
Mappings declared inside a shape block are scoped to that shape:
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
circle :ring, radius: 120 do
|
|
115
|
+
map bass, to: :radius, range: 80..240
|
|
116
|
+
map beat_pulse, to: :scale, range: 1.0..1.4
|
|
117
|
+
map high, to: :opacity, range: 0.2..1.0
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Transform aliases:
|
|
122
|
+
|
|
123
|
+
- `:translate_x` -> `transform.translate.x`
|
|
124
|
+
- `:translate_y` -> `transform.translate.y`
|
|
125
|
+
- `:rotate` and `:rotation` -> `transform.rotate`
|
|
126
|
+
- `:scale` -> `transform.scale`
|
|
127
|
+
- `:scale_x` -> `transform.scale.x`
|
|
128
|
+
- `:scale_y` -> `transform.scale.y`
|
|
129
|
+
- `:origin_x` -> `transform.origin.x`
|
|
130
|
+
- `:origin_y` -> `transform.origin.y`
|
|
131
|
+
|
|
132
|
+
You can also map to a named shape from the layer scope:
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
rect :panel, width: 360, height: 160
|
|
136
|
+
map bass, to: shape(:panel).rotate, range: -12..12
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Mappings inside a static `custom_shape` block are applied to each primitive
|
|
140
|
+
generated by that custom shape:
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
custom_shape :badge, radius: 120 do
|
|
144
|
+
fill "#22d3ee"
|
|
145
|
+
map beat_pulse, to: :scale, range: 0.8..1.2
|
|
146
|
+
end
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Custom Shapes
|
|
150
|
+
|
|
151
|
+
Custom shapes are registered in Ruby and expanded into regular shape
|
|
152
|
+
primitives before the browser receives the scene.
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
class DiamondShape
|
|
156
|
+
include Vizcore::Shape
|
|
157
|
+
|
|
158
|
+
param :radius, default: 100, min: 10, max: 400
|
|
159
|
+
|
|
160
|
+
def draw(ctx)
|
|
161
|
+
radius = ctx.param(:radius)
|
|
162
|
+
|
|
163
|
+
ctx.polygon points: [
|
|
164
|
+
[0, radius],
|
|
165
|
+
[radius, 0],
|
|
166
|
+
[0, -radius],
|
|
167
|
+
[-radius, 0]
|
|
168
|
+
]
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
Vizcore.register_shape :diamond, DiamondShape
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Use the registered shape from a layer:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
layer :generated_logo do
|
|
179
|
+
custom_shape :diamond, radius: 140 do
|
|
180
|
+
rotate 45
|
|
181
|
+
stroke width: 2, color: "#ffffff"
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Block registration is supported for small generators:
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
Vizcore.register_shape :spark do |ctx|
|
|
190
|
+
ctx.star points: 5, radius: ctx.param(:radius, 80), inner_radius: 32
|
|
191
|
+
end
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`draw(ctx)` may return a primitive hash, an array of primitive hashes, or build
|
|
195
|
+
primitives with `ctx.draw`, `ctx.circle`, `ctx.rect`, `ctx.path`, and the other
|
|
196
|
+
shape methods. Values declared with `param` are validated against their
|
|
197
|
+
`min`/`max` metadata before `draw(ctx)` runs, and dynamic custom shape
|
|
198
|
+
descriptors include the same schema for editor tooling.
|
|
199
|
+
|
|
200
|
+
By default, custom shapes are expanded when the DSL is evaluated. Use
|
|
201
|
+
`dynamic: true` when the generator needs mapped params, `ctx.time`, `ctx.frame`,
|
|
202
|
+
or `ctx.audio` at runtime:
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
custom_shape :orbit, count: 32, radius: 260, dynamic: true do
|
|
206
|
+
fill "#22d3ee"
|
|
207
|
+
map bass, to: :radius, range: 120..280
|
|
208
|
+
map beat_pulse, to: :scale, range: 0.8..1.2
|
|
209
|
+
end
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Inside a dynamic custom shape block, mappings to custom params such as `:radius`
|
|
213
|
+
are applied before `draw(ctx)` runs. Transform aliases such as `:scale` and
|
|
214
|
+
`:rotate` are applied to the generated primitives after expansion.
|
|
215
|
+
|
|
216
|
+
Use `static: true` for generators that are independent of runtime context. Static
|
|
217
|
+
custom shapes with identical renderer, params, layer context, palette, and
|
|
218
|
+
resolution reuse a cached expansion, while each call still receives its own copy
|
|
219
|
+
of the generated primitives.
|
|
220
|
+
|
|
221
|
+
## Coordinates
|
|
222
|
+
|
|
223
|
+
New shape schema layers use center-origin logical coordinates by default:
|
|
224
|
+
|
|
225
|
+
- `x` increases to the right.
|
|
226
|
+
- `y` increases upward.
|
|
227
|
+
- `x: 0, y: 0` is the center of the canvas.
|
|
228
|
+
|
|
229
|
+
Legacy `circle` and `line` layers without `shape_schema_version: 2` keep the old
|
|
230
|
+
coordinate heuristic for compatibility with existing examples.
|
|
231
|
+
|
|
232
|
+
Set `units :ndc` on the layer to use normalized device coordinates directly.
|
|
233
|
+
|
|
234
|
+
## Validation
|
|
235
|
+
|
|
236
|
+
The DSL raises early for malformed primitives:
|
|
237
|
+
|
|
238
|
+
- duplicate shape IDs within a layer
|
|
239
|
+
- negative `radius`, `inner_radius`, `width`, `height`, or `stroke_width`
|
|
240
|
+
- `polygon` with fewer than 3 points
|
|
241
|
+
- `polyline` with fewer than 2 points
|
|
242
|
+
- `path` without commands
|
|
243
|
+
- `path` whose estimated flattened segment count exceeds `max_segments`
|
|
244
|
+
- unknown `custom_shape`
|
|
245
|
+
- custom shapes that return unsupported primitive kinds
|
|
246
|
+
|
|
247
|
+
`vizcore validate` also emits warnings for shape payloads that are renderable but
|
|
248
|
+
likely surprising: unsupported primitive kinds in raw `params[:shapes]`, fills
|
|
249
|
+
that line fallback will ignore, opacity values outside `0..1`, and zero or very
|
|
250
|
+
large scale values that will collapse or clamp.
|
|
251
|
+
|
|
252
|
+
## Renderer Notes
|
|
253
|
+
|
|
254
|
+
The browser renderer uses a Canvas2D shape backend composited through the
|
|
255
|
+
existing WebGL layer pipeline. It supports fill, stroke color/width, opacity,
|
|
256
|
+
dash, line caps/joins, transforms, and logical/ndc coordinates for the shape
|
|
257
|
+
schema.
|
|
258
|
+
|
|
259
|
+
If Canvas2D is unavailable, the browser falls back to the existing line renderer.
|
|
260
|
+
That fallback ignores fill and only approximates stroke geometry. The software
|
|
261
|
+
snapshot renderer also uses line flattening.
|
|
262
|
+
|
|
263
|
+
The browser HUD includes local shape editor controls for resolved shape layers:
|
|
264
|
+
primitive kind, translate, rotate, scale, opacity, fill, stroke color, and stroke
|
|
265
|
+
width can be adjusted in the running view without mutating the source DSL file.
|
|
266
|
+
Dynamic custom shape params with `param` metadata are also exposed as HUD
|
|
267
|
+
controls; changing one sends a runtime override to the server so the Ruby custom
|
|
268
|
+
shape is re-expanded on the next frame. The HUD also lists valid mapping target
|
|
269
|
+
paths for layer params, primitive params/transforms, and custom shape params.
|
data/examples/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Vizcore Examples
|
|
2
|
+
|
|
3
|
+
Run the browser gallery for launch commands and scene metadata:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
vizcore gallery
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Most examples also work directly:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
vizcore start examples/basic.rb
|
|
13
|
+
vizcore start examples/audio_inspector.rb --audio-source mic
|
|
14
|
+
vizcore start examples/audio_inspector.rb --audio-source mic --noise-gate 0.001
|
|
15
|
+
vizcore start examples/vj_techno_warehouse.rb --audio-source file --audio-file examples/assets/complex_demo_loop.wav
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Core Examples
|
|
19
|
+
|
|
20
|
+
| File | Description |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `basic.rb` | Single wireframe cube layer |
|
|
23
|
+
| `intro_drop.rb` | Beat-triggered scene transition |
|
|
24
|
+
| `file_audio_demo.rb` | File audio source walkthrough |
|
|
25
|
+
| `complex_audio_showcase.rb` | Dense multi-layer showcase |
|
|
26
|
+
| `rhythm_geometry.rb` | Drum-reactive geometric pattern |
|
|
27
|
+
| `ruby_crystal_show.rb` | Ruby-themed crystal visual |
|
|
28
|
+
| `parser_visualizer.rb` | Parser-themed token and AST sketch |
|
|
29
|
+
| `live_coding_minimal.rb` | Tiny live-coding scene |
|
|
30
|
+
| `club_intro_drop.rb` | Intro, build, drop flow |
|
|
31
|
+
| `shader_playground.rb` | Focused shader params example |
|
|
32
|
+
| `audio_inspector.rb` | Audio feature visualization |
|
|
33
|
+
| `readme_demo.rb` | Minimal beat pulse to ring radius demo |
|
|
34
|
+
| `midi_scene_switch.rb` | MIDI scene switching |
|
|
35
|
+
| `midi_controller_show.rb` | MIDI pads and CC controls |
|
|
36
|
+
| `kansai_rubykaigi_visual.rb` | Event showcase visual |
|
|
37
|
+
| `custom_shader.rb` | Custom GLSL shader |
|
|
38
|
+
| `unyo_liquid.rb` | Liquid wobble and FFT blob |
|
|
39
|
+
|
|
40
|
+
## VJ Set Examples
|
|
41
|
+
|
|
42
|
+
Ready-to-run scenes grouped by genre / mood. All scenes accept live mic input
|
|
43
|
+
or any audio file. `B` toggles Blackout, `F` toggles Freeze, and scenes that
|
|
44
|
+
declare tap tempo use Space.
|
|
45
|
+
|
|
46
|
+
| File | Genre / Mood | BPM | Scenes | Notes |
|
|
47
|
+
|---|---|---|---|---|
|
|
48
|
+
| `vj_techno_warehouse.rb` | Techno / Warehouse | 128-140 | 4 | wireframe + particles |
|
|
49
|
+
| `vj_dnb_jungle.rb` | Drum & Bass / Jungle | 170-180 | 3 | kick/snare/hihat split |
|
|
50
|
+
| `vj_ambient_chill_room.rb` | Ambient / Chill | 60-90 | 2 | beatless, drone-friendly |
|
|
51
|
+
| `vj_hiphop_cipher.rb` | HipHop / Cipher | 85-100 | 3 | text-forward |
|
|
52
|
+
| `vj_jpop_idol_live.rb` | J-POP / Idol | 130-180 | 4 | color fields + tap tempo |
|
|
53
|
+
| `vj_synthwave_retro.rb` | Synthwave / Retro | 100-120 | 3 | circle and line primitives |
|
|
54
|
+
| `vj_glitch_industrial.rb` | Glitch / Industrial | n/a | 3 | feedback + difference blend |
|
|
55
|
+
| `vj_festival_mainstage.rb` | EDM / Mainstage | 124-132 | 5 | uses `extends:` and `group` |
|
|
56
|
+
|
|
57
|
+
Use `examples/vj_festival_mainstage.yml` as a manifest pattern for file-audio
|
|
58
|
+
rehearsal. Replace `audio_file` with your set recording or switch to
|
|
59
|
+
`audio_source: mic` for live input.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Example Assets
|
|
2
|
+
|
|
3
|
+
`complex_demo_loop.wav` is bundled for repeatable file-audio testing.
|
|
4
|
+
|
|
5
|
+
For logos or show-specific art, place your own files in this directory and
|
|
6
|
+
reference them from a scene:
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
layer :logo do
|
|
10
|
+
type :svg
|
|
11
|
+
file "assets/your_logo.svg"
|
|
12
|
+
fit :contain
|
|
13
|
+
map beat_pulse, to: :scale, range: 0.9..1.08
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
No copyrighted venue logos, artist marks, photos, or fonts are bundled with
|
|
18
|
+
Vizcore examples. Keep those assets local to your project unless you have the
|
|
19
|
+
right to redistribute them.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Visualizes the same audio features shown in the HUD inspector.
|
|
4
|
+
Vizcore.define do
|
|
5
|
+
audio_normalize mode: :adaptive, window: 2.0, target: 0.85, floor: 0.001
|
|
6
|
+
|
|
7
|
+
scene :audio_inspector do
|
|
8
|
+
layer :bars do
|
|
9
|
+
shader :audio_bars
|
|
10
|
+
param :bar_count, default: 32.0, range: 12.0..64.0, step: 1.0
|
|
11
|
+
param :floor_glow, default: 0.18, range: 0.0..1.0, step: 0.02
|
|
12
|
+
blend :screen
|
|
13
|
+
map amplitude, to: :floor_glow, gain: 1.6, range: 0.08..0.5
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
layer :peak_blob do
|
|
17
|
+
type :radial_blob
|
|
18
|
+
radius 0.28
|
|
19
|
+
wobble 0.35
|
|
20
|
+
blend :add
|
|
21
|
+
map amplitude, to: :radius, range: 0.22..0.58, curve: :sqrt
|
|
22
|
+
map fft_spectrum => :spectrum
|
|
23
|
+
map treble, to: :wobble, range: 0.2..1.2
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
layer :label do
|
|
27
|
+
type :text
|
|
28
|
+
content "AUDIO"
|
|
29
|
+
font_size 76
|
|
30
|
+
glow_strength 0.2
|
|
31
|
+
map beat_pulse, to: :glow_strength, range: 0.12..0.8
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# File-audio friendly intro -> build -> drop flow.
|
|
4
|
+
Vizcore.define do
|
|
5
|
+
scene :intro do
|
|
6
|
+
layer :grid do
|
|
7
|
+
shader :neon_grid
|
|
8
|
+
opacity 0.75
|
|
9
|
+
map mid, to: :effect_intensity, range: 0.08..0.28
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
layer :title do
|
|
13
|
+
type :text
|
|
14
|
+
content "INTRO"
|
|
15
|
+
font_size 84
|
|
16
|
+
map beat_pulse, to: :glow_strength, range: 0.12..0.65
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
scene :build do
|
|
21
|
+
layer :rings do
|
|
22
|
+
shader :spectrum_rings
|
|
23
|
+
blend :screen
|
|
24
|
+
map bass, to: :effect_intensity, gain: 1.4, range: 0.16..0.5
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
layer :particles do
|
|
28
|
+
type :particle_field
|
|
29
|
+
count 2200
|
|
30
|
+
blend :add
|
|
31
|
+
map amplitude, to: :speed, range: 0.4..3.2
|
|
32
|
+
map treble, to: :sparkle, range: 0.0..0.9
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
scene :drop do
|
|
37
|
+
layer :tunnel do
|
|
38
|
+
shader :bass_tunnel
|
|
39
|
+
blend :screen
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
layer :flash do
|
|
43
|
+
shader :glitch_flash
|
|
44
|
+
blend :add
|
|
45
|
+
map beat_pulse, to: :intensity, range: 0.2..1.0, attack: 1.0, release: 0.08
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
layer :drop_text do
|
|
49
|
+
type :text
|
|
50
|
+
content "DROP"
|
|
51
|
+
font_size 122
|
|
52
|
+
blend :screen
|
|
53
|
+
map beat_pulse, to: :glow_strength, range: 0.3..1.0
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
transition from: :intro, to: :build do
|
|
58
|
+
trigger { beat_count >= 32 || frame_count >= 240 }
|
|
59
|
+
effect :crossfade, duration: 1.0
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
transition from: :build, to: :drop do
|
|
63
|
+
trigger { beat_count >= 64 || frame_count >= 480 }
|
|
64
|
+
effect :flash, duration: 0.35
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
key "i" do
|
|
68
|
+
switch_scene :intro
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
key "u" do
|
|
72
|
+
switch_scene :build
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
key "d" do
|
|
76
|
+
switch_scene :drop
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Kansai RubyKaigi visual: ruby crystal, water ripple, geometric pattern, and title.
|
|
4
|
+
Vizcore.define do
|
|
5
|
+
scene :kansai_rubykaigi do
|
|
6
|
+
layer :lake_ripple do
|
|
7
|
+
shader :liquid_wobble
|
|
8
|
+
wobble 0.18
|
|
9
|
+
warp 0.32
|
|
10
|
+
distortion 0.16
|
|
11
|
+
opacity 0.86
|
|
12
|
+
blend :screen
|
|
13
|
+
effect :feedback
|
|
14
|
+
effect_intensity 0.08
|
|
15
|
+
|
|
16
|
+
map bass, to: :wobble, gain: 0.9, range: 0.12..0.58, curve: :sqrt
|
|
17
|
+
map mid, to: :warp, gain: 1.2, range: 0.22..1.45
|
|
18
|
+
map high, to: :effect_intensity, range: 0.04..0.22
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
layer :kyoto_pattern do
|
|
22
|
+
shader :kaleidoscope
|
|
23
|
+
opacity 0.34
|
|
24
|
+
blend :add
|
|
25
|
+
vj_effect :mirror
|
|
26
|
+
effect_intensity 0.18
|
|
27
|
+
|
|
28
|
+
map mid, to: :effect_intensity, gain: 1.2, range: 0.08..0.42
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
layer :ruby_glow do
|
|
32
|
+
shader :ruby_crystal
|
|
33
|
+
facets 8.0
|
|
34
|
+
refraction 0.52
|
|
35
|
+
opacity 0.82
|
|
36
|
+
blend :screen
|
|
37
|
+
effect :bloom
|
|
38
|
+
|
|
39
|
+
map bass, to: :refraction, gain: 0.9, range: 0.34..0.86, curve: :sqrt
|
|
40
|
+
map beat_pulse, to: :effect_intensity, range: 0.12..0.72
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
layer :spark_line do
|
|
44
|
+
type :particle_field
|
|
45
|
+
count 1800
|
|
46
|
+
force_field :vortex
|
|
47
|
+
turbulence 0.18
|
|
48
|
+
blend :add
|
|
49
|
+
|
|
50
|
+
map amplitude, to: :speed, gain: 2.2, range: 0.25..4.2, curve: :sqrt
|
|
51
|
+
map bass, to: :size, gain: 2.0, range: 1.4..5.4
|
|
52
|
+
map hihat, to: :sparkle, gain: 2.4, range: 0.0..1.0
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
layer :event_title do
|
|
56
|
+
type :text
|
|
57
|
+
content "KANSAI RUBYKAIGI"
|
|
58
|
+
font "IBM Plex Sans"
|
|
59
|
+
font_size 66
|
|
60
|
+
align :center
|
|
61
|
+
color "#fff4e6"
|
|
62
|
+
stroke width: 2, color: "#120617"
|
|
63
|
+
shadow color: "#ff335f", blur: 20
|
|
64
|
+
glow_strength 0.28
|
|
65
|
+
blend :screen
|
|
66
|
+
|
|
67
|
+
map beat_pulse, to: :glow_strength, range: 0.2..0.92
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Short scene intended for live-coding demos.
|
|
4
|
+
Vizcore.define do
|
|
5
|
+
scene :main do
|
|
6
|
+
layer :pulse do
|
|
7
|
+
type :radial_blob
|
|
8
|
+
radius 0.34
|
|
9
|
+
wobble 0.2
|
|
10
|
+
map amplitude, to: :radius, range: 0.22..0.7, curve: :sqrt
|
|
11
|
+
map fft_spectrum => :spectrum
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
layer :beat_label do
|
|
15
|
+
type :text
|
|
16
|
+
content "VIZCORE"
|
|
17
|
+
font_size 86
|
|
18
|
+
glow_strength 0.2
|
|
19
|
+
map beat_pulse, to: :glow_strength, range: 0.12..0.85
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# MIDI controller showcase: pads switch scenes, knobs control global shader uniforms.
|
|
4
|
+
Vizcore.define do
|
|
5
|
+
set :global_intensity, 0.65
|
|
6
|
+
set :global_color, 0.15
|
|
7
|
+
|
|
8
|
+
midi :controller, device: :default
|
|
9
|
+
|
|
10
|
+
scene :midi_warmup do
|
|
11
|
+
layer :ribbon do
|
|
12
|
+
shader :waveform_ribbon
|
|
13
|
+
blend :screen
|
|
14
|
+
effect :bloom
|
|
15
|
+
map mid, to: :effect_intensity, range: 0.08..0.24
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
layer :title do
|
|
19
|
+
type :text
|
|
20
|
+
content "MIDI CONTROL"
|
|
21
|
+
font_size 72
|
|
22
|
+
color "#e8fbff"
|
|
23
|
+
glow_strength 0.16
|
|
24
|
+
blend :screen
|
|
25
|
+
map beat_pulse, to: :glow_strength, range: 0.12..0.65
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
scene :midi_drop do
|
|
30
|
+
layer :stars do
|
|
31
|
+
shader :starfield
|
|
32
|
+
blend :screen
|
|
33
|
+
effect :glitch
|
|
34
|
+
map high, to: :effect_intensity, range: 0.1..0.65
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
layer :drop_text do
|
|
38
|
+
type :text
|
|
39
|
+
content "DROP"
|
|
40
|
+
font_size 118
|
|
41
|
+
color "#fff1d6"
|
|
42
|
+
glow_strength 0.25
|
|
43
|
+
blend :add
|
|
44
|
+
map beat_pulse, to: :glow_strength, range: 0.25..1.0
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
scene :midi_crystal do
|
|
49
|
+
layer :crystal do
|
|
50
|
+
shader :ruby_crystal
|
|
51
|
+
facets 7.0
|
|
52
|
+
refraction 0.44
|
|
53
|
+
blend :screen
|
|
54
|
+
map bass, to: :refraction, gain: 0.9, range: 0.32..0.82
|
|
55
|
+
map mid, to: :facets, gain: 1.8, range: 5.0..10.0
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
midi_map note: 36 do
|
|
60
|
+
switch_scene :midi_warmup
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
midi_map note: 37 do
|
|
64
|
+
switch_scene :midi_drop
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
midi_map note: 38 do
|
|
68
|
+
switch_scene :midi_crystal
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
midi_map cc: 1 do |value|
|
|
72
|
+
set :global_intensity, value / 127.0
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
midi_map cc: 2 do |value|
|
|
76
|
+
set :global_color, value / 127.0
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
Vizcore.define do
|
|
4
|
+
set :global_intensity, 0.65
|
|
5
|
+
|
|
4
6
|
midi :controller, device: :default
|
|
5
7
|
|
|
6
8
|
scene :warmup do
|
|
7
9
|
layer :grid do
|
|
8
|
-
shader :
|
|
10
|
+
shader :waveform_ribbon
|
|
9
11
|
map frequency_band(:mid) => :intensity
|
|
10
12
|
end
|
|
11
13
|
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Parser-themed visual sketch: token flow, AST energy, and reduce flashes.
|
|
4
|
+
Vizcore.define do
|
|
5
|
+
scene :parser_visualizer do
|
|
6
|
+
layer :token_stream do
|
|
7
|
+
shader :waveform_ribbon
|
|
8
|
+
blend :screen
|
|
9
|
+
effect :crt
|
|
10
|
+
effect_intensity 0.18
|
|
11
|
+
map amplitude, to: :effect_intensity, range: 0.08..0.32
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
layer :ast_nodes do
|
|
15
|
+
type :particle_field
|
|
16
|
+
count 2200
|
|
17
|
+
force_field :vortex
|
|
18
|
+
turbulence 0.28
|
|
19
|
+
blend :add
|
|
20
|
+
map bass, to: :size, gain: 3.0, range: 1.8..6.5, curve: :sqrt
|
|
21
|
+
map mid, to: :speed, gain: 2.0, range: 0.4..4.2
|
|
22
|
+
map hihat, to: :sparkle, gain: 2.2, range: 0.0..1.0
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
layer :reduce_flash do
|
|
26
|
+
shader :ruby_crystal
|
|
27
|
+
facets 7.0
|
|
28
|
+
refraction 0.42
|
|
29
|
+
blend :add
|
|
30
|
+
effect :bloom
|
|
31
|
+
map kick, to: :effect_intensity, gain: 2.0, range: 0.05..0.55
|
|
32
|
+
map beat_pulse, to: :refraction, range: 0.32..0.86
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
layer :parser_label do
|
|
36
|
+
type :text
|
|
37
|
+
content "SHIFT -> REDUCE -> ACCEPT"
|
|
38
|
+
font "IBM Plex Mono"
|
|
39
|
+
font_size 58
|
|
40
|
+
align :center
|
|
41
|
+
fill "#d9ffe8"
|
|
42
|
+
stroke width: 2, color: "#06111f"
|
|
43
|
+
glow_strength 0.26
|
|
44
|
+
blend :screen
|
|
45
|
+
map beat_pulse, to: :glow_strength, range: 0.18..0.9
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|