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.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +70 -117
  3. data/docs/.nojekyll +0 -0
  4. data/docs/assets/playground-worker.js +373 -0
  5. data/docs/assets/playground.css +440 -0
  6. data/docs/assets/playground.js +652 -0
  7. data/docs/assets/site.css +744 -0
  8. data/docs/assets/vizcore-demo.gif +0 -0
  9. data/docs/assets/vizcore-poster.png +0 -0
  10. data/docs/assets/vj-tunnel.js +159 -0
  11. data/docs/index.html +225 -0
  12. data/docs/playground.html +81 -0
  13. data/docs/shape_dsl.md +269 -0
  14. data/examples/README.md +59 -0
  15. data/examples/assets/README.md +19 -0
  16. data/examples/audio_inspector.rb +34 -0
  17. data/examples/club_intro_drop.rb +78 -0
  18. data/examples/kansai_rubykaigi_visual.rb +70 -0
  19. data/examples/live_coding_minimal.rb +22 -0
  20. data/examples/midi_controller_show.rb +78 -0
  21. data/examples/midi_scene_switch.rb +3 -1
  22. data/examples/parser_visualizer.rb +48 -0
  23. data/examples/readme_demo.rb +17 -0
  24. data/examples/rhythm_geometry.rb +34 -0
  25. data/examples/ruby_crystal_show.rb +35 -0
  26. data/examples/shader_playground.rb +18 -0
  27. data/examples/unyo_liquid.rb +59 -0
  28. data/examples/vj_ambient_chill_room.rb +124 -0
  29. data/examples/vj_dnb_jungle.rb +170 -0
  30. data/examples/vj_festival_mainstage.rb +245 -0
  31. data/examples/vj_festival_mainstage.yml +17 -0
  32. data/examples/vj_glitch_industrial.rb +164 -0
  33. data/examples/vj_hiphop_cipher.rb +167 -0
  34. data/examples/vj_jpop_idol_live.rb +210 -0
  35. data/examples/vj_synthwave_retro.rb +173 -0
  36. data/examples/vj_techno_warehouse.rb +195 -0
  37. data/frontend/index.html +494 -2
  38. data/frontend/src/audio-inspector.js +40 -0
  39. data/frontend/src/custom-shape-param-controls.js +106 -0
  40. data/frontend/src/live-controls.js +131 -0
  41. data/frontend/src/main.js +1060 -16
  42. data/frontend/src/mapping-target-selector.js +109 -0
  43. data/frontend/src/midi-learn.js +194 -0
  44. data/frontend/src/performance-monitor.js +183 -0
  45. data/frontend/src/plugin-runtime.js +130 -0
  46. data/frontend/src/projector-mode.js +56 -0
  47. data/frontend/src/renderer/engine.js +157 -3
  48. data/frontend/src/renderer/layer-manager.js +442 -30
  49. data/frontend/src/renderer/shader-manager.js +26 -0
  50. data/frontend/src/runtime-control-preset.js +11 -0
  51. data/frontend/src/shader-error-overlay.js +29 -0
  52. data/frontend/src/shader-param-controls.js +93 -0
  53. data/frontend/src/shaders/builtins.js +380 -2
  54. data/frontend/src/shaders/post-effects.js +52 -0
  55. data/frontend/src/shape-editor-controls.js +157 -0
  56. data/frontend/src/visual-regression.js +67 -0
  57. data/frontend/src/visual-settings-preset.js +103 -0
  58. data/frontend/src/visuals/geometry.js +666 -0
  59. data/frontend/src/visuals/image-renderer.js +291 -0
  60. data/frontend/src/visuals/particle-system.js +56 -10
  61. data/frontend/src/visuals/shape-renderer.js +475 -0
  62. data/frontend/src/visuals/spectrogram-renderer.js +226 -0
  63. data/frontend/src/visuals/svg-arc.js +104 -0
  64. data/frontend/src/visuals/text-renderer.js +112 -11
  65. data/frontend/src/websocket-client.js +12 -1
  66. data/lib/vizcore/analysis/adaptive_normalizer.rb +70 -0
  67. data/lib/vizcore/analysis/beat_detector.rb +4 -2
  68. data/lib/vizcore/analysis/bpm_estimator.rb +8 -0
  69. data/lib/vizcore/analysis/feature_recorder.rb +159 -0
  70. data/lib/vizcore/analysis/feature_replay.rb +84 -0
  71. data/lib/vizcore/analysis/pipeline.rb +235 -11
  72. data/lib/vizcore/analysis/tap_tempo.rb +74 -0
  73. data/lib/vizcore/analysis.rb +4 -0
  74. data/lib/vizcore/audio/dummy_sine_input.rb +1 -1
  75. data/lib/vizcore/audio/fixture_input.rb +65 -0
  76. data/lib/vizcore/audio/input_manager.rb +4 -2
  77. data/lib/vizcore/audio/mic_input.rb +24 -8
  78. data/lib/vizcore/audio/portaudio_ffi.rb +106 -1
  79. data/lib/vizcore/audio.rb +1 -0
  80. data/lib/vizcore/cli/doctor.rb +159 -0
  81. data/lib/vizcore/cli/dsl_reference.rb +99 -0
  82. data/lib/vizcore/cli/layer_docs.rb +46 -0
  83. data/lib/vizcore/cli/scene_diagnostics.rb +23 -0
  84. data/lib/vizcore/cli/scene_inspector.rb +136 -0
  85. data/lib/vizcore/cli/scene_validator.rb +337 -0
  86. data/lib/vizcore/cli/shader_template.rb +68 -0
  87. data/lib/vizcore/cli/shader_uniform_docs.rb +54 -0
  88. data/lib/vizcore/cli.rb +689 -18
  89. data/lib/vizcore/config.rb +103 -2
  90. data/lib/vizcore/control_preset.rb +68 -0
  91. data/lib/vizcore/dsl/engine.rb +277 -5
  92. data/lib/vizcore/dsl/layer_builder.rb +1280 -23
  93. data/lib/vizcore/dsl/layer_group_builder.rb +112 -0
  94. data/lib/vizcore/dsl/mapping_resolver.rb +290 -7
  95. data/lib/vizcore/dsl/mapping_transform_builder.rb +71 -0
  96. data/lib/vizcore/dsl/reaction_builder.rb +44 -0
  97. data/lib/vizcore/dsl/scene_builder.rb +61 -5
  98. data/lib/vizcore/dsl/shader_source_resolver.rb +67 -6
  99. data/lib/vizcore/dsl/style_builder.rb +68 -0
  100. data/lib/vizcore/dsl/timeline_builder.rb +138 -0
  101. data/lib/vizcore/dsl/transition_controller.rb +77 -0
  102. data/lib/vizcore/dsl.rb +5 -1
  103. data/lib/vizcore/layer_catalog.rb +275 -0
  104. data/lib/vizcore/project_manifest.rb +152 -0
  105. data/lib/vizcore/renderer/png_writer.rb +57 -0
  106. data/lib/vizcore/renderer/render_sequence.rb +153 -0
  107. data/lib/vizcore/renderer/scene_frame_source.rb +132 -0
  108. data/lib/vizcore/renderer/scene_serializer.rb +36 -3
  109. data/lib/vizcore/renderer/snapshot.rb +38 -0
  110. data/lib/vizcore/renderer/snapshot_renderer.rb +938 -0
  111. data/lib/vizcore/renderer.rb +5 -0
  112. data/lib/vizcore/server/frame_broadcaster.rb +143 -8
  113. data/lib/vizcore/server/gallery_app.rb +155 -0
  114. data/lib/vizcore/server/gallery_page.rb +100 -0
  115. data/lib/vizcore/server/gallery_runner.rb +48 -0
  116. data/lib/vizcore/server/rack_app.rb +203 -4
  117. data/lib/vizcore/server/runner.rb +391 -22
  118. data/lib/vizcore/server/scene_dependency_watcher.rb +79 -0
  119. data/lib/vizcore/server/websocket_handler.rb +60 -10
  120. data/lib/vizcore/server.rb +4 -0
  121. data/lib/vizcore/shape.rb +719 -0
  122. data/lib/vizcore/sync/osc_message.rb +103 -0
  123. data/lib/vizcore/sync/osc_receiver.rb +68 -0
  124. data/lib/vizcore/sync.rb +4 -0
  125. data/lib/vizcore/templates/midi_control_scene.rb +3 -1
  126. data/lib/vizcore/templates/plugin_layer.rb +20 -0
  127. data/lib/vizcore/templates/plugin_readme.md +23 -0
  128. data/lib/vizcore/templates/plugin_renderer.js +43 -0
  129. data/lib/vizcore/templates/plugin_scene.rb +14 -0
  130. data/lib/vizcore/templates/project_readme.md +7 -23
  131. data/lib/vizcore/templates/rubykaigi_scene.rb +30 -0
  132. data/lib/vizcore/version.rb +1 -1
  133. data/lib/vizcore.rb +28 -0
  134. data/scripts/browser_capture.mjs +75 -0
  135. data/sig/vizcore.rbs +461 -0
  136. metadata +94 -3
  137. data/docs/GETTING_STARTED.md +0 -105
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Minimal scene used to generate docs/assets/vizcore-demo.gif.
4
+ # It intentionally shows one idea: detected beats expand the rings.
5
+ Vizcore.define do
6
+ scene :readme_demo do
7
+ layer :beat_rings do
8
+ palette "#24f6ff", "#ff2bbd", "#caff2e"
9
+
10
+ circle count: 4 do
11
+ radius 92
12
+ stroke 3
13
+ map beat_pulse, to: :radius, gain: 160.0, min: 56, max: 164, attack: 1.0, release: 0.2
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Recommended audio file for this scene:
4
+ # examples/assets/complex_demo_loop.wav
5
+ # Drum-only sync check:
6
+ # spec/fixtures/audio/kick_120bpm.wav
7
+ # Motion is gated by audio level, so silence holds the shape still.
8
+ Vizcore.define do
9
+ scene :rhythm_geometry do
10
+ layer :morphing_geometry do
11
+ shader :unyo_geometry
12
+ sides 7.0
13
+ scale 1.02
14
+ wobble 0.72
15
+ twist 0.84
16
+ pulse 0.0
17
+ kick 0.0
18
+ snare 0.0
19
+ line_glow 0.38
20
+ effect :bloom
21
+ effect_intensity 0.42
22
+
23
+ map beat_count => :seed
24
+ map beat_pulse, to: :pulse, range: 0.0..1.65, attack: 1.0, release: 0.14
25
+ map amplitude, to: :scale, gain: 0.7, range: 0.82..1.25, curve: :sqrt, attack: 0.95, release: 0.18
26
+ map frequency_band(:low), to: :kick, gain: 3.8, range: 0.0..1.45, curve: :sqrt, attack: 1.0, release: 0.08
27
+ map frequency_band(:low), to: :wobble, gain: 3.0, range: 0.45..1.7, curve: :sqrt, attack: 0.95, release: 0.16
28
+ map frequency_band(:mid), to: :twist, gain: 2.4, range: 0.55..2.4, curve: :sqrt
29
+ map frequency_band(:high), to: :snare, gain: 2.2, range: 0.0..1.1, curve: :sqrt, attack: 1.0, release: 0.12
30
+ map frequency_band(:high), to: :line_glow, gain: 2.0, range: 0.28..1.3
31
+ map frequency_band(:high), to: :effect_intensity, gain: 1.4, range: 0.24..0.78
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Ruby-themed showcase using crystal, text, and particle layers.
4
+ Vizcore.define do
5
+ scene :ruby_crystal do
6
+ layer :crystal_core do
7
+ shader :ruby_crystal
8
+ facets 6.0
9
+ refraction 0.48
10
+ blend :screen
11
+
12
+ map bass, to: :refraction, gain: 0.8, range: 0.28..0.78, curve: :sqrt
13
+ map mid, to: :facets, gain: 2.0, range: 5.0..10.0
14
+ end
15
+
16
+ layer :gem_sparks do
17
+ type :particle_field
18
+ count 2600
19
+ blend :add
20
+ map amplitude, to: :speed, gain: 2.6, range: 0.2..4.8, curve: :sqrt
21
+ map bass, to: :size, gain: 3.2, range: 1.8..7.0
22
+ map treble, to: :sparkle, gain: 2.6, range: 0.0..1.0
23
+ end
24
+
25
+ layer :ruby_title do
26
+ type :text
27
+ content "RUBY"
28
+ font_size 118
29
+ color "#ff335f"
30
+ glow_strength 0.35
31
+ blend :screen
32
+ map beat_pulse, to: :glow_strength, range: 0.24..0.9
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Minimal shader-focused scene for trying mapped parameters.
4
+ Vizcore.define do
5
+ scene :shader_playground do
6
+ layer :liquid do
7
+ shader :liquid_wobble
8
+ param :wobble, default: 0.35, range: 0.0..2.0, step: 0.05
9
+ param :warp, default: 0.45, range: 0.0..3.0, step: 0.05
10
+ param :distortion, default: 0.25, range: 0.0..2.0, step: 0.05
11
+ blend :screen
12
+
13
+ map amplitude, to: :wobble, gain: 2.2, range: 0.18..1.2, curve: :sqrt
14
+ map bass, to: :warp, gain: 2.4, range: 0.25..2.2
15
+ map treble, to: :distortion, gain: 2.0, range: 0.2..1.6
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ Vizcore.define do
4
+ scene :unyo do
5
+ layer :liquid do
6
+ shader :liquid_wobble
7
+ opacity 1.0
8
+ blend :alpha
9
+ effect :feedback
10
+ effect_intensity 0.14
11
+ wobble 0.25
12
+ warp 0.45
13
+ distortion 0.25
14
+
15
+ map amplitude, to: :wobble, gain: 3.5, range: 0.12..1.4, curve: :sqrt, attack: 0.9, release: 0.18
16
+ map frequency_band(:low), to: :warp, gain: 2.2, range: 0.25..2.4, attack: 0.8, release: 0.2
17
+ map frequency_band(:high), to: :distortion, gain: 1.8, range: 0.1..1.6
18
+ map beat_pulse, to: :effect_intensity, range: 0.08..0.35, attack: 1.0, release: 0.2
19
+ end
20
+
21
+ layer :particles do
22
+ type :particle_field
23
+ count 7000
24
+ blend :add
25
+ opacity 0.55
26
+ size 2.8
27
+ force_field :vortex
28
+ turbulence 0.55
29
+ bass_explosion 0.9
30
+ sparkle 0.35
31
+
32
+ map amplitude, to: :speed, gain: 4.0, range: 0.4..4.0, curve: :sqrt
33
+ map frequency_band(:low), to: :size, gain: 6.0, range: 2.0..8.0, curve: :sqrt
34
+ map beat_pulse, to: :bass_explosion, gain: 1.2, range: 0.3..1.8
35
+ end
36
+
37
+ layer :blob_outline do
38
+ type :radial_blob
39
+ blend :add
40
+ opacity 0.65
41
+ segments 192
42
+ radius 0.42
43
+ wobble 0.2
44
+
45
+ map fft_spectrum => :spectrum
46
+ map amplitude, to: :wobble, gain: 2.8, range: 0.08..0.75, curve: :sqrt
47
+ map frequency_band(:low), to: :radius, gain: 0.8, range: 0.36..0.72
48
+ end
49
+
50
+ layer :title do
51
+ type :text
52
+ content "UNYO"
53
+ font_size 72
54
+ color "#f8fbff"
55
+ glow_strength 0.08
56
+ map beat_pulse, to: :glow_strength, range: 0.08..0.42, attack: 1.0, release: 0.2
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ # vj_ambient_chill_room.rb
4
+ #
5
+ # Genre : Ambient / Chill Room
6
+ # BPM : none, or 60-90 when a pulse appears
7
+ # Duration: slow rotation between two long scenes
8
+ # Audio : --audio-source mic
9
+ # --audio-source file --audio-file examples/assets/complex_demo_loop.wav
10
+ # Keys : 1 bloom, 2 nebula, B blackout, F freeze
11
+ # MIDI : note 36..37 = scenes, CC 1 = global intensity
12
+ Vizcore.define do
13
+ set :global_intensity, 0.7
14
+ audio_normalize mode: :adaptive, window: 8.0, target: 0.72, floor: 0.03
15
+
16
+ theme :chill_room do
17
+ palette "#1e293b", "#64748b", "#a5b4fc", "#f8fafc"
18
+ background "#020617"
19
+ end
20
+
21
+ style :soft_screen do
22
+ blend :screen
23
+ opacity 0.52
24
+ end
25
+
26
+ scene :bloom do
27
+ use_theme :chill_room
28
+
29
+ layer :slow_ribbon do
30
+ shader :waveform_ribbon
31
+ use_style :soft_screen
32
+ effect :bloom
33
+ effect_intensity 0.18
34
+ map amplitude, to: :opacity, gain: 0.85, range: 0.28..0.86, curve: :sqrt, attack: 0.18, release: 0.72
35
+ map beat_pulse, to: :effect_intensity, range: 0.12..0.34, attack: 0.24, release: 0.82
36
+ map fft_spectrum => :deform
37
+ end
38
+
39
+ layer :breathing_halo do
40
+ type :radial_blob
41
+ opacity 0.46
42
+ blend :add
43
+ segments 192
44
+ radius 0.42
45
+ wobble 0.18
46
+ map amplitude, to: :wobble, gain: 1.3, range: 0.08..0.48, curve: :sqrt, attack: 0.2, release: 0.82
47
+ map beat_confidence, to: :radius, gain: 0.14, range: 0.38..0.54
48
+ map fft_spectrum => :deform
49
+ end
50
+ end
51
+
52
+ scene :nebula do
53
+ use_theme :chill_room
54
+
55
+ layer :deep_spectrum do
56
+ type :spectrogram
57
+ scroll :horizontal
58
+ bins 80
59
+ history 220
60
+ gain 0.62
61
+ opacity 0.5
62
+ blend :screen
63
+ effect :motion_blur
64
+ effect_intensity 0.12
65
+ map amplitude, to: :opacity, gain: 0.7, range: 0.22..0.68, attack: 0.18, release: 0.76
66
+ map beat_pulse, to: :effect_intensity, range: 0.08..0.26, release: 0.82
67
+ map fft_spectrum => :deform
68
+ end
69
+
70
+ layer :nebula_points do
71
+ type :particle_field
72
+ count 1200
73
+ speed 0.18
74
+ size 2.6
75
+ force_field :drift
76
+ turbulence 0.12
77
+ opacity 0.42
78
+ blend :add
79
+ map amplitude, to: :speed, gain: 0.9, range: 0.08..0.72, curve: :sqrt, attack: 0.22, release: 0.84
80
+ map low, to: :size, gain: 2.2, range: 1.8..5.2
81
+ map fft_spectrum => :deform
82
+ end
83
+ end
84
+
85
+ transition from: :bloom, to: :nebula do
86
+ trigger { seconds >= 90 || beat_count >= 96 }
87
+ effect :crossfade, duration: 3.0
88
+ end
89
+
90
+ transition from: :nebula, to: :bloom do
91
+ trigger { seconds >= 90 || beat_count >= 96 }
92
+ effect :crossfade, duration: 3.0
93
+ end
94
+
95
+ midi :controller, device: :default
96
+
97
+ midi_map note: 36 do
98
+ switch_scene :bloom
99
+ end
100
+
101
+ midi_map note: 37 do
102
+ switch_scene :nebula
103
+ end
104
+
105
+ midi_map cc: 1 do |value|
106
+ set :global_intensity, value / 127.0
107
+ end
108
+
109
+ key "1" do
110
+ switch_scene :bloom
111
+ end
112
+
113
+ key "2" do
114
+ switch_scene :nebula
115
+ end
116
+
117
+ key "b" do
118
+ blackout
119
+ end
120
+
121
+ key "f" do
122
+ freeze
123
+ end
124
+ end
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ # vj_dnb_jungle.rb
4
+ #
5
+ # Genre : Drum & Bass / Jungle
6
+ # BPM : 170-180
7
+ # Duration: 3-scene break workout
8
+ # Audio : --audio-source mic
9
+ # --audio-source file --audio-file examples/assets/complex_demo_loop.wav
10
+ # Keys : 1 rollers, 2 amen, 3 reese, B blackout, F freeze, Space tap-tempo
11
+ # MIDI : note 36..38 = scenes, note 40 = reese, CC 1 = global intensity
12
+ Vizcore.define do
13
+ set :global_intensity, 0.88
14
+ audio_normalize mode: :adaptive, window: 2.5, target: 0.86, floor: 0.04
15
+ bpm 176
16
+ bpm_lock true
17
+ tap_tempo key: :space
18
+
19
+ theme :jungle_neon do
20
+ palette "#00f5d4", "#00bbf9", "#f15bb5", "#fee440"
21
+ background "#030712"
22
+ end
23
+
24
+ style :fast_add do
25
+ blend :add
26
+ opacity 0.76
27
+ end
28
+
29
+ scene :rollers do
30
+ use_theme :jungle_neon
31
+
32
+ layer :star_tunnel do
33
+ shader :starfield
34
+ blend :screen
35
+ effect :motion_blur
36
+ effect_intensity 0.16
37
+ map amplitude, to: :warp, gain: 1.8, range: 0.18..1.3, curve: :sqrt
38
+ map beat_pulse, to: :effect_intensity, range: 0.12..0.42, attack: 1.0, release: 0.08
39
+ map fft_spectrum => :deform
40
+ end
41
+
42
+ layer :rolling_particles do
43
+ type :particle_field
44
+ count 4200 # tune: 2600 for laptops, 6000 for stage machines
45
+ force_field :flow
46
+ speed 2.6
47
+ size 1.6
48
+ use_style :fast_add
49
+ react_to amplitude do
50
+ change :speed, gain: 3.6, range: 1.2..7.2, curve: :sqrt
51
+ change :size, gain: 2.4, range: 1.2..4.6
52
+ end
53
+ map hihat, to: :sparkle, gain: 2.8, range: 0.1..1.0, attack: 1.0, release: 0.05
54
+ map fft_spectrum => :deform
55
+ end
56
+ end
57
+
58
+ scene :amen do
59
+ use_theme :jungle_neon
60
+
61
+ layer :kick_cube do
62
+ type :wireframe_cube
63
+ opacity 0.6
64
+ blend :add
65
+ map kick, to: :scale, gain: 0.9, range: 0.74..1.46, curve: :sqrt, attack: 1.0, release: 0.08
66
+ map low, to: :rotation_speed, gain: 1.4, range: 0.12..2.4
67
+ map fft_spectrum => :deform
68
+ end
69
+
70
+ layer :snare_cube do
71
+ type :wireframe_cube
72
+ opacity 0.48
73
+ blend :difference
74
+ map snare, to: :color_shift, gain: 2.2, range: 0.1..1.0, attack: 1.0, release: 0.06
75
+ map mid, to: :rotation_speed, gain: 1.6, range: 0.2..2.8
76
+ map fft_spectrum => :deform
77
+ end
78
+
79
+ layer :hat_text do
80
+ type :text
81
+ content "176 BPM"
82
+ font "Inter"
83
+ font_size 52
84
+ align :center
85
+ color "#eaffff"
86
+ glow_strength 0.18
87
+ blend :screen
88
+ map hihat, to: :glow_strength, gain: 2.8, range: 0.16..0.95, attack: 1.0, release: 0.05
89
+ map beat_pulse, to: :letter_spacing, gain: 18.0, min: 0.0, max: 24.0
90
+ map fft_spectrum => :deform
91
+ end
92
+ end
93
+
94
+ scene :reese do
95
+ use_theme :jungle_neon
96
+
97
+ layer :reese_warp do
98
+ shader :bass_tunnel
99
+ blend :screen
100
+ effect :feedback
101
+ effect_intensity 0.18
102
+ map bass, to: :warp, gain: 3.0, range: 0.2..2.2, curve: :sqrt
103
+ map kick, to: :effect_intensity, gain: 1.1, range: 0.12..0.62, attack: 1.0, release: 0.1
104
+ map fft_spectrum => :deform
105
+ end
106
+
107
+ layer :chromatic_noise do
108
+ shader :glitch_flash
109
+ blend :add
110
+ effect :chromatic
111
+ effect_intensity 0.22
112
+ opacity 0.58
113
+ map amplitude, to: :opacity, gain: 0.8, range: 0.34..0.84
114
+ map onset(:high), to: :effect_intensity, gain: 2.4, range: 0.12..0.9, attack: 1.0, release: 0.05
115
+ map fft_spectrum => :deform
116
+ end
117
+ end
118
+
119
+ transition from: :rollers, to: :amen do
120
+ trigger { beat_count >= 32 || frame_count >= 360 }
121
+ effect :crossfade, duration: 0.45
122
+ end
123
+
124
+ transition from: :amen, to: :rollers do
125
+ trigger { beat_count >= 64 || frame_count >= 720 }
126
+ effect :flash, duration: 0.18
127
+ end
128
+
129
+ midi :controller, device: :default
130
+
131
+ midi_map note: 36 do
132
+ switch_scene :rollers
133
+ end
134
+
135
+ midi_map note: 37 do
136
+ switch_scene :amen
137
+ end
138
+
139
+ midi_map note: 38 do
140
+ switch_scene :reese
141
+ end
142
+
143
+ midi_map note: 40 do
144
+ switch_scene :reese
145
+ end
146
+
147
+ midi_map cc: 1 do |value|
148
+ set :global_intensity, value / 127.0
149
+ end
150
+
151
+ key "1" do
152
+ switch_scene :rollers
153
+ end
154
+
155
+ key "2" do
156
+ switch_scene :amen
157
+ end
158
+
159
+ key "3" do
160
+ switch_scene :reese
161
+ end
162
+
163
+ key "b" do
164
+ blackout
165
+ end
166
+
167
+ key "f" do
168
+ freeze
169
+ end
170
+ end
@@ -0,0 +1,245 @@
1
+ # frozen_string_literal: true
2
+
3
+ # vj_festival_mainstage.rb
4
+ #
5
+ # Genre : EDM / Festival mainstage
6
+ # BPM : 124-132
7
+ # Duration: opener, warmup, build, drop, outro
8
+ # Audio : --audio-source mic
9
+ # --audio-source file --audio-file examples/assets/complex_demo_loop.wav
10
+ # Keys : 1..5 scenes, B blackout, F freeze, Space tap-tempo
11
+ # MIDI : note 36..40 = scenes, CC 1 = global intensity
12
+ #
13
+ # Manifest: examples/vj_festival_mainstage.yml shows a reusable file-audio setup.
14
+ Vizcore.define do
15
+ set :global_intensity, 0.92
16
+ audio_normalize mode: :adaptive, window: 3.0, target: 0.88, floor: 0.04
17
+ bpm 128
18
+ bpm_lock true
19
+ tap_tempo key: :space
20
+
21
+ theme :mainstage do
22
+ palette "#ffffff", "#00f5ff", "#ff2f92", "#fffb00"
23
+ background "#020617"
24
+ end
25
+
26
+ style :stage_glow do
27
+ blend :screen
28
+ opacity 0.82
29
+ end
30
+
31
+ scene :opener do
32
+ use_theme :mainstage
33
+
34
+ layer :opener_logo_slot do
35
+ type :text
36
+ content "MAIN STAGE"
37
+ font "Inter"
38
+ font_size 78
39
+ align :center
40
+ color "#ffffff"
41
+ stroke width: 2, color: "#020617"
42
+ shadow color: "#00f5ff", blur: 20
43
+ glow_strength 0.24
44
+ use_style :stage_glow
45
+ map amplitude, to: :glow_strength, gain: 1.4, range: 0.18..0.88, curve: :sqrt
46
+ map beat_pulse, to: :font_size, gain: 20.0, min: 72.0, max: 106.0
47
+ map fft_spectrum => :deform
48
+ end
49
+
50
+ layer :countdown_rings do
51
+ type :shape
52
+ blend :add
53
+ opacity 0.52
54
+ circle x: 640, y: 360, radius: 130, count: 6 do
55
+ stroke 3
56
+ map low, to: :radius, gain: 120.0, min: 110.0, max: 230.0
57
+ map beat_pulse, to: :stroke, gain: 5.0, min: 2.0, max: 8.0
58
+ end
59
+ end
60
+ end
61
+
62
+ scene :warmup do
63
+ use_theme :mainstage
64
+
65
+ layer :warmup_grid do
66
+ shader :neon_grid
67
+ use_style :stage_glow
68
+ effect :bloom
69
+ effect_intensity 0.16
70
+ map amplitude, to: :effect_intensity, gain: 1.1, range: 0.12..0.52, curve: :sqrt
71
+ map beat_pulse, to: :pulse, range: 0.12..0.62
72
+ map fft_spectrum => :deform
73
+ end
74
+
75
+ layer :warmup_cube do
76
+ type :wireframe_cube
77
+ opacity 0.64
78
+ blend :add
79
+ map bass, to: :rotation_speed, gain: 2.0, range: 0.18..3.2
80
+ map kick, to: :scale, gain: 0.55, range: 0.82..1.4
81
+ map fft_spectrum => :deform
82
+ end
83
+ end
84
+
85
+ scene :build do
86
+ use_theme :mainstage
87
+
88
+ layer :riser_tunnel do
89
+ shader :bass_tunnel
90
+ use_style :stage_glow
91
+ effect :motion_blur
92
+ effect_intensity 0.18
93
+ map amplitude, to: :warp, gain: 2.2, range: 0.18..1.8, curve: :sqrt
94
+ map beat_pulse, to: :effect_intensity, range: 0.12..0.55, attack: 1.0, release: 0.1
95
+ map fft_spectrum => :deform
96
+ end
97
+
98
+ layer :riser_particles do
99
+ type :particle_field
100
+ count 3600 # tune: 2400 on laptops, 7000 on mainstage GPUs
101
+ force_field :fountain
102
+ speed 1.6
103
+ size 2.2
104
+ blend :add
105
+ map high, to: :speed, gain: 3.8, range: 0.8..7.2, curve: :sqrt
106
+ map kick, to: :bass_explosion, gain: 1.2, range: 0.2..1.5, attack: 1.0, release: 0.08
107
+ map fft_spectrum => :deform
108
+ end
109
+ end
110
+
111
+ scene :drop, extends: :build do
112
+ use_theme :mainstage
113
+
114
+ group :foreground do
115
+ blend :add
116
+ opacity 0.84
117
+
118
+ layer :drop_crystal do
119
+ shader :ruby_crystal
120
+ facets 10.0
121
+ refraction 0.68
122
+ effect :chromatic
123
+ effect_intensity 0.2
124
+ map low, to: :refraction, gain: 1.2, range: 0.42..1.0, curve: :sqrt
125
+ map beat_pulse, to: :effect_intensity, range: 0.16..0.86, attack: 1.0, release: 0.08
126
+ map fft_spectrum => :deform
127
+ end
128
+
129
+ layer :drop_title do
130
+ type :text
131
+ content "DROP"
132
+ font_size 132
133
+ align :center
134
+ color "#ffffff"
135
+ glow_strength 0.42
136
+ shadow color: "#ff2f92", blur: 26
137
+ map amplitude, to: :glow_strength, gain: 1.4, range: 0.3..1.0
138
+ map kick, to: :font_size, gain: 36.0, min: 120.0, max: 172.0
139
+ map fft_spectrum => :deform
140
+ end
141
+ end
142
+ end
143
+
144
+ scene :outro do
145
+ use_theme :mainstage
146
+
147
+ layer :afterglow do
148
+ shader :waveform_ribbon
149
+ blend :screen
150
+ opacity 0.56
151
+ effect :feedback
152
+ effect_intensity 0.1
153
+ map amplitude, to: :opacity, gain: 0.7, range: 0.3..0.72
154
+ map beat_pulse, to: :effect_intensity, range: 0.06..0.24
155
+ map fft_spectrum => :deform
156
+ end
157
+
158
+ layer :thanks_text do
159
+ type :text
160
+ content "THANK YOU"
161
+ font_size 70
162
+ align :center
163
+ color "#ffffff"
164
+ glow_strength 0.18
165
+ blend :screen
166
+ map mid, to: :glow_strength, gain: 1.4, range: 0.12..0.58
167
+ map beat_pulse, to: :letter_spacing, gain: 12.0, min: 0.0, max: 18.0
168
+ map fft_spectrum => :deform
169
+ end
170
+ end
171
+
172
+ transition from: :opener, to: :warmup do
173
+ on_bar 8
174
+ effect :crossfade, duration: 0.8
175
+ end
176
+
177
+ transition from: :warmup, to: :build do
178
+ on_bar 16
179
+ effect :crossfade, duration: 0.75
180
+ end
181
+
182
+ transition from: :build, to: :drop do
183
+ trigger { beat_count >= 32 || frame_count >= 480 }
184
+ effect :flash, duration: 0.3
185
+ end
186
+
187
+ transition from: :drop, to: :outro do
188
+ on_bar 32
189
+ effect :crossfade, duration: 1.0
190
+ end
191
+
192
+ midi :controller, device: :default
193
+
194
+ midi_map note: 36 do
195
+ switch_scene :opener
196
+ end
197
+
198
+ midi_map note: 37 do
199
+ switch_scene :warmup
200
+ end
201
+
202
+ midi_map note: 38 do
203
+ switch_scene :build
204
+ end
205
+
206
+ midi_map note: 39 do
207
+ switch_scene :drop
208
+ end
209
+
210
+ midi_map note: 40 do
211
+ switch_scene :outro
212
+ end
213
+
214
+ midi_map cc: 1 do |value|
215
+ set :global_intensity, value / 127.0
216
+ end
217
+
218
+ key "1" do
219
+ switch_scene :opener
220
+ end
221
+
222
+ key "2" do
223
+ switch_scene :warmup
224
+ end
225
+
226
+ key "3" do
227
+ switch_scene :build
228
+ end
229
+
230
+ key "4" do
231
+ switch_scene :drop
232
+ end
233
+
234
+ key "5" do
235
+ switch_scene :outro
236
+ end
237
+
238
+ key "b" do
239
+ blackout
240
+ end
241
+
242
+ key "f" do
243
+ freeze
244
+ end
245
+ end