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,131 @@
1
+ export const createLiveControlState = () => ({
2
+ blackout: false,
3
+ freeze: false,
4
+ });
5
+
6
+ export const toggleLiveControl = (state, key) => {
7
+ const control = String(key || "");
8
+ if (control !== "blackout" && control !== "freeze") {
9
+ return { ...state };
10
+ }
11
+
12
+ return {
13
+ ...state,
14
+ [control]: !state?.[control],
15
+ };
16
+ };
17
+
18
+ export const liveControlStatusText = (state) => {
19
+ const values = [];
20
+ if (state?.blackout) values.push("Blackout");
21
+ if (state?.freeze) values.push("Freeze");
22
+ return values.length ? `Live: ${values.join(" + ")}` : "Live: output";
23
+ };
24
+
25
+ export const shortcutActionForKey = (event) => {
26
+ if (isEditableShortcutTarget(event?.target)) {
27
+ return null;
28
+ }
29
+
30
+ const key = String(event?.key || "").toLowerCase();
31
+ if (key === "b") return "blackout";
32
+ if (key === "f") return "freeze";
33
+ return null;
34
+ };
35
+
36
+ export const shortcutSceneIndexForKey = (event, sceneCount) => {
37
+ if (isEditableShortcutTarget(event?.target)) {
38
+ return null;
39
+ }
40
+
41
+ const index = Number.parseInt(String(event?.key || ""), 10) - 1;
42
+ if (!Number.isInteger(index) || index < 0 || index >= 9 || index >= sceneCount) {
43
+ return null;
44
+ }
45
+
46
+ return index;
47
+ };
48
+
49
+ export const keyboardActionForKey = (event, mappings) => {
50
+ if (isEditableShortcutTarget(event?.target)) {
51
+ return null;
52
+ }
53
+
54
+ const key = normalizeShortcutKey(event?.key);
55
+ if (!key) {
56
+ return null;
57
+ }
58
+
59
+ const mapping = normalizeKeyboardMappings(mappings).find((entry) => entry.key === key);
60
+ return mapping?.action || null;
61
+ };
62
+
63
+ export const normalizeKeyboardMappings = (mappings) => {
64
+ if (!Array.isArray(mappings)) {
65
+ return [];
66
+ }
67
+
68
+ return mappings.flatMap((entry) => {
69
+ const key = normalizeShortcutKey(entry?.key);
70
+ const action = normalizeKeyboardAction(entry?.action);
71
+ if (!key || !action) {
72
+ return [];
73
+ }
74
+
75
+ return [{ key, action }];
76
+ });
77
+ };
78
+
79
+ export const isTapTempoShortcut = (event, configuredKey) => {
80
+ if (isEditableShortcutTarget(event?.target)) {
81
+ return false;
82
+ }
83
+
84
+ const key = normalizeShortcutKey(configuredKey);
85
+ if (!key) {
86
+ return false;
87
+ }
88
+
89
+ return normalizeShortcutKey(event?.key) === key;
90
+ };
91
+
92
+ export const normalizeShortcutKey = (value) => {
93
+ const raw = String(value || "");
94
+ if (raw === " ") {
95
+ return "space";
96
+ }
97
+
98
+ const key = raw.trim().toLowerCase();
99
+ if (key === "spacebar") {
100
+ return "space";
101
+ }
102
+
103
+ return key;
104
+ };
105
+
106
+ const normalizeKeyboardAction = (action) => {
107
+ const type = String(action?.type || "").trim();
108
+ if (type === "switch_scene") {
109
+ const scene = String(action?.scene || "").trim();
110
+ return scene ? { type, scene } : null;
111
+ }
112
+
113
+ if (type === "live_control") {
114
+ const control = String(action?.control || "").trim();
115
+ return control === "blackout" || control === "freeze" ? { type, control } : null;
116
+ }
117
+
118
+ return null;
119
+ };
120
+
121
+ export const isEditableShortcutTarget = (target) => {
122
+ if (!target) {
123
+ return false;
124
+ }
125
+
126
+ const tagName = String(target.tagName || "").toLowerCase();
127
+ return tagName === "input"
128
+ || tagName === "textarea"
129
+ || tagName === "select"
130
+ || target.isContentEditable === true;
131
+ };