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
@@ -1,15 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "base64"
3
4
  require "pathname"
4
5
 
5
6
  module Vizcore
6
7
  module DSL
7
- # Replaces layer `glsl` paths with inlined shader source text.
8
+ # Replaces external layer source paths with browser-ready inline payloads.
8
9
  class ShaderSourceResolver
10
+ MEDIA_MIME_TYPES = {
11
+ ".gif" => "image/gif",
12
+ ".jpg" => "image/jpeg",
13
+ ".jpeg" => "image/jpeg",
14
+ ".png" => "image/png",
15
+ ".svg" => "image/svg+xml",
16
+ ".webp" => "image/webp",
17
+ ".mp4" => "video/mp4",
18
+ ".ogv" => "video/ogg",
19
+ ".webm" => "video/webm"
20
+ }.freeze
21
+
9
22
  # @param definition [Hash] DSL definition payload
10
23
  # @param scene_file [String, Pathname] source scene file
11
- # @raise [ArgumentError] when a referenced GLSL file is missing
12
- # @return [Hash] deep-copied definition with `:glsl_source` entries
24
+ # @raise [ArgumentError] when a referenced source file is missing
25
+ # @return [Hash] deep-copied definition with resolved layer source entries
13
26
  def resolve(definition:, scene_file:)
14
27
  scene_path = Pathname.new(scene_file.to_s).expand_path
15
28
  base_dir = scene_path.dirname
@@ -29,8 +42,13 @@ module Vizcore
29
42
  def resolve_layer(layer, base_dir:)
30
43
  layer_hash = symbolize_hash(layer)
31
44
  shader_path = layer_hash[:glsl]
32
- return layer_hash unless shader_path
45
+ layer_hash = resolve_shader_layer(layer_hash, base_dir: base_dir) if shader_path
46
+ layer_hash = resolve_media_layer(layer_hash, base_dir: base_dir) if media_layer?(layer_hash)
47
+ layer_hash
48
+ end
33
49
 
50
+ def resolve_shader_layer(layer_hash, base_dir:)
51
+ shader_path = layer_hash.fetch(:glsl)
34
52
  full_path = resolve_path(base_dir: base_dir, shader_path: shader_path)
35
53
  raise ArgumentError, "GLSL file not found: #{shader_path}" unless full_path.file?
36
54
 
@@ -39,8 +57,51 @@ module Vizcore
39
57
  layer_hash
40
58
  end
41
59
 
42
- def resolve_path(base_dir:, shader_path:)
43
- path = Pathname.new(shader_path.to_s)
60
+ def resolve_media_layer(layer_hash, base_dir:)
61
+ params = symbolize_hash(layer_hash[:params] || {})
62
+ media_path = params[:file]
63
+ return layer_hash unless media_path
64
+
65
+ full_path = resolve_path(base_dir: base_dir, relative_path: media_path)
66
+ raise ArgumentError, "#{media_layer_label(layer_hash)} file not found: #{media_path}" unless full_path.file?
67
+
68
+ mime_type = MEDIA_MIME_TYPES[full_path.extname.downcase]
69
+ raise ArgumentError, "Unsupported #{media_layer_label(layer_hash)} file extension: #{media_path}" unless mime_type
70
+ raise ArgumentError, "Unsupported SVG file extension: #{media_path}" if svg_layer?(layer_hash) && mime_type != "image/svg+xml"
71
+ raise ArgumentError, "Unsupported Image file extension: #{media_path}" if image_layer?(layer_hash) && !mime_type.start_with?("image/")
72
+ raise ArgumentError, "Unsupported Video file extension: #{media_path}" if video_layer?(layer_hash) && !mime_type.start_with?("video/")
73
+
74
+ params[:file] = media_path.to_s
75
+ params[:src] = "data:#{mime_type};base64,#{Base64.strict_encode64(full_path.binread)}"
76
+ layer_hash[:params] = params
77
+ layer_hash
78
+ end
79
+
80
+ def svg_layer?(layer_hash)
81
+ %i[svg svg_layer].include?(layer_hash[:type]&.to_sym)
82
+ end
83
+
84
+ def image_layer?(layer_hash)
85
+ %i[image image_layer photo].include?(layer_hash[:type]&.to_sym)
86
+ end
87
+
88
+ def video_layer?(layer_hash)
89
+ %i[video video_layer footage].include?(layer_hash[:type]&.to_sym)
90
+ end
91
+
92
+ def media_layer?(layer_hash)
93
+ svg_layer?(layer_hash) || image_layer?(layer_hash) || video_layer?(layer_hash)
94
+ end
95
+
96
+ def media_layer_label(layer_hash)
97
+ return "SVG" if svg_layer?(layer_hash)
98
+ return "Video" if video_layer?(layer_hash)
99
+
100
+ "Image"
101
+ end
102
+
103
+ def resolve_path(base_dir:, relative_path: nil, shader_path: nil)
104
+ path = Pathname.new((relative_path || shader_path).to_s)
44
105
  return path.expand_path if path.absolute?
45
106
 
46
107
  base_dir.join(path).expand_path
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vizcore
4
+ module DSL
5
+ # Collects reusable layer parameter presets for the `style` DSL.
6
+ class StyleBuilder
7
+ # @param name [Symbol, String] style identifier
8
+ # @param kind [String] user-facing DSL kind for error messages
9
+ def initialize(name:, kind: "style")
10
+ @name = name.to_sym
11
+ @kind = kind
12
+ @params = {}
13
+ end
14
+
15
+ # Evaluate a style block.
16
+ #
17
+ # @yield Style parameter declarations
18
+ # @return [Vizcore::DSL::StyleBuilder]
19
+ def evaluate(&block)
20
+ instance_eval(&block) if block
21
+ raise ArgumentError, "#{@kind} #{@name} requires at least one parameter" if @params.empty?
22
+
23
+ self
24
+ end
25
+
26
+ # @return [Hash] serialized style payload
27
+ def to_h
28
+ {
29
+ name: @name,
30
+ params: @params.dup
31
+ }
32
+ end
33
+
34
+ # Store an ordered color palette for styles and themes.
35
+ #
36
+ # @param colors [Array<String, Array<String>>] color values such as "#00ffff"
37
+ # @raise [ArgumentError] when no non-blank colors are supplied
38
+ # @return [Array<String>]
39
+ def palette(*colors)
40
+ @params[:palette] = normalize_palette(colors)
41
+ end
42
+
43
+ # Stores one-argument style setters into `params`.
44
+ # @api private
45
+ def method_missing(method_name, *args, &block)
46
+ if block.nil? && args.length == 1
47
+ @params[method_name.to_sym] = args.first
48
+ return args.first
49
+ end
50
+
51
+ super
52
+ end
53
+
54
+ def respond_to_missing?(_method_name, _include_private = false)
55
+ true
56
+ end
57
+
58
+ private
59
+
60
+ def normalize_palette(colors)
61
+ values = colors.flatten.map { |color| color.to_s.strip }.reject(&:empty?)
62
+ raise ArgumentError, "#{@kind} #{@name} palette requires at least one color" if values.empty?
63
+
64
+ values
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vizcore
4
+ module DSL
5
+ # Collects ordered timeline scene markers and converts them to transitions.
6
+ class TimelineBuilder
7
+ DEFAULT_BEATS_PER_BAR = 4
8
+
9
+ Point = Struct.new(:value, :unit, keyword_init: true)
10
+
11
+ def initialize(beats_per_bar: DEFAULT_BEATS_PER_BAR)
12
+ @beats_per_bar = positive_integer(beats_per_bar, "beats_per_bar")
13
+ @entries = []
14
+ end
15
+
16
+ # Evaluate a timeline block.
17
+ #
18
+ # @yield Timeline marker definitions
19
+ # @return [Vizcore::DSL::TimelineBuilder]
20
+ def evaluate(&block)
21
+ instance_eval(&block) if block
22
+ validate_entries!
23
+ self
24
+ end
25
+
26
+ # Add a scene marker at a timeline position.
27
+ #
28
+ # @param position [Numeric, Point] seconds by default, or a value from `seconds`, `beats`, or `bars`
29
+ # @param scene [Symbol, String] scene to activate at the position
30
+ # @return [Hash]
31
+ def at(position, scene:)
32
+ point = normalize_position(position)
33
+ entry = {
34
+ at: point.value,
35
+ unit: point.unit,
36
+ scene: scene.to_sym
37
+ }
38
+ @entries << entry
39
+ entry
40
+ end
41
+
42
+ # @param value [Numeric] seconds from the timeline start
43
+ # @return [Point]
44
+ def seconds(value)
45
+ Point.new(value: non_negative_float(value, "timeline seconds"), unit: :seconds)
46
+ end
47
+
48
+ # @param value [Numeric] beats from the timeline start
49
+ # @return [Point]
50
+ def beats(value)
51
+ Point.new(value: non_negative_float(value, "timeline beats"), unit: :beats)
52
+ end
53
+
54
+ # @param value [Numeric] bars from the timeline start
55
+ # @param beats_per_bar [Integer, nil] meter override
56
+ # @return [Point]
57
+ def bars(value, beats_per_bar: nil)
58
+ beats_per_measure = beats_per_bar.nil? ? @beats_per_bar : positive_integer(beats_per_bar, "beats_per_bar")
59
+ beats(non_negative_float(value, "timeline bars") * beats_per_measure)
60
+ end
61
+
62
+ # @return [Array<Hash>] serialized marker definitions
63
+ def to_h
64
+ @entries.map(&:dup)
65
+ end
66
+
67
+ # @return [Array<Hash>] generated scene transitions
68
+ def transitions
69
+ @entries.each_cons(2).map do |from_entry, to_entry|
70
+ delta = to_entry.fetch(:at) - from_entry.fetch(:at)
71
+ {
72
+ from: from_entry.fetch(:scene),
73
+ to: to_entry.fetch(:scene),
74
+ trigger: trigger_for(delta, from_entry.fetch(:unit))
75
+ }
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def normalize_position(position)
82
+ return position if position.is_a?(Point)
83
+
84
+ seconds(position)
85
+ end
86
+
87
+ def trigger_for(delta, unit)
88
+ case unit
89
+ when :seconds
90
+ proc { seconds >= delta }
91
+ when :beats
92
+ proc { beat_count >= delta }
93
+ else
94
+ proc { false }
95
+ end
96
+ end
97
+
98
+ def validate_entries!
99
+ return if @entries.length < 2
100
+
101
+ unit = @entries.first.fetch(:unit)
102
+ @entries.each_cons(2) do |from_entry, to_entry|
103
+ raise ArgumentError, "timeline entries must use the same unit" unless to_entry.fetch(:unit) == unit
104
+
105
+ from_position = from_entry.fetch(:at)
106
+ to_position = to_entry.fetch(:at)
107
+ raise ArgumentError, "timeline positions must increase" unless to_position > from_position
108
+ end
109
+ end
110
+
111
+ def non_negative_float(value, name)
112
+ numeric = parse_float(value, name)
113
+ raise ArgumentError, "#{name} must be non-negative" if numeric.negative?
114
+
115
+ numeric
116
+ end
117
+
118
+ def positive_integer(value, name)
119
+ numeric = parse_integer(value, name)
120
+ raise ArgumentError, "#{name} must be positive" unless numeric.positive?
121
+
122
+ numeric
123
+ end
124
+
125
+ def parse_float(value, name)
126
+ Float(value)
127
+ rescue ArgumentError, TypeError
128
+ raise ArgumentError, "#{name} must be numeric"
129
+ end
130
+
131
+ def parse_integer(value, name)
132
+ Integer(value)
133
+ rescue ArgumentError, TypeError
134
+ raise ArgumentError, "#{name} must be an integer"
135
+ end
136
+ end
137
+ end
138
+ end
@@ -4,6 +4,8 @@ module Vizcore
4
4
  module DSL
5
5
  # Evaluates transition rules and returns scene-change payloads.
6
6
  class TransitionController
7
+ DEFAULT_FRAME_RATE = 60.0
8
+
7
9
  # @param scenes [Array<Hash>]
8
10
  # @param transitions [Array<Hash>]
9
11
  def initialize(scenes:, transitions:)
@@ -108,6 +110,8 @@ module Vizcore
108
110
  def initialize(audio, frame_count:)
109
111
  @audio = symbolize_hash(audio)
110
112
  @bands = symbolize_hash(@audio[:bands])
113
+ @onsets = symbolize_hash(@audio[:onsets])
114
+ @drums = symbolize_hash(@audio[:drums])
111
115
  @frame_count = Integer(frame_count)
112
116
  rescue StandardError
113
117
  @frame_count = 0
@@ -124,16 +128,84 @@ module Vizcore
124
128
  @bands[name.to_sym].to_f
125
129
  end
126
130
 
131
+ # @return [Float]
132
+ def sub
133
+ frequency_band(:sub)
134
+ end
135
+
136
+ # @return [Float]
137
+ def low
138
+ frequency_band(:low)
139
+ end
140
+
141
+ # @return [Float]
142
+ def bass
143
+ frequency_band(:low)
144
+ end
145
+
146
+ # @return [Float]
147
+ def mid
148
+ frequency_band(:mid)
149
+ end
150
+
151
+ # @return [Float]
152
+ def high
153
+ frequency_band(:high)
154
+ end
155
+
156
+ # @return [Float]
157
+ def treble
158
+ frequency_band(:high)
159
+ end
160
+
127
161
  # @return [Array<Float>]
128
162
  def fft_spectrum
129
163
  Array(@audio[:fft])
130
164
  end
131
165
 
166
+ # @param name [Symbol, String, nil]
167
+ # @return [Float]
168
+ def onset(name = nil)
169
+ return @audio[:onset].to_f if name.nil?
170
+
171
+ @onsets[name.to_sym].to_f
172
+ end
173
+
174
+ # @return [Float]
175
+ def kick
176
+ @drums[:kick].to_f
177
+ end
178
+
179
+ # @return [Float]
180
+ def snare
181
+ @drums[:snare].to_f
182
+ end
183
+
184
+ # @return [Float]
185
+ def hihat
186
+ @drums[:hihat].to_f
187
+ end
188
+
132
189
  # @return [Boolean]
133
190
  def beat?
134
191
  !!@audio[:beat]
135
192
  end
136
193
 
194
+ # @return [Boolean]
195
+ def beat
196
+ beat?
197
+ end
198
+
199
+ # @return [Float]
200
+ def beat_confidence
201
+ @audio[:beat_confidence].to_f
202
+ end
203
+
204
+ # @return [Float]
205
+ def beat_pulse
206
+ @audio[:beat_pulse].to_f
207
+ end
208
+
137
209
  # @return [Integer]
138
210
  def beat_count
139
211
  Integer(@audio[:beat_count] || 0)
@@ -151,6 +223,11 @@ module Vizcore
151
223
  @frame_count
152
224
  end
153
225
 
226
+ # @return [Float] scene-local elapsed seconds at the default runtime frame rate
227
+ def seconds
228
+ @frame_count / DEFAULT_FRAME_RATE
229
+ end
230
+
154
231
  private
155
232
 
156
233
  def symbolize_hash(value)
data/lib/vizcore/dsl.rb CHANGED
@@ -6,11 +6,15 @@ module Vizcore
6
6
  end
7
7
  end
8
8
 
9
- require_relative "dsl/layer_builder"
10
9
  require_relative "dsl/file_watcher"
11
10
  require_relative "dsl/mapping_resolver"
11
+ require_relative "dsl/mapping_transform_builder"
12
12
  require_relative "dsl/midi_map_executor"
13
+ require_relative "dsl/reaction_builder"
14
+ require_relative "dsl/style_builder"
15
+ require_relative "dsl/layer_builder"
13
16
  require_relative "dsl/scene_builder"
14
17
  require_relative "dsl/shader_source_resolver"
18
+ require_relative "dsl/timeline_builder"
15
19
  require_relative "dsl/transition_controller"
16
20
  require_relative "dsl/engine"