vizcore 0.1.0 → 1.0.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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +544 -9
  3. data/docs/.nojekyll +0 -0
  4. data/docs/assets/site.css +744 -0
  5. data/docs/assets/vizcore-demo.gif +0 -0
  6. data/docs/assets/vizcore-poster.png +0 -0
  7. data/docs/assets/vj-tunnel.js +159 -0
  8. data/docs/index.html +224 -0
  9. data/examples/README.md +59 -0
  10. data/examples/assets/README.md +19 -0
  11. data/examples/audio_inspector.rb +34 -0
  12. data/examples/club_intro_drop.rb +78 -0
  13. data/examples/kansai_rubykaigi_visual.rb +70 -0
  14. data/examples/live_coding_minimal.rb +22 -0
  15. data/examples/midi_controller_show.rb +78 -0
  16. data/examples/midi_scene_switch.rb +3 -1
  17. data/examples/parser_visualizer.rb +48 -0
  18. data/examples/readme_demo.rb +17 -0
  19. data/examples/rhythm_geometry.rb +34 -0
  20. data/examples/ruby_crystal_show.rb +35 -0
  21. data/examples/shader_playground.rb +18 -0
  22. data/examples/unyo_liquid.rb +59 -0
  23. data/examples/vj_ambient_chill_room.rb +124 -0
  24. data/examples/vj_dnb_jungle.rb +170 -0
  25. data/examples/vj_festival_mainstage.rb +245 -0
  26. data/examples/vj_festival_mainstage.yml +17 -0
  27. data/examples/vj_glitch_industrial.rb +164 -0
  28. data/examples/vj_hiphop_cipher.rb +167 -0
  29. data/examples/vj_jpop_idol_live.rb +210 -0
  30. data/examples/vj_synthwave_retro.rb +173 -0
  31. data/examples/vj_techno_warehouse.rb +195 -0
  32. data/frontend/index.html +468 -2
  33. data/frontend/src/audio-inspector.js +40 -0
  34. data/frontend/src/live-controls.js +131 -0
  35. data/frontend/src/main.js +792 -16
  36. data/frontend/src/midi-learn.js +194 -0
  37. data/frontend/src/performance-monitor.js +183 -0
  38. data/frontend/src/plugin-runtime.js +130 -0
  39. data/frontend/src/projector-mode.js +56 -0
  40. data/frontend/src/renderer/engine.js +148 -3
  41. data/frontend/src/renderer/layer-manager.js +428 -30
  42. data/frontend/src/renderer/shader-manager.js +26 -0
  43. data/frontend/src/runtime-control-preset.js +11 -0
  44. data/frontend/src/shader-error-overlay.js +29 -0
  45. data/frontend/src/shader-param-controls.js +93 -0
  46. data/frontend/src/shaders/builtins.js +380 -2
  47. data/frontend/src/shaders/post-effects.js +52 -0
  48. data/frontend/src/visual-regression.js +67 -0
  49. data/frontend/src/visual-settings-preset.js +103 -0
  50. data/frontend/src/visuals/geometry.js +268 -0
  51. data/frontend/src/visuals/image-renderer.js +291 -0
  52. data/frontend/src/visuals/particle-system.js +56 -10
  53. data/frontend/src/visuals/spectrogram-renderer.js +226 -0
  54. data/frontend/src/visuals/text-renderer.js +112 -11
  55. data/frontend/src/websocket-client.js +12 -1
  56. data/lib/vizcore/analysis/adaptive_normalizer.rb +70 -0
  57. data/lib/vizcore/analysis/beat_detector.rb +4 -2
  58. data/lib/vizcore/analysis/bpm_estimator.rb +8 -0
  59. data/lib/vizcore/analysis/feature_recorder.rb +159 -0
  60. data/lib/vizcore/analysis/feature_replay.rb +84 -0
  61. data/lib/vizcore/analysis/pipeline.rb +235 -11
  62. data/lib/vizcore/analysis/tap_tempo.rb +74 -0
  63. data/lib/vizcore/analysis.rb +4 -0
  64. data/lib/vizcore/audio/dummy_sine_input.rb +1 -1
  65. data/lib/vizcore/audio/fixture_input.rb +65 -0
  66. data/lib/vizcore/audio/input_manager.rb +4 -2
  67. data/lib/vizcore/audio/mic_input.rb +24 -8
  68. data/lib/vizcore/audio/portaudio_ffi.rb +106 -1
  69. data/lib/vizcore/audio.rb +1 -0
  70. data/lib/vizcore/cli/doctor.rb +159 -0
  71. data/lib/vizcore/cli/dsl_reference.rb +99 -0
  72. data/lib/vizcore/cli/layer_docs.rb +46 -0
  73. data/lib/vizcore/cli/scene_diagnostics.rb +23 -0
  74. data/lib/vizcore/cli/scene_inspector.rb +136 -0
  75. data/lib/vizcore/cli/scene_validator.rb +245 -0
  76. data/lib/vizcore/cli/shader_template.rb +68 -0
  77. data/lib/vizcore/cli/shader_uniform_docs.rb +54 -0
  78. data/lib/vizcore/cli.rb +689 -18
  79. data/lib/vizcore/config.rb +103 -2
  80. data/lib/vizcore/control_preset.rb +68 -0
  81. data/lib/vizcore/dsl/engine.rb +277 -5
  82. data/lib/vizcore/dsl/layer_builder.rb +491 -22
  83. data/lib/vizcore/dsl/layer_group_builder.rb +112 -0
  84. data/lib/vizcore/dsl/mapping_resolver.rb +132 -3
  85. data/lib/vizcore/dsl/mapping_transform_builder.rb +71 -0
  86. data/lib/vizcore/dsl/reaction_builder.rb +44 -0
  87. data/lib/vizcore/dsl/scene_builder.rb +61 -5
  88. data/lib/vizcore/dsl/shader_source_resolver.rb +67 -6
  89. data/lib/vizcore/dsl/style_builder.rb +68 -0
  90. data/lib/vizcore/dsl/timeline_builder.rb +138 -0
  91. data/lib/vizcore/dsl/transition_controller.rb +77 -0
  92. data/lib/vizcore/dsl.rb +5 -1
  93. data/lib/vizcore/layer_catalog.rb +273 -0
  94. data/lib/vizcore/project_manifest.rb +152 -0
  95. data/lib/vizcore/renderer/png_writer.rb +57 -0
  96. data/lib/vizcore/renderer/render_sequence.rb +153 -0
  97. data/lib/vizcore/renderer/scene_frame_source.rb +119 -0
  98. data/lib/vizcore/renderer/scene_serializer.rb +36 -3
  99. data/lib/vizcore/renderer/snapshot.rb +38 -0
  100. data/lib/vizcore/renderer/snapshot_renderer.rb +446 -0
  101. data/lib/vizcore/renderer.rb +5 -0
  102. data/lib/vizcore/server/frame_broadcaster.rb +91 -5
  103. data/lib/vizcore/server/gallery_app.rb +155 -0
  104. data/lib/vizcore/server/gallery_page.rb +100 -0
  105. data/lib/vizcore/server/gallery_runner.rb +48 -0
  106. data/lib/vizcore/server/rack_app.rb +203 -4
  107. data/lib/vizcore/server/runner.rb +370 -22
  108. data/lib/vizcore/server/scene_dependency_watcher.rb +79 -0
  109. data/lib/vizcore/server/websocket_handler.rb +60 -10
  110. data/lib/vizcore/server.rb +4 -0
  111. data/lib/vizcore/sync/osc_message.rb +103 -0
  112. data/lib/vizcore/sync/osc_receiver.rb +68 -0
  113. data/lib/vizcore/sync.rb +4 -0
  114. data/lib/vizcore/templates/midi_control_scene.rb +3 -1
  115. data/lib/vizcore/templates/plugin_layer.rb +20 -0
  116. data/lib/vizcore/templates/plugin_readme.md +23 -0
  117. data/lib/vizcore/templates/plugin_renderer.js +43 -0
  118. data/lib/vizcore/templates/plugin_scene.rb +14 -0
  119. data/lib/vizcore/templates/project_readme.md +7 -23
  120. data/lib/vizcore/templates/rubykaigi_scene.rb +30 -0
  121. data/lib/vizcore/version.rb +1 -1
  122. data/lib/vizcore.rb +27 -0
  123. data/scripts/browser_capture.mjs +75 -0
  124. data/sig/vizcore.rbs +362 -0
  125. metadata +83 -3
  126. data/docs/GETTING_STARTED.md +0 -105
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ # vj_jpop_idol_live.rb
4
+ #
5
+ # Genre : J-POP / Idol live
6
+ # BPM : 130-180
7
+ # Duration: verse, pre-chorus, chorus, bridge
8
+ # Audio : --audio-source mic
9
+ # --audio-source file --audio-file examples/assets/complex_demo_loop.wav
10
+ # Keys : 1..4 scenes, T palette scene, B blackout, F freeze, Space tap-tempo
11
+ # MIDI : note 36..39 = scenes, CC 1 = global intensity
12
+ #
13
+ # Logo slot: place your own SVG at examples/assets/your_logo.svg and add an svg
14
+ # layer in :verse. No logo asset is bundled here.
15
+ Vizcore.define do
16
+ set :global_intensity, 0.9
17
+ audio_normalize mode: :adaptive, window: 3.0, target: 0.84, floor: 0.04
18
+ bpm 154
19
+ tap_tempo key: :space
20
+
21
+ theme :idol_pastel do
22
+ palette "#ff7eb6", "#7afcff", "#feff9c", "#fff4f4", "#bdb2ff", "#caffbf"
23
+ background "#090a1f"
24
+ end
25
+
26
+ theme :idol_vivid do
27
+ palette "#ff006e", "#3a86ff", "#ffbe0b", "#06d6a0", "#ffffff"
28
+ background "#030712"
29
+ end
30
+
31
+ style :penlight do
32
+ blend :add
33
+ opacity 0.76
34
+ end
35
+
36
+ scene :verse do
37
+ use_theme :idol_pastel
38
+
39
+ layer :color_base do
40
+ shader :gradient_pulse
41
+ blend :screen
42
+ opacity 0.48
43
+ map amplitude, to: :effect_intensity, gain: 0.7, range: 0.08..0.32
44
+ map beat_pulse, to: :pulse, range: 0.08..0.36, attack: 1.0, release: 0.16
45
+ map fft_spectrum => :deform
46
+ end
47
+
48
+ layer :logo_placeholder do
49
+ type :text
50
+ content "YOUR LOGO"
51
+ font "Inter"
52
+ font_size 46
53
+ align :center
54
+ color "#fff4f4"
55
+ glow_strength 0.14
56
+ blend :screen
57
+ # Replace this text with:
58
+ # type :svg
59
+ # file "assets/your_logo.svg"
60
+ map low, to: :glow_strength, gain: 1.4, range: 0.12..0.56
61
+ map beat_pulse, to: :font_size, gain: 10.0, min: 42.0, max: 56.0
62
+ map fft_spectrum => :deform
63
+ end
64
+ end
65
+
66
+ scene :pre_chorus do
67
+ use_theme :idol_pastel
68
+
69
+ layer :spark_grid do
70
+ shader :neon_grid
71
+ use_style :penlight
72
+ effect :bloom
73
+ effect_intensity 0.18
74
+ map high, to: :effect_intensity, gain: 1.6, range: 0.14..0.62
75
+ map beat_pulse, to: :pulse, range: 0.15..0.8, attack: 1.0, release: 0.12
76
+ map fft_spectrum => :deform
77
+ end
78
+
79
+ layer :pastel_particles do
80
+ type :particle_field
81
+ count 2400
82
+ force_field :fountain
83
+ size 2.6
84
+ use_style :penlight
85
+ map amplitude, to: :speed, gain: 2.6, range: 0.4..4.8, curve: :sqrt
86
+ map hihat, to: :sparkle, gain: 2.2, range: 0.2..1.0, attack: 1.0, release: 0.06
87
+ map fft_spectrum => :deform
88
+ end
89
+ end
90
+
91
+ scene :chorus do
92
+ use_theme :idol_vivid
93
+
94
+ layer :chorus_burst do
95
+ shader :kaleidoscope
96
+ blend :screen
97
+ opacity 0.92
98
+ effect :bloom
99
+ effect_intensity 0.3
100
+ vj_effect :mirror
101
+ map amplitude, to: :effect_intensity, gain: 1.6, range: 0.22..0.95, curve: :sqrt
102
+ map beat_pulse, to: :zoom, range: 0.12..1.0, attack: 1.0, release: 0.12
103
+ map fft_spectrum => :deform
104
+ end
105
+
106
+ layer :chorus_confetti do
107
+ type :particle_field
108
+ count 5200 # tune: lower to 3000 when FPS drops
109
+ force_field :burst
110
+ size 3.0
111
+ speed 2.4
112
+ blend :add
113
+ map high, to: :sparkle, gain: 2.8, range: 0.2..1.0
114
+ map kick, to: :bass_explosion, gain: 1.6, range: 0.4..2.0, attack: 1.0, release: 0.08
115
+ map fft_spectrum => :deform
116
+ end
117
+ end
118
+
119
+ scene :bridge do
120
+ use_theme :idol_pastel
121
+
122
+ layer :bridge_ribbon do
123
+ shader :waveform_ribbon
124
+ blend :screen
125
+ opacity 0.6
126
+ effect :motion_blur
127
+ effect_intensity 0.12
128
+ map amplitude, to: :opacity, gain: 0.8, range: 0.34..0.76, curve: :sqrt
129
+ map beat_pulse, to: :effect_intensity, range: 0.08..0.28
130
+ map fft_spectrum => :deform
131
+ end
132
+
133
+ layer :bridge_title do
134
+ type :text
135
+ content "BRIDGE"
136
+ font_size 64
137
+ color "#ffffff"
138
+ glow_strength 0.18
139
+ blend :screen
140
+ map mid, to: :glow_strength, gain: 1.8, range: 0.14..0.72
141
+ map beat_pulse, to: :letter_spacing, gain: 12.0, min: 0.0, max: 18.0
142
+ map fft_spectrum => :deform
143
+ end
144
+ end
145
+
146
+ transition from: :verse, to: :pre_chorus do
147
+ on_bar 8
148
+ effect :crossfade, duration: 0.65
149
+ end
150
+
151
+ transition from: :pre_chorus, to: :chorus do
152
+ on_bar 8
153
+ effect :flash, duration: 0.28
154
+ end
155
+
156
+ transition from: :chorus, to: :bridge do
157
+ on_bar 16
158
+ effect :crossfade, duration: 0.8
159
+ end
160
+
161
+ midi :controller, device: :default
162
+
163
+ midi_map note: 36 do
164
+ switch_scene :verse
165
+ end
166
+
167
+ midi_map note: 37 do
168
+ switch_scene :pre_chorus
169
+ end
170
+
171
+ midi_map note: 38 do
172
+ switch_scene :chorus
173
+ end
174
+
175
+ midi_map note: 39 do
176
+ switch_scene :bridge
177
+ end
178
+
179
+ midi_map cc: 1 do |value|
180
+ set :global_intensity, value / 127.0
181
+ end
182
+
183
+ key "1" do
184
+ switch_scene :verse
185
+ end
186
+
187
+ key "2" do
188
+ switch_scene :pre_chorus
189
+ end
190
+
191
+ key "3" do
192
+ switch_scene :chorus
193
+ end
194
+
195
+ key "4" do
196
+ switch_scene :bridge
197
+ end
198
+
199
+ key "t" do
200
+ switch_scene :chorus
201
+ end
202
+
203
+ key "b" do
204
+ blackout
205
+ end
206
+
207
+ key "f" do
208
+ freeze
209
+ end
210
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ # vj_synthwave_retro.rb
4
+ #
5
+ # Genre : Synthwave / Retro 80s
6
+ # BPM : 100-120
7
+ # Duration: sunset, highway, laser
8
+ # Audio : --audio-source mic
9
+ # --audio-source file --audio-file examples/assets/complex_demo_loop.wav
10
+ # Keys : 1 sunset, 2 highway, 3 laser, B blackout, F freeze, Space tap-tempo
11
+ # MIDI : note 36..38 = scenes, CC 1 = global intensity
12
+ Vizcore.define do
13
+ set :global_intensity, 0.86
14
+ audio_normalize mode: :adaptive, window: 3.5, target: 0.82, floor: 0.04
15
+ bpm 112
16
+ tap_tempo key: :space
17
+
18
+ theme :retro_neon do
19
+ palette "#ff006e", "#8338ec", "#3a86ff", "#ffbe0b"
20
+ background "#070019"
21
+ end
22
+
23
+ style :neon_lines do
24
+ blend :add
25
+ opacity 0.72
26
+ end
27
+
28
+ scene :sunset do
29
+ use_theme :retro_neon
30
+
31
+ layer :sun_disc do
32
+ type :shape
33
+ use_style :neon_lines
34
+ circle x: 640, y: 250, radius: 170, count: 8 do
35
+ stroke 3
36
+ map amplitude, to: :radius, gain: 80.0, min: 150.0, max: 230.0, curve: :sqrt
37
+ map beat_pulse, to: :stroke, gain: 4.0, min: 2.0, max: 7.0
38
+ end
39
+ end
40
+
41
+ layer :sunset_spectrum do
42
+ type :spectrogram
43
+ scroll :horizontal
44
+ bins 64
45
+ history 140
46
+ gain 0.7
47
+ opacity 0.36
48
+ blend :screen
49
+ effect :bloom
50
+ effect_intensity 0.14
51
+ map high, to: :gain, gain: 1.4, range: 0.52..1.55
52
+ map beat_pulse, to: :effect_intensity, range: 0.1..0.42
53
+ map fft_spectrum => :deform
54
+ end
55
+ end
56
+
57
+ scene :highway do
58
+ use_theme :retro_neon
59
+
60
+ layer :road_grid do
61
+ type :shape
62
+ use_style :neon_lines
63
+ line x1: 110, y1: 680, x2: 640, y2: 360 do
64
+ stroke 2
65
+ map amplitude, to: :stroke, gain: 5.0, min: 1.0, max: 8.0
66
+ end
67
+ line x1: 1170, y1: 680, x2: 640, y2: 360 do
68
+ stroke 2
69
+ map beat_pulse, to: :stroke, gain: 5.0, min: 1.0, max: 8.0
70
+ end
71
+ line x1: 0, y1: 610, x2: 1280, y2: 610 do
72
+ stroke 2
73
+ map fft_spectrum => :y1
74
+ end
75
+ line x1: 0, y1: 520, x2: 1280, y2: 520 do
76
+ stroke 2
77
+ map mid, to: :stroke, gain: 5.0, min: 1.0, max: 7.0
78
+ end
79
+ end
80
+
81
+ layer :highway_grid_shader do
82
+ shader :neon_grid
83
+ blend :screen
84
+ opacity 0.58
85
+ effect :chromatic
86
+ effect_intensity 0.16
87
+ map low, to: :effect_intensity, gain: 1.4, range: 0.1..0.5
88
+ map beat_pulse, to: :pulse, range: 0.12..0.72
89
+ map fft_spectrum => :deform
90
+ end
91
+ end
92
+
93
+ scene :laser do
94
+ use_theme :retro_neon
95
+
96
+ layer :laser_fan do
97
+ type :shape
98
+ use_style :neon_lines
99
+ line x1: 120, y1: 100, x2: 1180, y2: 650 do
100
+ stroke 4
101
+ map amplitude, to: :stroke, gain: 7.0, min: 2.0, max: 12.0
102
+ end
103
+ line x1: 1180, y1: 100, x2: 120, y2: 650 do
104
+ stroke 4
105
+ map beat_pulse, to: :stroke, gain: 8.0, min: 2.0, max: 13.0
106
+ end
107
+ line x1: 640, y1: 0, x2: 640, y2: 720 do
108
+ stroke 3
109
+ map fft_spectrum => :x1
110
+ end
111
+ end
112
+
113
+ layer :laser_glow do
114
+ shader :glitch_flash
115
+ blend :add
116
+ opacity 0.46
117
+ effect :bloom
118
+ effect_intensity 0.24
119
+ vj_effect :color_shift
120
+ map high, to: :effect_intensity, gain: 2.1, range: 0.18..0.84
121
+ map kick, to: :opacity, gain: 1.1, range: 0.34..0.92
122
+ map fft_spectrum => :deform
123
+ end
124
+ end
125
+
126
+ transition from: :sunset, to: :highway do
127
+ on_bar 8
128
+ effect :crossfade, duration: 0.8
129
+ end
130
+
131
+ transition from: :highway, to: :laser do
132
+ on_bar 8
133
+ effect :flash, duration: 0.25
134
+ end
135
+
136
+ midi :controller, device: :default
137
+
138
+ midi_map note: 36 do
139
+ switch_scene :sunset
140
+ end
141
+
142
+ midi_map note: 37 do
143
+ switch_scene :highway
144
+ end
145
+
146
+ midi_map note: 38 do
147
+ switch_scene :laser
148
+ end
149
+
150
+ midi_map cc: 1 do |value|
151
+ set :global_intensity, value / 127.0
152
+ end
153
+
154
+ key "1" do
155
+ switch_scene :sunset
156
+ end
157
+
158
+ key "2" do
159
+ switch_scene :highway
160
+ end
161
+
162
+ key "3" do
163
+ switch_scene :laser
164
+ end
165
+
166
+ key "b" do
167
+ blackout
168
+ end
169
+
170
+ key "f" do
171
+ freeze
172
+ end
173
+ end
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ # vj_techno_warehouse.rb
4
+ #
5
+ # Genre : Techno / Warehouse
6
+ # BPM : 128-140
7
+ # Duration: long-loopable
8
+ # Audio : --audio-source mic
9
+ # --audio-source file --audio-file examples/assets/complex_demo_loop.wav
10
+ # Keys : 1..4 scenes, B blackout, F freeze, Space tap-tempo
11
+ # MIDI : note 36..39 = scenes, CC 1 = global intensity
12
+ #
13
+ # Keep particle counts near the comments below for laptops; raise them for LED walls.
14
+ Vizcore.define do
15
+ set :global_intensity, 0.85
16
+ audio_normalize mode: :adaptive, window: 4.0, target: 0.82, floor: 0.04
17
+ bpm 134
18
+ bpm_lock true
19
+ tap_tempo key: :space
20
+
21
+ theme :warehouse do
22
+ palette "#050505", "#e8e8e8", "#ff003c"
23
+ background "#000000"
24
+ end
25
+
26
+ style :hard_screen do
27
+ blend :screen
28
+ opacity 0.82
29
+ end
30
+
31
+ scene :loop do
32
+ use_theme :warehouse
33
+
34
+ layer :bg_grid do
35
+ shader :neon_grid
36
+ use_style :hard_screen
37
+ effect :crt
38
+ effect_intensity 0.08
39
+ map bass, to: :effect_intensity, gain: 0.8, range: 0.05..0.22, curve: :sqrt
40
+ map beat_pulse, to: :pulse, range: 0.08..0.32, attack: 1.0, release: 0.16
41
+ map fft_spectrum => :deform
42
+ end
43
+
44
+ layer :floor_mesh do
45
+ type :mesh
46
+ geometry :icosahedron
47
+ material :wireframe
48
+ scale 0.72
49
+ opacity 0.55
50
+ map amplitude, to: :opacity, gain: 0.8, range: 0.38..0.72, curve: :sqrt
51
+ map beat_confidence, to: :scale, gain: 0.28, range: 0.68..1.02
52
+ map fft_spectrum => :deform
53
+ end
54
+ end
55
+
56
+ scene :build do
57
+ use_theme :warehouse
58
+
59
+ layer :ribbon_pressure do
60
+ type :waveform
61
+ source :audio
62
+ style :ribbon
63
+ height 0.34
64
+ opacity 0.78
65
+ blend :screen
66
+ map amplitude, to: :height, gain: 1.4, range: 0.22..0.72, curve: :sqrt, attack: 0.85, release: 0.2
67
+ map kick, to: :color_shift, range: 0.0..0.9, attack: 1.0, release: 0.08
68
+ map fft_spectrum => :deform
69
+ end
70
+
71
+ layer :strobe_particles do
72
+ type :particle_field
73
+ count 2600 # tune: 1800 for older laptops, 5000 for stronger GPUs
74
+ size 2.0
75
+ speed 1.3
76
+ force_field :vortex
77
+ blend :add
78
+ react_to bass do
79
+ change :speed, gain: 2.6, range: 0.6..4.4, curve: :sqrt
80
+ change :opacity, gain: 0.9, range: 0.46..0.94
81
+ end
82
+ map beat_pulse, to: :sparkle, range: 0.1..1.0, attack: 1.0, release: 0.12
83
+ map fft_spectrum => :deform
84
+ end
85
+ end
86
+
87
+ scene :peak do
88
+ use_theme :warehouse
89
+
90
+ layer :crystal_shards do
91
+ shader :ruby_crystal
92
+ blend :screen
93
+ facets 11.0
94
+ refraction 0.62
95
+ effect :chromatic
96
+ effect_intensity 0.18
97
+ map low, to: :refraction, gain: 1.0, range: 0.36..0.9, curve: :sqrt
98
+ map kick, to: :effect_intensity, gain: 1.2, range: 0.16..0.72, attack: 1.0, release: 0.07
99
+ map fft_spectrum => :deform
100
+ end
101
+
102
+ layer :peak_mesh do
103
+ type :mesh
104
+ geometry :icosahedron
105
+ material :wireframe
106
+ scale 0.96
107
+ deform 0.22
108
+ blend :add
109
+ map amplitude, to: :deform, gain: 2.0, range: 0.12..1.25, curve: :sqrt
110
+ map beat_confidence, to: :scale, gain: 0.35, range: 0.84..1.32
111
+ map fft_spectrum => :color_shift
112
+ end
113
+ end
114
+
115
+ scene :breakdown do
116
+ use_theme :warehouse
117
+
118
+ layer :vertical_spectrum do
119
+ type :spectrogram
120
+ scroll :vertical
121
+ bins 96
122
+ history 180
123
+ gain 0.75
124
+ opacity 0.74
125
+ blend :screen
126
+ effect :feedback
127
+ effect_intensity 0.1
128
+ map amplitude, to: :opacity, range: 0.32..0.88, attack: 0.55, release: 0.35
129
+ map high, to: :gain, gain: 1.6, range: 0.55..1.75
130
+ map beat_pulse, to: :effect_intensity, range: 0.04..0.32
131
+ map fft_spectrum => :deform
132
+ end
133
+ end
134
+
135
+ transition from: :loop, to: :build do
136
+ on_bar 16
137
+ effect :crossfade, duration: 1.0
138
+ end
139
+
140
+ transition from: :build, to: :peak do
141
+ trigger { beat_count >= 32 || frame_count >= 480 }
142
+ effect :flash, duration: 0.24
143
+ end
144
+
145
+ transition from: :breakdown, to: :loop do
146
+ on_bar 16
147
+ effect :crossfade, duration: 1.2
148
+ end
149
+
150
+ midi :controller, device: :default
151
+
152
+ midi_map note: 36 do
153
+ switch_scene :loop
154
+ end
155
+
156
+ midi_map note: 37 do
157
+ switch_scene :build
158
+ end
159
+
160
+ midi_map note: 38 do
161
+ switch_scene :peak
162
+ end
163
+
164
+ midi_map note: 39 do
165
+ switch_scene :breakdown
166
+ end
167
+
168
+ midi_map cc: 1 do |value|
169
+ set :global_intensity, value / 127.0
170
+ end
171
+
172
+ key "1" do
173
+ switch_scene :loop
174
+ end
175
+
176
+ key "2" do
177
+ switch_scene :build
178
+ end
179
+
180
+ key "3" do
181
+ switch_scene :peak
182
+ end
183
+
184
+ key "4" do
185
+ switch_scene :breakdown
186
+ end
187
+
188
+ key "b" do
189
+ blackout
190
+ end
191
+
192
+ key "f" do
193
+ freeze
194
+ end
195
+ end