@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.
Files changed (441) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +60 -0
  3. package/PRIVACY.md +46 -0
  4. package/README.md +311 -0
  5. package/SECURITY.md +21 -0
  6. package/apps/desktop/README.md +966 -0
  7. package/apps/desktop/analysis/protocol.ts +223 -0
  8. package/apps/desktop/application/capability-binding.ts +594 -0
  9. package/apps/desktop/application/context.ts +97 -0
  10. package/apps/desktop/application/creative-iteration.ts +1385 -0
  11. package/apps/desktop/application/default-registry.ts +146 -0
  12. package/apps/desktop/application/directing-contract.ts +218 -0
  13. package/apps/desktop/application/directing-plan.ts +178 -0
  14. package/apps/desktop/application/errors.ts +18 -0
  15. package/apps/desktop/application/gateway-port.ts +867 -0
  16. package/apps/desktop/application/html-overlay-browser-runtime.ts +687 -0
  17. package/apps/desktop/application/html-overlay-integrity.ts +337 -0
  18. package/apps/desktop/application/html-overlay-renderer.ts +45 -0
  19. package/apps/desktop/application/index.ts +13 -0
  20. package/apps/desktop/application/operation-completion-checkpoint.ts +333 -0
  21. package/apps/desktop/application/operation-effects.ts +94 -0
  22. package/apps/desktop/application/operation.ts +224 -0
  23. package/apps/desktop/application/operations/analysis/faces.ts +244 -0
  24. package/apps/desktop/application/operations/analysis/music.ts +248 -0
  25. package/apps/desktop/application/operations/analysis/project-auto-zooms.ts +302 -0
  26. package/apps/desktop/application/operations/analysis/project-inactivity.ts +381 -0
  27. package/apps/desktop/application/operations/analysis/scenes.ts +272 -0
  28. package/apps/desktop/application/operations/analysis/shared.ts +202 -0
  29. package/apps/desktop/application/operations/derive/edit-batch.ts +967 -0
  30. package/apps/desktop/application/operations/derive/follow-faces.ts +454 -0
  31. package/apps/desktop/application/operations/edit/bind-candidate-revision.ts +91 -0
  32. package/apps/desktop/application/operations/edit/create-candidate-revision.ts +377 -0
  33. package/apps/desktop/application/operations/edit/create-revision.ts +255 -0
  34. package/apps/desktop/application/operations/edit/freeze-revision.ts +182 -0
  35. package/apps/desktop/application/operations/gateway/image.ts +41 -0
  36. package/apps/desktop/application/operations/gateway/index.ts +17 -0
  37. package/apps/desktop/application/operations/gateway/shared.ts +122 -0
  38. package/apps/desktop/application/operations/gateway/speech.ts +41 -0
  39. package/apps/desktop/application/operations/gateway/transcription.ts +42 -0
  40. package/apps/desktop/application/operations/gateway/video.ts +41 -0
  41. package/apps/desktop/application/operations/index.ts +31 -0
  42. package/apps/desktop/application/operations/iteration/create-candidate.ts +240 -0
  43. package/apps/desktop/application/operations/iteration/create-matrix.ts +117 -0
  44. package/apps/desktop/application/operations/iteration/select.ts +155 -0
  45. package/apps/desktop/application/operations/iteration/shared.ts +250 -0
  46. package/apps/desktop/application/operations/media/audio-effects.ts +376 -0
  47. package/apps/desktop/application/operations/media/binding.ts +79 -0
  48. package/apps/desktop/application/operations/media/capabilities.ts +112 -0
  49. package/apps/desktop/application/operations/media/color-grade.ts +343 -0
  50. package/apps/desktop/application/operations/media/html-overlay.ts +802 -0
  51. package/apps/desktop/application/operations/media/index.ts +8 -0
  52. package/apps/desktop/application/operations/media/ingest.ts +303 -0
  53. package/apps/desktop/application/operations/media/overlay.ts +729 -0
  54. package/apps/desktop/application/operations/media/shared.ts +845 -0
  55. package/apps/desktop/application/operations/media/transform-platform.ts +120 -0
  56. package/apps/desktop/application/operations/project/commit-edits.ts +2054 -0
  57. package/apps/desktop/application/operations/project/promote-selection.ts +495 -0
  58. package/apps/desktop/application/operations/project/snapshot.ts +95 -0
  59. package/apps/desktop/application/operations/recording/index.ts +5 -0
  60. package/apps/desktop/application/operations/recording/pause.ts +34 -0
  61. package/apps/desktop/application/operations/recording/resume.ts +34 -0
  62. package/apps/desktop/application/operations/recording/shared.ts +199 -0
  63. package/apps/desktop/application/operations/recording/start.ts +169 -0
  64. package/apps/desktop/application/operations/recording/stop.ts +34 -0
  65. package/apps/desktop/application/operations/render/bind-candidate-output.ts +324 -0
  66. package/apps/desktop/application/operations/render/materialize-selection.ts +322 -0
  67. package/apps/desktop/application/operations/render/project-caption-plan.ts +287 -0
  68. package/apps/desktop/application/operations/render/project-plan.ts +939 -0
  69. package/apps/desktop/application/operations/render/project-spatial-receipt.ts +70 -0
  70. package/apps/desktop/application/operations/render/project.ts +1922 -0
  71. package/apps/desktop/application/operations/shared.ts +67 -0
  72. package/apps/desktop/application/operations/slopcamera-portable.ts +1188 -0
  73. package/apps/desktop/application/operations/slopcamera-visuals.ts +784 -0
  74. package/apps/desktop/application/operations/spatial-project.ts +209 -0
  75. package/apps/desktop/application/operations/spatial-render.ts +415 -0
  76. package/apps/desktop/application/operations/spatial-scene.ts +97 -0
  77. package/apps/desktop/application/operations/studio.ts +143 -0
  78. package/apps/desktop/application/output-publication-lease.ts +163 -0
  79. package/apps/desktop/application/project-publication-lease.ts +233 -0
  80. package/apps/desktop/application/project-store.ts +196 -0
  81. package/apps/desktop/application/receipts.ts +533 -0
  82. package/apps/desktop/application/registry.ts +182 -0
  83. package/apps/desktop/application/spatial-assets.ts +675 -0
  84. package/apps/desktop/application/spatial-compositor-cadence.ts +23 -0
  85. package/apps/desktop/application/spatial-project-authority.ts +35 -0
  86. package/apps/desktop/application/spatial-project-lease.ts +126 -0
  87. package/apps/desktop/application/spatial-project-render-preparation.ts +225 -0
  88. package/apps/desktop/application/spatial-project-store.ts +286 -0
  89. package/apps/desktop/application/spatial-render-projection.ts +201 -0
  90. package/apps/desktop/application/spatial-render.ts +677 -0
  91. package/apps/desktop/application/spatial-spz.ts +44 -0
  92. package/apps/desktop/application/spatial-world-import.ts +135 -0
  93. package/apps/desktop/application/spatial-world-provenance.ts +46 -0
  94. package/apps/desktop/application/studio-port.ts +58 -0
  95. package/apps/desktop/application/verified-receipt-reconciliation.ts +1574 -0
  96. package/apps/desktop/capture/protocol.ts +689 -0
  97. package/apps/desktop/cli/analyzer.ts +406 -0
  98. package/apps/desktop/cli/args.ts +3181 -0
  99. package/apps/desktop/cli/asset-ingest.ts +747 -0
  100. package/apps/desktop/cli/atomic-render-effects.ts +210 -0
  101. package/apps/desktop/cli/atomic-render-platform.ts +205 -0
  102. package/apps/desktop/cli/atomic-render.ts +50 -0
  103. package/apps/desktop/cli/audio-analysis.ts +252 -0
  104. package/apps/desktop/cli/bounded-map.ts +39 -0
  105. package/apps/desktop/cli/bundle-service.ts +256 -0
  106. package/apps/desktop/cli/capabilities.ts +212 -0
  107. package/apps/desktop/cli/capture-bundle.ts +1117 -0
  108. package/apps/desktop/cli/command-host-resources.ts +251 -0
  109. package/apps/desktop/cli/commands.ts +6836 -0
  110. package/apps/desktop/cli/directing-blob.ts +291 -0
  111. package/apps/desktop/cli/directing-media.ts +517 -0
  112. package/apps/desktop/cli/directing-quote.ts +89 -0
  113. package/apps/desktop/cli/directing-service.ts +288 -0
  114. package/apps/desktop/cli/emoji-assets.ts +538 -0
  115. package/apps/desktop/cli/errors.ts +29 -0
  116. package/apps/desktop/cli/face-analysis-service.ts +940 -0
  117. package/apps/desktop/cli/filter-script.ts +76 -0
  118. package/apps/desktop/cli/gateway-application-port.ts +1142 -0
  119. package/apps/desktop/cli/gateway-credential.ts +81 -0
  120. package/apps/desktop/cli/gateway-media-artifacts.ts +723 -0
  121. package/apps/desktop/cli/gateway-media-catalog.ts +922 -0
  122. package/apps/desktop/cli/gateway-media-service.ts +3106 -0
  123. package/apps/desktop/cli/gateway-media-signature.ts +122 -0
  124. package/apps/desktop/cli/gateway-provider-options.ts +562 -0
  125. package/apps/desktop/cli/gateway-scene-provider.ts +391 -0
  126. package/apps/desktop/cli/help.ts +501 -0
  127. package/apps/desktop/cli/html-overlay-gpu.ts +97 -0
  128. package/apps/desktop/cli/html-overlay-renderer.ts +2478 -0
  129. package/apps/desktop/cli/io.ts +290 -0
  130. package/apps/desktop/cli/main.ts +123 -0
  131. package/apps/desktop/cli/media-effects-service.ts +885 -0
  132. package/apps/desktop/cli/media-ingest-model.ts +364 -0
  133. package/apps/desktop/cli/media-ingest-platform.ts +227 -0
  134. package/apps/desktop/cli/media-ingest-program.ts +200 -0
  135. package/apps/desktop/cli/media-ingest.ts +30 -0
  136. package/apps/desktop/cli/music-analysis-service.ts +434 -0
  137. package/apps/desktop/cli/mutation-lock.ts +530 -0
  138. package/apps/desktop/cli/native-assets.d.ts +12 -0
  139. package/apps/desktop/cli/native-media-runtime.macos.ts +7 -0
  140. package/apps/desktop/cli/overlay-playback.ts +177 -0
  141. package/apps/desktop/cli/paths.ts +265 -0
  142. package/apps/desktop/cli/portable-surface.ts +242 -0
  143. package/apps/desktop/cli/project-camera-receipt.ts +112 -0
  144. package/apps/desktop/cli/project-face-camera.ts +394 -0
  145. package/apps/desktop/cli/project-inactivity-service.ts +552 -0
  146. package/apps/desktop/cli/project-media-integrity.ts +121 -0
  147. package/apps/desktop/cli/project-renderer.ts +1526 -0
  148. package/apps/desktop/cli/project-service.ts +519 -0
  149. package/apps/desktop/cli/project-state-transaction.ts +520 -0
  150. package/apps/desktop/cli/query-limits.ts +1 -0
  151. package/apps/desktop/cli/recording-controller.ts +1567 -0
  152. package/apps/desktop/cli/recording-daemon.ts +931 -0
  153. package/apps/desktop/cli/recording-ref.ts +56 -0
  154. package/apps/desktop/cli/renamed-environment.ts +6 -0
  155. package/apps/desktop/cli/renderer.ts +1439 -0
  156. package/apps/desktop/cli/run-cli-test-helper.ts +60 -0
  157. package/apps/desktop/cli/scene-analysis-service.ts +879 -0
  158. package/apps/desktop/cli/spatial-compositor-verifier.ts +213 -0
  159. package/apps/desktop/cli/spatial-project-service.ts +90 -0
  160. package/apps/desktop/cli/spatial-scene-service.ts +105 -0
  161. package/apps/desktop/cli/spatial-world-service.ts +39 -0
  162. package/apps/desktop/cli/speech-analysis-service.ts +682 -0
  163. package/apps/desktop/cli/studio-assemble.ts +58 -0
  164. package/apps/desktop/cli/studio-command.ts +60 -0
  165. package/apps/desktop/cli/studio-custody.ts +60 -0
  166. package/apps/desktop/cli/studio-encode.ts +216 -0
  167. package/apps/desktop/cli/studio-exr.ts +52 -0
  168. package/apps/desktop/cli/studio-files.ts +179 -0
  169. package/apps/desktop/cli/studio-output-validation.ts +162 -0
  170. package/apps/desktop/cli/studio-process.ts +145 -0
  171. package/apps/desktop/cli/studio-runtime.ts +77 -0
  172. package/apps/desktop/cli/studio-scaffold.ts +70 -0
  173. package/apps/desktop/cli/studio-service.ts +301 -0
  174. package/apps/desktop/cli/studio-spatial-asset.ts +248 -0
  175. package/apps/desktop/cli/studio-template-names.ts +3 -0
  176. package/apps/desktop/cli/studio-workflow.ts +19 -0
  177. package/apps/desktop/cli/time.ts +25 -0
  178. package/apps/desktop/cli/workflow-code.ts +584 -0
  179. package/apps/desktop/cli/workflow-runs.ts +576 -0
  180. package/apps/desktop/code/advanced.ts +139 -0
  181. package/apps/desktop/code/application-node-planner.ts +1288 -0
  182. package/apps/desktop/code/compiler.ts +329 -0
  183. package/apps/desktop/code/contracts.ts +13 -0
  184. package/apps/desktop/code/creative-recipes.ts +94 -0
  185. package/apps/desktop/code/define-workflow.ts +115 -0
  186. package/apps/desktop/code/editing.ts +284 -0
  187. package/apps/desktop/code/file-candidate-provenance.ts +420 -0
  188. package/apps/desktop/code/file-candidate.ts +69 -0
  189. package/apps/desktop/code/graph-builder.ts +10 -0
  190. package/apps/desktop/code/host-resource-policy.ts +55 -0
  191. package/apps/desktop/code/plan-contracts.ts +159 -0
  192. package/apps/desktop/code/planning.ts +361 -0
  193. package/apps/desktop/code/public.ts +134 -0
  194. package/apps/desktop/code/reference-projection.ts +62 -0
  195. package/apps/desktop/code/run-contracts.ts +466 -0
  196. package/apps/desktop/code/run-store.ts +2478 -0
  197. package/apps/desktop/code/runtime-identity.ts +328 -0
  198. package/apps/desktop/code/scheduler.ts +3067 -0
  199. package/apps/desktop/code/semantic-builder.ts +1436 -0
  200. package/apps/desktop/code/source-bundle.ts +1641 -0
  201. package/apps/desktop/code/source-typecheck.ts +211 -0
  202. package/apps/desktop/code/testing.ts +79 -0
  203. package/apps/desktop/code/worker-client.ts +1675 -0
  204. package/apps/desktop/code/worker-effects.ts +141 -0
  205. package/apps/desktop/code/worker-entry.ts +435 -0
  206. package/apps/desktop/code/worker-lease-guardian.ts +179 -0
  207. package/apps/desktop/code/worker-process-identity.ts +484 -0
  208. package/apps/desktop/code/worker-protocol.ts +211 -0
  209. package/apps/desktop/code/workflow-effects.ts +132 -0
  210. package/apps/desktop/contracts/analysis.ts +949 -0
  211. package/apps/desktop/contracts/edit.ts +576 -0
  212. package/apps/desktop/contracts/index.ts +9 -0
  213. package/apps/desktop/contracts/media-effects.ts +139 -0
  214. package/apps/desktop/contracts/project-render.ts +644 -0
  215. package/apps/desktop/contracts/project.ts +740 -0
  216. package/apps/desktop/contracts/recording.ts +1434 -0
  217. package/apps/desktop/contracts/render.ts +334 -0
  218. package/apps/desktop/contracts/runtime.ts +155 -0
  219. package/apps/desktop/contracts/spatial-compositor.ts +58 -0
  220. package/apps/desktop/contracts/spatial-project.ts +159 -0
  221. package/apps/desktop/contracts/spatial-world.ts +48 -0
  222. package/apps/desktop/contracts/video-effects.ts +120 -0
  223. package/apps/desktop/core/alignment-apply.ts +400 -0
  224. package/apps/desktop/core/audio-alignment.ts +466 -0
  225. package/apps/desktop/core/auto-zoom.ts +209 -0
  226. package/apps/desktop/core/canonical-json.ts +14 -0
  227. package/apps/desktop/core/emoji.ts +210 -0
  228. package/apps/desktop/core/events.ts +409 -0
  229. package/apps/desktop/core/face-framing.ts +533 -0
  230. package/apps/desktop/core/face-tracks.ts +326 -0
  231. package/apps/desktop/core/inactivity.ts +137 -0
  232. package/apps/desktop/core/index.ts +30 -0
  233. package/apps/desktop/core/intervals.ts +123 -0
  234. package/apps/desktop/core/montage.ts +236 -0
  235. package/apps/desktop/core/music-analysis.ts +518 -0
  236. package/apps/desktop/core/plan.ts +244 -0
  237. package/apps/desktop/core/project-auto-zoom.ts +75 -0
  238. package/apps/desktop/core/project-camera-spatial.ts +676 -0
  239. package/apps/desktop/core/project-camera.ts +403 -0
  240. package/apps/desktop/core/project-captions.ts +888 -0
  241. package/apps/desktop/core/project-inactivity.ts +125 -0
  242. package/apps/desktop/core/project-metadata.ts +927 -0
  243. package/apps/desktop/core/project-plan.ts +375 -0
  244. package/apps/desktop/core/project-render-plan.ts +303 -0
  245. package/apps/desktop/core/project-time.ts +469 -0
  246. package/apps/desktop/core/render-plan.ts +442 -0
  247. package/apps/desktop/core/scene-cache.ts +174 -0
  248. package/apps/desktop/core/scene-sampling.ts +448 -0
  249. package/apps/desktop/core/spatial-compositor.ts +22 -0
  250. package/apps/desktop/core/spatial-durability.ts +99 -0
  251. package/apps/desktop/core/spatial-project.ts +169 -0
  252. package/apps/desktop/core/spatial-shot-clock.ts +32 -0
  253. package/apps/desktop/core/speech-analysis.ts +333 -0
  254. package/apps/desktop/core/storage.ts +970 -0
  255. package/apps/desktop/core/time-map.ts +91 -0
  256. package/apps/desktop/core/time.ts +61 -0
  257. package/apps/desktop/core/video-effects.ts +660 -0
  258. package/apps/desktop/dist/cli/NebulaSans-Bold-26se8aek.otf +0 -0
  259. package/apps/desktop/dist/cli/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  260. package/apps/desktop/dist/cli/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  261. package/apps/desktop/dist/cli/NebulaSans-Book-8cenzchw.otf +0 -0
  262. package/apps/desktop/dist/cli/main.js +5086 -0
  263. package/apps/desktop/html-overlay/catalog.ts +171 -0
  264. package/apps/desktop/html-overlay/contracts.ts +372 -0
  265. package/apps/desktop/html-overlay/execution-profile.ts +77 -0
  266. package/apps/desktop/html-overlay/index.ts +98 -0
  267. package/apps/desktop/html-overlay/libraries.ts +263 -0
  268. package/apps/desktop/html-overlay/random.ts +49 -0
  269. package/apps/desktop/html-overlay/runtime.ts +813 -0
  270. package/apps/desktop/html-overlay/scaffolds.ts +792 -0
  271. package/apps/desktop/html-overlay/spark-runtime.ts +88 -0
  272. package/apps/desktop/html-overlay/spatial-splat-runtime.ts +60 -0
  273. package/apps/desktop/html-overlay/spatial.ts +720 -0
  274. package/apps/desktop/studio/assets/README.md +39 -0
  275. package/apps/desktop/studio/assets/contracts.ts +129 -0
  276. package/apps/desktop/studio/assets/network.ts +64 -0
  277. package/apps/desktop/studio/assets/poly-haven.ts +148 -0
  278. package/apps/desktop/studio/drivers/blender_driver.py +466 -0
  279. package/apps/desktop/studio/drivers/cadquery_driver.py +176 -0
  280. package/apps/desktop/studio/education/driver.py +308 -0
  281. package/apps/desktop/studio/education/lesson.py +180 -0
  282. package/apps/desktop/studio/education/toolkit.py +249 -0
  283. package/apps/desktop/workflows/chaptered-demo.ts +48 -0
  284. package/apps/desktop/workflows/creative-iteration.ts +107 -0
  285. package/apps/desktop/workflows/creative-selection.ts +92 -0
  286. package/apps/desktop/workflows/fragments.ts +486 -0
  287. package/apps/desktop/workflows/index.ts +93 -0
  288. package/apps/desktop/workflows/polished-screen-demo.ts +128 -0
  289. package/apps/desktop/workflows/scene-direction.ts +12 -0
  290. package/apps/desktop/workflows/social-variants.ts +75 -0
  291. package/apps/desktop/workflows/talking-head-cleanup.ts +53 -0
  292. package/dist/NebulaSans-Bold-26se8aek.otf +0 -0
  293. package/dist/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  294. package/dist/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  295. package/dist/NebulaSans-Book-8cenzchw.otf +0 -0
  296. package/dist/cli.js +479 -0
  297. package/dist/code/advanced.js +270 -0
  298. package/dist/code/index.js +2240 -0
  299. package/dist/generate.js +24 -0
  300. package/dist/host-resources.js +26 -0
  301. package/dist/index-42zsesc1.js +2257 -0
  302. package/dist/index-7308egqr.js +48 -0
  303. package/dist/index-8txs6fkn.js +712 -0
  304. package/dist/index-mcy8z0br.js +192 -0
  305. package/dist/index-p63wavx0.js +2029 -0
  306. package/dist/index-r7gdhmsp.js +424 -0
  307. package/dist/index-sh6xbav6.js +1219 -0
  308. package/dist/index-z1w83f81.js +4 -0
  309. package/dist/index-z7239b4h.js +2363 -0
  310. package/dist/index-zfeg9hmw.js +2013 -0
  311. package/dist/index.js +241 -0
  312. package/dist/operations.js +29 -0
  313. package/dist/skill-install-dh0ntqba.js +10 -0
  314. package/dist/vectorize/worker.js +142 -0
  315. package/dist/workflow.js +16 -0
  316. package/docs/README.md +38 -0
  317. package/docs/studio.md +215 -0
  318. package/examples/studio/blender/README.md +26 -0
  319. package/examples/studio/blender/character.py +152 -0
  320. package/examples/studio/blender/cloth.py +101 -0
  321. package/examples/studio/blender/color_chart.py +29 -0
  322. package/examples/studio/blender/fluid.py +78 -0
  323. package/examples/studio/blender/import_model.py +74 -0
  324. package/examples/studio/blender/product.py +53 -0
  325. package/examples/studio/blender/shaded_street.py +481 -0
  326. package/examples/studio/blender/studio_scene.py +147 -0
  327. package/examples/studio/cadquery/README.md +13 -0
  328. package/examples/studio/cadquery/bracket.py +36 -0
  329. package/examples/studio/cadquery/import_step.py +12 -0
  330. package/examples/studio/education/README.md +46 -0
  331. package/examples/studio/education/lesson.json +99 -0
  332. package/examples/studio/education/scene.py +7 -0
  333. package/examples/studio/hybrid-scene.ts +96 -0
  334. package/examples/studio/native-workflow.ts +14 -0
  335. package/examples/studio/vgpu/README.md +64 -0
  336. package/examples/studio/vgpu/heat-field.mjs +290 -0
  337. package/package.json +304 -0
  338. package/packages/scene/src/index.ts +1 -0
  339. package/packages/scene/src/scene.ts +215 -0
  340. package/schema/diagram.schema.json +334 -0
  341. package/skills/slopcamera/SKILL.md +45 -0
  342. package/skills/slopcamera/agents/openai.yaml +4 -0
  343. package/skills/slopcamera/references/customization.md +77 -0
  344. package/skills/slopcamera/references/diagrams.md +153 -0
  345. package/skills/slopcamera/references/directed-scenes.md +42 -0
  346. package/skills/slopcamera/references/directing-video.md +18 -0
  347. package/skills/slopcamera/references/educational-video.md +26 -0
  348. package/skills/slopcamera/references/gateway-media.md +134 -0
  349. package/skills/slopcamera/references/install.md +62 -0
  350. package/skills/slopcamera/references/native-studio.md +31 -0
  351. package/skills/slopcamera/references/reference-led-3d.md +140 -0
  352. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-1.jpg +0 -0
  353. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-2.jpg +0 -0
  354. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-1.png +0 -0
  355. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-2.png +0 -0
  356. package/skills/slopcamera/references/rubber-stamp-field-notes.md +144 -0
  357. package/skills/slopcamera/references/vectorization.md +29 -0
  358. package/skills/slopcamera/references/video-projects.md +187 -0
  359. package/skills/slopcamera/references/visual-communication.md +120 -0
  360. package/skills/slopcamera/references/workflows-sdk.md +45 -0
  361. package/skills/slopcamera/scripts/compose-rubber-stamp-field-note.ts +229 -0
  362. package/src/artifacts.ts +106 -0
  363. package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
  364. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
  365. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
  366. package/src/assets/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
  367. package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
  368. package/src/assets/fonts/nebula-sans/PROVENANCE.md +21 -0
  369. package/src/assets.d.ts +9 -0
  370. package/src/cli.ts +601 -0
  371. package/src/cloud-errors.ts +26 -0
  372. package/src/code/advanced.ts +10 -0
  373. package/src/code/boundary.ts +21 -0
  374. package/src/code/canonical-json.ts +129 -0
  375. package/src/code/compiler.ts +953 -0
  376. package/src/code/contracts.ts +576 -0
  377. package/src/code/define-workflow.ts +334 -0
  378. package/src/code/errors.ts +41 -0
  379. package/src/code/graph-builder.ts +945 -0
  380. package/src/code/index.ts +121 -0
  381. package/src/code/json-snapshot.ts +899 -0
  382. package/src/code/json-utf8.ts +88 -0
  383. package/src/code/portable-builder.ts +136 -0
  384. package/src/code/projection.ts +378 -0
  385. package/src/code/public-operations.ts +450 -0
  386. package/src/code/runtime.ts +580 -0
  387. package/src/code/sha256.ts +36 -0
  388. package/src/config.ts +180 -0
  389. package/src/desktop.ts +253 -0
  390. package/src/fs.ts +10 -0
  391. package/src/generate.ts +704 -0
  392. package/src/host-resource-posix.ts +161 -0
  393. package/src/host-resources.ts +1749 -0
  394. package/src/icons.ts +58 -0
  395. package/src/index.ts +200 -0
  396. package/src/label-layout.ts +130 -0
  397. package/src/layout.ts +413 -0
  398. package/src/lint.ts +127 -0
  399. package/src/mcp/boundary.ts +354 -0
  400. package/src/mcp/index.ts +33 -0
  401. package/src/mcp/server.ts +272 -0
  402. package/src/mcp/tools.ts +963 -0
  403. package/src/mcp/types.ts +71 -0
  404. package/src/operations.ts +775 -0
  405. package/src/parse.ts +861 -0
  406. package/src/process-environment.ts +17 -0
  407. package/src/render.ts +437 -0
  408. package/src/skill-install.ts +49 -0
  409. package/src/spatial-scene/authoring.ts +27 -0
  410. package/src/spatial-scene/camera-track.ts +83 -0
  411. package/src/spatial-scene/contracts.ts +277 -0
  412. package/src/spatial-scene/evaluate.ts +145 -0
  413. package/src/spatial-scene/gltf.ts +558 -0
  414. package/src/spatial-scene/identity.ts +260 -0
  415. package/src/spatial-scene/index.ts +10 -0
  416. package/src/spatial-scene/inspect.ts +68 -0
  417. package/src/spatial-scene/math.ts +280 -0
  418. package/src/spatial-scene/patch.ts +131 -0
  419. package/src/spatial-scene/time.ts +53 -0
  420. package/src/studio/contracts.ts +129 -0
  421. package/src/studio/index.ts +2 -0
  422. package/src/studio/plan.ts +156 -0
  423. package/src/studio/shared.ts +41 -0
  424. package/src/theme.ts +68 -0
  425. package/src/tldr.ts +474 -0
  426. package/src/types.ts +212 -0
  427. package/src/vectorize/archive.ts +101 -0
  428. package/src/vectorize/command.ts +797 -0
  429. package/src/vectorize/index.ts +27 -0
  430. package/src/vectorize/limits.ts +61 -0
  431. package/src/vectorize/metrics.ts +351 -0
  432. package/src/vectorize/pixels.ts +323 -0
  433. package/src/vectorize/supervisor.ts +339 -0
  434. package/src/vectorize/svg.ts +188 -0
  435. package/src/vectorize/tool.ts +542 -0
  436. package/src/vectorize/types.ts +113 -0
  437. package/src/vectorize/vectorize.ts +634 -0
  438. package/src/vectorize/worker-protocol.ts +40 -0
  439. package/src/vectorize/worker.ts +209 -0
  440. package/src/version.ts +1 -0
  441. package/src/workflow.ts +409 -0
@@ -0,0 +1,147 @@
1
+ """Small authored scene helpers; include this exact file in the source bundle."""
2
+
3
+ import math
4
+ import bpy
5
+ from mathutils import Vector
6
+
7
+
8
+ def reset():
9
+ bpy.ops.object.select_all(action="SELECT")
10
+ bpy.ops.object.delete(use_global=False)
11
+ scene = bpy.context.scene
12
+ scene.unit_settings.system = "METRIC"
13
+ scene.unit_settings.scale_length = 1.0
14
+ scene.world = bpy.data.worlds.new("Studio environment")
15
+ scene.world.use_nodes = True
16
+ scene.world.node_tree.nodes["Background"].inputs["Color"].default_value = (0.055, 0.075, 0.12, 1)
17
+ scene.world.node_tree.nodes["Background"].inputs["Strength"].default_value = 0.24
18
+ scene.render.image_settings.color_mode = "RGB"
19
+ scene.view_settings.look = "AgX - Medium High Contrast"
20
+ return scene
21
+
22
+
23
+ def material(name, color, metallic=0.0, roughness=0.35, transmission=0.0, texture=False):
24
+ mat = bpy.data.materials.new(name)
25
+ mat.diffuse_color = (*color, 1)
26
+ mat.use_nodes = True
27
+ nodes = mat.node_tree.nodes
28
+ shader = nodes.get("Principled BSDF")
29
+ shader.inputs["Base Color"].default_value = (*color, 1)
30
+ shader.inputs["Metallic"].default_value = metallic
31
+ shader.inputs["Roughness"].default_value = roughness
32
+ shader.inputs["Transmission Weight"].default_value = transmission
33
+ shader.inputs["IOR"].default_value = 1.46
34
+ if texture:
35
+ noise = nodes.new("ShaderNodeTexNoise")
36
+ noise.inputs["Scale"].default_value = 180
37
+ noise.inputs["Detail"].default_value = 2
38
+ bump = nodes.new("ShaderNodeBump")
39
+ bump.inputs["Strength"].default_value = 0.16
40
+ bump.inputs["Distance"].default_value = 0.001
41
+ mat.node_tree.links.new(noise.outputs["Fac"], bump.inputs["Height"])
42
+ mat.node_tree.links.new(bump.outputs["Normal"], shader.inputs["Normal"])
43
+ return mat
44
+
45
+
46
+ def finish(obj, name, mat, bevel=0.0, smooth=True):
47
+ obj.name = name
48
+ if mat:
49
+ obj.data.materials.append(mat)
50
+ if bevel:
51
+ modifier = obj.modifiers.new("Machined edge radius", "BEVEL")
52
+ modifier.width = bevel
53
+ modifier.segments = 3
54
+ if smooth and obj.type == "MESH":
55
+ for polygon in obj.data.polygons:
56
+ polygon.use_smooth = True
57
+ return obj
58
+
59
+
60
+ def cube(name, location, scale, mat, bevel=0.0):
61
+ bpy.ops.mesh.primitive_cube_add(size=1, location=location)
62
+ obj = bpy.context.object
63
+ obj.scale = scale
64
+ bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
65
+ return finish(obj, name, mat, bevel, False)
66
+
67
+
68
+ def sphere(name, location, scale, mat, segments=48):
69
+ bpy.ops.mesh.primitive_uv_sphere_add(segments=segments, ring_count=24, radius=1, location=location)
70
+ obj = bpy.context.object
71
+ obj.scale = scale
72
+ bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
73
+ return finish(obj, name, mat)
74
+
75
+
76
+ def cylinder(name, location, radius, depth, mat, bevel=0.0, rotation=(0, 0, 0), vertices=64):
77
+ bpy.ops.mesh.primitive_cylinder_add(vertices=vertices, radius=radius, depth=depth,
78
+ location=location, rotation=rotation)
79
+ return finish(bpy.context.object, name, mat, bevel)
80
+
81
+
82
+ def torus(name, location, major, minor, mat, rotation=(0, 0, 0)):
83
+ bpy.ops.mesh.primitive_torus_add(major_segments=72, minor_segments=12, major_radius=major,
84
+ minor_radius=minor, location=location, rotation=rotation)
85
+ return finish(bpy.context.object, name, mat)
86
+
87
+
88
+ def aim(obj, target):
89
+ obj.rotation_euler = (Vector(target) - obj.location).to_track_quat("-Z", "Y").to_euler()
90
+
91
+
92
+ def area(name, location, target, energy, color, size, size_y=None):
93
+ data = bpy.data.lights.new(name, "AREA")
94
+ data.energy = energy
95
+ data.color = color
96
+ data.shape = "RECTANGLE"
97
+ data.size = size
98
+ data.size_y = size_y if size_y else size
99
+ obj = bpy.data.objects.new(name, data)
100
+ bpy.context.collection.objects.link(obj)
101
+ obj.location = location
102
+ aim(obj, target)
103
+ return obj
104
+
105
+
106
+ def camera(location, target, lens=55, fstop=4.0):
107
+ data = bpy.data.cameras.new("Cinema camera")
108
+ data.lens = lens
109
+ data.sensor_width = 36
110
+ data.clip_start = 0.005
111
+ data.clip_end = 100
112
+ data.dof.use_dof = True
113
+ data.dof.aperture_fstop = fstop
114
+ data.dof.aperture_blades = 8
115
+ obj = bpy.data.objects.new("Cinema camera", data)
116
+ bpy.context.collection.objects.link(obj)
117
+ obj.location = location
118
+ aim(obj, target)
119
+ data.dof.focus_distance = (Vector(target) - obj.location).length
120
+ bpy.context.scene.camera = obj
121
+ return obj
122
+
123
+
124
+ def floor(size=200, z=0, color=(0.055, 0.075, 0.10)):
125
+ return cube("Seamless studio floor", (0, 0, z - 0.02), (size, size, 0.04),
126
+ material("Slate studio floor", color, roughness=0.45), 0.01)
127
+
128
+
129
+ def studio_lights(scale=1):
130
+ area("Warm softbox", (-2 * scale, -2 * scale, 3 * scale), (0, 0, scale),
131
+ 300 * scale * scale, (1.0, 0.82, 0.62), 2 * scale)
132
+ area("Cool edge strip", (2 * scale, scale, 2.2 * scale), (0, 0, scale),
133
+ 420 * scale * scale, (0.45, 0.68, 1.0), 0.45 * scale, 2 * scale)
134
+ area("Front fill", (0, -3 * scale, 1.5 * scale), (0, 0, scale),
135
+ 90 * scale * scale, (0.8, 0.9, 1), 2 * scale)
136
+
137
+
138
+ def set_linear_animation(obj):
139
+ if obj.animation_data and obj.animation_data.action:
140
+ for slot in obj.animation_data.action.slots:
141
+ for layer in obj.animation_data.action.layers:
142
+ for strip in layer.strips:
143
+ bag = strip.channelbag(slot)
144
+ if bag:
145
+ for curve in bag.fcurves:
146
+ for key in curve.keyframe_points:
147
+ key.interpolation = "LINEAR"
@@ -0,0 +1,13 @@
1
+ # Authored CAD studio examples
2
+
3
+ `bracket.py` builds a parametric millimeter-scale instrument mount with counterbored mounting holes, an upright circular aperture, fillets, and a separate isolation pad. Its `build(context)` hook returns a CadQuery `Assembly`; the driver uses that return value as the configured `exportVariable`.
4
+
5
+ `import_step.py` imports an exact caller-declared STEP dependency, defaulting to `assets/bracket.step`. It preserves the assembly import surface supported by the installed CadQuery reader. STEP is the resulting CAD solid/assembly; the Python source retains the editable feature program.
6
+
7
+ Use a build job with STEP and GLB file outputs. Automatic native CAD geometry uses millimeters and right-handed Z-up. STEP output must declare that space; standard GLB output must declare meters and right-handed Y-up. The driver records solid validity, volume, bounds, face/solid counts, and tessellation settings. STEP uses CadQuery's assembly writer. GLB uses CadQuery's colored assembly conversion with OCCT's explicit unit and coordinate-system converter: input 0.001 meters per unit, output one meter per unit, Z-up to Y-up. This conversion includes mesh positions and assembly transforms; CadQuery 2.8's high-level GLB writer alone leaves numeric millimeters unchanged.
8
+
9
+ Parameters for the bracket are `widthMm` (default 100), `depthMm` (64), `heightMm` (56), and `thicknessMm` (8). Optional `rootTranslationMm` and `rootRotationDegrees` exercise translated and Z-rotated assemblies. The fixture bounds each parameter. A practical initial mesh tolerance is 0.1mm with angular tolerance 0.1 radians. Inspect GLB vertex bounds and complete node transforms after conversion; the existence of a file does not establish correct scale.
10
+
11
+ To photograph the generated GLB, include it in a new Blender source bundle with `import_model.py` and `studio_scene.py`. This separates exact CAD source, tessellated delivery geometry, and the cinematic scene while keeping their source identities available for review.
12
+
13
+ IGES is not exposed by this high-level CadQuery adapter. Additional OCCT/FreeCAD ingestion is a separate future qualified capability. The driver does not install packages, download assets, accept arbitrary executable arguments, or silently repair failed CAD geometry.
@@ -0,0 +1,36 @@
1
+ """Parametric instrument mount in millimeters; exports an editable solid assembly."""
2
+
3
+ import cadquery as cq
4
+
5
+
6
+ def build(context):
7
+ parameters = context["parameters"]
8
+ width = float(parameters.get("widthMm", 100))
9
+ depth = float(parameters.get("depthMm", 64))
10
+ height = float(parameters.get("heightMm", 56))
11
+ thickness = float(parameters.get("thicknessMm", 8))
12
+ if not (50 <= width <= 160 and 40 <= depth <= 100 and 30 <= height <= 100 and 5 <= thickness <= 12):
13
+ raise ValueError("Fixture dimensions exceed the qualified instrument-mount range")
14
+ base = cq.Workplane("XY").box(width, depth, thickness).edges("|Z").fillet(5)
15
+ base = base.faces(">Z").workplane().pushPoints([(-width / 2 + 14, -depth / 2 + 12),
16
+ (width / 2 - 14, -depth / 2 + 12),
17
+ (-width / 2 + 14, depth / 2 - 12),
18
+ (width / 2 - 14, depth / 2 - 12)]).cboreHole(6, 11, 3)
19
+ upright = (cq.Workplane("XY").box(width - 22, thickness, height).edges("|Z").fillet(2)
20
+ .translate((0, depth / 2 - thickness / 2, height / 2 + thickness / 2)))
21
+ # Round each primitive before union: the union also contains the already
22
+ # rounded base and counterbores, whose vertical seam edges cannot be filleted.
23
+ body = base.union(upright)
24
+ # Cylindrical aperture runs through the vertical mounting plate.
25
+ aperture = cq.Workplane("XZ").center(0, height * 0.60).circle(12).extrude(depth, both=True)
26
+ body = body.cut(aperture)
27
+ assembly = cq.Assembly(name="InstrumentMount")
28
+ assembly.add(body, name="MachinedBracket", color=cq.Color(0.70, 0.45, 0.16))
29
+ pad = cq.Workplane("XY").box(width - 32, depth - 28, 2).translate((0, -3, thickness / 2 + 1))
30
+ assembly.add(pad, name="IsolationPad", color=cq.Color(0.04, 0.055, 0.07))
31
+ translation = parameters.get("rootTranslationMm", [0, 0, 0])
32
+ rotation = float(parameters.get("rootRotationDegrees", 0))
33
+ if len(translation) != 3 or any(abs(float(value)) > 1000 for value in translation) or not -180 <= rotation <= 180:
34
+ raise ValueError("Fixture root transform exceeds its qualified range")
35
+ assembly.loc = cq.Location(tuple(float(value) for value in translation), (0, 0, 1), rotation)
36
+ return assembly
@@ -0,0 +1,12 @@
1
+ """Import a caller-declared STEP assembly; its exact bytes belong in the bundle."""
2
+
3
+ from pathlib import Path
4
+ import cadquery as cq
5
+
6
+
7
+ def build(context):
8
+ relative = context["parameters"].get("input", "assets/bracket.step")
9
+ path = (Path(context["sourceRoot"]) / relative).resolve(strict=True)
10
+ if not path.is_relative_to(Path(context["sourceRoot"]).resolve()):
11
+ raise ValueError("STEP fixture input must be inside the retained source bundle")
12
+ return cq.Assembly.importStep(str(path), unit="MM")
@@ -0,0 +1,46 @@
1
+ # A narrated geometry lesson
2
+
3
+ This example renders a ten-second portrait Manim scene. Luma, an original copper lantern robot, points to a right triangle while 25 unit tiles rearrange into a five-by-five square. The final formula uses Manim Community's Typst renderer. The example demonstrates the 3–4–5 triangle; it does not prove Pythagoras for arbitrary triangles.
4
+
5
+ ## Author the retained lesson
6
+
7
+ `lesson.json` contains the mathematical parameters, presentation text, cue times, and timing provenance. Times are integer microseconds. Caption words, mouth shapes, and gestures use half-open intervals; gaps between mouth cues select the resting mouth.
8
+
9
+ The checked example has authored caption and mouth timings. These timings are a creative draft, not measured speech alignment. The complete narration script is:
10
+
11
+ > A right triangle. Three up, four across. Square both legs: nine plus sixteen. That's twenty-five. So the long side is five.
12
+
13
+ Use `parameters.lessonFile: "lesson.json"`, or supply the same validated data in `parameters.lesson`. The supported tile template takes two integer legs, each at most 12, with an integer hypotenuse at most 15. All displayed triangle lengths, square counts, and tile destinations derive from those values. Other explanations use an explicitly trusted Python scene with the reusable presenter, caption rail, `math_label`, and timing helpers.
14
+
15
+ Include exactly these source files in the retained bundle:
16
+
17
+ | Bundle path | Source |
18
+ | --- | --- |
19
+ | `scene.py` | This example's explicit entrypoint |
20
+ | `lesson.json` | This example's retained lesson |
21
+ | `lesson.py` | `apps/desktop/studio/education/lesson.py` |
22
+ | `toolkit.py` | `apps/desktop/studio/education/toolkit.py` |
23
+
24
+ The host records each file's bytes and digest. The fixed driver is separate from the author bundle. Importing or planning a bundle does not execute these files. Rendering runs explicitly trusted current-user Python; it is not a security sandbox or a hermetic build.
25
+
26
+ ## Render the scene
27
+
28
+ Select Manim Community 0.21 with its Typst optional dependency, the Cairo renderer, `scene: "PythagoreanLesson"`, and `transparent: false`. The sample uses 480×854, 24/1 FPS, and frames `[0, 240)`. The reusable layout supports portrait aspect ratios from 0.48 through 0.75 and fits its title, panel, presenter, and captions inside the camera.
29
+
30
+ Declare `beauty` PNG frames at `frames/%06d.png` and/or one opaque MP4 at `lesson.mp4`. PNG still output captures the last frame in the requested interval. Frame numbers retain the requested native indices; movie PTS starts at zero at the same exact rational cadence. Output interpretation is sRGB, uint8, RGB, opaque, color, unitless. Transparent rendering requires PNG with RGBA and straight alpha. The MP4 uses lossless RGB encoding so ordinary project assembly can avoid an extra chroma conversion during handoff.
31
+
32
+ The driver profile supports up to 2048 pixels per dimension, four megapixels, 60 FPS, and intervals ending by frame 14,400. It checks the declared output byte and file limits, and the host independently checks physical outputs and decoded media. Cairo is a CPU profile. The driver does not claim GPU rendering or generate audio.
33
+
34
+ ## Bind narration, sound effects, and delivery captions
35
+
36
+ The optional narration shape is `{"assetId":"voice_luma","transcript":"..."}`. Sound effects use `{"assetId":"tile_click","atUs":7600000,"gainDb":-18}`. These are inert references to existing retained SLOPCAMERA assets; the host verifies the source bytes and places audio in the ordinary project clock. The Manim driver never resolves credentials, synthesizes speech, or fetches an asset.
37
+
38
+ For measured mouth movement, run Rhubarb on the exact retained WAV/OGG and import its JSON with `rhubarb_mouth_cues`. Retain the original cue receipt and recognizer identity with the audio, set `mouthTiming: "rhubarb"`, and retain the returned microsecond cues in the lesson. The converter discards absolute `soundFile` metadata and rejects overlap, nonfinite timestamps, or cues outside the lesson. Rhubarb mouth shapes are not word alignment; supply measured word timings separately before setting `captionTiming: "aligned"`.
39
+
40
+ Set `showCaptions: false` when the ordinary project caption layer owns visible delivery captions. Keep the same retained word timings so the delivery can preserve exact emphasis without rendering captions twice. Review actual frames and the assembled voice together before claiming lip-sync quality.
41
+
42
+ ## Focused checks
43
+
44
+ `python -B -m unittest discover -s apps/desktop/studio/education -p 'test_*.py'` runs pure parser, geometry, timing, profile, and path tests without importing Manim. Native qualification is a separate admitted host run and must inspect the actual decoded frames, exact cadence, text margins, triangle/tile geometry, and narration synchronization.
45
+
46
+ The opt-in `apps/desktop/studio/education/qualify_native.py --output <fresh-absolute-directory>` runs static-frame, rational-cadence, alpha, short-scene, byte-budget, and portrait fixtures with the invoking Python runtime. It retains source manifests, jobs, logs, per-file digests, decoded PNG/MP4 pixel comparisons, and a contact sheet. Its observation file is explicitly separate from the host's authoritative studio receipt. Run it through the repository's native-work admission process.
@@ -0,0 +1,99 @@
1
+ {
2
+ "kind": "slopcamera.education-lesson",
3
+ "schemaVersion": 1,
4
+ "title": "Why the long side is five",
5
+ "subtitle": "A 3–4–5 right triangle, one square at a time",
6
+ "durationUs": 10000000,
7
+ "topic": { "kind": "pythagorean-tiles", "legs": [3, 4] },
8
+ "beats": { "squaresUs": 3200000, "rearrangeUs": 5300000, "resultUs": 7600000 },
9
+ "presenter": { "name": "Luma" },
10
+ "captionTiming": "authored",
11
+ "mouthTiming": "authored",
12
+ "showCaptions": true,
13
+ "captions": [
14
+ { "words": [
15
+ { "text": "A", "startUs": 150000, "endUs": 290000 },
16
+ { "text": "right", "startUs": 290000, "endUs": 650000 },
17
+ { "text": "triangle.", "startUs": 650000, "endUs": 1150000 }
18
+ ] },
19
+ { "words": [
20
+ { "text": "Three", "startUs": 1250000, "endUs": 1680000 },
21
+ { "text": "up,", "startUs": 1680000, "endUs": 1940000 },
22
+ { "text": "four", "startUs": 2110000, "endUs": 2490000 },
23
+ { "text": "across.", "startUs": 2490000, "endUs": 3050000 }
24
+ ] },
25
+ { "words": [
26
+ { "text": "Square", "startUs": 3200000, "endUs": 3630000 },
27
+ { "text": "both", "startUs": 3630000, "endUs": 3940000 },
28
+ { "text": "legs:", "startUs": 3940000, "endUs": 4350000 }
29
+ ] },
30
+ { "words": [
31
+ { "text": "nine", "startUs": 4460000, "endUs": 4860000 },
32
+ { "text": "plus", "startUs": 4860000, "endUs": 5150000 },
33
+ { "text": "sixteen.", "startUs": 5150000, "endUs": 5820000 }
34
+ ] },
35
+ { "words": [
36
+ { "text": "That’s", "startUs": 6090000, "endUs": 6480000 },
37
+ { "text": "twenty-five.", "startUs": 6480000, "endUs": 7390000 }
38
+ ] },
39
+ { "words": [
40
+ { "text": "So", "startUs": 7690000, "endUs": 7910000 },
41
+ { "text": "the", "startUs": 7910000, "endUs": 8130000 },
42
+ { "text": "long", "startUs": 8130000, "endUs": 8530000 },
43
+ { "text": "side", "startUs": 8530000, "endUs": 8890000 },
44
+ { "text": "is", "startUs": 8890000, "endUs": 9090000 },
45
+ { "text": "five.", "startUs": 9090000, "endUs": 9740000 }
46
+ ] }
47
+ ],
48
+ "mouthCues": [
49
+ { "startUs": 150000, "endUs": 290000, "value": "C" },
50
+ { "startUs": 290000, "endUs": 650000, "value": "E" },
51
+ { "startUs": 650000, "endUs": 870000, "value": "D" },
52
+ { "startUs": 870000, "endUs": 1150000, "value": "H" },
53
+ { "startUs": 1250000, "endUs": 1490000, "value": "B" },
54
+ { "startUs": 1490000, "endUs": 1680000, "value": "C" },
55
+ { "startUs": 1680000, "endUs": 1940000, "value": "A" },
56
+ { "startUs": 2110000, "endUs": 2280000, "value": "G" },
57
+ { "startUs": 2280000, "endUs": 2490000, "value": "E" },
58
+ { "startUs": 2490000, "endUs": 2760000, "value": "D" },
59
+ { "startUs": 2760000, "endUs": 3050000, "value": "B" },
60
+ { "startUs": 3200000, "endUs": 3430000, "value": "F" },
61
+ { "startUs": 3430000, "endUs": 3630000, "value": "C" },
62
+ { "startUs": 3630000, "endUs": 3790000, "value": "A" },
63
+ { "startUs": 3790000, "endUs": 3940000, "value": "E" },
64
+ { "startUs": 3940000, "endUs": 4160000, "value": "H" },
65
+ { "startUs": 4160000, "endUs": 4350000, "value": "B" },
66
+ { "startUs": 4460000, "endUs": 4680000, "value": "D" },
67
+ { "startUs": 4680000, "endUs": 4860000, "value": "B" },
68
+ { "startUs": 4860000, "endUs": 5000000, "value": "A" },
69
+ { "startUs": 5000000, "endUs": 5150000, "value": "C" },
70
+ { "startUs": 5150000, "endUs": 5450000, "value": "B" },
71
+ { "startUs": 5450000, "endUs": 5660000, "value": "C" },
72
+ { "startUs": 5660000, "endUs": 5820000, "value": "B" },
73
+ { "startUs": 6090000, "endUs": 6310000, "value": "D" },
74
+ { "startUs": 6310000, "endUs": 6480000, "value": "B" },
75
+ { "startUs": 6480000, "endUs": 6700000, "value": "F" },
76
+ { "startUs": 6700000, "endUs": 6990000, "value": "C" },
77
+ { "startUs": 6990000, "endUs": 7170000, "value": "G" },
78
+ { "startUs": 7170000, "endUs": 7390000, "value": "D" },
79
+ { "startUs": 7690000, "endUs": 7910000, "value": "F" },
80
+ { "startUs": 7910000, "endUs": 8130000, "value": "B" },
81
+ { "startUs": 8130000, "endUs": 8330000, "value": "H" },
82
+ { "startUs": 8330000, "endUs": 8530000, "value": "E" },
83
+ { "startUs": 8530000, "endUs": 8740000, "value": "D" },
84
+ { "startUs": 8740000, "endUs": 8890000, "value": "B" },
85
+ { "startUs": 8890000, "endUs": 9090000, "value": "C" },
86
+ { "startUs": 9090000, "endUs": 9290000, "value": "G" },
87
+ { "startUs": 9290000, "endUs": 9510000, "value": "D" },
88
+ { "startUs": 9510000, "endUs": 9740000, "value": "G" }
89
+ ],
90
+ "gestures": [
91
+ { "startUs": 150000, "endUs": 1150000, "kind": "open" },
92
+ { "startUs": 1250000, "endUs": 3050000, "kind": "point" },
93
+ { "startUs": 3200000, "endUs": 4350000, "kind": "open" },
94
+ { "startUs": 4460000, "endUs": 5820000, "kind": "point" },
95
+ { "startUs": 6090000, "endUs": 7390000, "kind": "nod" },
96
+ { "startUs": 7690000, "endUs": 9740000, "kind": "point" }
97
+ ],
98
+ "sfx": []
99
+ }
@@ -0,0 +1,7 @@
1
+ """An explicitly trusted author entrypoint, evaluated only by a render job."""
2
+
3
+ from toolkit import EducationalScene, lesson_from_context
4
+
5
+
6
+ class PythagoreanLesson(EducationalScene):
7
+ lesson_data = lesson_from_context(SLOPCAMERA_CONTEXT)
@@ -0,0 +1,96 @@
1
+ import { z } from "zod";
2
+ import {
3
+ parseSpatialScene, parseSpatialValue, SpatialAssetIdSchema, SpatialAssetManifestSchema, SpatialCameraSchema, SpatialPayloadSchema,
4
+ type SpatialSceneV1,
5
+ } from "@hraness/slopcamera/code";
6
+
7
+ /** Retained manifests and explicit host bindings; importing this authoring example is inert. */
8
+ const boundAssetSchema = z.strictObject({
9
+ asset: SpatialAssetManifestSchema,
10
+ binding: z.strictObject({ assetId: SpatialAssetIdSchema, artifact: SpatialPayloadSchema }),
11
+ }).refine(value => value.asset.assetId === value.binding.assetId && value.asset.payload.sha256 === value.binding.artifact.sha256
12
+ && value.asset.payload.bytes === value.binding.artifact.bytes, "Asset binding must identify its exact retained payload.");
13
+ const inputSchema = z.strictObject({
14
+ panel: boundAssetSchema, font: boundAssetSchema, city: boundAssetSchema.optional(),
15
+ camera: SpatialCameraSchema.optional(), motion: z.enum(["locked", "reveal", "portal-loop"]).default("reveal"),
16
+ durationUs: z.number().int().min(1).max(4_000_000).default(4_000_000),
17
+ });
18
+ export type HybridWorldSceneInput = z.input<typeof inputSchema>;
19
+ export const HYBRID_PANEL = Object.freeze({ center: Object.freeze([2.3, 1.47, -0.837] as const), width: 1.35, height: 2.4 });
20
+ export const HYBRID_PANEL_CAMERA = SpatialCameraSchema.parse({ cameraId: "camera_panel", name: "Calibrated world panel",
21
+ pose: { position: [2.3, 1.47, 1.2255], rotation: [0,0,0,1] },
22
+ projection: { kind: "perspective", width: 720, height: 1280, fx: 1100, fy: 1100, cx: 360, cy: 640, near: 0.03, far: 100 } });
23
+ Object.freeze(HYBRID_PANEL_CAMERA.pose.position); Object.freeze(HYBRID_PANEL_CAMERA.pose.rotation);
24
+ Object.freeze(HYBRID_PANEL_CAMERA.pose); Object.freeze(HYBRID_PANEL_CAMERA.projection); Object.freeze(HYBRID_PANEL_CAMERA);
25
+ const common = { parentId: null, placement: { kind: "world" }, origin: { kind: "authored" }, visible: true };
26
+ const transform = (position: readonly number[]) => ({ position: [...position], rotation: [0,0,0,1], scale: [1,1,1] });
27
+ const unlit = (color: string) => ({ kind: "unlit", color, opacity: 1 });
28
+ function lookAt(position: number[], target: readonly number[]) {
29
+ const x = position[0]! - target[0]!, y = position[1]! - target[1]!, z = position[2]! - target[2]!;
30
+ const yaw = Math.atan2(x,z) / 2, pitch = -Math.atan2(y,Math.hypot(x,z)) / 2;
31
+ return { position, rotation: [Math.cos(yaw)*Math.sin(pitch), Math.sin(yaw)*Math.cos(pitch), -Math.sin(yaw)*Math.sin(pitch), Math.cos(yaw)*Math.cos(pitch)] };
32
+ }
33
+
34
+ /** One four-second explanation lives on a real plane in the same meter-based city. */
35
+ export function createHybridWorldScene(input: unknown): {
36
+ readonly scene: SpatialSceneV1; readonly bindings: readonly z.infer<typeof boundAssetSchema>["binding"][];
37
+ } {
38
+ const value = parseSpatialValue(inputSchema, input, "hybrid world scene"), camera = value.camera ?? HYBRID_PANEL_CAMERA;
39
+ const panel = value.panel.asset.interpretation, font = value.font.asset.interpretation;
40
+ if (panel.kind !== "video" && panel.kind !== "image" && panel.kind !== "diagram") throw new Error("Panel requires explicit video, image or diagram media.");
41
+ if (panel.kind === "video" && panel.durationUs < value.durationUs) throw new Error("Panel video must cover the complete authored segment; no implicit looping.");
42
+ if (font.kind !== "font" || font.format !== "otf") throw new Error("The example requires a declared OTF font.");
43
+ if (value.city && (value.city.asset.interpretation.kind !== "gltf" || value.city.asset.interpretation.format !== "glb")) throw new Error("City requires an admitted GLB profile.");
44
+ const x = HYBRID_PANEL.center[0], y = HYBRID_PANEL.center[1], z = HYBRID_PANEL.center[2];
45
+ const box = (id: string, name: string, position: number[], size: number[], color: string) => ({ ...common,
46
+ entityId: `entity_${id}`, kind: "mesh", name, geometry: { kind: "box", size }, material: unlit(color), transform: transform(position) });
47
+ const label = (id: string, text: string, atY: number, fontSize: number, color: string) => ({ ...common,
48
+ entityId: `entity_${id}`, kind: "text", name: text, fontAssetId: value.font.asset.assetId, text, fontSize, width: 1.12, color, align: "center", transform: transform([x,atY,z+0.016]) });
49
+ const entities: unknown[] = [
50
+ // All surfaces are world-space. The copper frame and foreground post have
51
+ // actual thickness; a later camera move can reveal and occlude their edges.
52
+ box("panel_back", "Midnight panel matte", [x,y,z-0.04], [1.44,2.49,0.07], "#091723"),
53
+ box("panel_left", "Copper left edge", [x-0.71,y,z+0.005], [0.035,2.51,0.10], "#bf8a56"),
54
+ box("panel_right", "Copper right edge", [x+0.71,y,z+0.005], [0.035,2.51,0.10], "#bf8a56"),
55
+ box("panel_top", "Copper top edge", [x,y+1.25,z+0.005], [1.455,0.035,0.10], "#ddba7c"),
56
+ box("panel_bottom", "Copper bottom edge", [x,y-1.25,z+0.005], [1.455,0.035,0.10], "#9b683f"),
57
+ { ...common, entityId: "entity_panel_media", kind: panel.kind, name: "Retained explanation in world space", assetId: value.panel.asset.assetId,
58
+ width: 1.26, height: 0.70875, fit: "contain", opacity: 1, transform: transform([x,y+0.02,z+0.013]),
59
+ ...(panel.kind === "video" ? { sourceOffsetUs: 0, playback: "once" } : {}) },
60
+ label("eyebrow", "DESIGN FOR SHADE", y+0.98, 0.063, "#80c6c3"),
61
+ label("title", "FOLLOW THE LIGHT", y+0.76, 0.095, "#f2eee3"),
62
+ label("caption", "Shade intercepts sunlight.", y-0.64, 0.058, "#d5e5de"),
63
+ label("note", "An illustrative energy split", y-0.80, 0.046, "#83a4ad"),
64
+ label("footer", "SUNLIGHT / SHADE / COMFORT", y-1.08, 0.034, "#809399"),
65
+ box("depth_post", "Foreground copper depth cue", [x+0.70,y-0.21,z+0.50], [0.048,2.32,0.065], "#7f573a"),
66
+ { ...common, entityId: "entity_ambient", kind: "light", name: "Soft sky", light: "ambient", color: "#d5e6ef", intensity: 1.3, transform: transform([0,0,0]) },
67
+ { ...common, entityId: "entity_sun", kind: "light", name: "Warm afternoon", light: "directional", color: "#ffe0b0", intensity: 2.4,
68
+ transform: { ...transform([5,8,5]), ...lookAt([5,8,5],[0,0,0]) } },
69
+ box("sky", "Warm blue horizon", [0,10,-50], [150,100,0.10], "#acbec0"),
70
+ ];
71
+ if (value.city) entities.push({ ...common, entityId: "entity_shared_city", kind: "mesh", name: "Retained native city preview LOD",
72
+ geometry: { kind: "asset", assetId: value.city.asset.assetId, materialMode: "source" }, material: unlit("#ffffff"), transform: transform([0,0,0]) });
73
+ else entities.push(box("ground", "Qualification ground", [0,-0.04,0], [80,0.08,80], "#d0cabd"));
74
+ const assets = [value.panel,value.font,...(value.city ? [value.city] : [])];
75
+ // A portal loop returns to the exact authored pose for a match cut into a
76
+ // native shot; its final five percent is a held camera, never extrapolation.
77
+ // Dense bounded keys preserve the eased turn instead of reversing velocity
78
+ // abruptly at a sparse peak. They still evaluate solely from absolute time.
79
+ const fractions = Array.from({ length: 41 }, (_, index) => index/40);
80
+ const times = [...new Set(fractions.map(t => Math.round(t*value.durationUs)))];
81
+ const poses = times.map(timeUs => {
82
+ const t = timeUs/value.durationUs;
83
+ const progress = value.motion === "portal-loop" ? t <= 0.55 ? (t-0.25)/0.30 : (0.95-t)/0.40 : (t-0.25)/0.75;
84
+ const u = Math.max(0,Math.min(1,progress));
85
+ const ease = u*u*(3-2*u);
86
+ const start = camera.pose.position, end = [4.5,2.7,4.4];
87
+ return ease === 0 ? camera.pose : lookAt(start.map((n,i) => n+(end[i]!-n)*ease), [x-0.35*ease,y+0.1*ease,z]);
88
+ });
89
+ const animations = value.motion === "locked" ? [] : [
90
+ { channelId: "channel_reveal_position", targetId: camera.cameraId, property: "position", interpolation: "linear", keys: times.map((timeUs,i) => ({ timeUs,value: poses[i]!.position })) },
91
+ { channelId: "channel_reveal_rotation", targetId: camera.cameraId, property: "rotation", interpolation: "slerp", keys: times.map((timeUs,i) => ({ timeUs,value: poses[i]!.rotation })) },
92
+ ];
93
+ const scene = parseSpatialScene({ kind: "slopcamera.spatial-scene", schemaVersion: 1, sceneId: "scene_hybrid_world_explainer", coordinates: "right-handed-y-up-meters",
94
+ durationUs: value.durationUs, cameras: [camera], assets: assets.map(item => item.asset), entities, animations, generators: [], overrides: [] });
95
+ return { scene, bindings: assets.map(item => item.binding) };
96
+ }
@@ -0,0 +1,14 @@
1
+ import { defineWorkflow, StudioRunInputSchema } from "@hraness/slopcamera/local/code";
2
+
3
+ // Input retains the bundle manifest returned by `studio bundle` and its exact job.
4
+ // Runtime selection and --allow-trusted-code belong to the CLI invocation.
5
+ export default defineWorkflow({
6
+ id: "native-studio-shot",
7
+ version: 1,
8
+ inputSchemaId: "native-studio-shot-input-v1",
9
+ inputSchema: StudioRunInputSchema,
10
+ build(workflow, input) {
11
+ const shot = workflow.studio.run("produce-shot", input);
12
+ return { shot };
13
+ },
14
+ });
@@ -0,0 +1,64 @@
1
+ # Render an energy-flow panel with vgpu
2
+
3
+ This example renders an animated diagram on a Metal GPU, then saves an opaque sRGB PNG sequence for an existing scene renderer to use as a screen surface. The energy split is authored illustrative data. The pulses and colored glazing explain the graphic; they are not a thermal simulation or measured performance.
4
+
5
+ The example runs as an explicit trusted Node command. Importing its module does not load vgpu, execute a shader or acquire a GPU. It does not add a new SLOPCAMERA scene engine, a provider client or an editor. SLOPCAMERA's existing Three.js renderer can retain scene and camera ownership when consuming the resulting media.
6
+
7
+ ## Provision a separate runtime
8
+
9
+ Use Node 24 on macOS for the qualified profile. Upstream vgpu documents Node 22+; other runtimes and GPU backends require separate qualification. Keep these dependencies in a dedicated directory outside tracked source:
10
+
11
+ ```json
12
+ {
13
+ "name": "slopcamera-vgpu-example-runtime",
14
+ "private": true,
15
+ "type": "module",
16
+ "dependencies": {
17
+ "vgpu": "0.4.1",
18
+ "pngjs": "7.0.0"
19
+ }
20
+ }
21
+ ```
22
+
23
+ In that directory, generate a lockfile and install with lifecycle execution disabled:
24
+
25
+ ```sh
26
+ npm install --package-lock-only --ignore-scripts
27
+ npm ci --ignore-scripts
28
+ ```
29
+
30
+ The pinned vgpu adapter uses `webgpu@0.4.0`, which includes native Dawn binaries. Its macOS install hook normally modifies quarantine metadata, while vgpu's adapter hook may download a fallback binary. This example does not execute those hooks or modify platform security settings. Provision and review the native runtime separately if loading it fails.
31
+
32
+ ## Render
33
+
34
+ Create the parent of the output directory first. The output directory itself must be new. Paths must be absolute and physical; the command preserves prior runs.
35
+
36
+ ```sh
37
+ node /absolute/slopcamera/examples/studio/vgpu/heat-field.mjs \
38
+ --runtime /absolute/vgpu-runtime \
39
+ --output /absolute/retained-media/new-energy-panel
40
+ ```
41
+
42
+ On Hraness hosts, wrap this native command with the installed `hra-host-run` in the `mac-native` lane. The default output is 96 frames at 24 fps, 768×432. Optional `--frames`, `--start-frame`, `--width` and `--height` values remain within a 16:9, 1024 px, 240-frame profile. A frame's shader time is its absolute frame number divided by 24; a selected nonzero interval retains that time while filenames begin at zero.
43
+
44
+ Unset ambient `VGPU_*`, `NODE_OPTIONS` and `NODE_PATH` settings before invocation. The example rejects these overrides, explicitly requests Metal hardware, checks the observed hardware adapter and loaded native module, and records their identities. It permits no automatic CPU fallback as successful evidence.
45
+
46
+ Each frame contains GPU-rendered pixels and original bitmap labels added after readback. Numerical energy quantities are separate from display colors. The shader performs the piecewise sRGB transfer; each PNG carries an explicit sRGB chunk. Calibration checks top-left row order, RGB channel order and an sRGB middle-gray value. Every retained PNG is decoded and compared with its source bytes.
47
+
48
+ `manifest.json` records absolute times, runtime and native-binary hashes, shader/source/lock hashes, actual adapter identity, interpretation and frame digests. It appears after all frames verify and the GPU wrapper disposes. An incomplete directory has no completion manifest and remains available for diagnosis. This optional trusted runtime is not an OS sandbox or a hermetic dependency closure.
49
+
50
+ The PNG files are ordinary media. Import them through a supported SLOPCAMERA media path with their manifest's frame cadence and sRGB interpretation; no vgpu object needs to cross into Three.js. Encoding them or admitting them to a native Studio job is a separate explicit action. The current native Studio adapters do not execute WGSL.
51
+
52
+ ## Check without a GPU
53
+
54
+ Run these tests from a source checkout; the published package includes the example and this guide, but omits test files.
55
+
56
+ ```sh
57
+ node --test examples/studio/vgpu/heat-field.test.mjs
58
+ ```
59
+
60
+ These tests cover bounds, nonzero frame clocks, energy conservation, override rejection, authored layout and PNG tagging. They do not claim native shader execution. Actual hardware qualification must also inspect the retained frames.
61
+
62
+ The September 9, 2026 qualification rendered 96 distinct frames on an Apple M4 Max with Metal 3 and Node 24.18.1. All PNG pixel comparisons and color/orientation calibration passed. Absolute frame 24 was identical when rendered in a fresh process alone, in a three-frame interval starting at 23, and in the full sequence starting at zero. That observation applies to this pinned runtime and device; it is not a cross-device bitwise guarantee.
63
+
64
+ For future Three WebGPU work, vgpu provides a [WGSL-to-TSL bridge](https://github.com/vercel-labs/vgpu/blob/ca6cf99fbeb109a3294d043a10de16819e1b9dad/docs/topics/threejs.docs.md). That bridge leaves Three in charge of scenes and resources. It does not establish compatibility with SLOPCAMERA's current WebGL2/Spark profile. [Node runtime requirements](https://github.com/vercel-labs/vgpu/blob/ca6cf99fbeb109a3294d043a10de16819e1b9dad/packages/adapter-node/README.md).