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
@@ -9,6 +9,10 @@ module Vizcore
9
9
  module Server
10
10
  # Stateless WebSocket endpoint manager for frame broadcast transport.
11
11
  class WebSocketHandler
12
+ PROTOCOL_VERSION = "vizcore.frame.v1"
13
+ MAX_BUFFERED_FRAME_BYTES = 1_000_000
14
+ DROPPABLE_MESSAGE_TYPES = Set["audio_frame"].freeze
15
+
12
16
  class << self
13
17
  # Rack endpoint for WebSocket upgrade handling.
14
18
  #
@@ -36,15 +40,29 @@ module Vizcore
36
40
  def broadcast(type:, payload:)
37
41
  return false unless faye_websocket_class
38
42
 
39
- message = JSON.generate(type: type, payload: payload)
43
+ message = JSON.generate(protocol: PROTOCOL_VERSION, type: type, payload: payload)
40
44
 
41
45
  each_socket do |socket|
42
- send_message(socket, message)
46
+ send_message(socket, message, type: type)
43
47
  end
44
48
 
45
49
  true
46
50
  end
47
51
 
52
+ # Send one typed payload to a single websocket client.
53
+ #
54
+ # @param socket [#send]
55
+ # @param type [String]
56
+ # @param payload [Hash]
57
+ # @return [Boolean] false when websocket backend is unavailable
58
+ def send_to(socket, type:, payload:)
59
+ return false unless faye_websocket_class
60
+
61
+ message = JSON.generate(protocol: PROTOCOL_VERSION, type: type, payload: payload)
62
+ send_message(socket, message, type: type)
63
+ true
64
+ end
65
+
48
66
  # @return [Integer]
49
67
  def connection_count
50
68
  mutex.synchronize { sockets.size }
@@ -55,6 +73,11 @@ module Vizcore
55
73
  mutex.synchronize { @last_error }
56
74
  end
57
75
 
76
+ # @return [Integer]
77
+ def dropped_frame_count
78
+ mutex.synchronize { @dropped_frame_count || 0 }
79
+ end
80
+
58
81
  # Register one inbound message handler for client -> server control messages.
59
82
  #
60
83
  # @yieldparam message [Hash]
@@ -79,21 +102,44 @@ module Vizcore
79
102
  nil
80
103
  end
81
104
 
82
- def send_message(socket, message)
105
+ def send_message(socket, message, type:)
106
+ return if drop_for_backpressure?(socket, type)
107
+
83
108
  if event_machine_reactor_running?
84
- EventMachine.schedule { safe_send(socket, message) }
109
+ EventMachine.schedule { safe_send(socket, message, type: type) }
85
110
  else
86
- safe_send(socket, message)
111
+ safe_send(socket, message, type: type)
87
112
  end
88
113
  end
89
114
 
90
- def safe_send(socket, message)
115
+ def safe_send(socket, message, type:)
116
+ return if drop_for_backpressure?(socket, type)
117
+
91
118
  socket.send(message)
92
119
  rescue StandardError => e
93
120
  set_last_error(e)
94
121
  unregister(socket)
95
122
  end
96
123
 
124
+ def drop_for_backpressure?(socket, type)
125
+ return false unless DROPPABLE_MESSAGE_TYPES.include?(type.to_s)
126
+
127
+ buffered_amount = socket_buffered_amount(socket)
128
+ return false unless buffered_amount && buffered_amount > MAX_BUFFERED_FRAME_BYTES
129
+
130
+ increment_dropped_frame_count
131
+ true
132
+ end
133
+
134
+ def socket_buffered_amount(socket)
135
+ return socket.buffered_amount if socket.respond_to?(:buffered_amount)
136
+ return socket.bufferedAmount if socket.respond_to?(:bufferedAmount)
137
+
138
+ nil
139
+ rescue StandardError
140
+ nil
141
+ end
142
+
97
143
  def event_machine_reactor_running?
98
144
  require "eventmachine"
99
145
  EventMachine.reactor_running?
@@ -105,9 +151,9 @@ module Vizcore
105
151
  [500, json_headers, [JSON.generate(error: "Missing dependency: faye-websocket")]]
106
152
  end
107
153
 
108
- def handle_message(_socket, raw_message)
154
+ def handle_message(socket, raw_message)
109
155
  message = JSON.parse(raw_message)
110
- dispatch_message(message)
156
+ dispatch_message(message, socket)
111
157
  message
112
158
  rescue JSON::ParserError => e
113
159
  set_last_error(e)
@@ -139,12 +185,16 @@ module Vizcore
139
185
  mutex.synchronize { @last_error = error }
140
186
  end
141
187
 
142
- def dispatch_message(message)
188
+ def increment_dropped_frame_count
189
+ mutex.synchronize { @dropped_frame_count = (@dropped_frame_count || 0) + 1 }
190
+ end
191
+
192
+ def dispatch_message(message, socket)
143
193
  handler = mutex.synchronize { @message_handler }
144
194
  return unless handler
145
195
  return unless message.is_a?(Hash)
146
196
 
147
- handler.call(message)
197
+ handler.call(message, socket)
148
198
  rescue StandardError => e
149
199
  set_last_error(e)
150
200
  nil
@@ -7,6 +7,10 @@ module Vizcore
7
7
  end
8
8
 
9
9
  require_relative "server/frame_broadcaster"
10
+ require_relative "server/gallery_page"
11
+ require_relative "server/gallery_app"
12
+ require_relative "server/gallery_runner"
10
13
  require_relative "server/rack_app"
14
+ require_relative "server/scene_dependency_watcher"
11
15
  require_relative "server/runner"
12
16
  require_relative "server/websocket_handler"