Class: Vizcore::CLI
- Inherits:
-
Thor
- Object
- Thor
- Vizcore::CLI
- Defined in:
- lib/vizcore/cli.rb
Overview
Thor-based CLI entrypoint for Vizcore.
Constant Summary collapse
- SCAFFOLD_TEMPLATES =
{ "standard" => { label: "standard", start_scene: "scenes/basic.rb", files: [ ["basic_scene.rb", "scenes/basic.rb", "Minimal wireframe starter"], ["intro_drop_scene.rb", "scenes/intro_drop.rb", "Transition flow with beat trigger"], ["midi_control_scene.rb", "scenes/midi_control.rb", "MIDI note/CC mapping example"], ["custom_shader_scene.rb", "scenes/custom_shader.rb", "Custom GLSL + post/VJ effect example"], ["custom_wave.frag", "shaders/custom_wave.frag", "Custom GLSL fragment shader"] ], notes: [ "`scenes/custom_shader.rb` references `shaders/custom_wave.frag`.", "Use `vizcore devices midi` before running `scenes/midi_control.rb`." ] }, "minimal" => { label: "minimal", start_scene: "scenes/basic.rb", files: [ ["basic_scene.rb", "scenes/basic.rb", "Minimal wireframe starter"] ], notes: [] }, "shader" => { label: "shader", start_scene: "scenes/custom_shader.rb", files: [ ["custom_shader_scene.rb", "scenes/custom_shader.rb", "Custom GLSL + post/VJ effect example"], ["custom_wave.frag", "shaders/custom_wave.frag", "Custom GLSL fragment shader"] ], notes: [ "`scenes/custom_shader.rb` references `shaders/custom_wave.frag`." ] }, "midi" => { label: "midi", start_scene: "scenes/midi_control.rb", files: [ ["midi_control_scene.rb", "scenes/midi_control.rb", "MIDI note/CC mapping example"] ], notes: [ "Run `vizcore devices midi` before starting the MIDI scene." ] }, "live-set" => { label: "live-set", start_scene: "scenes/live_set.rb", files: [ ["intro_drop_scene.rb", "scenes/live_set.rb", "Two-scene transition flow with beat trigger"] ], notes: [ "Use file audio or a microphone input with clear beats for transition triggers." ] }, "rubykaigi" => { label: "rubykaigi", start_scene: "scenes/rubykaigi.rb", files: [ ["rubykaigi_scene.rb", "scenes/rubykaigi.rb", "Ruby conference visual starter"] ], notes: [ "This scene uses Ruby-red text and audio-reactive geometry for talk or event visuals." ] } }.freeze
- PLUGIN_SCAFFOLD_FILES =
[ ["plugin_readme.md", "README.md"], ["plugin_layer.rb", "lib/{{plugin_name}}.rb"], ["plugin_renderer.js", "frontend/{{plugin_name}}-renderer.js"], ["plugin_scene.rb", "examples/{{plugin_name}}_scene.rb"] ].freeze
- DEFAULT_CAPTURE_PORT =
4579
Class Method Summary collapse
-
.exit_on_failure? ⇒ Boolean
Exit with non-zero status when a Thor command fails.
Instance Method Summary collapse
-
#browser_capture(url) ⇒ void
Capture browser-rendered output from a running Vizcore server.
-
#calibrate(command = nil) ⇒ void
Run calibration helpers.
-
#capture(scene_file) ⇒ void
Start Vizcore and capture a browser-rendered canvas from the projector route.
-
#demo ⇒ void
Start a bundled scene with bundled audio for first-run verification.
-
#devices(type = nil) ⇒ void
Print audio and/or MIDI devices detected by the runtime.
-
#doctor ⇒ void
Print local environment checks for Vizcore runtime dependencies.
-
#dsl_docs ⇒ void
Print generated documentation for the Ruby scene DSL.
-
#features ⇒ void
Print optional dependency feature flags for automation and doctor-style checks.
-
#gallery ⇒ void
Start a browser gallery for bundled example scenes.
-
#inspect_scene(scene_file) ⇒ void
Load a scene DSL file and print its runtime structure.
-
#layers ⇒ void
Print supported layer types, params, and browser-side capabilities.
-
#new(name) ⇒ void
Generate a new Vizcore project scaffold.
-
#plugin(command = nil, name = nil) ⇒ void
Run plugin helper commands.
-
#record_features(audio_file) ⇒ void
Analyze an audio file and persist feature frames as JSON.
-
#render(scene_file) ⇒ void
Load a scene DSL file and write a software-rendered PNG image sequence or MP4.
-
#shader(command = nil, name = nil) ⇒ void
Run custom shader helper commands.
-
#shader_docs ⇒ void
Print generated documentation for custom GLSL uniforms.
-
#snapshot(scene_file) ⇒ void
Load a scene DSL file and write a software-rendered PNG preview.
-
#start(scene_file = nil) ⇒ void
Start the Vizcore server with the given scene file.
-
#validate(scene_file) ⇒ void
Load and validate a scene DSL file without starting the server.
Class Method Details
.exit_on_failure? ⇒ Boolean
Exit with non-zero status when a Thor command fails.
31 32 33 |
# File 'lib/vizcore/cli.rb', line 31 def self.exit_on_failure? true end |
Instance Method Details
#browser_capture(url) ⇒ void
This method returns an undefined value.
Capture browser-rendered output from a running Vizcore server.
447 448 449 450 451 452 453 454 455 456 457 458 |
# File 'lib/vizcore/cli.rb', line 447 def browser_capture(url) run_browser_capture( url, out: .fetch(:out), selector: .fetch(:selector), wait: .fetch(:wait), width: .fetch(:width), height: .fetch(:height), wait_for_frame: .fetch(:wait_for_frame), frame_timeout: .fetch(:frame_timeout) ) end |
#calibrate(command = nil) ⇒ void
This method returns an undefined value.
Run calibration helpers.
308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'lib/vizcore/cli.rb', line 308 def calibrate(command = nil) raise Thor::Error, "Unknown calibrate command: #{command || '(nil)'}. Use `vizcore calibrate audio`." unless command.to_s == "audio" result = Vizcore::Audio::Calibration.new( source: .fetch(:audio_source), file_path: [:audio_file], audio_device: [:audio_device], duration: .fetch(:duration), fps: .fetch(:fps) ).call print_calibration_result(result, format: .fetch(:format)) rescue ArgumentError => e raise Thor::Error, e. end |
#capture(scene_file) ⇒ void
This method returns an undefined value.
Start Vizcore and capture a browser-rendered canvas from the projector route.
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 |
# File 'lib/vizcore/cli.rb', line 482 def capture(scene_file) config = Config.new( scene_file: scene_file, host: .fetch(:host), port: .fetch(:port), audio_source: .fetch(:audio_source), audio_file: [:audio_file], feature_file: [:feature_file], control_preset: [:control_preset], reload: false, projector_mode: true, allow_public_control: .fetch(:allow_public_control) ) validate_snapshot_config!(config) warn_untrusted_scene(config.scene_file) unless .fetch(:trust) pid = Kernel.spawn(*temporary_server_command(config), out: File::NULL, err: File::NULL) begin wait_for_http("http://#{config.host}:#{config.port}/health", timeout: .fetch(:timeout)) run_browser_capture( "http://#{config.host}:#{config.port}/projector", out: .fetch(:out), selector: .fetch(:selector), wait: .fetch(:wait), width: .fetch(:width), height: .fetch(:height), wait_for_frame: .fetch(:wait_for_frame), frame_timeout: .fetch(:frame_timeout) ) ensure stop_temporary_server(pid) end rescue StandardError => e raise Thor::Error, e. end |
#demo ⇒ void
This method returns an undefined value.
Start a bundled scene with bundled audio for first-run verification.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/vizcore/cli.rb', line 183 def demo config = Config.new( scene_file: Vizcore.root.join("examples", "rhythm_geometry.rb"), host: .fetch(:host), port: .fetch(:port), audio_source: :file, audio_file: Vizcore.root.join("examples", "assets", "complex_demo_loop.wav"), noise_gate: .fetch(:noise_gate), bpm: [:bpm], bpm_lock: .fetch(:bpm_lock), control_preset: [:control_preset], osc_port: [:osc_port], scene_switch_effect: [:scene_switch_effect], scene_switch_effect_duration: [:scene_switch_duration], projector_mode: .fetch(:projector), allow_public_control: .fetch(:allow_public_control) ) Server::Runner.new(config).run rescue ArgumentError => e raise Thor::Error, e. end |
#devices(type = nil) ⇒ void
This method returns an undefined value.
Print audio and/or MIDI devices detected by the runtime.
249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/vizcore/cli.rb', line 249 def devices(type = nil) case type when nil print_audio_devices print_midi_devices when "audio" print_audio_devices when "midi" print_midi_devices else raise Thor::Error, "Unknown type: #{type}. Use `audio` or `midi`." end end |
#doctor ⇒ void
This method returns an undefined value.
Print local environment checks for Vizcore runtime dependencies.
268 269 270 271 272 273 274 |
# File 'lib/vizcore/cli.rb', line 268 def doctor report = Vizcore::CLISupport::Doctor.new.call report.checks.each do |check| say("#{status_label(check.status)} #{check.name}: #{check.}") end raise Thor::Error, "vizcore doctor found required failures" if report.failure? end |
#dsl_docs ⇒ void
This method returns an undefined value.
Print generated documentation for the Ruby scene DSL.
380 381 382 |
# File 'lib/vizcore/cli.rb', line 380 def dsl_docs Vizcore::CLISupport::DslReference.new.lines.each { |line| say(line) } end |
#features ⇒ void
This method returns an undefined value.
Print optional dependency feature flags for automation and doctor-style checks.
282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/vizcore/cli.rb', line 282 def features payload = Vizcore.features case .fetch(:format).to_s when "json" say(JSON.pretty_generate(payload.transform_keys(&:to_s))) when "text" payload.each do |name, available| say("#{available ? '[ok]' : '[warn]'} #{name}: #{available ? 'available' : 'unavailable'}") end else raise Thor::Error, "unsupported features format: #{.fetch(:format)}" end end |
#gallery ⇒ void
This method returns an undefined value.
Start a browser gallery for bundled example scenes.
211 212 213 214 215 216 |
# File 'lib/vizcore/cli.rb', line 211 def gallery Vizcore::Server::GalleryRunner.new( host: .fetch(:host), port: .fetch(:port) ).run end |
#inspect_scene(scene_file) ⇒ void
This method returns an undefined value.
Load a scene DSL file and print its runtime structure.
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/vizcore/cli.rb', line 331 def inspect_scene(scene_file) format = .fetch(:format).to_s diagnostics = Vizcore::CLISupport::SceneDiagnostics.new(scene_file: scene_file) result = diagnostics.validate if format == "json" payload = { issues: result.issues.map(&:to_h), definition: result.definition ? Vizcore::CLISupport::SceneInspector.new(definition: result.definition).to_h : nil } say(JSON.pretty_generate(payload)) raise Thor::Error, "scene inspection failed" unless result.definition return end raise Thor::Error, "unsupported inspect format: #{format}" unless format == "text" print_issues(result.issues) raise Thor::Error, "scene inspection failed" unless result.definition diagnostics.inspect_lines(result.definition).each { |line| say(line) } end |
#layers ⇒ void
This method returns an undefined value.
Print supported layer types, params, and browser-side capabilities.
371 372 373 |
# File 'lib/vizcore/cli.rb', line 371 def layers Vizcore::CLISupport::LayerDocs.new.lines.each { |line| say(line) } end |
#new(name) ⇒ void
This method returns an undefined value.
Generate a new Vizcore project scaffold.
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/vizcore/cli.rb', line 227 def new(name) scaffold = scaffold_template(.fetch(:template)) root = Pathname.new(name). FileUtils.mkdir_p(root) write_project_readme(root.join("README.md"), project_name: name, scaffold: scaffold) scaffold.fetch(:files).each do |template_name, destination, _description| write_template(template_name, root.join(destination), project_name: name) end say("Created project scaffold (#{scaffold.fetch(:label)}): #{root}") say("Next: cd #{name} && vizcore start #{scaffold.fetch(:start_scene)}") rescue ArgumentError => e raise Thor::Error, e. end |
#plugin(command = nil, name = nil) ⇒ void
This method returns an undefined value.
Run plugin helper commands.
420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/vizcore/cli.rb', line 420 def plugin(command = nil, name = nil) case command.to_s when "new" create_plugin_scaffold(name) when "check" check_plugin_scaffold(name) else raise Thor::Error, "Unknown plugin command: #{command || '(nil)'}. Use `vizcore plugin new NAME` or `vizcore plugin check PATH`." end rescue ArgumentError => e raise Thor::Error, e. end |
#record_features(audio_file) ⇒ void
This method returns an undefined value.
Analyze an audio file and persist feature frames as JSON.
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 |
# File 'lib/vizcore/cli.rb', line 649 def record_features(audio_file) result = Vizcore::Analysis::FeatureRecorder.new( audio_file: audio_file, frames: .fetch(:frames), fps: .fetch(:fps), noise_gate: .fetch(:noise_gate), audio_normalize: feature_audio_normalize_setting, bpm: [:bpm], bpm_lock: .fetch(:bpm_lock), cache_root: feature_record_cache_root ).write(out: .fetch(:out)) say( "Features written: #{result[:path]} " \ "(frames=#{result[:frames]}, fps=#{result[:fps]}, sample_rate=#{result[:sample_rate]})" ) rescue StandardError => e raise Thor::Error, e. end |
#render(scene_file) ⇒ void
This method returns an undefined value.
Load a scene DSL file and write a software-rendered PNG image sequence or MP4.
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 |
# File 'lib/vizcore/cli.rb', line 590 def render(scene_file) feature_file = resolve_render_feature_cache if feature_cache_enabled?(scene_file: scene_file) config = Config.new( scene_file: scene_file, audio_source: .fetch(:audio_source), audio_file: [:audio_file], audio_device: [:audio_device], noise_gate: .fetch(:noise_gate), bpm: [:bpm], bpm_lock: .fetch(:bpm_lock), feature_file: feature_file ) validate_snapshot_config!(config) warn_untrusted_scene(config.scene_file) unless .fetch(:trust) result = Vizcore::Renderer::RenderSequence.new( config: config, frames: .fetch(:frames), fps: .fetch(:fps), width: .fetch(:width), height: .fetch(:height), duration: [:duration], from_frame: .fetch(:from_frame), to_frame: [:to_frame], resume: .fetch(:resume), seed: [:seed], transparent: .fetch(:transparent), video_codec: [:codec], video_bitrate: [:bitrate], video_crf: [:crf], pixel_format: [:pix_fmt], progress_reporter: render_progress_reporter ).write(out: .fetch(:out)) return say((result)) if result[:format] == :mp4 say( "Frames written: #{result[:path]} " \ "(scene=#{result[:scene]}, frames=#{result[:frames]}, fps=#{result[:fps]}, #{result[:width]}x#{result[:height]})" ) rescue StandardError => e raise Thor::Error, e. end |
#shader(command = nil, name = nil) ⇒ void
This method returns an undefined value.
Run custom shader helper commands.
401 402 403 404 405 406 407 408 409 410 |
# File 'lib/vizcore/cli.rb', line 401 def shader(command = nil, name = nil) case command.to_s when "new" create_shader_template(name) else raise Thor::Error, "Unknown shader command: #{command || '(nil)'}. Use `vizcore shader new NAME`." end rescue ArgumentError => e raise Thor::Error, e. end |
#shader_docs ⇒ void
This method returns an undefined value.
Print generated documentation for custom GLSL uniforms.
389 390 391 |
# File 'lib/vizcore/cli.rb', line 389 def shader_docs Vizcore::CLISupport::ShaderUniformDocs.new.lines.each { |line| say(line) } end |
#snapshot(scene_file) ⇒ void
This method returns an undefined value.
Load a scene DSL file and write a software-rendered PNG preview.
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 |
# File 'lib/vizcore/cli.rb', line 535 def snapshot(scene_file) config = Config.new( scene_file: scene_file, audio_source: .fetch(:audio_source), audio_file: [:audio_file], audio_device: [:audio_device], noise_gate: .fetch(:noise_gate), bpm: [:bpm], bpm_lock: .fetch(:bpm_lock) ) validate_snapshot_config!(config) warn_untrusted_scene(config.scene_file) unless .fetch(:trust) result = Vizcore::Renderer::Snapshot.new( config: config, width: .fetch(:width), height: .fetch(:height), transparent: .fetch(:transparent) ).write(out: .fetch(:out)) say("Snapshot written: #{result[:path]} (scene=#{result[:scene]}, #{result[:width]}x#{result[:height]})") rescue StandardError => e raise Thor::Error, e. end |
#start(scene_file = nil) ⇒ void
This method returns an undefined value.
Start the Vizcore server with the given scene file.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/vizcore/cli.rb', line 137 def start(scene_file = nil) manifest = load_project_manifest([:manifest]) profile = [:profile] load_manifest_plugins(manifest, profile: profile) defaults = manifest&.config_defaults(profile: profile) || {} config = Config.new( scene_file: scene_file || defaults[:scene_file], host: .fetch(:host), port: .fetch(:port), audio_source: [:audio_source] || defaults[:audio_source] || Config::DEFAULT_AUDIO_SOURCE, audio_file: [:audio_file] || defaults[:audio_file], audio_device: [:audio_device] || defaults[:audio_device], feature_file: [:feature_file] || defaults[:feature_file], control_preset: [:control_preset] || defaults[:control_preset], plugin_assets: defaults[:plugin_assets], noise_gate: .fetch(:noise_gate), bpm: [:bpm], bpm_lock: .fetch(:bpm_lock), osc_port: [:osc_port] || defaults[:osc_port], scene_switch_effect: [:scene_switch_effect] || defaults[:scene_switch_effect], scene_switch_effect_duration: [:scene_switch_duration] || defaults[:scene_switch_effect_duration], reload: .fetch(:reload), projector_mode: .fetch(:projector), allow_public_control: .fetch(:allow_public_control) ) warn_untrusted_scene(config.scene_file, project_root: manifest&.root || Dir.pwd) unless .fetch(:trust) Server::Runner.new(config, manifest: manifest, initial_profile: profile).run rescue ArgumentError => e raise Thor::Error, e. end |
#validate(scene_file) ⇒ void
This method returns an undefined value.
Load and validate a scene DSL file without starting the server.
359 360 361 362 363 364 365 |
# File 'lib/vizcore/cli.rb', line 359 def validate(scene_file) result = Vizcore::CLISupport::SceneDiagnostics.new(scene_file: scene_file, strict: .fetch(:strict)).validate print_issues(result.issues) raise Thor::Error, "scene validation failed" unless result.valid? say("Scene valid: #{scene_file}") end |