framerudiments 0.4.6__tar.gz → 0.4.7__tar.gz
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.
- {framerudiments-0.4.6/src/framerudiments.egg-info → framerudiments-0.4.7}/PKG-INFO +8 -1
- {framerudiments-0.4.6 → framerudiments-0.4.7}/README.md +7 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/RELEASE_NOTES.md +18 -0
- framerudiments-0.4.7/docs/bounded-preflight.md +45 -0
- framerudiments-0.4.7/docs/media/bounded-preflight.svg +19 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/pyproject.toml +1 -1
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/__init__.py +1 -1
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/cli.py +12 -2
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/render.py +39 -5
- {framerudiments-0.4.6 → framerudiments-0.4.7/src/framerudiments.egg-info}/PKG-INFO +8 -1
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments.egg-info/SOURCES.txt +2 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_pipeline.py +49 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_rich_subtitles.py +2 -1
- {framerudiments-0.4.6 → framerudiments-0.4.7}/AGENTS.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/LICENSE +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/MANIFEST.in +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/analysis-releases.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/ECOSYSTEM.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/FrameRudiments-PATCH_WORKFLOW.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/annular-modulation.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/authoring-workspace.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/beat-alignment.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/controlled-audio-response.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/expanded-effects.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/extraction.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/full-preset-analysis.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/hybrid-preset-analysis.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/keyframed-mattes.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/beat-alignment-evidence.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/beat-alignment.mp4 +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/beat-alignment.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/demo-transcript.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/effects-pipeline.svg +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/full-frame-comparison.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/full-frame-demo.mp4 +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/media-evidence.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/natural-materials.mp4 +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/natural-materials.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/palette-grade-comparison.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/preset-test-cards.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/rangoli-transcript.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/rangoli.mp4 +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/rangoli.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/test-card-inputs/colour-bars.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/test-card-inputs/grid-rings.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/media/test-card-inputs/text-card.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/multi-stem-modulation.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/music-reactive-3d.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/natural-materials.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/particle-smoke.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/phase3-compositing.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/preset-behaviour.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/preset-profiling.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/project-format.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/projectm-local-runtime.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/quality-effects.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/rangoli.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/rich-lyric-effects.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/rudiment-renderers.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/scoped-post-effects.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/solid-spatial-renderers.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/spatial-renderers.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/spatiotemporal-supersampling.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/spectrum.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/sprite-visualisations.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/stem-sources-and-masks.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/variable-bpm-word-subtitles.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/visualisation-atlas.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/visualisation-coverage-matrix.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/visualiser-routing.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/visualisers.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/docs/workflow-media.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/integration/test_fire_volume_gpu.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/integration/test_music_spatial_gpu.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/integration/test_preset_analysis.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/integration/test_released_preset_analysis.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/integration/test_visualisers_gpu.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/Run-ControlledPresetAnalysis.ps1 +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/Run-FullPresetAnalysis.ps1 +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/Run-HybridPresetAnalysis.ps1 +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/Run-PresetBehaviourAnalysis.ps1 +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/authoring_preview.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/bake_mantaflow_fire.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/build_sprite_assets.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/check_projectm_runtime.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/check_release_packages.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/controlled_preset_analysis.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/ensure_projectm_runtime.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/full_preset_analysis.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_particle_gallery.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_post_effect_gallery.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_quality_gallery.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_rich_lyric_gallery.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_sprite_gallery.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_supersampling_gallery.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_timing_gallery.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_visualisation_gallery.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_visualiser_routing_gallery.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/install_analysis_releases.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/prepare_fire_atlas.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/prepare_pixelcue_taggers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/preset_behaviour_pipeline.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/profile_visualisation_coverage.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/profile_visualisers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/projectm_dll_diagnostics.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/render_natural_material_demo.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/repair_projectm_mingw.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/select_projectm_generator.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/validate_patch.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/setup.cfg +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/__main__.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/advanced_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/atlas.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/audio_probes.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/beat_alignment.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/beat_timeline.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/choreography.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/circular_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/compositor.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/controlled_profiling.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/demo.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/effect_catalogue.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/effect_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/effects.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/encoding.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_assets/mantaflow/NOTICE.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_assets/mantaflow/atlas.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_assets/mantaflow/flames.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_assets/marburg/NOTICE.md +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_assets/marburg/atlas.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_assets/marburg/flames.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_assets.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_fluid.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_renderer.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/fire_volume.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/flight.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/gpu_spatial_backend.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/io.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/keyframes.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/layer_animation.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/layer_displacement.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/layer_masks.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/lyric_indicator.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/modulation.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/motion.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/music_spatial_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/natural_materials.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/output_quality.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/particle_engine.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/post_effects.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/preset_library.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/preset_profiling.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/profile_analysis.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/project.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/projectm_backend.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/quality_effects.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/rangoli_renderer.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/rich_subtitles.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/rudiment_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/scoped_effects.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/solid_spatial_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/spatial_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/spectrum.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/arcade.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/crystal.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/fire.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/generated-neon.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/glass.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/hud.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/ice.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/lcd-amber.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/lcd-green.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/lcd.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/led.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/manifest.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/metal.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/mono.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/neon.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/pixel.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/plasma.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_assets/vfd.png +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_catalogue.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/sprite_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/stem_blend.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/stemlab.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/subtitles.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/super_sampling.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/terrain_field.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/timeline.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visual_style.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualisation_catalogue.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/butterchurn-page.js +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/butterchurn-worker.mjs +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/feedback.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/feedback.milk +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/julia.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/julia.milk +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/kaleidoscope.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/kaleidoscope.milk +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/package-lock.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/package.json +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_assets/rangoli-background.milk +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_routing.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualiser_setup.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/visualisers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments/word_timing.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments.egg-info/dependency_links.txt +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments.egg-info/entry_points.txt +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments.egg-info/requires.txt +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/src/framerudiments.egg-info/top_level.txt +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/conftest.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_adapters.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_advanced_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_authoring_preview.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_beat_alignment.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_behaviour_pipeline.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_checkpoint_batches.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_controlled_audio.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_coverage_matrix.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_default_antialias.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_effect_batch.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_encoding.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_extracted_helpers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_fire_methods.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_flight.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_full_preset_analysis.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_gpu_ci_isolation.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_hybrid_launcher.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_keyframes.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_layer_masks.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_lyrics.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_music_spatial_pipeline.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_music_spatial_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_natural_materials.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_particle_engine.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_patch_validation.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_phase3_animation.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_phase3_gpu_injection.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_preset_profiling.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_projectm_dll_diagnostics.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_projectm_generator.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_projectm_runtime_preflight.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_pytest_temp_isolation.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_quality_effects.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_rangoli_renderer.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_release_metadata.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_repair_projectm_mingw.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_rudiment_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_scoped_effects.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_solid_spatial_integration.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_solid_spatial_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_spatial_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_spectrum.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_sprite_renderers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_stem_blend.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_stem_source_integration.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_supersampling.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_timeline.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_variable_bpm_words.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_visualisation_modulation.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_visualiser_routing.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_visualisers.py +0 -0
- {framerudiments-0.4.6 → framerudiments-0.4.7}/tests/test_windows_launcher_splitpath.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: framerudiments
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.7
|
|
4
4
|
Summary: Deterministic Shorts and lyric visualisers using DanceRudiments and StemLab evidence.
|
|
5
5
|
Author: Kieran Simkin
|
|
6
6
|
License-Expression: MIT
|
|
@@ -121,6 +121,7 @@ framerudiments --version
|
|
|
121
121
|
framerudiments demo demo --font /path/to/a/font.ttf
|
|
122
122
|
framerudiments plan demo/project.json --output demo-plan.json
|
|
123
123
|
framerudiments preflight demo/project.json --output preflight --ffmpeg /path/to/ffmpeg
|
|
124
|
+
framerudiments preflight demo/project.json --output bounded-preflight --max-frames 3 --ffmpeg /path/to/ffmpeg
|
|
124
125
|
framerudiments render demo/project.json --output render --ffmpeg /path/to/ffmpeg
|
|
125
126
|
```
|
|
126
127
|
|
|
@@ -130,6 +131,12 @@ ffprobe. Environment alternatives are `FRAMERUDIMENTS_FFMPEG` and
|
|
|
130
131
|
font or FFmpeg location is hardcoded into the engine. The synthetic demo creates
|
|
131
132
|
its own tone, sprite, LRC, CUE and four-dimensional recording.
|
|
132
133
|
|
|
134
|
+
For expensive long projects, `preflight --max-frames N` validates a bounded
|
|
135
|
+
sequential prefix and records the exact incomplete scope in `manifest.json`.
|
|
136
|
+
This preserves stateful particles and feedback inside the prefix without paying
|
|
137
|
+
for a complete unencoded pass before the complete encoded render. It never
|
|
138
|
+
claims later frames were checked. See [bounded preflight](docs/bounded-preflight.md).
|
|
139
|
+
|
|
133
140
|
## Capabilities
|
|
134
141
|
|
|
135
142
|
* Portrait, landscape and square frame-addressed Pillow composition, at native
|
|
@@ -90,6 +90,7 @@ framerudiments --version
|
|
|
90
90
|
framerudiments demo demo --font /path/to/a/font.ttf
|
|
91
91
|
framerudiments plan demo/project.json --output demo-plan.json
|
|
92
92
|
framerudiments preflight demo/project.json --output preflight --ffmpeg /path/to/ffmpeg
|
|
93
|
+
framerudiments preflight demo/project.json --output bounded-preflight --max-frames 3 --ffmpeg /path/to/ffmpeg
|
|
93
94
|
framerudiments render demo/project.json --output render --ffmpeg /path/to/ffmpeg
|
|
94
95
|
```
|
|
95
96
|
|
|
@@ -99,6 +100,12 @@ ffprobe. Environment alternatives are `FRAMERUDIMENTS_FFMPEG` and
|
|
|
99
100
|
font or FFmpeg location is hardcoded into the engine. The synthetic demo creates
|
|
100
101
|
its own tone, sprite, LRC, CUE and four-dimensional recording.
|
|
101
102
|
|
|
103
|
+
For expensive long projects, `preflight --max-frames N` validates a bounded
|
|
104
|
+
sequential prefix and records the exact incomplete scope in `manifest.json`.
|
|
105
|
+
This preserves stateful particles and feedback inside the prefix without paying
|
|
106
|
+
for a complete unencoded pass before the complete encoded render. It never
|
|
107
|
+
claims later frames were checked. See [bounded preflight](docs/bounded-preflight.md).
|
|
108
|
+
|
|
102
109
|
## Capabilities
|
|
103
110
|
|
|
104
111
|
* Portrait, landscape and square frame-addressed Pillow composition, at native
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
# FrameRudiments 0.4.7
|
|
2
|
+
|
|
3
|
+
- `preflight --max-frames N` composes a declared sequential prefix for expensive
|
|
4
|
+
long projects instead of forcing a complete unencoded pass before rendering.
|
|
5
|
+
- The manifest records full versus bounded scope, frames rendered, total frames,
|
|
6
|
+
sequential-state behaviour and the explicit later-frame validation limit.
|
|
7
|
+
- The final rendered file still receives complete decode, CFR, frame-count,
|
|
8
|
+
audio and encoded-checkpoint verification; bounded preflight does not weaken
|
|
9
|
+
or relabel final technical QA.
|
|
10
|
+
- Focused regression coverage preserves default full-preflight behaviour, exact
|
|
11
|
+
prefix boundaries, final-prefix QA capture and fail-closed limits.
|
|
12
|
+
- Wrapped-word layout coverage now follows visual reading order across current
|
|
13
|
+
Pillow text metrics instead of assuming every word remains on one row.
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
Generated explanatory diagram; not a benchmark or rendered campaign frame.
|
|
18
|
+
|
|
1
19
|
# FrameRudiments 0.4.6
|
|
2
20
|
|
|
3
21
|
- Encoding now accepts the complete named libx264 preset range: `ultrafast`,
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Bounded sequential preflight
|
|
2
|
+
|
|
3
|
+
`framerudiments preflight` remains a full, unencoded composition pass by
|
|
4
|
+
default. For a long or unusually expensive project, `--max-frames N` composes
|
|
5
|
+
only the first `N` frames in order:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
framerudiments preflight project.json --output preflight-prefix --max-frames 3
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The mode is a cost and failure-surface check. It verifies pinned inputs,
|
|
12
|
+
audio identity, project construction, sequential state creation, the declared
|
|
13
|
+
prefix and cleanup. It saves frame zero, ordinary checkpoints encountered in
|
|
14
|
+
the prefix and the last rendered prefix frame. `manifest.json` records:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"preflight_scope": {
|
|
19
|
+
"mode": "bounded-prefix",
|
|
20
|
+
"frames_rendered": 3,
|
|
21
|
+
"total_frames": 15850,
|
|
22
|
+
"complete": false,
|
|
23
|
+
"sequential": true,
|
|
24
|
+
"note": "Only the declared sequential prefix was composed; later frames remain unvalidated."
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Why the prefix is sequential
|
|
30
|
+
|
|
31
|
+
Feedback visualisers, emitters and historical effects can depend on every
|
|
32
|
+
preceding frame. Randomly drawing distant checkpoints would reset or omit that
|
|
33
|
+
history and could create misleading evidence. The bounded mode therefore starts
|
|
34
|
+
at frame zero and advances normally. It does not describe later checkpoints,
|
|
35
|
+
the ending, full cleanup behaviour or the encoded result.
|
|
36
|
+
|
|
37
|
+
Run the complete `render` afterward. The renderer still composes every frame,
|
|
38
|
+
encodes the soundtrack, extracts all encoded QA checkpoints and verifies full
|
|
39
|
+
decode, constant frame rate, exact frame count, timestamps, dimensions, audio
|
|
40
|
+
shape and duration. Creative review and attended listening remain separate.
|
|
41
|
+
|
|
42
|
+

|
|
43
|
+
|
|
44
|
+
Generated explanatory diagram. The short amber prefix represents frames that
|
|
45
|
+
were actually composed; the outlined remainder is explicitly unvalidated.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="960" height="360" viewBox="0 0 960 360" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">Full preflight compared with bounded sequential preflight</title>
|
|
3
|
+
<desc id="desc">A full preflight composes every frame before rendering. A bounded preflight composes a short sequential prefix and labels the remainder unvalidated.</desc>
|
|
4
|
+
<rect width="960" height="360" fill="#16051f"/>
|
|
5
|
+
<text x="48" y="55" fill="#fff2cf" font-family="sans-serif" font-size="28" font-weight="700">Generated workflow illustration</text>
|
|
6
|
+
<text x="48" y="105" fill="#fff2cf" font-family="sans-serif" font-size="22">Full preflight</text>
|
|
7
|
+
<rect x="250" y="78" width="650" height="38" rx="19" fill="#ffb52e"/>
|
|
8
|
+
<text x="575" y="104" fill="#351300" text-anchor="middle" font-family="sans-serif" font-size="17" font-weight="700">every frame composed without encoding</text>
|
|
9
|
+
<path d="M575 126v45" stroke="#ffcf62" stroke-width="4" marker-end="url(#arrow)"/>
|
|
10
|
+
<text x="48" y="201" fill="#fff2cf" font-family="sans-serif" font-size="22">Complete render</text>
|
|
11
|
+
<rect x="250" y="174" width="650" height="38" rx="19" fill="#ff7a28"/>
|
|
12
|
+
<text x="575" y="200" fill="#351300" text-anchor="middle" font-family="sans-serif" font-size="17" font-weight="700">every frame composed again and encoded</text>
|
|
13
|
+
<text x="48" y="279" fill="#fff2cf" font-family="sans-serif" font-size="22">Bounded preflight</text>
|
|
14
|
+
<rect x="250" y="252" width="92" height="38" rx="19" fill="#ffb52e"/>
|
|
15
|
+
<rect x="342" y="252" width="558" height="38" rx="19" fill="none" stroke="#9c759f" stroke-width="3" stroke-dasharray="10 10"/>
|
|
16
|
+
<text x="296" y="278" fill="#351300" text-anchor="middle" font-family="sans-serif" font-size="16" font-weight="700">prefix</text>
|
|
17
|
+
<text x="621" y="278" fill="#d8b9dc" text-anchor="middle" font-family="sans-serif" font-size="17">later frames explicitly unvalidated</text>
|
|
18
|
+
<defs><marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto"><path d="M0,0 L0,6 L9,3 z" fill="#ffcf62"/></marker></defs>
|
|
19
|
+
</svg>
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "framerudiments"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.7"
|
|
8
8
|
description = "Deterministic Shorts and lyric visualisers using DanceRudiments and StemLab evidence."
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
readme = "README.md"
|
|
@@ -76,7 +76,13 @@ def main(argv=None):
|
|
|
76
76
|
item.add_argument("--output", required=True, help="A new evidence/output directory; never overwrites")
|
|
77
77
|
item.add_argument("--ffmpeg")
|
|
78
78
|
item.add_argument("--ffprobe")
|
|
79
|
-
if name == "
|
|
79
|
+
if name == "preflight":
|
|
80
|
+
item.add_argument(
|
|
81
|
+
"--max-frames",
|
|
82
|
+
type=int,
|
|
83
|
+
help="Compose only this many initial sequential frames; later frames remain unvalidated",
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
80
86
|
item.add_argument("--preset", default="fast")
|
|
81
87
|
item.add_argument("--crf", type=int, default=20)
|
|
82
88
|
args = parser.parse_args(argv)
|
|
@@ -161,7 +167,11 @@ def main(argv=None):
|
|
|
161
167
|
print(output)
|
|
162
168
|
else:
|
|
163
169
|
runner = preflight if args.command == "preflight" else render
|
|
164
|
-
extra =
|
|
170
|
+
extra = (
|
|
171
|
+
{"preset": args.preset, "crf": args.crf}
|
|
172
|
+
if args.command == "render"
|
|
173
|
+
else {"max_frames": args.max_frames}
|
|
174
|
+
)
|
|
165
175
|
result = runner(args.project, args.output, ffmpeg=args.ffmpeg, ffprobe=args.ffprobe, **extra)
|
|
166
176
|
print(json.dumps({"state": result["state"], "frames": result["frames"], "output": args.output}))
|
|
167
177
|
return 0
|
|
@@ -107,9 +107,38 @@ def _prepare(project, output, ffmpeg, ffprobe, scene, renderers):
|
|
|
107
107
|
return project, output, ffmpeg, ffprobe, compositor
|
|
108
108
|
|
|
109
109
|
|
|
110
|
-
def preflight(
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
def preflight(
|
|
111
|
+
project,
|
|
112
|
+
output,
|
|
113
|
+
*,
|
|
114
|
+
ffmpeg=None,
|
|
115
|
+
ffprobe=None,
|
|
116
|
+
scene=None,
|
|
117
|
+
renderers=None,
|
|
118
|
+
max_frames=None,
|
|
119
|
+
):
|
|
120
|
+
p = Project.load(project) if not isinstance(project, Project) else project
|
|
121
|
+
if max_frames is None:
|
|
122
|
+
frame_count = p.frame_count
|
|
123
|
+
elif type(max_frames) is not int or not 1 <= max_frames <= p.frame_count:
|
|
124
|
+
raise ValueError(f"Preflight max_frames must be an integer in [1,{p.frame_count}]")
|
|
125
|
+
else:
|
|
126
|
+
frame_count = max_frames
|
|
127
|
+
p, out, ffmpeg, ffprobe, compositor = _prepare(p, output, ffmpeg, ffprobe, scene, renderers)
|
|
128
|
+
selected = {frame for frame in checkpoints(p) if frame < frame_count}
|
|
129
|
+
selected.add(frame_count - 1)
|
|
130
|
+
scope = dict(
|
|
131
|
+
mode="full" if frame_count == p.frame_count else "bounded-prefix",
|
|
132
|
+
frames_rendered=frame_count,
|
|
133
|
+
total_frames=p.frame_count,
|
|
134
|
+
complete=frame_count == p.frame_count,
|
|
135
|
+
sequential=True,
|
|
136
|
+
note=(
|
|
137
|
+
"All project frames were composed."
|
|
138
|
+
if frame_count == p.frame_count
|
|
139
|
+
else "Only the declared sequential prefix was composed; later frames remain unvalidated."
|
|
140
|
+
),
|
|
141
|
+
)
|
|
113
142
|
effects = None
|
|
114
143
|
try:
|
|
115
144
|
effects = (
|
|
@@ -118,7 +147,7 @@ def preflight(project, output, *, ffmpeg=None, ffprobe=None, scene=None, rendere
|
|
|
118
147
|
else None
|
|
119
148
|
)
|
|
120
149
|
with (out / "rudiment-analysis.jsonl").open("w", encoding="utf-8") as analysis:
|
|
121
|
-
for n in range(
|
|
150
|
+
for n in range(frame_count):
|
|
122
151
|
image, context = compositor.frame(n, apply_quality=False)
|
|
123
152
|
if effects:
|
|
124
153
|
if n in selected:
|
|
@@ -141,10 +170,15 @@ def preflight(project, output, *, ffmpeg=None, ffprobe=None, scene=None, rendere
|
|
|
141
170
|
p.verify_inputs()
|
|
142
171
|
result = dict(
|
|
143
172
|
p.summary(),
|
|
173
|
+
preflight_scope=scope,
|
|
144
174
|
composition=compositor.evidence(),
|
|
145
175
|
full_frame_effects=effects.evidence() if effects else None,
|
|
146
176
|
analysis_sidecar=_sidecar(out),
|
|
147
|
-
state=
|
|
177
|
+
state=(
|
|
178
|
+
"full preflight passed; no encoded video"
|
|
179
|
+
if scope["complete"]
|
|
180
|
+
else "bounded-prefix preflight passed; later frames unvalidated; no encoded video"
|
|
181
|
+
),
|
|
148
182
|
)
|
|
149
183
|
write_json(out / "manifest.json", result)
|
|
150
184
|
return result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: framerudiments
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.7
|
|
4
4
|
Summary: Deterministic Shorts and lyric visualisers using DanceRudiments and StemLab evidence.
|
|
5
5
|
Author: Kieran Simkin
|
|
6
6
|
License-Expression: MIT
|
|
@@ -121,6 +121,7 @@ framerudiments --version
|
|
|
121
121
|
framerudiments demo demo --font /path/to/a/font.ttf
|
|
122
122
|
framerudiments plan demo/project.json --output demo-plan.json
|
|
123
123
|
framerudiments preflight demo/project.json --output preflight --ffmpeg /path/to/ffmpeg
|
|
124
|
+
framerudiments preflight demo/project.json --output bounded-preflight --max-frames 3 --ffmpeg /path/to/ffmpeg
|
|
124
125
|
framerudiments render demo/project.json --output render --ffmpeg /path/to/ffmpeg
|
|
125
126
|
```
|
|
126
127
|
|
|
@@ -130,6 +131,12 @@ ffprobe. Environment alternatives are `FRAMERUDIMENTS_FFMPEG` and
|
|
|
130
131
|
font or FFmpeg location is hardcoded into the engine. The synthetic demo creates
|
|
131
132
|
its own tone, sprite, LRC, CUE and four-dimensional recording.
|
|
132
133
|
|
|
134
|
+
For expensive long projects, `preflight --max-frames N` validates a bounded
|
|
135
|
+
sequential prefix and records the exact incomplete scope in `manifest.json`.
|
|
136
|
+
This preserves stateful particles and feedback inside the prefix without paying
|
|
137
|
+
for a complete unencoded pass before the complete encoded render. It never
|
|
138
|
+
claims later frames were checked. See [bounded preflight](docs/bounded-preflight.md).
|
|
139
|
+
|
|
133
140
|
## Capabilities
|
|
134
141
|
|
|
135
142
|
* Portrait, landscape and square frame-addressed Pillow composition, at native
|
|
@@ -10,6 +10,7 @@ docs/FrameRudiments-PATCH_WORKFLOW.md
|
|
|
10
10
|
docs/annular-modulation.md
|
|
11
11
|
docs/authoring-workspace.md
|
|
12
12
|
docs/beat-alignment.md
|
|
13
|
+
docs/bounded-preflight.md
|
|
13
14
|
docs/controlled-audio-response.md
|
|
14
15
|
docs/expanded-effects.md
|
|
15
16
|
docs/extraction.md
|
|
@@ -45,6 +46,7 @@ docs/workflow-media.md
|
|
|
45
46
|
docs/media/beat-alignment-evidence.json
|
|
46
47
|
docs/media/beat-alignment.mp4
|
|
47
48
|
docs/media/beat-alignment.png
|
|
49
|
+
docs/media/bounded-preflight.svg
|
|
48
50
|
docs/media/demo-transcript.md
|
|
49
51
|
docs/media/effects-pipeline.svg
|
|
50
52
|
docs/media/full-frame-comparison.png
|
|
@@ -135,3 +135,52 @@ def test_custom_scene_hook_and_preflight(demo, tmp_path):
|
|
|
135
135
|
assert calls == list(range(240))
|
|
136
136
|
assert result["composition"]["custom_scene"]
|
|
137
137
|
assert "no encoded" in result["state"]
|
|
138
|
+
assert result["preflight_scope"] == {
|
|
139
|
+
"mode": "full",
|
|
140
|
+
"frames_rendered": 240,
|
|
141
|
+
"total_frames": 240,
|
|
142
|
+
"complete": True,
|
|
143
|
+
"sequential": True,
|
|
144
|
+
"note": "All project frames were composed.",
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
calls.clear()
|
|
148
|
+
bounded = preflight(demo, tmp_path / "bounded-preflight", scene=scene, max_frames=3)
|
|
149
|
+
assert calls == [0, 1, 2]
|
|
150
|
+
assert bounded["preflight_scope"] == {
|
|
151
|
+
"mode": "bounded-prefix",
|
|
152
|
+
"frames_rendered": 3,
|
|
153
|
+
"total_frames": 240,
|
|
154
|
+
"complete": False,
|
|
155
|
+
"sequential": True,
|
|
156
|
+
"note": "Only the declared sequential prefix was composed; later frames remain unvalidated.",
|
|
157
|
+
}
|
|
158
|
+
assert "later frames unvalidated" in bounded["state"]
|
|
159
|
+
assert (tmp_path / "bounded-preflight" / "qa" / "source-00000002.png").exists()
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@pytest.mark.parametrize("limit", [0, -1, 241, 1.5, True])
|
|
163
|
+
def test_bounded_preflight_rejects_invalid_frame_limit(demo, tmp_path, limit):
|
|
164
|
+
with pytest.raises(ValueError, match="Preflight max_frames"):
|
|
165
|
+
preflight(demo, tmp_path / f"bad-preflight-{limit}", max_frames=limit)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def test_cli_forwards_bounded_preflight_limit(monkeypatch, capsys):
|
|
169
|
+
from framerudiments import cli
|
|
170
|
+
|
|
171
|
+
received = {}
|
|
172
|
+
|
|
173
|
+
def fake_preflight(project, output, **kwargs):
|
|
174
|
+
received.update(project=project, output=output, **kwargs)
|
|
175
|
+
return {"state": "bounded-prefix preflight passed", "frames": 240}
|
|
176
|
+
|
|
177
|
+
monkeypatch.setattr(cli, "preflight", fake_preflight)
|
|
178
|
+
assert cli.main(["preflight", "project.json", "--output", "out", "--max-frames", "3"]) == 0
|
|
179
|
+
assert received == {
|
|
180
|
+
"project": "project.json",
|
|
181
|
+
"output": "out",
|
|
182
|
+
"ffmpeg": None,
|
|
183
|
+
"ffprobe": None,
|
|
184
|
+
"max_frames": 3,
|
|
185
|
+
}
|
|
186
|
+
assert '"state": "bounded-prefix preflight passed"' in capsys.readouterr().out
|
|
@@ -199,7 +199,8 @@ def test_word_centres_follow_wrapped_text_layout_and_stay_in_box(project):
|
|
|
199
199
|
centres = word_centres(text, "Lights follow every word")
|
|
200
200
|
assert len(centres) == 4
|
|
201
201
|
assert all(text.box[0] <= x <= text.box[2] for x, _ in centres)
|
|
202
|
-
assert all(a[
|
|
202
|
+
assert all(a[1] <= b[1] for a, b in zip(centres, centres[1:]))
|
|
203
|
+
assert all(a[0] < b[0] for a, b in zip(centres, centres[1:]) if a[1] == b[1])
|
|
203
204
|
|
|
204
205
|
|
|
205
206
|
def test_rich_highlight_can_tint_single_word_without_destroying_gradients(project):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{framerudiments-0.4.6 → framerudiments-0.4.7}/scripts/generate_visualiser_routing_gallery.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|