@hraness/slopcamera 3.2.4
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.
- package/LICENSE +21 -0
- package/NOTICE.md +60 -0
- package/PRIVACY.md +46 -0
- package/README.md +311 -0
- package/SECURITY.md +21 -0
- package/apps/desktop/README.md +966 -0
- package/apps/desktop/analysis/protocol.ts +223 -0
- package/apps/desktop/application/capability-binding.ts +594 -0
- package/apps/desktop/application/context.ts +97 -0
- package/apps/desktop/application/creative-iteration.ts +1385 -0
- package/apps/desktop/application/default-registry.ts +146 -0
- package/apps/desktop/application/directing-contract.ts +218 -0
- package/apps/desktop/application/directing-plan.ts +178 -0
- package/apps/desktop/application/errors.ts +18 -0
- package/apps/desktop/application/gateway-port.ts +867 -0
- package/apps/desktop/application/html-overlay-browser-runtime.ts +687 -0
- package/apps/desktop/application/html-overlay-integrity.ts +337 -0
- package/apps/desktop/application/html-overlay-renderer.ts +45 -0
- package/apps/desktop/application/index.ts +13 -0
- package/apps/desktop/application/operation-completion-checkpoint.ts +333 -0
- package/apps/desktop/application/operation-effects.ts +94 -0
- package/apps/desktop/application/operation.ts +224 -0
- package/apps/desktop/application/operations/analysis/faces.ts +244 -0
- package/apps/desktop/application/operations/analysis/music.ts +248 -0
- package/apps/desktop/application/operations/analysis/project-auto-zooms.ts +302 -0
- package/apps/desktop/application/operations/analysis/project-inactivity.ts +381 -0
- package/apps/desktop/application/operations/analysis/scenes.ts +272 -0
- package/apps/desktop/application/operations/analysis/shared.ts +202 -0
- package/apps/desktop/application/operations/derive/edit-batch.ts +967 -0
- package/apps/desktop/application/operations/derive/follow-faces.ts +454 -0
- package/apps/desktop/application/operations/edit/bind-candidate-revision.ts +91 -0
- package/apps/desktop/application/operations/edit/create-candidate-revision.ts +377 -0
- package/apps/desktop/application/operations/edit/create-revision.ts +255 -0
- package/apps/desktop/application/operations/edit/freeze-revision.ts +182 -0
- package/apps/desktop/application/operations/gateway/image.ts +41 -0
- package/apps/desktop/application/operations/gateway/index.ts +17 -0
- package/apps/desktop/application/operations/gateway/shared.ts +122 -0
- package/apps/desktop/application/operations/gateway/speech.ts +41 -0
- package/apps/desktop/application/operations/gateway/transcription.ts +42 -0
- package/apps/desktop/application/operations/gateway/video.ts +41 -0
- package/apps/desktop/application/operations/index.ts +31 -0
- package/apps/desktop/application/operations/iteration/create-candidate.ts +240 -0
- package/apps/desktop/application/operations/iteration/create-matrix.ts +117 -0
- package/apps/desktop/application/operations/iteration/select.ts +155 -0
- package/apps/desktop/application/operations/iteration/shared.ts +250 -0
- package/apps/desktop/application/operations/media/audio-effects.ts +376 -0
- package/apps/desktop/application/operations/media/binding.ts +79 -0
- package/apps/desktop/application/operations/media/capabilities.ts +112 -0
- package/apps/desktop/application/operations/media/color-grade.ts +343 -0
- package/apps/desktop/application/operations/media/html-overlay.ts +802 -0
- package/apps/desktop/application/operations/media/index.ts +8 -0
- package/apps/desktop/application/operations/media/ingest.ts +303 -0
- package/apps/desktop/application/operations/media/overlay.ts +729 -0
- package/apps/desktop/application/operations/media/shared.ts +845 -0
- package/apps/desktop/application/operations/media/transform-platform.ts +120 -0
- package/apps/desktop/application/operations/project/commit-edits.ts +2054 -0
- package/apps/desktop/application/operations/project/promote-selection.ts +495 -0
- package/apps/desktop/application/operations/project/snapshot.ts +95 -0
- package/apps/desktop/application/operations/recording/index.ts +5 -0
- package/apps/desktop/application/operations/recording/pause.ts +34 -0
- package/apps/desktop/application/operations/recording/resume.ts +34 -0
- package/apps/desktop/application/operations/recording/shared.ts +199 -0
- package/apps/desktop/application/operations/recording/start.ts +169 -0
- package/apps/desktop/application/operations/recording/stop.ts +34 -0
- package/apps/desktop/application/operations/render/bind-candidate-output.ts +324 -0
- package/apps/desktop/application/operations/render/materialize-selection.ts +322 -0
- package/apps/desktop/application/operations/render/project-caption-plan.ts +287 -0
- package/apps/desktop/application/operations/render/project-plan.ts +939 -0
- package/apps/desktop/application/operations/render/project-spatial-receipt.ts +70 -0
- package/apps/desktop/application/operations/render/project.ts +1922 -0
- package/apps/desktop/application/operations/shared.ts +67 -0
- package/apps/desktop/application/operations/slopcamera-portable.ts +1188 -0
- package/apps/desktop/application/operations/slopcamera-visuals.ts +784 -0
- package/apps/desktop/application/operations/spatial-project.ts +209 -0
- package/apps/desktop/application/operations/spatial-render.ts +415 -0
- package/apps/desktop/application/operations/spatial-scene.ts +97 -0
- package/apps/desktop/application/operations/studio.ts +143 -0
- package/apps/desktop/application/output-publication-lease.ts +163 -0
- package/apps/desktop/application/project-publication-lease.ts +233 -0
- package/apps/desktop/application/project-store.ts +196 -0
- package/apps/desktop/application/receipts.ts +533 -0
- package/apps/desktop/application/registry.ts +182 -0
- package/apps/desktop/application/spatial-assets.ts +675 -0
- package/apps/desktop/application/spatial-compositor-cadence.ts +23 -0
- package/apps/desktop/application/spatial-project-authority.ts +35 -0
- package/apps/desktop/application/spatial-project-lease.ts +126 -0
- package/apps/desktop/application/spatial-project-render-preparation.ts +225 -0
- package/apps/desktop/application/spatial-project-store.ts +286 -0
- package/apps/desktop/application/spatial-render-projection.ts +201 -0
- package/apps/desktop/application/spatial-render.ts +677 -0
- package/apps/desktop/application/spatial-spz.ts +44 -0
- package/apps/desktop/application/spatial-world-import.ts +135 -0
- package/apps/desktop/application/spatial-world-provenance.ts +46 -0
- package/apps/desktop/application/studio-port.ts +58 -0
- package/apps/desktop/application/verified-receipt-reconciliation.ts +1574 -0
- package/apps/desktop/capture/protocol.ts +689 -0
- package/apps/desktop/cli/analyzer.ts +406 -0
- package/apps/desktop/cli/args.ts +3181 -0
- package/apps/desktop/cli/asset-ingest.ts +747 -0
- package/apps/desktop/cli/atomic-render-effects.ts +210 -0
- package/apps/desktop/cli/atomic-render-platform.ts +205 -0
- package/apps/desktop/cli/atomic-render.ts +50 -0
- package/apps/desktop/cli/audio-analysis.ts +252 -0
- package/apps/desktop/cli/bounded-map.ts +39 -0
- package/apps/desktop/cli/bundle-service.ts +256 -0
- package/apps/desktop/cli/capabilities.ts +212 -0
- package/apps/desktop/cli/capture-bundle.ts +1117 -0
- package/apps/desktop/cli/command-host-resources.ts +251 -0
- package/apps/desktop/cli/commands.ts +6836 -0
- package/apps/desktop/cli/directing-blob.ts +291 -0
- package/apps/desktop/cli/directing-media.ts +517 -0
- package/apps/desktop/cli/directing-quote.ts +89 -0
- package/apps/desktop/cli/directing-service.ts +288 -0
- package/apps/desktop/cli/emoji-assets.ts +538 -0
- package/apps/desktop/cli/errors.ts +29 -0
- package/apps/desktop/cli/face-analysis-service.ts +940 -0
- package/apps/desktop/cli/filter-script.ts +76 -0
- package/apps/desktop/cli/gateway-application-port.ts +1142 -0
- package/apps/desktop/cli/gateway-credential.ts +81 -0
- package/apps/desktop/cli/gateway-media-artifacts.ts +723 -0
- package/apps/desktop/cli/gateway-media-catalog.ts +922 -0
- package/apps/desktop/cli/gateway-media-service.ts +3106 -0
- package/apps/desktop/cli/gateway-media-signature.ts +122 -0
- package/apps/desktop/cli/gateway-provider-options.ts +562 -0
- package/apps/desktop/cli/gateway-scene-provider.ts +391 -0
- package/apps/desktop/cli/help.ts +501 -0
- package/apps/desktop/cli/html-overlay-gpu.ts +97 -0
- package/apps/desktop/cli/html-overlay-renderer.ts +2478 -0
- package/apps/desktop/cli/io.ts +290 -0
- package/apps/desktop/cli/main.ts +123 -0
- package/apps/desktop/cli/media-effects-service.ts +885 -0
- package/apps/desktop/cli/media-ingest-model.ts +364 -0
- package/apps/desktop/cli/media-ingest-platform.ts +227 -0
- package/apps/desktop/cli/media-ingest-program.ts +200 -0
- package/apps/desktop/cli/media-ingest.ts +30 -0
- package/apps/desktop/cli/music-analysis-service.ts +434 -0
- package/apps/desktop/cli/mutation-lock.ts +530 -0
- package/apps/desktop/cli/native-assets.d.ts +12 -0
- package/apps/desktop/cli/native-media-runtime.macos.ts +7 -0
- package/apps/desktop/cli/overlay-playback.ts +177 -0
- package/apps/desktop/cli/paths.ts +265 -0
- package/apps/desktop/cli/portable-surface.ts +242 -0
- package/apps/desktop/cli/project-camera-receipt.ts +112 -0
- package/apps/desktop/cli/project-face-camera.ts +394 -0
- package/apps/desktop/cli/project-inactivity-service.ts +552 -0
- package/apps/desktop/cli/project-media-integrity.ts +121 -0
- package/apps/desktop/cli/project-renderer.ts +1526 -0
- package/apps/desktop/cli/project-service.ts +519 -0
- package/apps/desktop/cli/project-state-transaction.ts +520 -0
- package/apps/desktop/cli/query-limits.ts +1 -0
- package/apps/desktop/cli/recording-controller.ts +1567 -0
- package/apps/desktop/cli/recording-daemon.ts +931 -0
- package/apps/desktop/cli/recording-ref.ts +56 -0
- package/apps/desktop/cli/renamed-environment.ts +6 -0
- package/apps/desktop/cli/renderer.ts +1439 -0
- package/apps/desktop/cli/run-cli-test-helper.ts +60 -0
- package/apps/desktop/cli/scene-analysis-service.ts +879 -0
- package/apps/desktop/cli/spatial-compositor-verifier.ts +213 -0
- package/apps/desktop/cli/spatial-project-service.ts +90 -0
- package/apps/desktop/cli/spatial-scene-service.ts +105 -0
- package/apps/desktop/cli/spatial-world-service.ts +39 -0
- package/apps/desktop/cli/speech-analysis-service.ts +682 -0
- package/apps/desktop/cli/studio-assemble.ts +58 -0
- package/apps/desktop/cli/studio-command.ts +60 -0
- package/apps/desktop/cli/studio-custody.ts +60 -0
- package/apps/desktop/cli/studio-encode.ts +216 -0
- package/apps/desktop/cli/studio-exr.ts +52 -0
- package/apps/desktop/cli/studio-files.ts +179 -0
- package/apps/desktop/cli/studio-output-validation.ts +162 -0
- package/apps/desktop/cli/studio-process.ts +145 -0
- package/apps/desktop/cli/studio-runtime.ts +77 -0
- package/apps/desktop/cli/studio-scaffold.ts +70 -0
- package/apps/desktop/cli/studio-service.ts +301 -0
- package/apps/desktop/cli/studio-spatial-asset.ts +248 -0
- package/apps/desktop/cli/studio-template-names.ts +3 -0
- package/apps/desktop/cli/studio-workflow.ts +19 -0
- package/apps/desktop/cli/time.ts +25 -0
- package/apps/desktop/cli/workflow-code.ts +584 -0
- package/apps/desktop/cli/workflow-runs.ts +576 -0
- package/apps/desktop/code/advanced.ts +139 -0
- package/apps/desktop/code/application-node-planner.ts +1288 -0
- package/apps/desktop/code/compiler.ts +329 -0
- package/apps/desktop/code/contracts.ts +13 -0
- package/apps/desktop/code/creative-recipes.ts +94 -0
- package/apps/desktop/code/define-workflow.ts +115 -0
- package/apps/desktop/code/editing.ts +284 -0
- package/apps/desktop/code/file-candidate-provenance.ts +420 -0
- package/apps/desktop/code/file-candidate.ts +69 -0
- package/apps/desktop/code/graph-builder.ts +10 -0
- package/apps/desktop/code/host-resource-policy.ts +55 -0
- package/apps/desktop/code/plan-contracts.ts +159 -0
- package/apps/desktop/code/planning.ts +361 -0
- package/apps/desktop/code/public.ts +134 -0
- package/apps/desktop/code/reference-projection.ts +62 -0
- package/apps/desktop/code/run-contracts.ts +466 -0
- package/apps/desktop/code/run-store.ts +2478 -0
- package/apps/desktop/code/runtime-identity.ts +328 -0
- package/apps/desktop/code/scheduler.ts +3067 -0
- package/apps/desktop/code/semantic-builder.ts +1436 -0
- package/apps/desktop/code/source-bundle.ts +1641 -0
- package/apps/desktop/code/source-typecheck.ts +211 -0
- package/apps/desktop/code/testing.ts +79 -0
- package/apps/desktop/code/worker-client.ts +1675 -0
- package/apps/desktop/code/worker-effects.ts +141 -0
- package/apps/desktop/code/worker-entry.ts +435 -0
- package/apps/desktop/code/worker-lease-guardian.ts +179 -0
- package/apps/desktop/code/worker-process-identity.ts +484 -0
- package/apps/desktop/code/worker-protocol.ts +211 -0
- package/apps/desktop/code/workflow-effects.ts +132 -0
- package/apps/desktop/contracts/analysis.ts +949 -0
- package/apps/desktop/contracts/edit.ts +576 -0
- package/apps/desktop/contracts/index.ts +9 -0
- package/apps/desktop/contracts/media-effects.ts +139 -0
- package/apps/desktop/contracts/project-render.ts +644 -0
- package/apps/desktop/contracts/project.ts +740 -0
- package/apps/desktop/contracts/recording.ts +1434 -0
- package/apps/desktop/contracts/render.ts +334 -0
- package/apps/desktop/contracts/runtime.ts +155 -0
- package/apps/desktop/contracts/spatial-compositor.ts +58 -0
- package/apps/desktop/contracts/spatial-project.ts +159 -0
- package/apps/desktop/contracts/spatial-world.ts +48 -0
- package/apps/desktop/contracts/video-effects.ts +120 -0
- package/apps/desktop/core/alignment-apply.ts +400 -0
- package/apps/desktop/core/audio-alignment.ts +466 -0
- package/apps/desktop/core/auto-zoom.ts +209 -0
- package/apps/desktop/core/canonical-json.ts +14 -0
- package/apps/desktop/core/emoji.ts +210 -0
- package/apps/desktop/core/events.ts +409 -0
- package/apps/desktop/core/face-framing.ts +533 -0
- package/apps/desktop/core/face-tracks.ts +326 -0
- package/apps/desktop/core/inactivity.ts +137 -0
- package/apps/desktop/core/index.ts +30 -0
- package/apps/desktop/core/intervals.ts +123 -0
- package/apps/desktop/core/montage.ts +236 -0
- package/apps/desktop/core/music-analysis.ts +518 -0
- package/apps/desktop/core/plan.ts +244 -0
- package/apps/desktop/core/project-auto-zoom.ts +75 -0
- package/apps/desktop/core/project-camera-spatial.ts +676 -0
- package/apps/desktop/core/project-camera.ts +403 -0
- package/apps/desktop/core/project-captions.ts +888 -0
- package/apps/desktop/core/project-inactivity.ts +125 -0
- package/apps/desktop/core/project-metadata.ts +927 -0
- package/apps/desktop/core/project-plan.ts +375 -0
- package/apps/desktop/core/project-render-plan.ts +303 -0
- package/apps/desktop/core/project-time.ts +469 -0
- package/apps/desktop/core/render-plan.ts +442 -0
- package/apps/desktop/core/scene-cache.ts +174 -0
- package/apps/desktop/core/scene-sampling.ts +448 -0
- package/apps/desktop/core/spatial-compositor.ts +22 -0
- package/apps/desktop/core/spatial-durability.ts +99 -0
- package/apps/desktop/core/spatial-project.ts +169 -0
- package/apps/desktop/core/spatial-shot-clock.ts +32 -0
- package/apps/desktop/core/speech-analysis.ts +333 -0
- package/apps/desktop/core/storage.ts +970 -0
- package/apps/desktop/core/time-map.ts +91 -0
- package/apps/desktop/core/time.ts +61 -0
- package/apps/desktop/core/video-effects.ts +660 -0
- package/apps/desktop/dist/cli/NebulaSans-Bold-26se8aek.otf +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Book-5ax05zvn.woff2 +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Book-8cenzchw.otf +0 -0
- package/apps/desktop/dist/cli/main.js +5086 -0
- package/apps/desktop/html-overlay/catalog.ts +171 -0
- package/apps/desktop/html-overlay/contracts.ts +372 -0
- package/apps/desktop/html-overlay/execution-profile.ts +77 -0
- package/apps/desktop/html-overlay/index.ts +98 -0
- package/apps/desktop/html-overlay/libraries.ts +263 -0
- package/apps/desktop/html-overlay/random.ts +49 -0
- package/apps/desktop/html-overlay/runtime.ts +813 -0
- package/apps/desktop/html-overlay/scaffolds.ts +792 -0
- package/apps/desktop/html-overlay/spark-runtime.ts +88 -0
- package/apps/desktop/html-overlay/spatial-splat-runtime.ts +60 -0
- package/apps/desktop/html-overlay/spatial.ts +720 -0
- package/apps/desktop/studio/assets/README.md +39 -0
- package/apps/desktop/studio/assets/contracts.ts +129 -0
- package/apps/desktop/studio/assets/network.ts +64 -0
- package/apps/desktop/studio/assets/poly-haven.ts +148 -0
- package/apps/desktop/studio/drivers/blender_driver.py +466 -0
- package/apps/desktop/studio/drivers/cadquery_driver.py +176 -0
- package/apps/desktop/studio/education/driver.py +308 -0
- package/apps/desktop/studio/education/lesson.py +180 -0
- package/apps/desktop/studio/education/toolkit.py +249 -0
- package/apps/desktop/workflows/chaptered-demo.ts +48 -0
- package/apps/desktop/workflows/creative-iteration.ts +107 -0
- package/apps/desktop/workflows/creative-selection.ts +92 -0
- package/apps/desktop/workflows/fragments.ts +486 -0
- package/apps/desktop/workflows/index.ts +93 -0
- package/apps/desktop/workflows/polished-screen-demo.ts +128 -0
- package/apps/desktop/workflows/scene-direction.ts +12 -0
- package/apps/desktop/workflows/social-variants.ts +75 -0
- package/apps/desktop/workflows/talking-head-cleanup.ts +53 -0
- package/dist/NebulaSans-Bold-26se8aek.otf +0 -0
- package/dist/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
- package/dist/NebulaSans-Book-5ax05zvn.woff2 +0 -0
- package/dist/NebulaSans-Book-8cenzchw.otf +0 -0
- package/dist/cli.js +479 -0
- package/dist/code/advanced.js +270 -0
- package/dist/code/index.js +2240 -0
- package/dist/generate.js +24 -0
- package/dist/host-resources.js +26 -0
- package/dist/index-42zsesc1.js +2257 -0
- package/dist/index-7308egqr.js +48 -0
- package/dist/index-8txs6fkn.js +712 -0
- package/dist/index-mcy8z0br.js +192 -0
- package/dist/index-p63wavx0.js +2029 -0
- package/dist/index-r7gdhmsp.js +424 -0
- package/dist/index-sh6xbav6.js +1219 -0
- package/dist/index-z1w83f81.js +4 -0
- package/dist/index-z7239b4h.js +2363 -0
- package/dist/index-zfeg9hmw.js +2013 -0
- package/dist/index.js +241 -0
- package/dist/operations.js +29 -0
- package/dist/skill-install-dh0ntqba.js +10 -0
- package/dist/vectorize/worker.js +142 -0
- package/dist/workflow.js +16 -0
- package/docs/README.md +38 -0
- package/docs/studio.md +215 -0
- package/examples/studio/blender/README.md +26 -0
- package/examples/studio/blender/character.py +152 -0
- package/examples/studio/blender/cloth.py +101 -0
- package/examples/studio/blender/color_chart.py +29 -0
- package/examples/studio/blender/fluid.py +78 -0
- package/examples/studio/blender/import_model.py +74 -0
- package/examples/studio/blender/product.py +53 -0
- package/examples/studio/blender/shaded_street.py +481 -0
- package/examples/studio/blender/studio_scene.py +147 -0
- package/examples/studio/cadquery/README.md +13 -0
- package/examples/studio/cadquery/bracket.py +36 -0
- package/examples/studio/cadquery/import_step.py +12 -0
- package/examples/studio/education/README.md +46 -0
- package/examples/studio/education/lesson.json +99 -0
- package/examples/studio/education/scene.py +7 -0
- package/examples/studio/hybrid-scene.ts +96 -0
- package/examples/studio/native-workflow.ts +14 -0
- package/examples/studio/vgpu/README.md +64 -0
- package/examples/studio/vgpu/heat-field.mjs +290 -0
- package/package.json +304 -0
- package/packages/scene/src/index.ts +1 -0
- package/packages/scene/src/scene.ts +215 -0
- package/schema/diagram.schema.json +334 -0
- package/skills/slopcamera/SKILL.md +45 -0
- package/skills/slopcamera/agents/openai.yaml +4 -0
- package/skills/slopcamera/references/customization.md +77 -0
- package/skills/slopcamera/references/diagrams.md +153 -0
- package/skills/slopcamera/references/directed-scenes.md +42 -0
- package/skills/slopcamera/references/directing-video.md +18 -0
- package/skills/slopcamera/references/educational-video.md +26 -0
- package/skills/slopcamera/references/gateway-media.md +134 -0
- package/skills/slopcamera/references/install.md +62 -0
- package/skills/slopcamera/references/native-studio.md +31 -0
- package/skills/slopcamera/references/reference-led-3d.md +140 -0
- package/skills/slopcamera/references/rubber-stamp-examples/poster-example-1.jpg +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/poster-example-2.jpg +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-1.png +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-2.png +0 -0
- package/skills/slopcamera/references/rubber-stamp-field-notes.md +144 -0
- package/skills/slopcamera/references/vectorization.md +29 -0
- package/skills/slopcamera/references/video-projects.md +187 -0
- package/skills/slopcamera/references/visual-communication.md +120 -0
- package/skills/slopcamera/references/workflows-sdk.md +45 -0
- package/skills/slopcamera/scripts/compose-rubber-stamp-field-note.ts +229 -0
- package/src/artifacts.ts +106 -0
- package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/PROVENANCE.md +21 -0
- package/src/assets.d.ts +9 -0
- package/src/cli.ts +601 -0
- package/src/cloud-errors.ts +26 -0
- package/src/code/advanced.ts +10 -0
- package/src/code/boundary.ts +21 -0
- package/src/code/canonical-json.ts +129 -0
- package/src/code/compiler.ts +953 -0
- package/src/code/contracts.ts +576 -0
- package/src/code/define-workflow.ts +334 -0
- package/src/code/errors.ts +41 -0
- package/src/code/graph-builder.ts +945 -0
- package/src/code/index.ts +121 -0
- package/src/code/json-snapshot.ts +899 -0
- package/src/code/json-utf8.ts +88 -0
- package/src/code/portable-builder.ts +136 -0
- package/src/code/projection.ts +378 -0
- package/src/code/public-operations.ts +450 -0
- package/src/code/runtime.ts +580 -0
- package/src/code/sha256.ts +36 -0
- package/src/config.ts +180 -0
- package/src/desktop.ts +253 -0
- package/src/fs.ts +10 -0
- package/src/generate.ts +704 -0
- package/src/host-resource-posix.ts +161 -0
- package/src/host-resources.ts +1749 -0
- package/src/icons.ts +58 -0
- package/src/index.ts +200 -0
- package/src/label-layout.ts +130 -0
- package/src/layout.ts +413 -0
- package/src/lint.ts +127 -0
- package/src/mcp/boundary.ts +354 -0
- package/src/mcp/index.ts +33 -0
- package/src/mcp/server.ts +272 -0
- package/src/mcp/tools.ts +963 -0
- package/src/mcp/types.ts +71 -0
- package/src/operations.ts +775 -0
- package/src/parse.ts +861 -0
- package/src/process-environment.ts +17 -0
- package/src/render.ts +437 -0
- package/src/skill-install.ts +49 -0
- package/src/spatial-scene/authoring.ts +27 -0
- package/src/spatial-scene/camera-track.ts +83 -0
- package/src/spatial-scene/contracts.ts +277 -0
- package/src/spatial-scene/evaluate.ts +145 -0
- package/src/spatial-scene/gltf.ts +558 -0
- package/src/spatial-scene/identity.ts +260 -0
- package/src/spatial-scene/index.ts +10 -0
- package/src/spatial-scene/inspect.ts +68 -0
- package/src/spatial-scene/math.ts +280 -0
- package/src/spatial-scene/patch.ts +131 -0
- package/src/spatial-scene/time.ts +53 -0
- package/src/studio/contracts.ts +129 -0
- package/src/studio/index.ts +2 -0
- package/src/studio/plan.ts +156 -0
- package/src/studio/shared.ts +41 -0
- package/src/theme.ts +68 -0
- package/src/tldr.ts +474 -0
- package/src/types.ts +212 -0
- package/src/vectorize/archive.ts +101 -0
- package/src/vectorize/command.ts +797 -0
- package/src/vectorize/index.ts +27 -0
- package/src/vectorize/limits.ts +61 -0
- package/src/vectorize/metrics.ts +351 -0
- package/src/vectorize/pixels.ts +323 -0
- package/src/vectorize/supervisor.ts +339 -0
- package/src/vectorize/svg.ts +188 -0
- package/src/vectorize/tool.ts +542 -0
- package/src/vectorize/types.ts +113 -0
- package/src/vectorize/vectorize.ts +634 -0
- package/src/vectorize/worker-protocol.ts +40 -0
- package/src/vectorize/worker.ts +209 -0
- package/src/version.ts +1 -0
- package/src/workflow.ts +409 -0
package/docs/studio.md
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Native film studio
|
|
2
|
+
|
|
3
|
+
Slopcamera lets an agent retain a production scene, direct a native renderer, inspect its exact outputs and bring the result into an ordinary video project. Blender handles detailed 3D, CadQuery handles parametric solids and STEP, and Manim Community handles educational animation. Existing Three/Spark rendering, diagrams, image generation, narration, captions, effects and short-clip directing remain available in the same CLI.
|
|
4
|
+
|
|
5
|
+
Native authoring preserves the engine's control. A Blender source can use armatures, skinning, IK, shape keys, geometry nodes, materials, lights, cameras and simulation caches. A CadQuery program preserves dimensions and solid operations. A Manim scene preserves mathematical objects and timing. Portable meshes and finished videos are derivatives; retain the native source when later edits require it.
|
|
6
|
+
|
|
7
|
+
Use the [Slopcamera source installation](how-to/use-current-source.md) for the `studio` commands described here. Start with the [one-second native film tutorial](tutorials/first-native-film.md) for a bounded CPU shot, or use [educational animation with narration](how-to/educational-video.md) for Manim.
|
|
8
|
+
|
|
9
|
+
## Make the first shot
|
|
10
|
+
|
|
11
|
+
Install a supported engine yourself, or use an existing installation. Slopcamera does not silently install or upgrade native tools. The initial qualified versions are Blender 5.2.1 LTS, CadQuery 2.8.0 and Manim Community 0.21.0. Select the exact Blender executable or Python virtual environment for each invocation.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
slopcamera studio init product --template blender-product --json
|
|
15
|
+
slopcamera studio bundle product/source.json --json
|
|
16
|
+
slopcamera studio plan product/job.json --json
|
|
17
|
+
slopcamera studio probe product/job.json --blender-bin /Applications/Blender.app/Contents/MacOS/Blender --json
|
|
18
|
+
slopcamera studio run product/job.json --blender-bin /Applications/Blender.app/Contents/MacOS/Blender --allow-trusted-code --json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The scaffold creates `scene.py`, any explicit helpers, `source.json` and `job.json`. Edit the source and job to direct the shot. After a source edit, run `studio bundle` again, copy the returned `bundleSha256` into the job and choose a new `jobId`. Reusing an old job ID with changed inputs is a conflict. `studio plan` parses and hashes the request without loading a native engine.
|
|
22
|
+
|
|
23
|
+
The default Blender product job requests Cycles GPU rendering. An unavailable GPU fails clearly. Select `device: "cpu"` in a new job when CPU rendering is intended; no fallback is implicit. Initial Metal shader compilation can make the first render substantially slower than later frames.
|
|
24
|
+
|
|
25
|
+
Other starters:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
slopcamera studio init character --template blender-character
|
|
29
|
+
slopcamera studio init city --template blender-shaded-street
|
|
30
|
+
slopcamera studio init cloth --template blender-cloth
|
|
31
|
+
slopcamera studio init liquid --template blender-fluid
|
|
32
|
+
slopcamera studio init bracket --template cadquery-bracket
|
|
33
|
+
slopcamera studio init lesson --template manim-lesson
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Run CAD or Manim with `--python /absolute/path/to/venv/bin/python`. Preserve that virtual-environment path: resolving its interpreter symlink to a system Python can select the wrong package environment.
|
|
37
|
+
|
|
38
|
+
The shaded-street starter provides an original city, a detailed native character and a calibrated three-second camera approach in 360×640 portrait. Set the render dimensions to 720×1280 for a larger output, select `shot: "speaker"` with no `motion` for a fixed presenter view, or use `motion: "return"` for the world-panel reveal. Native source and all helpers are included in the scaffold. The [hybrid scene example](../examples/studio/hybrid-scene.ts) uses the same panel dimensions and camera contract with Three.
|
|
39
|
+
|
|
40
|
+
Set `panelTexture: "panel.png"` and include that opaque 9:16 PNG in `source.json` to reuse a finished Three frame or diagram on the native board. The starter packs its sRGB pixels into an unlit native surface at the shared world position; other geometry still occludes it. This is a baked image derivative. It preserves the depicted frame, while the original Three scene remains the source for editing its content.
|
|
41
|
+
|
|
42
|
+
## Source and output contract
|
|
43
|
+
|
|
44
|
+
`source.json` lists exactly the files to retain. Its paths are relative to the manifest's directory, or to an explicit `--source-root`. Imports do not recursively discover siblings, follow file symlinks or run Python.
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"engine": "blender",
|
|
49
|
+
"entrypoint": { "kind": "python", "path": "scene.py" },
|
|
50
|
+
"files": ["scene.py", "studio_scene.py", "models/product.glb", "textures/basecolor.png"]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The host stores a content-addressed manifest and immutable file copies under `artifacts/slopcamera/private/studio/bundles/`. Jobs bind those retained bytes, typed engine settings, parameters, a stage, output declarations and limits. The source may execute at module scope or use the documented engine hooks. Blender and CadQuery support `build(context)`; an explicit bake job may call `bake(context)`. Manim selects a named scene class. See the checked examples for the exact hook contracts.
|
|
55
|
+
|
|
56
|
+
`SLOPCAMERA_CONTEXT` supplies detached parameters, stage, render clock and the private source/output/working roots. Helpers and imported assets belong in the explicit bundle. Diagnostics and temporary files belong in the working root; only declared deliverables belong in the output root. The host rejects undeclared files, links, empty outputs, missing frames and exceeded limits.
|
|
57
|
+
|
|
58
|
+
Frame intervals are half-open: `startFrame: 24, endFrameExclusive: 48` means 24 frames. Frame rate is a reduced rational numerator/denominator. Raster outputs declare channels, precision, color space, alpha and semantic meaning. Model outputs declare units, up axis and handedness. CadQuery's adapter explicitly converts its millimeter geometry into meter-scale, Y-up GLB; STEP remains millimeters and Z-up.
|
|
59
|
+
|
|
60
|
+
Successful receipts include the exact source/job/plan/runtime identities and every physical output hash and length. Runtime identity records executable and driver hashes plus observed package/version evidence. It is not a hash of every system library, font, installed plugin or external read. Native source runs as the current user and the profile is explicitly nonhermetic.
|
|
61
|
+
|
|
62
|
+
## Turn frames into a project clip
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
slopcamera studio encode <studio-id> --output-id beauty --json
|
|
66
|
+
slopcamera studio assemble <studio-id> --output-id beauty --name "The first shot" --json
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Encoding accepts a successfully receipted PNG color sequence and creates a separately retained derivative. RGB becomes lossless H.264 RGB MP4; straight RGBA becomes lossless QTRLE MOV. The encoder checks every decoded frame against its source pixels and checks the exact clock. Native movie validation currently admits observed 8-bit RGB/RGBA interpretations; higher-precision video profiles require separate qualification. A 16-bit PNG sequence produces an explicitly recorded 8-bit derivative without dithering; the original masters remain intact. Linear EXR and data passes need an explicit compositing/color pipeline before delivery and are not silently converted by this command.
|
|
70
|
+
|
|
71
|
+
`studio assemble` reuses the verified encode and creates an ordinary video project with exact native/encode lineage. Its initial clip profile accepts opaque sRGB sequences up to 4096 pixels per side, 4000 frames and 60 seconds. Use `project add` for subsequent clips, narration and SFX, and `project render run` for delivery. Transparent sequences remain an explicit encode/overlay workflow.
|
|
72
|
+
|
|
73
|
+
The returned artifact is an ordinary local media reference. A repeated encode verifies its source and derivative receipts instead of resubmitting a completed conversion. Retain transparent MOV or linear masters for compositing; make a normal SDR delivery through the project renderer when broad player compatibility matters.
|
|
74
|
+
|
|
75
|
+
## Detailed assets, rigs and simulation
|
|
76
|
+
|
|
77
|
+
The supported Poly Haven adapter searches and imports free HDRIs, selected PBR maps and glTF model dependencies. A selection chooses one asset, resolution and file format; the plan retains author, license, API credit, catalog bytes and the complete dependency list. Imports verify those bytes and retain SHA-256 identities. Powered by [Poly Haven](https://polyhaven.com/).
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
slopcamera studio assets search query.json --json
|
|
81
|
+
slopcamera studio assets describe dirty_football --json
|
|
82
|
+
slopcamera studio assets plan selection.json --json
|
|
83
|
+
slopcamera studio assets import asset-plan.json --json
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
A search input is `{"provider":"poly-haven","query":"football","type":"models","limit":5}`. A model selection is `{"provider":"poly-haven","assetId":"dirty_football","resolution":"1k","kind":"model","format":"gltf"}`. Save the complete JSON plan returned by the plan command before importing it. The default total download bound is 50 MiB. Include the returned source files explicitly in a studio bundle; acquisition never executes or inserts an asset into a native scene. See the [asset adapter contract](../apps/desktop/studio/assets/README.md) for texture/HDRI selections, current terms and supported dependencies.
|
|
87
|
+
|
|
88
|
+
Use Blender's native importers for supplied GLB/glTF, OBJ/MTL, FBX and other supported formats. Retain all required textures, buffers and animation files. `examples/studio/blender/import_model.py` and the CadQuery STEP example show explicit local-input routes. Native imports have a broader feature set tha Slopcamera's deliberately bounded portable GLB parser; an imported native control rig is not automatically editable through portable spatial patches.
|
|
89
|
+
|
|
90
|
+
The original character example includes a deforming skeleton, blended weights, an IK target and facial shape keys. Keep control names and source parameters stable when directing later takes. Full upstream rigging APIs remain available to trusted authoring code, but arbitrary rig retargeting, production facial systems and third-party add-ons require their own setup and qualification.
|
|
91
|
+
|
|
92
|
+
Cloth and fluid starters use separate bake and render stages. Retain the resulting `.blend` and explicit caches, then create a source bundle with the native scene and its dependencies for a render job. A `.blend` entrypoint supports rendering with embedded-script execution disabled; rebuilding, rebaking, Python-dependent rig drivers or add-on initialization require an explicit authored Python setup. Unpacked FILE images must be exact existing declared bundle files, or their bytes must be packed in the scene. Linked libraries, volumes and other dependencies still need their own explicit source closure and validation. Preserve the relative cache layout when moving a bundle. Rendering a completed cache should not recompute its solver or depend on frame visitation order.
|
|
93
|
+
|
|
94
|
+
Physics settings are not proof of a bake. Review evaluated geometry, contact and cache evidence, then load the result in a fresh process. Cloth pins, collider thickness, object scale, time steps and warmup affect the image. Liquid surface and volume caches need explicit storage budgets. Keep native cache identity tied to the source and settings that produced it.
|
|
95
|
+
|
|
96
|
+
## Share assets across renderers
|
|
97
|
+
|
|
98
|
+
Keep each native source alongside its portable representations. Use `.blend` for the detailed character rig, cloth caches and procedural materials; use a validated static GLB for city geometry; use sRGB images and videos for finished diagrams, generated footage and graphics. A video displayed in a world-space plane can be occluded and filmed by another camera. Its pixels do not supply hidden geometry or new views of the depicted world.
|
|
99
|
+
|
|
100
|
+
| Representation | Useful transfer | Boundary |
|
|
101
|
+
| --- | --- | --- |
|
|
102
|
+
| Native `.blend`, STEP and caches | Edit or rerender in the originating tool | Native rig controls, solids, solvers and procedural materials remain engine-specific |
|
|
103
|
+
| Portable GLB | Share measured geometry, supported base-color materials and node TRS clips with Three | Admission rejects skins, morph targets and unsupported texture/material features; export an explicit compatible derivative |
|
|
104
|
+
| sRGB PNG or retained RGB(A) video | Mount a diagram, avatar, generated shot or GPU graphic in either scene | Preserve pixel size, alpha, color interpretation and the exact source clock |
|
|
105
|
+
| Splats | Film a captured appearance through the qualified Three/Spark profile | Appearance capture does not establish collision geometry, relighting or native mesh editability |
|
|
106
|
+
|
|
107
|
+
Admit an existing native output with an explicit asset identity:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
slopcamera studio asset studio_city --output-id city --asset-id asset_city --representation native --json
|
|
111
|
+
slopcamera studio asset studio_shot --output-id beauty --asset-id asset_reference --representation native --frame 1 --json
|
|
112
|
+
slopcamera studio encode studio_shot --output-id beauty --json
|
|
113
|
+
slopcamera studio asset studio_shot --output-id beauty --asset-id asset_movie --representation encoded-video --json
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The result contains an `asset`, a `binding`, and a retained admission `receipt`. Add the asset to the spatial scene and supply an array of bindings through `scene render --assets bindings.json`. The asset payload path is a logical locator; the binding selects the exact retained physical bytes. Admission verifies the native job, source lineage and supported representation without executing source or encoding again. A sequence needs an exact frame for image admission. Encoded-video admission requires one unambiguous completed `studio encode` derivative. Conflicting derivatives require explicit resolution; there is no implicit latest selection.
|
|
117
|
+
|
|
118
|
+
Prepared GLB geometry travels as a hash-bound local JSON resource, with source interpretation and validated primitives retained in the render evidence. Vertex arrays do not inflate the HTML document. An explicit resource fetch flag admits only its exact private path; the host and browser both verify its bytes. Existing geometry, texture, frame and resource limits still apply. Detailed native meshes may need an explicit preview LOD; preserve its export settings and measured bounds alongside the native source.
|
|
119
|
+
|
|
120
|
+
Blender owns full native scene production. Three owns Slopcamera's calibrated portable scene and world-space media composition. vgpu supplies programmable WebGPU passes. The [optional vgpu example](../examples/studio/vgpu/README.md) renders an exact-time graphic into retained raster frames for use on a world-space screen. It uses a separately provisioned runtime. It does not enable a second scene renderer or shared GPU textures inside Slopcamera's WebGL2/Spark profile. The upstream [Three integration](https://github.com/vercel-labs/vgpu/blob/main/docs/topics/threejs.docs.md) can expose WGSL functions as TSL nodes, but using that path requires a qualified Three WebGPU profile.
|
|
121
|
+
|
|
122
|
+
## Exchange calibrated cameras
|
|
123
|
+
|
|
124
|
+
Export one camera's evaluated poses and projection at a rational frame rate:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{"cameraId":"camera_hero","startUs":0,"frameRate":{"numerator":24,"denominator":1},"frameCount":480}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Save that sampling request as `sampling.json`, then run:
|
|
131
|
+
|
|
132
|
+
```sh
|
|
133
|
+
slopcamera scene camera-track scene.json --request sampling.json --output camera-track.json --json
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The inert `slopcamera.spatial-camera-track` document pins the scene revision and contains ordered `samples`, each with `frameIndex`, integer `timeUs`, exact rational `exactTimeUs`, and the existing `SpatialCamera` value. It preserves off-center principal points, unequal focal lengths, orthographic extents and the canonical Y-up meter basis. Export at most 2,048 frames per chunk within the 2 MiB JSON limit. Sampling uses the scene's half-open duration and independently rounds each exact sample once to microseconds.
|
|
137
|
+
|
|
138
|
+
Retain this JSON in a native source bundle. The fixed Blender driver exposes `SLOPCAMERA_APPLY_SPATIAL_CAMERA(camera, camera_object=None)` to authored Python. It converts canonical `(x,y,z)` to Blender `(x,-z,y)` and preserves the camera's local negative-Z direction. Apply each sample explicitly at its associated native frame; do not interpolate a second time using an unrelated easing curve. A supplied camera must have no parent, constraints or animation owners. Unsupported native parameter ranges fail rather than silently changing framing. The helper does not exchange depth of field, distortion, shutter, lighting or color transforms.
|
|
139
|
+
|
|
140
|
+
For a native animated camera, first calculate all requested poses on an unconstrained camera, then insert the saved poses as native keys. Calling the helper after adding an animation owner is rejected. A matching projection does not imply identical materials or lighting between renderers; use a shared raster surface when a cut must preserve finished pixels.
|
|
141
|
+
|
|
142
|
+
## Lighting, camera and color
|
|
143
|
+
|
|
144
|
+
The product source demonstrates beveled geometry, textured materials, glass, area lighting, a moving camera and depth of field. Native source can expose camera lens, focus, aperture, shutter and lighting parameters directly. Cycles and EEVEE have different rendering behavior; choosing EEVEE creates a different job and runtime profile.
|
|
145
|
+
|
|
146
|
+
Blender review PNGs use the chosen view transform and sRGB display output. Linear EXR beauty uses Linear Rec.709 and the declared half/full floating-point precision. Transparent PNG is straight alpha; transparent EXR is premultiplied. Auxiliary depth, normal, mask or object-ID files remain explicitly authored compositor outputs with data-space semantics. The host checks actual EXR channel precision and framing and decodes output files; physical units and coordinate meaning still need correct source and fixture validation.
|
|
147
|
+
|
|
148
|
+
Keep linear masters when grading or compositing requires them. Do not tone-map a review PNG a second time, apply a beauty transform to data passes or assume an exported GLB can reproduce arbitrary procedural materials. A splat capture describes observed appearance; it does not automatically provide editable objects, collision geometry or physically relightable materials.
|
|
149
|
+
|
|
150
|
+
## Educational films and generated media
|
|
151
|
+
|
|
152
|
+
The Manim starter produces a 10-second portrait example with an original Luma presenter, vector geometry, Typst mathematics, gestures and a caption rail. Its 3–4–5 construction rearranges nine plus sixteen equal-area tiles into a five-by-five square. This illustrates one Pythagoras example; it does not claim a general proof.
|
|
153
|
+
|
|
154
|
+
`lesson.json` retains the script, cue timing, gestures, mouth shapes and mathematical parameters. Cue provenance distinguishes authored timing from measured word or mouth alignment. Word highlights use half-open microsecond intervals; a resting mouth fills gaps. Portrait margins reserve room for the presenter, diagram and captions rather than cropping a landscape composition blindly. See `examples/studio/education/README.md` for the lesson fields and the standalone source closure.
|
|
155
|
+
|
|
156
|
+
Generate illustrations and narration through the existing Gateway operations, then retain their returned asset references:
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
slopcamera ai models list --type image --json
|
|
160
|
+
slopcamera ai image generate --model <image-model> --prompt-file illustration.txt --json
|
|
161
|
+
slopcamera ai models list --type speech --json
|
|
162
|
+
slopcamera ai speech generate --model <speech-model> --text-file narration.txt --json
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
These generation commands can incur provider charges. Use the live catalog and existing explicit upload controls. Studio execution itself makes no paid model call. It neither receives provider credentials in its child environment nor automatically regenerates narration or images when a scene renders.
|
|
166
|
+
|
|
167
|
+
Use `slopcamera diagram init|check|render` for structured diagrams, `slopcamera image vectorize` for local vectorization, existing transcription for measured captions, and ordinary audio/media operations for narration, music and SFX. Rhubarb mouth cues can be retained as measured performance input using the toolkit's conversion helper; mouth shapes are not word timestamps. A supplied or generated voice needs an actual listening/alignment review before authored cues can be described as synchronized speech.
|
|
168
|
+
|
|
169
|
+
Ordinary project overlays interpret `--position x,y` as a pixel offset from the selected anchor. Use `--anchor center --position 0,0` to center an overlay, or `--anchor top-left --position 42,70 --width 636 --height 180` to place a caption inside a 720×1280 portrait frame with 42-pixel side margins. A full-frame closing image uses `--anchor top-left --position 0,0` with the output dimensions. Inspect the rendered caption bounds and closing frame before delivery.
|
|
170
|
+
|
|
171
|
+
The Manim driver owns silent visuals and exact frames. It rejects source-side audio so the existing Slopcamera composition remains the audio owner. That separation lets an agent revise narration or sound independently while preserving the mathematical rendering and provider receipts.
|
|
172
|
+
|
|
173
|
+
## Qualified profiles and extension limits
|
|
174
|
+
|
|
175
|
+
Local acceptance used Blender 5.2.1 LTS on an Apple M4 Max, CadQuery 2.8.0 and Manim Community 0.21.0. These are measured fixtures, not a promise that every engine feature, device or imported asset behaves identically.
|
|
176
|
+
|
|
177
|
+
| Capability | Checked behavior | Boundary |
|
|
178
|
+
| --- | --- | --- |
|
|
179
|
+
| Cycles / EEVEE | Actual Metal renders; product materials, moving camera and depth of field | Other GPU backends need their own qualification; GPU rendering does not imply GPU physics |
|
|
180
|
+
| Character | Weighted mesh deformation, IK reach and facial shape keys survive native reload | Automatic production-rig retargeting is not supplied |
|
|
181
|
+
| Cloth / liquid | Real caches, changed evaluated geometry and fresh-process replay; liquid cache relocation | Solver validity and portable determinism depend on the source and runtime |
|
|
182
|
+
| CAD | Valid STEP round trip, preserved solid volume and measured meter/Y-up GLB bounds | Original third-party CAD feature history is not reconstructed |
|
|
183
|
+
| Color | Half-float linear EXR, preserved HDR values, premultiplied EXR and straight PNG edges | Auxiliary pass units and coordinate meaning require fixture-specific validation |
|
|
184
|
+
| Education | Portrait presenter, Typst mathematics, exact frame interval and transparent frame output | Authored cue timing is distinct from measured speech alignment |
|
|
185
|
+
| Acquisition | Free Poly Haven HDRI and complete glTF dependency closure, verified offline replay | Other catalogs use authorized supplied files; no generic marketplace automation |
|
|
186
|
+
|
|
187
|
+
Blender's native Python APIs can author Geometry Nodes, hair, volumes, additional solvers and compositor effects. Those APIs are available to trusted source; Slopcamera does not advertise each as a separately qualified automatic workflow. USD, Alembic and other interchange retain only the semantics their particular exporters support. Robotics or RL environments additionally need step/reset, state/action, sensor and physical validation contracts; a cinematic scene or splat capture alone does not supply those guarantees.
|
|
188
|
+
|
|
189
|
+
## Use native jobs in an agent workflow
|
|
190
|
+
|
|
191
|
+
The checked `examples/studio/native-workflow.ts` accepts `{bundle: {path: "<retained manifest>"}, job: <job document>}` as its input JSON. The local declarative SDK exposes `.studio.run()` through `@hraness/slopcamera/local/code`. Its closed operation is `slopcamera.studio.run`. Inputs refer to the retained bundle manifest and a parsed studio job; planning binds the installed runtime under normal host admission. Outputs are ordinary hash-bound media references and a studio receipt, ready for subsequent retained media operations.
|
|
192
|
+
|
|
193
|
+
```sh
|
|
194
|
+
slopcamera code run film.ts --input input.json --studio-python /absolute/venv/bin/python --allow-trusted-code --json
|
|
195
|
+
slopcamera runs resume <run-id> --studio-python /absolute/venv/bin/python --allow-trusted-code --json
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The same runtime/authorization flags are available on `workflows run`. Runtime selection alone does not authorize source execution. A missing native trust envelope pauses the node before dispatch; adding the explicit flag on resume permits the exact bound plan. Generic stored write approval cannot grant native code permission. Changing a runtime, source or job after binding requires a compatible new plan.
|
|
199
|
+
|
|
200
|
+
Use the source-backed Bun package for `code` workflows and local SDK imports. The copied macOS executable supports direct `studio` commands with embedded starters and drivers; its older workflow build-identity scanner still requires the installed source distribution.
|
|
201
|
+
|
|
202
|
+
Native results can be imported into ordinary Slopcamera projects with their declared video/audio roles. The existing V2 spatial renderer still has its qualified Three-specific rendering path; attaching a native candidate does not make that path consume it. Preserve a native shot's source and receipt alongside its ordinary project media derivative.
|
|
203
|
+
|
|
204
|
+
## Inspection and recovery
|
|
205
|
+
|
|
206
|
+
```sh
|
|
207
|
+
slopcamera studio inspect <studio-id> --json
|
|
208
|
+
slopcamera studio reconcile <studio-id> --json
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Inspection rechecks source and physical output hashes. Reconciliation can restore a missing receipt only when a closed successful process completion and an unchanged output-validation checkpoint exist. Earlier interrupted execution remains ambiguous and is never automatically resubmitted. Choose a new job ID for an explicitly revised attempt after custody is settled.
|
|
212
|
+
|
|
213
|
+
The supervisor bounds combined logs, the job deadline and termination/pipe-drain grace. It monitors output and scratch budgets, retains failure evidence and tracks native process groups. Live scans tolerate bounded disappearance of temporary cache entries; final output, source and scratch scans remain strict. Budget-monitor and validation failures retain a safe failed host stage separately from authored-process logs, without storing foreign exception text. A machine-wide durable activity marker survives CLI death; unresolved custody blocks later native dispatch. Detached sessions from authored source are unsupported. Do not delete an unresolved marker to bypass admission; inspect and resolve the actual process ownership first.
|
|
214
|
+
|
|
215
|
+
The native profile is trusted current-user execution without an OS sandbox. Private roots, clean environment variables, hashes and process supervision provide operational control and provenance. They do not confine arbitrary Python, installed plugins or native libraries. Keep unreviewed downloaded source inert until execution is explicitly authorized.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Authored Blender studio examples
|
|
2
|
+
|
|
3
|
+
These examples use Blender's native Python APIs through SLOPCAMERA's explicitly trusted source-bundle workflow. Include the selected entrypoint and `studio_scene.py` as declared bundle files. Imported assets and their dependencies must also be declared. The scripts do not download anything or use a provider.
|
|
4
|
+
|
|
5
|
+
| Entrypoint | Features | Initial qualification job |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| `product.py` | Machined metal, glass, fine surface detail, key/fill/rim lighting, camera move and focus pull | Render frames `[1,25)` at 24fps; start at 320×180/16 samples, then select 960×540/64-sample review frames |
|
|
8
|
+
| `character.py` | Weighted continuous arm, IK goal and pole, articulated skeleton, blink/smile/jaw shape keys | Render `[1,25)` at 24fps; compare frames 1, 9, 18 and 24 |
|
|
9
|
+
| `import_model.py` | Standard GLB, glTF or OBJ/MTL import, measured bounds, framed camera and lighting | Parameter `input` names a declared relative asset path; optional `environment` names a retained linear Rec.709 HDR/EXR; loaded images are packed into the native scene |
|
|
10
|
+
| `cloth.py` | Cloth dynamics, collision, woven shading, completed native point cache and Alembic deformation export | Bake with native `native/scene.blend` and directory `cache/cloth`; subsequently render the retained `.blend` at frame 32 |
|
|
11
|
+
| `fluid.py` | Mantaflow liquid volume, collision basin, meshed splash, retained simulation data and surface cache | Bake with native `native/scene.blend` and directory `cache/fluid`; subsequently render the retained `.blend` around frames 12–24 |
|
|
12
|
+
| `color_chart.py` | Known linear emission patches, including values above one, against a transparent background | One frame with denoising disabled, explicit RGBA PNG/straight and half-float EXR/premultiplied declarations; compare decoded center values and alpha |
|
|
13
|
+
|
|
14
|
+
Simulation scripts define `build(context)` and `bake(context)`. The fixed driver executes the Python module, calls `build` when present, saves the declared native scene, and calls `bake` only for a bake job. A render job never implicitly calls `bake`. Fluid resolution defaults to 24 and is bounded to 16–48 in this fixture. Cloth uses 40 simulation frames and fluid uses 32. Cloth defaults to a free drape; parameter `pinBackCorners: true` adds two fully weighted pin vertices and verifies that their evaluated positions remain fixed throughout the completed bake. The cache evidence JSON records evaluated geometry after the real bake; it is not a substitute for inspecting rendered images or reloading the cache.
|
|
15
|
+
|
|
16
|
+
For native-source render jobs, make a new source bundle containing the retained `.blend` and its complete explicitly declared cache/input tree. Preserve the relative layout. The fluid example stores its cache path relative to the native scene. The cloth scene retains the completed point cache in its `.blend` and additionally publishes an Alembic deformation cache.
|
|
17
|
+
|
|
18
|
+
For `.blend` entrypoints, unpacked `FILE` images must resolve to exact physical files declared inside the source bundle; otherwise the driver fails before rendering. Packing image bytes avoids ambient original paths. The import example packs all imported file images, including HDR environments that Blender has not yet decoded. Broader native dependencies, such as linked libraries, sequences, volumes and arbitrary authored handlers, still require explicit source management and feature-specific qualification; this check does not claim a complete hermetic Blender dependency graph.
|
|
19
|
+
|
|
20
|
+
The driver supports automatic beauty PNG/EXR files or frame sequences and GLB/USD model exports. An image sequence uses exactly one `%06d` token and the job's half-open frame interval. A beauty file requires one frame. Use SLOPCAMERA's ordinary retained media pipeline for video encoding. Authored Python may use Blender's full compositor API to write separately declared auxiliary outputs.
|
|
21
|
+
|
|
22
|
+
Automatic PNG beauty declares sRGB, RGB/opaque or RGBA/straight alpha, uint8 or uint16, color semantic and unitless units. Automatic EXR beauty declares linear Rec.709, float16 or float32, RGB/opaque or RGBA/premultiplied alpha. The driver sets output conversion explicitly and reports the source working space. GLB output declares meters, right-handed Y-up; USD output requires a meter-scale scene and declares right-handed Z-up.
|
|
23
|
+
|
|
24
|
+
`SLOPCAMERA_CONTEXT` contains `parameters`, `stage`, `render`, `sourceRoot`, `outputRoot`, and `workingRoot`. Paths are absolute retained roots. The object is detached from the driver's admitted job. The driver and source run as the current user; hashes and declared outputs provide identity and verification, not an operating-system sandbox or hermetic execution.
|
|
25
|
+
|
|
26
|
+
Capability qualification should record native Blender build/device logs, exact source and output hashes, full pixel decoding, selected-frame contact sheets, and observed runtime/storage. A configured feature is not yet a qualified feature. GPU selection uses native Cycles discovery and rejects an unavailable requested GPU instead of silently selecting CPU. EEVEE requires an explicit GPU request.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""An articulated studio character with a skinned IK arm and blended facial shapes."""
|
|
2
|
+
|
|
3
|
+
import math
|
|
4
|
+
import bpy
|
|
5
|
+
from studio_scene import reset, material, cube, cylinder, sphere, camera, floor, studio_lights
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def weighted(obj, armature, weights):
|
|
9
|
+
modifier = obj.modifiers.new("Character skin", "ARMATURE")
|
|
10
|
+
modifier.object = armature
|
|
11
|
+
obj.parent = armature
|
|
12
|
+
for bone_name, vertex_weights in weights.items():
|
|
13
|
+
group = obj.vertex_groups.new(name=bone_name)
|
|
14
|
+
for index, weight in vertex_weights:
|
|
15
|
+
if weight > 0:
|
|
16
|
+
group.add([index], weight, "REPLACE")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def rigid_skin(obj, armature, bone_name):
|
|
20
|
+
weighted(obj, armature, {bone_name: [(v.index, 1) for v in obj.data.vertices]})
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def build(context):
|
|
24
|
+
scene = reset()
|
|
25
|
+
ceramic = material("Warm porcelain shell", (0.69, 0.75, 0.73), roughness=0.26)
|
|
26
|
+
teal = material("Teal woven joint sleeve", (0.027, 0.23, 0.28), roughness=0.5, texture=True)
|
|
27
|
+
dark = material("Graphite facial details", (0.012, 0.027, 0.037), roughness=0.30)
|
|
28
|
+
copper = material("Copper joint collars", (0.56, 0.19, 0.065), metallic=0.82, roughness=0.3)
|
|
29
|
+
floor(size=25)
|
|
30
|
+
skeleton = bpy.data.armatures.new("Character deformation skeleton")
|
|
31
|
+
rig = bpy.data.objects.new("Character rig", skeleton)
|
|
32
|
+
bpy.context.collection.objects.link(rig)
|
|
33
|
+
bpy.context.view_layer.objects.active = rig
|
|
34
|
+
rig.select_set(True)
|
|
35
|
+
bpy.ops.object.mode_set(mode="EDIT")
|
|
36
|
+
definitions = [
|
|
37
|
+
("root", (0, 0, 0.1), (0, 0, 0.65), None),
|
|
38
|
+
("chest", (0, 0, 0.65), (0, 0, 1.20), "root"),
|
|
39
|
+
("head", (0, 0, 1.20), (0, 0, 1.67), "chest"),
|
|
40
|
+
("upper_arm.R", (0.29, 0, 1.15), (0.61, 0, 1.12), "chest"),
|
|
41
|
+
("forearm.R", (0.61, 0, 1.12), (0.91, 0, 1.09), "upper_arm.R"),
|
|
42
|
+
("upper_arm.L", (-0.29, 0, 1.15), (-0.42, 0, 0.85), "chest"),
|
|
43
|
+
("forearm.L", (-0.42, 0, 0.85), (-0.43, -0.025, 0.58), "upper_arm.L"),
|
|
44
|
+
("leg.R", (0.14, 0, 0.65), (0.14, 0, 0.14), "root"),
|
|
45
|
+
("leg.L", (-0.14, 0, 0.65), (-0.14, 0, 0.14), "root"),
|
|
46
|
+
]
|
|
47
|
+
for name, head, tail, parent in definitions:
|
|
48
|
+
bone = skeleton.edit_bones.new(name)
|
|
49
|
+
bone.head, bone.tail = head, tail
|
|
50
|
+
if parent:
|
|
51
|
+
bone.parent = skeleton.edit_bones[parent]
|
|
52
|
+
bpy.ops.object.mode_set(mode="OBJECT")
|
|
53
|
+
torso = sphere("Porcelain torso", (0, 0, 0.96), (0.29, 0.16, 0.36), ceramic)
|
|
54
|
+
rigid_skin(torso, rig, "chest")
|
|
55
|
+
head = sphere("Expressive head", (0, -0.012, 1.47), (0.275, 0.19, 0.245), ceramic)
|
|
56
|
+
rigid_skin(head, rig, "head")
|
|
57
|
+
head.shape_key_add(name="Basis")
|
|
58
|
+
jaw = head.shape_key_add(name="JawOpen")
|
|
59
|
+
for vertex in jaw.data:
|
|
60
|
+
if vertex.co.z < -0.02:
|
|
61
|
+
vertex.co.z -= 0.055 * min(1, -vertex.co.z / 0.18)
|
|
62
|
+
for side, x in (("L", -0.095), ("R", 0.095)):
|
|
63
|
+
eye = sphere("Eye." + side, (x, -0.190, 1.51), (0.038, 0.014, 0.053), dark)
|
|
64
|
+
rigid_skin(eye, rig, "head")
|
|
65
|
+
eye.shape_key_add(name="Basis")
|
|
66
|
+
blink = eye.shape_key_add(name="Blink")
|
|
67
|
+
for vertex in blink.data:
|
|
68
|
+
vertex.co.z *= 0.12
|
|
69
|
+
for frame, value in ((1, 0), (7, 0), (9, 1), (11, 0), (24, 0)):
|
|
70
|
+
blink.value = value
|
|
71
|
+
blink.keyframe_insert("value", frame=frame)
|
|
72
|
+
vertices, faces = [], []
|
|
73
|
+
for index in range(25):
|
|
74
|
+
x = (index / 24 - 0.5) * 0.17
|
|
75
|
+
for offset in (-0.007, 0.007):
|
|
76
|
+
vertices.append((x, -0.202, 1.40 + offset))
|
|
77
|
+
if index:
|
|
78
|
+
faces.append((2 * index - 2, 2 * index, 2 * index + 1, 2 * index - 1))
|
|
79
|
+
mesh = bpy.data.meshes.new("Mouth surface")
|
|
80
|
+
mesh.from_pydata(vertices, [], faces)
|
|
81
|
+
mouth = bpy.data.objects.new("Animated smile", mesh)
|
|
82
|
+
bpy.context.collection.objects.link(mouth)
|
|
83
|
+
mouth.data.materials.append(dark)
|
|
84
|
+
rigid_skin(mouth, rig, "head")
|
|
85
|
+
mouth.shape_key_add(name="Basis")
|
|
86
|
+
smile = mouth.shape_key_add(name="Smile")
|
|
87
|
+
open_mouth = mouth.shape_key_add(name="MouthOpen")
|
|
88
|
+
for index, vertex in enumerate(smile.data):
|
|
89
|
+
vertex.co.z += 0.055 * (abs(vertex.co.x) / 0.085) ** 1.7
|
|
90
|
+
for index, vertex in enumerate(open_mouth.data):
|
|
91
|
+
vertex.co.z += (0.018 if index % 2 else -0.018) * (1 - (vertex.co.x / 0.09) ** 2)
|
|
92
|
+
for frame, value in ((1, 0.1), (12, 0.3), (18, 1), (24, 0.85)):
|
|
93
|
+
smile.value = value
|
|
94
|
+
smile.keyframe_insert("value", frame=frame)
|
|
95
|
+
for frame, value in ((1, 0), (12, 0.1), (17, 0.8), (21, 0.2), (24, 0)):
|
|
96
|
+
open_mouth.value = value
|
|
97
|
+
open_mouth.keyframe_insert("value", frame=frame)
|
|
98
|
+
jaw.value = value
|
|
99
|
+
jaw.keyframe_insert("value", frame=frame)
|
|
100
|
+
# Continuous tube with blended weights demonstrates skin deformation at the elbow.
|
|
101
|
+
vertices, faces, weights = [], [], {"upper_arm.R": [], "forearm.R": []}
|
|
102
|
+
for ring in range(25):
|
|
103
|
+
x = 0.29 + ring / 24 * 0.62
|
|
104
|
+
z = 1.15 - ring / 24 * 0.06
|
|
105
|
+
blend = max(0, min(1, (x - 0.55) / 0.12))
|
|
106
|
+
for radial in range(16):
|
|
107
|
+
angle = radial * math.tau / 16
|
|
108
|
+
index = len(vertices)
|
|
109
|
+
vertices.append((x, math.cos(angle) * 0.073, z + math.sin(angle) * 0.073))
|
|
110
|
+
weights["upper_arm.R"].append((index, 1 - blend))
|
|
111
|
+
weights["forearm.R"].append((index, blend))
|
|
112
|
+
if ring:
|
|
113
|
+
previous = (radial + 1) % 16
|
|
114
|
+
faces.append(((ring - 1) * 16 + radial, (ring - 1) * 16 + previous,
|
|
115
|
+
ring * 16 + previous, ring * 16 + radial))
|
|
116
|
+
mesh = bpy.data.meshes.new("Continuous arm skin")
|
|
117
|
+
mesh.from_pydata(vertices, [], faces)
|
|
118
|
+
arm = bpy.data.objects.new("Deforming IK sleeve", mesh)
|
|
119
|
+
bpy.context.collection.objects.link(arm)
|
|
120
|
+
arm.data.materials.append(teal)
|
|
121
|
+
for polygon in mesh.polygons:
|
|
122
|
+
polygon.use_smooth = True
|
|
123
|
+
weighted(arm, rig, weights)
|
|
124
|
+
hand = sphere("Reaching hand", (0.94, 0, 1.09), (0.105, 0.085, 0.085), ceramic)
|
|
125
|
+
rigid_skin(hand, rig, "forearm.R")
|
|
126
|
+
for side, x in (("L", -0.14), ("R", 0.14)):
|
|
127
|
+
leg = cylinder("Leg." + side, (x, 0, 0.40), 0.10, 0.40, teal, 0.025)
|
|
128
|
+
rigid_skin(leg, rig, "leg." + side)
|
|
129
|
+
foot = sphere("Foot." + side, (x, -0.065, 0.11), (0.135, 0.19, 0.09), ceramic)
|
|
130
|
+
rigid_skin(foot, rig, "leg." + side)
|
|
131
|
+
left_arm = sphere("Left arm sleeve", (-0.39, 0, 0.91), (0.08, 0.085, 0.23), teal)
|
|
132
|
+
rigid_skin(left_arm, rig, "upper_arm.L")
|
|
133
|
+
left_hand = sphere("Left hand", (-0.43, -0.025, 0.58), (0.09, 0.085, 0.10), ceramic)
|
|
134
|
+
rigid_skin(left_hand, rig, "forearm.L")
|
|
135
|
+
for x in (-0.27, 0.27):
|
|
136
|
+
sphere("Shoulder collar", (x, 0, 1.15), (0.095, 0.10, 0.10), copper)
|
|
137
|
+
goal = bpy.data.objects.new("Right hand IK goal", None)
|
|
138
|
+
bpy.context.collection.objects.link(goal)
|
|
139
|
+
goal.empty_display_type = "SPHERE"
|
|
140
|
+
goal.empty_display_size = 0.05
|
|
141
|
+
for frame, location in ((1, (0.88, 0, 1.09)), (12, (0.69, -0.10, 1.45)),
|
|
142
|
+
(18, (0.62, -0.09, 1.59)), (24, (0.73, -0.08, 1.48))):
|
|
143
|
+
goal.location = location
|
|
144
|
+
goal.keyframe_insert("location", frame=frame)
|
|
145
|
+
pole = bpy.data.objects.new("Elbow pole", None)
|
|
146
|
+
bpy.context.collection.objects.link(pole)
|
|
147
|
+
pole.location = (0.6, -0.7, 0.8)
|
|
148
|
+
ik = rig.pose.bones["forearm.R"].constraints.new("IK")
|
|
149
|
+
ik.target, ik.pole_target, ik.chain_count, ik.use_stretch = goal, pole, 2, False
|
|
150
|
+
studio_lights(scale=1)
|
|
151
|
+
camera((2.4, -4.4, 2.1), (0.12, 0, 0.87), lens=47, fstop=8)
|
|
152
|
+
scene.frame_set((context.get("render") or {}).get("startFrame", 1))
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Bake a woven cloth over a rounded pedestal; render its retained native scene."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import bpy
|
|
6
|
+
from studio_scene import reset, material, cube, sphere, camera, floor, studio_lights
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def build(context):
|
|
10
|
+
scene = reset()
|
|
11
|
+
floor(size=15)
|
|
12
|
+
pedestal = sphere("Cloth collision pedestal", (0, 0, 0.53), (0.40, 0.38, 0.43),
|
|
13
|
+
material("Porcelain pedestal", (0.58, 0.63, 0.59), roughness=0.28))
|
|
14
|
+
pedestal.modifiers.new("Cloth collider", "COLLISION")
|
|
15
|
+
pedestal.collision.thickness_outer = 0.015
|
|
16
|
+
bpy.ops.mesh.primitive_grid_add(x_subdivisions=33, y_subdivisions=33, size=1.6, location=(0, 0, 1.12))
|
|
17
|
+
cloth = bpy.context.object
|
|
18
|
+
cloth.name = "Woven cloth"
|
|
19
|
+
cloth.data.materials.append(material("Copper velvet weave", (0.38, 0.10, 0.025), roughness=0.64, texture=True))
|
|
20
|
+
for polygon in cloth.data.polygons:
|
|
21
|
+
polygon.use_smooth = True
|
|
22
|
+
modifier = cloth.modifiers.new("Authored cloth solver", "CLOTH")
|
|
23
|
+
modifier.settings.quality = 6
|
|
24
|
+
modifier.settings.mass = 0.3
|
|
25
|
+
modifier.settings.tension_stiffness = 18
|
|
26
|
+
modifier.settings.compression_stiffness = 18
|
|
27
|
+
modifier.settings.shear_stiffness = 8
|
|
28
|
+
modifier.settings.bending_stiffness = 0.4
|
|
29
|
+
modifier.collision_settings.use_collision = True
|
|
30
|
+
modifier.collision_settings.distance_min = 0.012
|
|
31
|
+
modifier.collision_settings.use_self_collision = True
|
|
32
|
+
modifier.collision_settings.self_distance_min = 0.012
|
|
33
|
+
modifier.point_cache.frame_start = 1
|
|
34
|
+
modifier.point_cache.frame_end = 40
|
|
35
|
+
modifier.point_cache.use_disk_cache = False
|
|
36
|
+
if context["parameters"].get("pinBackCorners", False):
|
|
37
|
+
pins = [vertex.index for vertex in cloth.data.vertices if vertex.co.y > 0.79 and abs(vertex.co.x) > 0.79]
|
|
38
|
+
if len(pins) != 2:
|
|
39
|
+
raise RuntimeError("Expected exactly two authored back-corner pin vertices")
|
|
40
|
+
group = cloth.vertex_groups.new(name="Pinned back corners")
|
|
41
|
+
group.add(pins, 1.0, "REPLACE")
|
|
42
|
+
modifier.settings.vertex_group_mass = group.name
|
|
43
|
+
modifier.settings.pin_stiffness = 1.0
|
|
44
|
+
solidify = cloth.modifiers.new("Fabric thickness", "SOLIDIFY")
|
|
45
|
+
solidify.thickness = 0.005
|
|
46
|
+
subdivision = cloth.modifiers.new("Fabric finish", "SUBSURF")
|
|
47
|
+
subdivision.levels = 1
|
|
48
|
+
subdivision.render_levels = 1
|
|
49
|
+
studio_lights(scale=0.8)
|
|
50
|
+
camera((2.3, -2.8, 2.05), (0, 0, 0.62), lens=55, fstop=8)
|
|
51
|
+
scene.frame_start, scene.frame_end = 1, 40
|
|
52
|
+
scene.frame_set(1)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def bake(context):
|
|
56
|
+
scene = bpy.context.scene
|
|
57
|
+
cloth = bpy.data.objects["Woven cloth"]
|
|
58
|
+
cache = cloth.modifiers["Authored cloth solver"].point_cache
|
|
59
|
+
bpy.context.view_layer.objects.active = cloth
|
|
60
|
+
with bpy.context.temp_override(scene=scene, active_object=cloth, object=cloth, point_cache=cache):
|
|
61
|
+
bpy.ops.ptcache.bake(bake=True)
|
|
62
|
+
if not cache.is_baked:
|
|
63
|
+
raise RuntimeError("Cloth solver did not produce a completed bake")
|
|
64
|
+
cache_root = Path(context["outputRoot"]) / "cache" / "cloth"
|
|
65
|
+
cache_root.mkdir(parents=True, exist_ok=True)
|
|
66
|
+
facts = []
|
|
67
|
+
for frame in (1, 16, 32, 40):
|
|
68
|
+
scene.frame_set(frame)
|
|
69
|
+
evaluated = cloth.evaluated_get(bpy.context.evaluated_depsgraph_get())
|
|
70
|
+
mesh = evaluated.to_mesh()
|
|
71
|
+
facts.append({"frame": frame, "vertices": len(mesh.vertices),
|
|
72
|
+
"minZ": min((evaluated.matrix_world @ v.co).z for v in mesh.vertices),
|
|
73
|
+
"maxZ": max((evaluated.matrix_world @ v.co).z for v in mesh.vertices)})
|
|
74
|
+
evaluated.to_mesh_clear()
|
|
75
|
+
# Portable deformation cache supplements the native .blend's baked point cache.
|
|
76
|
+
bpy.ops.object.select_all(action="DESELECT")
|
|
77
|
+
cloth.select_set(True)
|
|
78
|
+
bpy.ops.wm.alembic_export(filepath=str(cache_root / "cloth.abc"), start=1, end=40,
|
|
79
|
+
selected=True, xsamples=1, gsamples=1, check_existing=False)
|
|
80
|
+
pin_facts = []
|
|
81
|
+
pin_group = cloth.vertex_groups.get("Pinned back corners")
|
|
82
|
+
if pin_group:
|
|
83
|
+
indices = [vertex.index for vertex in cloth.data.vertices if any(group.group == pin_group.index and group.weight == 1 for group in vertex.groups)]
|
|
84
|
+
finish = [modifier for modifier in cloth.modifiers if modifier.type in ("SOLIDIFY", "SUBSURF")]
|
|
85
|
+
flags = [modifier.show_viewport for modifier in finish]
|
|
86
|
+
try:
|
|
87
|
+
for modifier in finish:
|
|
88
|
+
modifier.show_viewport = False
|
|
89
|
+
for frame in range(1, 41):
|
|
90
|
+
scene.frame_set(frame)
|
|
91
|
+
evaluated = cloth.evaluated_get(bpy.context.evaluated_depsgraph_get())
|
|
92
|
+
mesh = evaluated.to_mesh()
|
|
93
|
+
pin_facts.append({"frame": frame, "positions": [list(evaluated.matrix_world @ mesh.vertices[index].co) for index in indices]})
|
|
94
|
+
evaluated.to_mesh_clear()
|
|
95
|
+
if any(abs(a - b) > 0.000001 for fact in pin_facts[1:] for first, current in zip(pin_facts[0]["positions"], fact["positions"]) for a, b in zip(first, current)):
|
|
96
|
+
raise RuntimeError("Completed cloth bake moved a fully weighted pin vertex")
|
|
97
|
+
finally:
|
|
98
|
+
for modifier, flag in zip(finish, flags):
|
|
99
|
+
modifier.show_viewport = flag
|
|
100
|
+
(cache_root / "bake-evidence.json").write_text(json.dumps({"isBaked": cache.is_baked, "frames": facts, "pins": pin_facts}, indent=2) + "\n")
|
|
101
|
+
scene.frame_set(32)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Known linear-emission patches for PNG/EXR color and alpha qualification."""
|
|
2
|
+
|
|
3
|
+
import bpy
|
|
4
|
+
from studio_scene import reset, camera
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def build(context):
|
|
8
|
+
scene = reset()
|
|
9
|
+
scene.world.node_tree.nodes["Background"].inputs["Strength"].default_value = 0
|
|
10
|
+
colors = ((0.18, 0.18, 0.18), (1, 0, 0), (0, 1, 0),
|
|
11
|
+
(0, 0, 1), (2, 1, 0.5), (0.5, 0.25, 0.125))
|
|
12
|
+
for index, color in enumerate(colors):
|
|
13
|
+
bpy.ops.mesh.primitive_plane_add(size=1, location=((index % 3 - 1), 0.4 if index < 3 else -0.4, 0))
|
|
14
|
+
patch = bpy.context.object
|
|
15
|
+
patch.name = "Linear emission patch " + str(index)
|
|
16
|
+
patch.scale = (0.8, 0.55, 1)
|
|
17
|
+
material = bpy.data.materials.new(patch.name)
|
|
18
|
+
material.use_nodes = True
|
|
19
|
+
material.node_tree.nodes.clear()
|
|
20
|
+
emission = material.node_tree.nodes.new("ShaderNodeEmission")
|
|
21
|
+
emission.inputs["Color"].default_value = (*color, 1)
|
|
22
|
+
emission.inputs["Strength"].default_value = 1
|
|
23
|
+
output = material.node_tree.nodes.new("ShaderNodeOutputMaterial")
|
|
24
|
+
material.node_tree.links.new(emission.outputs["Emission"], output.inputs["Surface"])
|
|
25
|
+
patch.data.materials.append(material)
|
|
26
|
+
shot = camera((0, 0, 4), (0, 0, 0))
|
|
27
|
+
shot.data.type = "ORTHO"
|
|
28
|
+
shot.data.ortho_scale = 3.2
|
|
29
|
+
shot.data.dof.use_dof = False
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Small liquid splash with an explicit Mantaflow bake and retained cache."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import bpy
|
|
7
|
+
from studio_scene import reset, material, cube, sphere, camera, floor, studio_lights
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def build(context):
|
|
11
|
+
scene = reset()
|
|
12
|
+
floor(size=15)
|
|
13
|
+
stone = material("Basin ceramic", (0.18, 0.26, 0.28), roughness=0.24)
|
|
14
|
+
for name, center, size in (
|
|
15
|
+
("Basin bottom", (0, 0, 0.05), (1.3, 1.1, 0.10)),
|
|
16
|
+
("Basin back", (0, 0.52, 0.18), (1.3, 0.10, 0.30)),
|
|
17
|
+
("Basin front", (0, -0.52, 0.14), (1.3, 0.10, 0.22)),
|
|
18
|
+
("Basin left", (-0.60, 0, 0.18), (0.10, 1.0, 0.30)),
|
|
19
|
+
("Basin right", (0.60, 0, 0.18), (0.10, 1.0, 0.30)),
|
|
20
|
+
):
|
|
21
|
+
wall = cube(name, center, size, stone, 0.02)
|
|
22
|
+
modifier = wall.modifiers.new("Liquid collision", "FLUID")
|
|
23
|
+
modifier.fluid_type = "EFFECTOR"
|
|
24
|
+
modifier.effector_settings.surface_distance = 0.001
|
|
25
|
+
liquid = material("Clear turquoise water", (0.25, 0.70, 0.74), roughness=0.09, transmission=0.88)
|
|
26
|
+
domain = cube("Liquid domain", (0, 0, 0.66), (1.45, 1.25, 1.35), liquid)
|
|
27
|
+
modifier = domain.modifiers.new("Authored liquid solver", "FLUID")
|
|
28
|
+
modifier.fluid_type = "DOMAIN"
|
|
29
|
+
settings = modifier.domain_settings
|
|
30
|
+
settings.domain_type = "LIQUID"
|
|
31
|
+
settings.resolution_max = int(context["parameters"].get("resolution", 24))
|
|
32
|
+
if not 16 <= settings.resolution_max <= 48:
|
|
33
|
+
raise ValueError("Fluid fixture resolution must stay between 16 and 48")
|
|
34
|
+
settings.cache_frame_start = 1
|
|
35
|
+
settings.cache_frame_end = 32
|
|
36
|
+
settings.cache_type = "ALL"
|
|
37
|
+
settings.cache_directory = str(Path(context["outputRoot"]) / "cache" / "fluid")
|
|
38
|
+
settings.cache_data_format = "UNI"
|
|
39
|
+
settings.use_mesh = True
|
|
40
|
+
settings.mesh_scale = 2
|
|
41
|
+
settings.timesteps_min = 1
|
|
42
|
+
settings.timesteps_max = 4
|
|
43
|
+
source = sphere("Initial liquid volume", (0, 0, 0.89), (0.30, 0.30, 0.27), liquid)
|
|
44
|
+
source.hide_render = True
|
|
45
|
+
flow = source.modifiers.new("Liquid source", "FLUID")
|
|
46
|
+
flow.fluid_type = "FLOW"
|
|
47
|
+
flow.flow_settings.flow_type = "LIQUID"
|
|
48
|
+
flow.flow_settings.flow_behavior = "GEOMETRY"
|
|
49
|
+
studio_lights(scale=0.8)
|
|
50
|
+
camera((2.3, -2.7, 1.9), (0, 0, 0.35), lens=55, fstop=8)
|
|
51
|
+
scene.frame_start, scene.frame_end = 1, 32
|
|
52
|
+
scene.frame_set(1)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def bake(context):
|
|
56
|
+
scene = bpy.context.scene
|
|
57
|
+
domain = bpy.data.objects["Liquid domain"]
|
|
58
|
+
settings = domain.modifiers["Authored liquid solver"].domain_settings
|
|
59
|
+
bpy.context.view_layer.objects.active = domain
|
|
60
|
+
bpy.ops.object.select_all(action="DESELECT")
|
|
61
|
+
domain.select_set(True)
|
|
62
|
+
with bpy.context.temp_override(scene=scene, active_object=domain, object=domain):
|
|
63
|
+
bpy.ops.fluid.bake_all()
|
|
64
|
+
if not settings.has_cache_baked_data or not settings.has_cache_baked_mesh:
|
|
65
|
+
raise RuntimeError("Liquid solver did not complete data and surface-mesh bakes")
|
|
66
|
+
facts = []
|
|
67
|
+
for frame in (1, 12, 24, 32):
|
|
68
|
+
scene.frame_set(frame)
|
|
69
|
+
evaluated = domain.evaluated_get(bpy.context.evaluated_depsgraph_get())
|
|
70
|
+
mesh = evaluated.to_mesh()
|
|
71
|
+
facts.append({"frame": frame, "vertices": len(mesh.vertices), "polygons": len(mesh.polygons)})
|
|
72
|
+
evaluated.to_mesh_clear()
|
|
73
|
+
cache_root = Path(context["outputRoot"]) / "cache" / "fluid"
|
|
74
|
+
(cache_root / "bake-evidence.json").write_text(json.dumps({"dataBaked": True, "meshBaked": True, "frames": facts}, indent=2) + "\n")
|
|
75
|
+
# The native scene stays movable with its declared cache dependency tree.
|
|
76
|
+
if bpy.data.filepath:
|
|
77
|
+
settings.cache_directory = "//" + os.path.relpath(cache_root, Path(bpy.data.filepath).parent)
|
|
78
|
+
scene.frame_set(24)
|