@volter/blender-engine 0.1.148 → 0.1.150

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 (245) hide show
  1. package/LICENSE +22 -5
  2. package/README.md +4 -11
  3. package/browser/addons/vrm/LICENSE_(OPTION1)_MIT.txt +22 -0
  4. package/browser/addons/vrm/LICENSE_(OPTION2)_GPL-3_0.txt +674 -0
  5. package/browser/addons/vrm/LICENSE_MAIN.txt +1 -0
  6. package/browser/addons/vrm/README.txt +3 -0
  7. package/browser/addons/vrm/__init__.py +41 -0
  8. package/browser/addons/vrm/blender_manifest.toml +16 -0
  9. package/browser/addons/vrm/common/__init__.py +1 -0
  10. package/browser/addons/vrm/common/animation.py +58 -0
  11. package/browser/addons/vrm/common/blender_manifest.py +82 -0
  12. package/browser/addons/vrm/common/char.py +16 -0
  13. package/browser/addons/vrm/common/convert.py +287 -0
  14. package/browser/addons/vrm/common/convert_any.py +48 -0
  15. package/browser/addons/vrm/common/debug.py +40 -0
  16. package/browser/addons/vrm/common/deep.py +162 -0
  17. package/browser/addons/vrm/common/error_dialog.py +274 -0
  18. package/browser/addons/vrm/common/fs.py +71 -0
  19. package/browser/addons/vrm/common/gl.py +20 -0
  20. package/browser/addons/vrm/common/gltf.py +1149 -0
  21. package/browser/addons/vrm/common/human_bone_mapper/__init__.py +1 -0
  22. package/browser/addons/vrm/common/human_bone_mapper/biped_mapping.py +84 -0
  23. package/browser/addons/vrm/common/human_bone_mapper/cats_blender_plugin_fix_model_mapping.py +63 -0
  24. package/browser/addons/vrm/common/human_bone_mapper/human_bone_mapper.py +203 -0
  25. package/browser/addons/vrm/common/human_bone_mapper/microsoft_rocketbox_mapping.py +69 -0
  26. package/browser/addons/vrm/common/human_bone_mapper/mixamo_mapping.py +62 -0
  27. package/browser/addons/vrm/common/human_bone_mapper/mmd_mapping.py +115 -0
  28. package/browser/addons/vrm/common/human_bone_mapper/mpfb_mapping.py +120 -0
  29. package/browser/addons/vrm/common/human_bone_mapper/ready_player_me_mapping.py +65 -0
  30. package/browser/addons/vrm/common/human_bone_mapper/reallusion_mapping.py +94 -0
  31. package/browser/addons/vrm/common/human_bone_mapper/rigify_meta_rig_mapping.py +65 -0
  32. package/browser/addons/vrm/common/human_bone_mapper/structure_based_mapping.py +891 -0
  33. package/browser/addons/vrm/common/human_bone_mapper/unreal_mapping.py +62 -0
  34. package/browser/addons/vrm/common/human_bone_mapper/vrm_addon_mapping.py +112 -0
  35. package/browser/addons/vrm/common/human_bone_mapper/vroid_mapping.py +89 -0
  36. package/browser/addons/vrm/common/legacy_gltf.py +16 -0
  37. package/browser/addons/vrm/common/logger.py +84 -0
  38. package/browser/addons/vrm/common/mtoon0.blend +0 -0
  39. package/browser/addons/vrm/common/mtoon1.blend +0 -0
  40. package/browser/addons/vrm/common/mtoon1_outline.blend +0 -0
  41. package/browser/addons/vrm/common/mtoon_auto_setup.blend +0 -0
  42. package/browser/addons/vrm/common/mtoon_unversioned.py +62 -0
  43. package/browser/addons/vrm/common/ops/__init__.py +10 -0
  44. package/browser/addons/vrm/common/ops/export_scene.py +67 -0
  45. package/browser/addons/vrm/common/ops/icyp.py +53 -0
  46. package/browser/addons/vrm/common/ops/import_scene.py +57 -0
  47. package/browser/addons/vrm/common/ops/vrm.py +2380 -0
  48. package/browser/addons/vrm/common/ops/wm.py +167 -0
  49. package/browser/addons/vrm/common/preferences.py +362 -0
  50. package/browser/addons/vrm/common/progress.py +87 -0
  51. package/browser/addons/vrm/common/rotation.py +89 -0
  52. package/browser/addons/vrm/common/safe_removal.py +46 -0
  53. package/browser/addons/vrm/common/scene_watcher.py +230 -0
  54. package/browser/addons/vrm/common/shader.py +2243 -0
  55. package/browser/addons/vrm/common/shape_key_mapper/__init__.py +1 -0
  56. package/browser/addons/vrm/common/shape_key_mapper/arkit_mapping.py +168 -0
  57. package/browser/addons/vrm/common/shape_key_mapper/mmd_mapping.py +62 -0
  58. package/browser/addons/vrm/common/shape_key_mapper/ready_player_me_mapping.py +52 -0
  59. package/browser/addons/vrm/common/shape_key_mapper/vrchat_mapping.py +17 -0
  60. package/browser/addons/vrm/common/third_party_user_extension.py +214 -0
  61. package/browser/addons/vrm/common/transparent_z_write.blend +0 -0
  62. package/browser/addons/vrm/common/version.py +161 -0
  63. package/browser/addons/vrm/common/vrm0/__init__.py +1 -0
  64. package/browser/addons/vrm/common/vrm0/human_bone.py +662 -0
  65. package/browser/addons/vrm/common/vrm0/material_property.py +346 -0
  66. package/browser/addons/vrm/common/vrm1/__init__.py +1 -0
  67. package/browser/addons/vrm/common/vrm1/expression_preset.py +207 -0
  68. package/browser/addons/vrm/common/vrm1/human_bone.py +822 -0
  69. package/browser/addons/vrm/common/workspace.py +227 -0
  70. package/browser/addons/vrm/common/writable_context.py +77 -0
  71. package/browser/addons/vrm/documentation/en-us/animation/index.md +63 -0
  72. package/browser/addons/vrm/documentation/en-us/create-humanoid-vrm-from-scratch/index.md +131 -0
  73. package/browser/addons/vrm/documentation/en-us/create-simple-vrm-from-scratch/index.md +30 -0
  74. package/browser/addons/vrm/documentation/en-us/development/index.md +136 -0
  75. package/browser/addons/vrm/documentation/en-us/index.md +41 -0
  76. package/browser/addons/vrm/documentation/en-us/installation/index.md +152 -0
  77. package/browser/addons/vrm/documentation/en-us/material-mtoon/index.md +122 -0
  78. package/browser/addons/vrm/documentation/en-us/material-pbr/index.md +94 -0
  79. package/browser/addons/vrm/documentation/en-us/scripting-api/index.md +391 -0
  80. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrm/index.md +57 -0
  81. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrma/index.md +17 -0
  82. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrm/index.md +61 -0
  83. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrma/index.md +13 -0
  84. package/browser/addons/vrm/documentation/ja-jp/animation/index.md +57 -0
  85. package/browser/addons/vrm/documentation/ja-jp/create-humanoid-vrm-from-scratch/index.md +129 -0
  86. package/browser/addons/vrm/documentation/ja-jp/create-simple-vrm-from-scratch/index.md +29 -0
  87. package/browser/addons/vrm/documentation/ja-jp/development/index.md +137 -0
  88. package/browser/addons/vrm/documentation/ja-jp/index.md +37 -0
  89. package/browser/addons/vrm/documentation/ja-jp/installation/index.md +150 -0
  90. package/browser/addons/vrm/documentation/ja-jp/material-mtoon/index.md +113 -0
  91. package/browser/addons/vrm/documentation/ja-jp/material-pbr/index.md +90 -0
  92. package/browser/addons/vrm/documentation/ja-jp/scripting-api/index.md +389 -0
  93. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrm/index.md +55 -0
  94. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrma/index.md +19 -0
  95. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrm/index.md +56 -0
  96. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrma/index.md +14 -0
  97. package/browser/addons/vrm/editor/__init__.py +1 -0
  98. package/browser/addons/vrm/editor/extension.py +425 -0
  99. package/browser/addons/vrm/editor/extension_accessor.py +75 -0
  100. package/browser/addons/vrm/editor/handler.py +84 -0
  101. package/browser/addons/vrm/editor/khr_character/__init__.py +1 -0
  102. package/browser/addons/vrm/editor/khr_character/panel.py +69 -0
  103. package/browser/addons/vrm/editor/khr_character/property_group.py +27 -0
  104. package/browser/addons/vrm/editor/khr_xmp_json_ld/__init__.py +1 -0
  105. package/browser/addons/vrm/editor/khr_xmp_json_ld/ops.py +464 -0
  106. package/browser/addons/vrm/editor/khr_xmp_json_ld/panel.py +136 -0
  107. package/browser/addons/vrm/editor/khr_xmp_json_ld/property_group.py +83 -0
  108. package/browser/addons/vrm/editor/khr_xmp_json_ld/ui_list.py +198 -0
  109. package/browser/addons/vrm/editor/make_armature.py +709 -0
  110. package/browser/addons/vrm/editor/menu.py +147 -0
  111. package/browser/addons/vrm/editor/migration.py +297 -0
  112. package/browser/addons/vrm/editor/mtoon1/__init__.py +1 -0
  113. package/browser/addons/vrm/editor/mtoon1/handler.py +20 -0
  114. package/browser/addons/vrm/editor/mtoon1/migration.py +536 -0
  115. package/browser/addons/vrm/editor/mtoon1/ops.py +304 -0
  116. package/browser/addons/vrm/editor/mtoon1/panel.py +442 -0
  117. package/browser/addons/vrm/editor/mtoon1/property_group.py +4977 -0
  118. package/browser/addons/vrm/editor/mtoon1/scene_watcher.py +381 -0
  119. package/browser/addons/vrm/editor/node_constraint1/__init__.py +1 -0
  120. package/browser/addons/vrm/editor/node_constraint1/panel.py +317 -0
  121. package/browser/addons/vrm/editor/node_constraint1/property_group.py +25 -0
  122. package/browser/addons/vrm/editor/ops.py +471 -0
  123. package/browser/addons/vrm/editor/panel.py +315 -0
  124. package/browser/addons/vrm/editor/property_group.py +888 -0
  125. package/browser/addons/vrm/editor/search.py +682 -0
  126. package/browser/addons/vrm/editor/spring_bone1/__init__.py +1 -0
  127. package/browser/addons/vrm/editor/spring_bone1/handler.py +994 -0
  128. package/browser/addons/vrm/editor/spring_bone1/menu.py +246 -0
  129. package/browser/addons/vrm/editor/spring_bone1/migration.py +86 -0
  130. package/browser/addons/vrm/editor/spring_bone1/ops.py +1679 -0
  131. package/browser/addons/vrm/editor/spring_bone1/panel.py +605 -0
  132. package/browser/addons/vrm/editor/spring_bone1/property_group.py +1457 -0
  133. package/browser/addons/vrm/editor/spring_bone1/ui_list.py +408 -0
  134. package/browser/addons/vrm/editor/subscription.py +123 -0
  135. package/browser/addons/vrm/editor/t_pose.py +713 -0
  136. package/browser/addons/vrm/editor/validation.py +1271 -0
  137. package/browser/addons/vrm/editor/vrm0/__init__.py +1 -0
  138. package/browser/addons/vrm/editor/vrm0/gizmo_group.py +63 -0
  139. package/browser/addons/vrm/editor/vrm0/handler.py +23 -0
  140. package/browser/addons/vrm/editor/vrm0/menu.py +145 -0
  141. package/browser/addons/vrm/editor/vrm0/migration.py +761 -0
  142. package/browser/addons/vrm/editor/vrm0/ops.py +2145 -0
  143. package/browser/addons/vrm/editor/vrm0/panel.py +1333 -0
  144. package/browser/addons/vrm/editor/vrm0/property_group.py +1818 -0
  145. package/browser/addons/vrm/editor/vrm0/ui_list.py +688 -0
  146. package/browser/addons/vrm/editor/vrm1/__init__.py +1 -0
  147. package/browser/addons/vrm/editor/vrm1/handler.py +28 -0
  148. package/browser/addons/vrm/editor/vrm1/menu.py +76 -0
  149. package/browser/addons/vrm/editor/vrm1/migration.py +321 -0
  150. package/browser/addons/vrm/editor/vrm1/ops.py +2679 -0
  151. package/browser/addons/vrm/editor/vrm1/panel.py +1243 -0
  152. package/browser/addons/vrm/editor/vrm1/property_group.py +2087 -0
  153. package/browser/addons/vrm/editor/vrm1/scene_watcher.py +90 -0
  154. package/browser/addons/vrm/editor/vrm1/ui_list.py +533 -0
  155. package/browser/addons/vrm/exporter/__init__.py +1 -0
  156. package/browser/addons/vrm/exporter/abstract_base_vrm_exporter.py +628 -0
  157. package/browser/addons/vrm/exporter/export_scene.py +930 -0
  158. package/browser/addons/vrm/exporter/gltf2_export_user_extension.py +45 -0
  159. package/browser/addons/vrm/exporter/khr_character_exporter.py +34 -0
  160. package/browser/addons/vrm/exporter/vrm0_exporter.py +4020 -0
  161. package/browser/addons/vrm/exporter/vrm1_exporter.py +3682 -0
  162. package/browser/addons/vrm/exporter/vrm_animation_exporter.py +1035 -0
  163. package/browser/addons/vrm/external/__init__.py +1 -0
  164. package/browser/addons/vrm/external/auto_rig_pro_support.py +3 -0
  165. package/browser/addons/vrm/external/io_scene_gltf2_support.py +418 -0
  166. package/browser/addons/vrm/external/rigify_support.py +1 -0
  167. package/browser/addons/vrm/importer/__init__.py +1 -0
  168. package/browser/addons/vrm/importer/abstract_base_vrm_importer.py +1548 -0
  169. package/browser/addons/vrm/importer/file_handler.py +34 -0
  170. package/browser/addons/vrm/importer/gltf2_import_user_extension.py +268 -0
  171. package/browser/addons/vrm/importer/import_scene.py +646 -0
  172. package/browser/addons/vrm/importer/license_validation.py +198 -0
  173. package/browser/addons/vrm/importer/vrm0_importer.py +1723 -0
  174. package/browser/addons/vrm/importer/vrm1_importer.py +2014 -0
  175. package/browser/addons/vrm/importer/vrm_animation_importer.py +763 -0
  176. package/browser/addons/vrm/importer/vrm_diff.py +316 -0
  177. package/browser/addons/vrm/locale/__init__.py +1 -0
  178. package/browser/addons/vrm/locale/ja_jp.py +826 -0
  179. package/browser/addons/vrm/locale/ruff.toml +8 -0
  180. package/browser/addons/vrm/locale/translation_dictionary.py +10 -0
  181. package/browser/addons/vrm/locale/zh_hans.py +928 -0
  182. package/browser/addons/vrm/registration.py +670 -0
  183. package/browser/addons/vrm.json +18 -0
  184. package/browser/blender-emscripten-engine.mts +66 -129
  185. package/browser/blender-engine.mts +20 -186
  186. package/browser/blender-wali-engine.mts +37 -81
  187. package/browser/describe-thrown.mts +3 -6
  188. package/browser/document-chunks.mts +4 -16
  189. package/browser/gltf_export.py +3161 -0
  190. package/browser/heap-growth.mts +23 -0
  191. package/browser/index.ts +3 -0
  192. package/browser/protocol.ts +130 -43
  193. package/browser/pull-job.mts +2 -10
  194. package/browser/rna.ts +190 -73
  195. package/browser/runtime.ts +271 -106
  196. package/browser/session-addons.mts +33 -0
  197. package/browser/session-frame.mts +5 -24
  198. package/browser/session.py +1389 -1446
  199. package/browser/three/attach-presenter.ts +11 -39
  200. package/browser/three/blender-base64.ts +1 -36
  201. package/browser/three/blender-corner-normals.ts +1 -23
  202. package/browser/three/blender-display-shaders.json +1 -1
  203. package/browser/three/blender-display-shaders.lut +0 -0
  204. package/browser/three/blender-display-transform.ts +2 -1
  205. package/browser/three/blender-frame-columns.ts +5 -13
  206. package/browser/three/blender-graph-material.ts +18 -3
  207. package/browser/three/blender-node-graph.ts +10 -34
  208. package/browser/three/blender-physical-material.ts +2 -31
  209. package/browser/three/blender-runtime-armature.ts +7 -60
  210. package/browser/three/blender-runtime-frame.ts +9 -23
  211. package/browser/three/blender-runtime-geometry.ts +22 -26
  212. package/browser/three/blender-runtime-lighting.ts +48 -178
  213. package/browser/three/blender-runtime-shadows.ts +187 -1
  214. package/browser/three/blender-runtime-skeleton.ts +53 -1
  215. package/browser/three/blender-runtime-view.ts +492 -306
  216. package/browser/three/blender-runtime-weights.ts +9 -72
  217. package/browser/three/blender-sky.ts +13 -33
  218. package/browser/three/blender-triangulate.ts +7 -35
  219. package/browser/three/blender-viewport-sampling.ts +235 -0
  220. package/browser/three/blender-workbench-material.ts +25 -29
  221. package/browser/three/blender-workbench-outline.ts +199 -0
  222. package/browser/three/blender-world-volume.ts +62 -10
  223. package/browser/three/presenter.ts +10 -26
  224. package/browser/three/release.ts +5 -21
  225. package/browser/three/sky-precompute-worker.ts +1 -18
  226. package/browser/three/sky-worker.ts +5 -23
  227. package/browser/three/world-field-sampler.ts +12 -26
  228. package/browser/volter_three.py +9 -105
  229. package/browser/worker.ts +195 -180
  230. package/package.json +5 -2
  231. package/wasm/BUNDLE.json +17 -17
  232. package/wasm/DEPENDENCY-LICENSES.txt +14 -0
  233. package/wasm/blender_browser.data.br +0 -0
  234. package/wasm/blender_browser.js +1 -1
  235. package/wasm/blender_browser.wasm.br +0 -0
  236. package/browser/frame-transfer.mts +0 -19
  237. package/browser/three/agx-base-srgb.lut +0 -0
  238. package/browser/three/agx-look-medium-high-contrast.lut +0 -0
  239. package/browser/three/agx-look-punchy.lut +0 -0
  240. package/browser/three/blender-agx.ts +0 -235
  241. package/browser/three/blender-display-lut.ts +0 -145
  242. package/browser/three/blender-filmic.ts +0 -49
  243. package/browser/three/blender-standard.ts +0 -68
  244. package/browser/three/blender-world-visibility.ts +0 -278
  245. package/browser/three/filmic-srgb.lut +0 -0
@@ -1,47 +1,4 @@
1
- """OUR BLENDER RENDERS WITH THREE.JS -- the ask, shipped INSIDE the Blender.
2
-
3
- THE RENDER OVERRIDE IS NOT THE EDITOR'S. `session.py` is the editor tab's
4
- long-lived session and carries this same override for the session it owns;
5
- this file is the other delivery of it -- a Blender STARTUP module that ships in
6
- the pack's resource tree (`scripts/startup/volter_three.py`), so a bare
7
- `blender -b ... -a` on ANY surface renders with three.js too. Blender imports
8
- every module in `scripts/startup` and calls its `register()`.
9
-
10
- THE ASK SHIPS WITH THE BLENDER; THE ANSWER DOES NOT. What renders is a
11
- PRESENTER the host attached to this process (`browser/three/attach-presenter.ts`
12
- around `browser/three/presenter.ts`): a canvas, the frame translated to
13
- three.js, a camera, the display transform. This file only asks. The channel is
14
- the directory protocol `session.py`'s header states, with one writer per
15
- directory:
16
-
17
- <root>/ask/ THIS PROGRAM writes and unlinks; the host only reads.
18
- <root>/reply/ the HOST writes and unlinks; this program only reads.
19
- <root>/arena.bin THIS PROGRAM writes (the export door does); host reads.
20
-
21
- NO PRESENTER, NO OVERRIDE. `register()` asks `{"op": "hello"}` and waits two
22
- seconds. Answered, it takes the engine ids and every render is a photograph.
23
- Unanswered, it prints ONE line naming the root it waited at and registers
24
- nothing at all, so Blender renders with Cycles -- correct, slow, and never
25
- silent.
26
-
27
- THE ENGINE IS TAKEN ON `load_post`, NOT IN `register()`, and that is a
28
- measurement. Blender's `bpy.utils.load_scripts` registers every startup module
29
- BEFORE it enables the add-ons, so at `register()` time `cycles.CyclesRender`
30
- does not exist yet and taking the `CYCLES` id here would be overwritten by the
31
- add-on moments later. Measured on the native 5.2.0 LTS oracle
32
- (`blender -b --python-expr ...` with this module's probe in
33
- `BLENDER_USER_SCRIPTS`): at `register()` `CYCLES` is unregistered, and the
34
- FIRST `load_post` -- which Blender fires for the startup file itself, before
35
- any `--python-expr` runs -- sees `<class 'cycles.CyclesRender'>`. So the
36
- handler is where the ids are taken, and it runs again after every file load
37
- because a load re-enables the add-ons and hands `CYCLES` back.
38
-
39
- WHAT THIS FILE DOES NOT CARRY, deliberately: the editor session's incremental
40
- geometry record (every frame ships in full -- `known` is always empty, so no
41
- presenter can ever be asked about geometry it does not hold), its document,
42
- its overlays, and its world SHADER reducer. A world here is a CONSTANT
43
- background or nothing, named as a warning; see `_world`.
44
- """
1
+ """Standalone Blender startup render override. Bare background Blender processes use the presenter’s ask/reply directory protocol, while session.py owns the editor session’s equivalent engine. The package carries protocol and data conversion without importing editor state."""
45
2
 
46
3
  import base64
47
4
  import json
@@ -65,19 +22,7 @@ REPLY = os.path.join(ROOT, "reply")
65
22
  EXPORT_BUFFER_PATH = os.environ.get(
66
23
  "VOLTER_EXPORT_BUFFER_PATH", os.path.join(ROOT, "arena.bin")
67
24
  )
68
- # THE FRAME'S IDENTITY IS A PAIR, `(session, revision)`, and the presenter
69
- # refuses a revision that went backwards under a name it already holds. One
70
- # process is one session; the revision only ever counts up within it.
71
- #
72
- # THE PID IS NOT THE NAME, and that is measured rather than cautious. A
73
- # presenter outlives the Blenders it serves, so two processes' names must
74
- # differ -- and in the browser the guest's pids START OVER: the second
75
- # `blender -b ... -a` on one page came up as the same pid, its revision
76
- # restarted at 1 under a name the view already held at 24, and every render in
77
- # it died on "The runtime frame is older than the displayed model" (measured
78
- # 2026-09-20 in the substrate tab; the first run on a freshly loaded page
79
- # always worked, which is what hid it). The start time is what makes the name
80
- # this process's own.
25
+ # Identify frames by process session and monotonic revision. Include process start time because guest pids can repeat while a presenter remains alive.
81
26
  SESSION = "volter-three:%d-%d" % (os.getpid(), time.time_ns())
82
27
  HELLO_TIMEOUT_SECONDS = 2.0
83
28
  POLL_SECONDS = 0.002
@@ -87,25 +32,7 @@ _REVISION = [0]
87
32
  _WARNED = set()
88
33
  _WARNINGS = []
89
34
  def _say(line):
90
- """One line on Blender's own stderr, resolved at CALL TIME.
91
-
92
- WHERE THIS LINE COMES OUT, and it is not where a reader looks first.
93
- MEASURED 2026-09-20 in the substrate tab with the whole command redirected
94
- (`blender ... > log 2>&1`): Python's `sys.stderr` in this build is NOT the
95
- process's fd 2. `print(..., file=sys.stderr)` and
96
- `sys.stderr.buffer.write(...)` BOTH reached the terminal and NEITHER
97
- reached the file, while `print()` to stdout reached the file and not the
98
- terminal. So the one line this module ever prints -- the one that says
99
- Cycles is about to render -- is read on the TERMINAL; a reader who greps
100
- only a redirect will conclude the fallback is silent when it is not. That
101
- reading cost an hour and a wrong diagnosis; it is written here so it costs
102
- nobody else one.
103
-
104
- The stream is taken at call time rather than captured at import because a
105
- startup module is imported while Blender is still standing its streams up
106
- and nothing here needs the captured one. Both spellings were measured to
107
- work; this is the plainer.
108
- """
35
+ """Write to Blender’s current stderr at call time, after the host has attached its streams."""
109
36
  print(line, file=sys.stderr or sys.stdout, flush=True)
110
37
 
111
38
 
@@ -250,8 +177,6 @@ def _export(depsgraph):
250
177
 
251
178
 
252
179
  def _present(depsgraph, capture):
253
- if not hasattr(_blender_web, "begin_render_export"):
254
- raise RuntimeError("This Blender artifact has no render-evaluated export")
255
180
  _blender_web.begin_render_export(depsgraph)
256
181
  try:
257
182
  answer = ask({"frame": _export(depsgraph), "capture": {**capture, "evaluation": "render"}})
@@ -317,6 +242,8 @@ def _photograph(depsgraph, width, height, linear=False):
317
242
  "AgX": "agx",
318
243
  "Filmic": "filmic",
319
244
  "Khronos PBR Neutral": "neutral",
245
+ "ACES 1.3": "aces13",
246
+ "ACES 2.0": "aces20",
320
247
  }.get(view.view_transform)
321
248
  if transform is None:
322
249
  raise RuntimeError(
@@ -349,20 +276,9 @@ def _photograph(depsgraph, width, height, linear=False):
349
276
 
350
277
 
351
278
  def _assert_photographed_from(reported, position, target, up):
352
- """The photograph answers with the pose it ACTUALLY used, back in Blender's
353
- frame, and it must be the pose that was sent -- exactly, with no tolerance.
354
-
355
- This is an instrument, not a nicety. A render's image is allowed to differ
356
- from Cycles (three.js is the renderer), so a camera placed in the wrong
357
- frame produces a picture nobody can call wrong: the lane shipped for its
358
- whole life photographing the model's underside from below the floor because
359
- Blender's Z-up numbers were read as three.js world space.
360
-
361
- The check is exact because the conversion is exact: the model root's world
362
- matrix is a signed axis permutation, so a vector through it and its inverse
363
- is bit-identical. A mismatch is the conversion being wrong, never the check
364
- being too strict -- do not widen it.
365
- """
279
+ """Require the photograph’s camera pose transformed back into Blender’s frame to equal the sent
280
+ pose exactly. The model root uses a signed axis permutation, so its transform and inverse
281
+ preserve values without a floating-point tolerance."""
366
282
  sent = {"position": position, "target": target, "up": up}
367
283
  if not isinstance(reported, dict):
368
284
  raise RuntimeError(
@@ -417,19 +333,7 @@ class VolterRenderEngine(bpy.types.RenderEngine):
417
333
 
418
334
 
419
335
  def _fill_result(engine, result, answer, png, width, height):
420
- """THE RENDER RESULT HOLDS SCENE-LINEAR PIXELS, and Blender runs the scene's
421
- view transform over them wherever it shows or saves one (`write_still`, the
422
- Image Editor), as it does over Cycles'. The photograph's PNG is the display
423
- image -- the transform already ran -- so loading it put every render
424
- through AgX or Filmic twice. Measured 2026-09-28 by Cyclotron's
425
- render view: a background 53 against the viewport's 59, a shadow's blue 2
426
- against 7. The same capture's linear frame goes in instead: half floats,
427
- RGBA, bottom row first, which is Blender's own row order. Linear 0.005,
428
- 0.05, 0.5 and 4.0 then save under AgX as 8, 58, 170 and 234 (the PNG
429
- path saved 3, 53, 160 and 190), and under Standard as 15, 64, 188 and 255,
430
- as the PNG path did.
431
-
432
- A renderer that sends no linear frame gets the old path, and says so."""
336
+ """Load scene-linear capture pixels into RenderResult so Blender applies the view transform once. A presenter without linear pixels uses the declared PNG path."""
433
337
  linear = answer.get("linearBase64") if isinstance(answer, dict) else None
434
338
  if linear and answer.get("linearWidth") == width and answer.get("linearHeight") == height:
435
339
  import numpy