@downdraft/engine 0.1.1 → 0.1.2-alpha.5

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 (1021) hide show
  1. package/app/README.md +11 -0
  2. package/app/src/renderer/bootstrap.ts +295 -19
  3. package/app/src/renderer/game-module.ts +60 -12
  4. package/app/src/renderer/hooks.ts +9 -1
  5. package/app/src/renderer/hot-reload.ts +9 -9
  6. package/app/src/renderer/mcp-harness.ts +2 -2
  7. package/app/src/renderer/standard-automation-tools.ts +104 -3
  8. package/app/src/shared/feature-log.ts +2 -1
  9. package/app/src/shared/mcp-discovery.ts +8 -3
  10. package/app/src/shared/mcp-proxy.ts +2 -2
  11. package/asset-bake/README.md +22 -0
  12. package/core/README.md +25 -0
  13. package/core/src/animation/skeleton-animator.ts +23 -5
  14. package/core/src/assets/manager.ts +4 -4
  15. package/core/src/ecs/events.ts +1 -1
  16. package/core/src/ecs/schedule.ts +1 -1
  17. package/core/src/ecs/world.ts +1 -1
  18. package/core/src/index.ts +3 -4
  19. package/core/src/library/host.ts +27 -13
  20. package/core/src/library/library.ts +13 -5
  21. package/core/src/module/cross-thread.ts +6 -0
  22. package/core/src/module/diagnostics.ts +10 -6
  23. package/core/src/module/host.ts +65 -18
  24. package/core/src/module/index.ts +1 -0
  25. package/core/src/module/module.ts +11 -5
  26. package/core/src/module/renderer-module.ts +15 -0
  27. package/core/src/physics/safety.ts +1 -1
  28. package/core/src/platform/bun-preload.ts +7 -2
  29. package/core/src/platform/glob-polyfill.ts +17 -8
  30. package/core/src/platform/pkg-root.ts +27 -0
  31. package/core/src/platform/runtime.ts +29 -0
  32. package/core/src/plugin/discovery.ts +1 -1
  33. package/core/src/plugin/extension-loaders.ts +6 -4
  34. package/core/src/plugin/host.ts +13 -13
  35. package/core/src/plugin/loader-asset.ts +5 -5
  36. package/core/src/plugin/loader-quickjs.ts +1 -1
  37. package/core/src/plugin/loader-wasm.ts +3 -3
  38. package/core/src/plugin/loader-worker.ts +1 -1
  39. package/core/src/plugin/manifest.ts +8 -3
  40. package/core/src/plugin/workshop.ts +3 -3
  41. package/core/src/profiling/index.ts +1 -1
  42. package/core/src/profiling/profiling-sab.ts +19 -0
  43. package/core/src/profiling/warnings.ts +1 -1
  44. package/core/src/profiling/worker-prelude.ts +1 -1
  45. package/core/src/render/bindless/frame-bindings.ts +1 -1
  46. package/core/src/render/bindless/material-manager.ts +2 -2
  47. package/core/src/render/bindless/texture-registry.ts +2 -2
  48. package/core/src/render/device.ts +5 -5
  49. package/core/src/render/frame-graph.ts +2 -2
  50. package/core/src/render/game-renderer.ts +42 -18
  51. package/core/src/render/hot-reload.ts +3 -3
  52. package/core/src/render/renderer-module-host.ts +32 -12
  53. package/core/src/render/shader-validator.ts +7 -7
  54. package/core/src/render/surface.ts +1 -1
  55. package/core/src/sab/errors.ts +1 -1
  56. package/core/src/sab/sab-polyfill.ts +1 -1
  57. package/core/src/save/migration-registry.ts +4 -4
  58. package/core/src/save/schema.ts +1 -1
  59. package/core/src/scene/prefab.ts +1 -1
  60. package/core/src/scene/scene-manager.ts +2 -2
  61. package/core/src/scene/scene.ts +4 -4
  62. package/core/src/scene/streaming.ts +2 -2
  63. package/core/src/scripting/hot-reload.ts +2 -2
  64. package/core/src/sim/hot-reload-pipeline.ts +30 -6
  65. package/core/src/sim/sim-state-helper.ts +1 -1
  66. package/core/src/sim/transient-state-registry.ts +1 -1
  67. package/core/src/sim/worker-loop.ts +2 -2
  68. package/core/src/telemetry/gpu-profiler.ts +3 -3
  69. package/core/src/util/index.ts +1 -1
  70. package/core/src/util/logger.ts +36 -5
  71. package/core/src/version.ts +13 -0
  72. package/core/src/worker/base-worker-host.ts +87 -25
  73. package/core/src/worker/buffer-sync.ts +1 -1
  74. package/core/src/worker/crash-recovery.ts +2 -2
  75. package/core/src/worker/instrumented-worker-host.ts +3 -3
  76. package/core/src/worker/rpc.ts +62 -11
  77. package/core/src/worker/sim-worker-base.ts +3 -8
  78. package/core/src/worker/task-pool.ts +2 -2
  79. package/dist/.dd-manifest.json +4119 -0
  80. package/dist/app/src/index.js +9 -0
  81. package/dist/app/src/renderer/bootstrap.js +446 -0
  82. package/dist/app/src/renderer/downdraft-base.css +93 -0
  83. package/dist/app/src/renderer/feature-log.js +180 -0
  84. package/dist/app/src/renderer/game-module.js +562 -0
  85. package/dist/app/src/renderer/hooks.js +82 -0
  86. package/dist/app/src/renderer/hot-reload.js +158 -0
  87. package/dist/app/src/renderer/import-cache.js +77 -0
  88. package/dist/app/src/renderer/index.js +149 -0
  89. package/dist/app/src/renderer/mcp-harness.js +112 -0
  90. package/dist/app/src/renderer/save-store-factory.js +180 -0
  91. package/dist/app/src/renderer/sim-bridge.js +138 -0
  92. package/dist/app/src/renderer/standard-automation-tools.js +720 -0
  93. package/dist/app/src/shared/feature-log.js +54 -0
  94. package/dist/app/src/shared/gpu-info.js +74 -0
  95. package/dist/app/src/shared/import-cache-store.js +123 -0
  96. package/dist/app/src/shared/index.js +4 -0
  97. package/dist/app/src/shared/mcp-discovery.js +55 -0
  98. package/dist/app/src/shared/mcp-proxy.js +71 -0
  99. package/dist/app/src/shared/types.js +13 -0
  100. package/dist/asset-bake/src/bake-audio.js +103 -0
  101. package/dist/asset-bake/src/bake-gltf.js +141 -0
  102. package/dist/asset-bake/src/bake.js +63 -0
  103. package/dist/asset-bake/src/cache.js +147 -0
  104. package/dist/asset-bake/src/config.js +93 -0
  105. package/dist/asset-bake/src/index.js +25 -0
  106. package/dist/core/src/animation/animation-event.js +24 -0
  107. package/dist/core/src/animation/bone-mask.js +103 -0
  108. package/dist/core/src/animation/clip.js +210 -0
  109. package/dist/core/src/animation/index.js +13 -0
  110. package/dist/core/src/animation/mixamo.js +78 -0
  111. package/dist/core/src/animation/morph-target.js +37 -0
  112. package/dist/core/src/animation/player.js +621 -0
  113. package/dist/core/src/animation/retarget.js +101 -0
  114. package/dist/core/src/animation/skeleton-animator.js +1361 -0
  115. package/dist/core/src/animation/skeleton.js +166 -0
  116. package/dist/core/src/animation/state-machine.js +252 -0
  117. package/dist/core/src/assets/blob-store.js +14 -0
  118. package/dist/core/src/assets/cache.js +168 -0
  119. package/dist/core/src/assets/cubemap-converter.js +129 -0
  120. package/dist/core/src/assets/environment-manager.js +84 -0
  121. package/dist/core/src/assets/import-cache.js +36 -0
  122. package/dist/core/src/assets/import-settings.js +34 -0
  123. package/dist/core/src/assets/importer.js +78 -0
  124. package/dist/core/src/assets/index.js +29 -0
  125. package/dist/core/src/assets/irradiance-generator.js +179 -0
  126. package/dist/core/src/assets/loader-audio.js +70 -0
  127. package/dist/core/src/assets/loader-cubemap.js +141 -0
  128. package/dist/core/src/assets/loader-dds.js +185 -0
  129. package/dist/core/src/assets/loader-hdr.js +430 -0
  130. package/dist/core/src/assets/loader-mesh.js +47 -0
  131. package/dist/core/src/assets/loader-shader.js +61 -0
  132. package/dist/core/src/assets/loader-texture.js +264 -0
  133. package/dist/core/src/assets/lod.js +150 -0
  134. package/dist/core/src/assets/manager.js +401 -0
  135. package/dist/core/src/assets/manifest.js +57 -0
  136. package/dist/core/src/assets/material-bridge.js +160 -0
  137. package/dist/core/src/assets/model-importer.js +32 -0
  138. package/dist/core/src/assets/model-normalizer.js +213 -0
  139. package/dist/core/src/assets/model-to-gpu.js +44 -0
  140. package/dist/core/src/assets/model-to-mesh.js +171 -0
  141. package/dist/core/src/assets/prefilter-generator.js +220 -0
  142. package/dist/core/src/audio/engine.js +153 -0
  143. package/dist/core/src/audio/interface.js +8 -0
  144. package/dist/core/src/audio/listener.js +19 -0
  145. package/dist/core/src/audio/mixer.js +124 -0
  146. package/dist/core/src/audio/registry.js +43 -0
  147. package/dist/core/src/audio/sab.js +74 -0
  148. package/dist/core/src/audio/source.js +60 -0
  149. package/dist/core/src/change-detection/atomics.js +1 -0
  150. package/dist/core/src/change-detection/tracker.js +26 -0
  151. package/dist/core/src/debug-draw/lines.js +27 -0
  152. package/dist/core/src/debug-draw/points.js +9 -0
  153. package/dist/core/src/debug-draw/queue.js +77 -0
  154. package/dist/core/src/debug-draw/text.js +12 -0
  155. package/dist/core/src/ecs/archetype.js +271 -0
  156. package/dist/core/src/ecs/component.js +109 -0
  157. package/dist/core/src/ecs/entity.js +11 -0
  158. package/dist/core/src/ecs/events.js +73 -0
  159. package/dist/core/src/ecs/hierarchy.js +104 -0
  160. package/dist/core/src/ecs/hmr-swap-registry.js +15 -0
  161. package/dist/core/src/ecs/index.js +14 -0
  162. package/dist/core/src/ecs/query.js +110 -0
  163. package/dist/core/src/ecs/resource.js +3 -0
  164. package/dist/core/src/ecs/schedule.js +157 -0
  165. package/dist/core/src/ecs/system-params.js +45 -0
  166. package/dist/core/src/ecs/system.js +18 -0
  167. package/dist/core/src/ecs/world.js +292 -0
  168. package/dist/core/src/index.js +191 -0
  169. package/dist/core/src/input/context.js +69 -0
  170. package/dist/core/src/input/dom-handler.js +288 -0
  171. package/dist/core/src/input/local-player-manager.js +145 -0
  172. package/dist/core/src/input/mapping.js +36 -0
  173. package/dist/core/src/input/multi-sab-bridge.js +224 -0
  174. package/dist/core/src/input/multi-state.js +48 -0
  175. package/dist/core/src/input/sab-bridge.js +66 -0
  176. package/dist/core/src/input/state.js +108 -0
  177. package/dist/core/src/input/ui-router.js +76 -0
  178. package/dist/core/src/library/host.js +291 -0
  179. package/dist/core/src/library/index.js +1 -0
  180. package/dist/core/src/library/library.js +20 -0
  181. package/dist/core/src/material/compiler.js +73 -0
  182. package/dist/core/src/material/graph-bridge.js +119 -0
  183. package/dist/core/src/material/index.js +6 -0
  184. package/dist/core/src/material/library.js +414 -0
  185. package/dist/core/src/material/material.js +120 -0
  186. package/dist/core/src/material/variants.js +37 -0
  187. package/dist/core/src/math/mat4.js +198 -0
  188. package/dist/core/src/math/perlin-noise-2d.js +66 -0
  189. package/dist/core/src/math/perlin-noise-3d.js +76 -0
  190. package/dist/core/src/math/quat.js +29 -0
  191. package/dist/core/src/math/rng.js +25 -0
  192. package/dist/core/src/math/trig.js +42 -0
  193. package/dist/core/src/math/value-noise.js +49 -0
  194. package/dist/core/src/mesh/builder.js +137 -0
  195. package/dist/core/src/mesh/csg.js +250 -0
  196. package/dist/core/src/mesh/greased-line.js +102 -0
  197. package/dist/core/src/mesh/mesh.js +6 -0
  198. package/dist/core/src/mesh/parametric.js +392 -0
  199. package/dist/core/src/mesh/skinning.js +30 -0
  200. package/dist/core/src/mesh/vertex-layout.js +65 -0
  201. package/dist/core/src/module/cross-thread.js +126 -0
  202. package/dist/core/src/module/diagnostics.js +99 -0
  203. package/dist/core/src/module/host.js +449 -0
  204. package/dist/core/src/module/index.js +6 -0
  205. package/dist/core/src/module/module.js +1 -0
  206. package/dist/core/src/module/registry.js +83 -0
  207. package/dist/core/src/module/renderer-module.js +13 -0
  208. package/dist/core/src/module/ts-loader.js +20 -0
  209. package/dist/core/src/particles/compute-pass.js +329 -0
  210. package/dist/core/src/particles/emitter.js +113 -0
  211. package/dist/core/src/particles/index.js +7 -0
  212. package/dist/core/src/particles/particle-data.js +33 -0
  213. package/dist/core/src/particles/render-pass.js +338 -0
  214. package/dist/core/src/particles/simulator.js +224 -0
  215. package/dist/core/src/particles/system.js +157 -0
  216. package/dist/core/src/physics/body.js +25 -0
  217. package/dist/core/src/physics/ccd-heuristic.js +46 -0
  218. package/dist/core/src/physics/character.js +184 -0
  219. package/dist/core/src/physics/collider.js +36 -0
  220. package/dist/core/src/physics/collision-system.js +62 -0
  221. package/dist/core/src/physics/events.js +74 -0
  222. package/dist/core/src/physics/index.js +24 -0
  223. package/dist/core/src/physics/interface.js +14 -0
  224. package/dist/core/src/physics/interpolation-buffer.js +182 -0
  225. package/dist/core/src/physics/lifecycle.js +66 -0
  226. package/dist/core/src/physics/load-shedder.js +155 -0
  227. package/dist/core/src/physics/physics-accumulator.js +94 -0
  228. package/dist/core/src/physics/physics-system.js +142 -0
  229. package/dist/core/src/physics/ragdoll-presets.js +248 -0
  230. package/dist/core/src/physics/ragdoll-system.js +193 -0
  231. package/dist/core/src/physics/ragdoll.js +117 -0
  232. package/dist/core/src/physics/raycast.js +97 -0
  233. package/dist/core/src/physics/realm-manager.js +431 -0
  234. package/dist/core/src/physics/realm-worker-pool.js +181 -0
  235. package/dist/core/src/physics/realm-worker.js +91 -0
  236. package/dist/core/src/physics/realm.js +137 -0
  237. package/dist/core/src/physics/registry.js +43 -0
  238. package/dist/core/src/physics/safety.js +211 -0
  239. package/dist/core/src/physics/snapshot-manager.js +118 -0
  240. package/dist/core/src/physics/worker-protocol.js +1 -0
  241. package/dist/core/src/platform/bun-preload.js +175 -0
  242. package/dist/core/src/platform/css-stub.js +4 -0
  243. package/dist/core/src/platform/glob-polyfill.js +137 -0
  244. package/dist/core/src/platform/hidpi.js +52 -0
  245. package/dist/core/src/platform/pkg-root.js +27 -0
  246. package/dist/core/src/platform/render-surface.js +15 -0
  247. package/dist/core/src/platform/rpc.js +82 -0
  248. package/dist/core/src/platform/runtime.js +93 -0
  249. package/dist/core/src/plugin/context.js +144 -0
  250. package/dist/core/src/plugin/diagnostics.js +20 -0
  251. package/dist/core/src/plugin/discovery.js +124 -0
  252. package/dist/core/src/plugin/extension-loaders.js +111 -0
  253. package/dist/core/src/plugin/host.js +542 -0
  254. package/dist/core/src/plugin/index.js +19 -0
  255. package/dist/core/src/plugin/loader-asset.js +105 -0
  256. package/dist/core/src/plugin/loader-quickjs.js +67 -0
  257. package/dist/core/src/plugin/loader-wasm.js +385 -0
  258. package/dist/core/src/plugin/loader-worker.js +228 -0
  259. package/dist/core/src/plugin/manifest.js +424 -0
  260. package/dist/core/src/plugin/material-registry.js +44 -0
  261. package/dist/core/src/plugin/mcp-tools.js +147 -0
  262. package/dist/core/src/plugin/permissions.js +152 -0
  263. package/dist/core/src/plugin/quickjs-bridge.js +219 -0
  264. package/dist/core/src/plugin/registry.js +92 -0
  265. package/dist/core/src/plugin/sandbox-shim.js +79 -0
  266. package/dist/core/src/plugin/sandbox-worker.js +194 -0
  267. package/dist/core/src/plugin/wasm-abi.js +62 -0
  268. package/dist/core/src/plugin/wasm-worker.js +234 -0
  269. package/dist/core/src/plugin/workshop.js +131 -0
  270. package/dist/core/src/profiling/event-loop.js +164 -0
  271. package/dist/core/src/profiling/index.js +23 -0
  272. package/dist/core/src/profiling/iops/idb-patch.js +211 -0
  273. package/dist/core/src/profiling/iops/opfs-patch.js +206 -0
  274. package/dist/core/src/profiling/profiling-sab.js +632 -0
  275. package/dist/core/src/profiling/task-latency.js +118 -0
  276. package/dist/core/src/profiling/thread-metrics.js +103 -0
  277. package/dist/core/src/profiling/trace-event-writer.js +165 -0
  278. package/dist/core/src/profiling/warnings.js +304 -0
  279. package/dist/core/src/profiling/worker-prelude.js +281 -0
  280. package/dist/core/src/render/bind-group.js +33 -0
  281. package/dist/core/src/render/bindless/bindless-struct.js +39 -0
  282. package/dist/core/src/render/bindless/bindless.wgsl.js +163 -0
  283. package/dist/core/src/render/bindless/frame-bindings.js +142 -0
  284. package/dist/core/src/render/bindless/index.js +6 -0
  285. package/dist/core/src/render/bindless/material-manager.js +182 -0
  286. package/dist/core/src/render/bindless/texture-registry.js +498 -0
  287. package/dist/core/src/render/buffer.js +74 -0
  288. package/dist/core/src/render/camera-2d.js +151 -0
  289. package/dist/core/src/render/camera-controller.js +370 -0
  290. package/dist/core/src/render/camera.js +332 -0
  291. package/dist/core/src/render/canvas-resize-watcher.js +36 -0
  292. package/dist/core/src/render/compute-kernel.js +130 -0
  293. package/dist/core/src/render/constants.js +2 -0
  294. package/dist/core/src/render/device.js +91 -0
  295. package/dist/core/src/render/frame-graph.js +594 -0
  296. package/dist/core/src/render/frustum.js +152 -0
  297. package/dist/core/src/render/fullscreen-vs.js +24 -0
  298. package/dist/core/src/render/g-buffer.js +156 -0
  299. package/dist/core/src/render/game-renderer.js +1165 -0
  300. package/dist/core/src/render/gpu-driven/cull-pass.js +352 -0
  301. package/dist/core/src/render/gpu-driven/hzb.js +183 -0
  302. package/dist/core/src/render/gpu-driven/index.js +6 -0
  303. package/dist/core/src/render/gpu-driven/indirect-draw-pass.js +300 -0
  304. package/dist/core/src/render/gpu-driven/instance-buffer.js +150 -0
  305. package/dist/core/src/render/gpu-driven/mesh-table.js +130 -0
  306. package/dist/core/src/render/gpu-driven/passes/hzb-build-pass.js +39 -0
  307. package/dist/core/src/render/gpu-utils.js +72 -0
  308. package/dist/core/src/render/hdr.js +69 -0
  309. package/dist/core/src/render/hot-reload.js +236 -0
  310. package/dist/core/src/render/ibl-bind-group.js +232 -0
  311. package/dist/core/src/render/ibl.js +148 -0
  312. package/dist/core/src/render/index.js +86 -0
  313. package/dist/core/src/render/input-manager.js +224 -0
  314. package/dist/core/src/render/lighting/area-light.js +142 -0
  315. package/dist/core/src/render/lighting/cluster-grid.js +255 -0
  316. package/dist/core/src/render/lighting/cluster-types.js +87 -0
  317. package/dist/core/src/render/lighting/ies-parser.js +111 -0
  318. package/dist/core/src/render/lighting.js +300 -0
  319. package/dist/core/src/render/material-types/depth.wgsl +44 -0
  320. package/dist/core/src/render/material-types/line.wgsl +50 -0
  321. package/dist/core/src/render/material-types/matcap.wgsl +51 -0
  322. package/dist/core/src/render/material-types/normal.wgsl +41 -0
  323. package/dist/core/src/render/material-types/physical.wgsl +152 -0
  324. package/dist/core/src/render/material-types/sprite.wgsl +46 -0
  325. package/dist/core/src/render/material-types/sss.wgsl +79 -0
  326. package/dist/core/src/render/material-types/toon.wgsl +79 -0
  327. package/dist/core/src/render/passes/README.md +121 -0
  328. package/dist/core/src/render/passes/atmosphere.js +107 -0
  329. package/dist/core/src/render/passes/cluster-lighting-pass.js +441 -0
  330. package/dist/core/src/render/passes/csm.js +338 -0
  331. package/dist/core/src/render/passes/cubemap-capture.js +93 -0
  332. package/dist/core/src/render/passes/debug-viz.js +248 -0
  333. package/dist/core/src/render/passes/debug.js +500 -0
  334. package/dist/core/src/render/passes/decal-mesh.js +86 -0
  335. package/dist/core/src/render/passes/decal-pass.js +344 -0
  336. package/dist/core/src/render/passes/deferred-lighting.js +406 -0
  337. package/dist/core/src/render/passes/depth-prepass.js +148 -0
  338. package/dist/core/src/render/passes/dome-360.js +68 -0
  339. package/dist/core/src/render/passes/fluid-render.js +116 -0
  340. package/dist/core/src/render/passes/gi-types.js +78 -0
  341. package/dist/core/src/render/passes/graph-compute.js +251 -0
  342. package/dist/core/src/render/passes/greased-line-pass.js +218 -0
  343. package/dist/core/src/render/passes/morph-target.js +35 -0
  344. package/dist/core/src/render/passes/opaque.js +966 -0
  345. package/dist/core/src/render/passes/point-light-shadow.js +221 -0
  346. package/dist/core/src/render/passes/procedural-texture.js +142 -0
  347. package/dist/core/src/render/passes/reflection-probe.js +100 -0
  348. package/dist/core/src/render/passes/rsm-pass.js +228 -0
  349. package/dist/core/src/render/passes/sdf-text.js +114 -0
  350. package/dist/core/src/render/passes/shadow-map.js +121 -0
  351. package/dist/core/src/render/passes/shadow.js +191 -0
  352. package/dist/core/src/render/passes/skinning-vs.js +102 -0
  353. package/dist/core/src/render/passes/skinning.js +282 -0
  354. package/dist/core/src/render/passes/sky-dome.js +380 -0
  355. package/dist/core/src/render/passes/skybox.js +146 -0
  356. package/dist/core/src/render/passes/spot-light-shadow.js +223 -0
  357. package/dist/core/src/render/passes/terrain.js +303 -0
  358. package/dist/core/src/render/passes/transparent.js +323 -0
  359. package/dist/core/src/render/passes/underwater-fog.js +173 -0
  360. package/dist/core/src/render/passes/video-texture.js +58 -0
  361. package/dist/core/src/render/passes/volumetric-pass.js +278 -0
  362. package/dist/core/src/render/passes/volumetric-types.js +96 -0
  363. package/dist/core/src/render/passes/water.js +697 -0
  364. package/dist/core/src/render/pbr.js +257 -0
  365. package/dist/core/src/render/pipeline.js +49 -0
  366. package/dist/core/src/render/render-pass.js +13 -0
  367. package/dist/core/src/render/renderer-input-bus.js +176 -0
  368. package/dist/core/src/render/renderer-module-host.js +539 -0
  369. package/dist/core/src/render/resource-tracker.js +59 -0
  370. package/dist/core/src/render/sab-canvas-overlay.js +83 -0
  371. package/dist/core/src/render/shader-validator.js +172 -0
  372. package/dist/core/src/render/shaders/debug/debug-line.wgsl +27 -0
  373. package/dist/core/src/render/shaders/debug/debug-point.wgsl +30 -0
  374. package/dist/core/src/render/shaders/debug/debug-text.wgsl +42 -0
  375. package/dist/core/src/render/shaders/debug-viz/aabb.wgsl +20 -0
  376. package/dist/core/src/render/shaders/debug-viz/depth.wgsl +29 -0
  377. package/dist/core/src/render/shaders/debug-viz/lod.wgsl +38 -0
  378. package/dist/core/src/render/shaders/debug-viz/normals.wgsl +30 -0
  379. package/dist/core/src/render/shaders/debug-viz/overdraw.wgsl +21 -0
  380. package/dist/core/src/render/shaders/debug-viz/tangents.wgsl +29 -0
  381. package/dist/core/src/render/shaders/debug-viz/wireframe.wgsl +33 -0
  382. package/dist/core/src/render/shaders/shadow-chunks.js +133 -0
  383. package/dist/core/src/render/skybox.js +123 -0
  384. package/dist/core/src/render/splitscreen.js +60 -0
  385. package/dist/core/src/render/surface.js +63 -0
  386. package/dist/core/src/render/tonemap.js +171 -0
  387. package/dist/core/src/render/tracked-render-pass.js +115 -0
  388. package/dist/core/src/render/viewport.js +81 -0
  389. package/dist/core/src/render/wgsl-hmr.js +66 -0
  390. package/dist/core/src/sab/core-input-channel.js +22 -0
  391. package/dist/core/src/sab/define.js +127 -0
  392. package/dist/core/src/sab/errors.js +60 -0
  393. package/dist/core/src/sab/game-input.js +299 -0
  394. package/dist/core/src/sab/gamepad-devices.js +205 -0
  395. package/dist/core/src/sab/grid-buffer.js +91 -0
  396. package/dist/core/src/sab/input.js +38 -0
  397. package/dist/core/src/sab/layout.js +160 -0
  398. package/dist/core/src/sab/multi-input-channel.js +39 -0
  399. package/dist/core/src/sab/record-buffer.js +130 -0
  400. package/dist/core/src/sab/sab-polyfill.js +47 -0
  401. package/dist/core/src/sab/sim-channel.js +397 -0
  402. package/dist/core/src/sab/slot-buffer.js +140 -0
  403. package/dist/core/src/sab/types.js +1 -0
  404. package/dist/core/src/safety/bounds.js +71 -0
  405. package/dist/core/src/safety/json.js +70 -0
  406. package/dist/core/src/safety/path.js +151 -0
  407. package/dist/core/src/save/binary-format.js +95 -0
  408. package/dist/core/src/save/game-save-system.js +101 -0
  409. package/dist/core/src/save/grid-save-system.js +102 -0
  410. package/dist/core/src/save/migrate.js +35 -0
  411. package/dist/core/src/save/migration-registry.js +66 -0
  412. package/dist/core/src/save/persist-types.js +4 -0
  413. package/dist/core/src/save/schema.js +36 -0
  414. package/dist/core/src/save/serializer.js +139 -0
  415. package/dist/core/src/scene/builder.js +31 -0
  416. package/dist/core/src/scene/camera.js +118 -0
  417. package/dist/core/src/scene/checkpoint.js +84 -0
  418. package/dist/core/src/scene/game-loop.js +155 -0
  419. package/dist/core/src/scene/index.js +14 -0
  420. package/dist/core/src/scene/layer.js +7 -0
  421. package/dist/core/src/scene/prefab.js +97 -0
  422. package/dist/core/src/scene/scene-manager.js +141 -0
  423. package/dist/core/src/scene/scene.js +147 -0
  424. package/dist/core/src/scene/sky.js +179 -0
  425. package/dist/core/src/scene/spatial-grid.js +140 -0
  426. package/dist/core/src/scene/streaming.js +247 -0
  427. package/dist/core/src/scene/vegetation.js +107 -0
  428. package/dist/core/src/scene/world.js +66 -0
  429. package/dist/core/src/scripting/binding.js +85 -0
  430. package/dist/core/src/scripting/hot-reload.js +123 -0
  431. package/dist/core/src/scripting/script.js +68 -0
  432. package/dist/core/src/sim/hot-reload-pipeline.js +65 -0
  433. package/dist/core/src/sim/sim-state-helper.js +40 -0
  434. package/dist/core/src/sim/transient-state-registry.js +63 -0
  435. package/dist/core/src/sim/types.js +4 -0
  436. package/dist/core/src/sim/worker-loop.js +168 -0
  437. package/dist/core/src/stores/game-store.js +81 -0
  438. package/dist/core/src/stores/hot-reload-store.js +19 -0
  439. package/dist/core/src/telemetry/collector.js +303 -0
  440. package/dist/core/src/telemetry/gc-controller.js +365 -0
  441. package/dist/core/src/telemetry/gc-profiler.js +82 -0
  442. package/dist/core/src/telemetry/gc-tracker.js +63 -0
  443. package/dist/core/src/telemetry/gpu-profiler.js +554 -0
  444. package/dist/core/src/telemetry/gpu-resource-tracker.js +234 -0
  445. package/dist/core/src/telemetry/gpu-timer-pool.js +223 -0
  446. package/dist/core/src/telemetry/gpu-timer.js +117 -0
  447. package/dist/core/src/telemetry/gpu-timestamp-gate.js +22 -0
  448. package/dist/core/src/telemetry/reporter.js +56 -0
  449. package/dist/core/src/types/engine-types.js +21 -0
  450. package/dist/core/src/ui-font-scale.js +111 -0
  451. package/dist/core/src/util/broad-phase-grid.js +77 -0
  452. package/dist/core/src/util/feature-log.js +176 -0
  453. package/dist/core/src/util/index.js +4 -0
  454. package/dist/core/src/util/logger.js +596 -0
  455. package/dist/core/src/version.js +11 -0
  456. package/dist/core/src/webgpu-destroy-augmentation.d.ts +25 -0
  457. package/dist/core/src/worker/base-worker-host.js +212 -0
  458. package/dist/core/src/worker/buffer-sync.js +454 -0
  459. package/dist/core/src/worker/crash-recovery.js +153 -0
  460. package/dist/core/src/worker/entity-sim-worker-host.js +128 -0
  461. package/dist/core/src/worker/instrumented-worker-host.js +139 -0
  462. package/dist/core/src/worker/rpc.js +244 -0
  463. package/dist/core/src/worker/sim-worker-base.js +558 -0
  464. package/dist/core/src/worker/sim-worker-host.js +271 -0
  465. package/dist/core/src/worker/task-pool.js +205 -0
  466. package/dist/core/src/worker/task-worker.js +77 -0
  467. package/dist/libraries/asset-browser/src/index.js +10 -0
  468. package/dist/libraries/asset-browser/src/software-thumbnails.js +940 -0
  469. package/dist/libraries/audio-kira/src/backend.js +405 -0
  470. package/dist/libraries/audio-kira/src/index.js +4 -0
  471. package/dist/libraries/audio-kira/src/library.js +54 -0
  472. package/dist/libraries/blitz-ui/src/index.js +13 -0
  473. package/dist/libraries/blitz-ui/src/native-module.js +162 -0
  474. package/dist/libraries/blitz-ui/src/native-osr-ffi.js +409 -0
  475. package/dist/libraries/blitz-ui/src/router.js +82 -0
  476. package/dist/libraries/blitz-ui/src/shaders/ui-blit.wgsl.js +32 -0
  477. package/dist/libraries/blitz-ui/src/ui-blit-pass.js +108 -0
  478. package/dist/libraries/character/src/character-animator.js +323 -0
  479. package/dist/libraries/character/src/customization.js +464 -0
  480. package/dist/libraries/character/src/index.js +19 -0
  481. package/dist/libraries/character/src/inspectable.js +77 -0
  482. package/dist/libraries/character/src/loader.js +336 -0
  483. package/dist/libraries/character/src/locomotion.js +84 -0
  484. package/dist/libraries/character/src/preview.js +280 -0
  485. package/dist/libraries/devtools/src/backend.js +449 -0
  486. package/dist/libraries/devtools/src/cdp-bridge.js +293 -0
  487. package/dist/libraries/devtools/src/collectors.js +318 -0
  488. package/dist/libraries/devtools/src/index.js +31 -0
  489. package/dist/libraries/devtools/src/native-providers.js +749 -0
  490. package/dist/libraries/devtools/src/snapshot.js +35 -0
  491. package/dist/libraries/devtools/src/verify.js +139 -0
  492. package/dist/libraries/devtools/src/web/browser.js +94 -0
  493. package/dist/libraries/devtools/src/web/host.js +183 -0
  494. package/dist/libraries/devtools/src/web/mirror.js +26 -0
  495. package/dist/libraries/devtools/src/web/server.js +187 -0
  496. package/dist/libraries/entities/src/index.js +3 -0
  497. package/dist/libraries/entities/src/library.js +46 -0
  498. package/dist/libraries/entities/src/model-renderer.js +1307 -0
  499. package/dist/libraries/entities/src/shaders/model.wgsl +375 -0
  500. package/dist/libraries/gamepad/src/feed-input.js +54 -0
  501. package/dist/libraries/gamepad/src/filters.js +44 -0
  502. package/dist/libraries/gamepad/src/glyphs.js +83 -0
  503. package/dist/libraries/gamepad/src/hub.js +164 -0
  504. package/dist/libraries/gamepad/src/index.js +10 -0
  505. package/dist/libraries/gamepad/src/library.js +56 -0
  506. package/dist/libraries/gamepad/src/source-sab.js +62 -0
  507. package/dist/libraries/gamepad/src/sysfs-enrich.js +125 -0
  508. package/dist/libraries/gaussian-splats/src/gpu-sort.js +506 -0
  509. package/dist/libraries/gaussian-splats/src/index.js +8 -0
  510. package/dist/libraries/gaussian-splats/src/library.js +44 -0
  511. package/dist/libraries/gaussian-splats/src/parser.js +297 -0
  512. package/dist/libraries/gaussian-splats/src/renderer.js +368 -0
  513. package/dist/libraries/gaussian-splats/src/sh-eval.js +196 -0
  514. package/dist/libraries/gaussian-splats/src/sorter.js +76 -0
  515. package/dist/libraries/gaussian-splats/src/tile-raster.js +424 -0
  516. package/dist/libraries/gpu-kernels/src/index.js +8 -0
  517. package/dist/libraries/gpu-kernels/src/kernel.js +591 -0
  518. package/dist/libraries/gpu-kernels/src/transpile.js +896 -0
  519. package/dist/libraries/html-ui-kit/src/behaviors.js +231 -0
  520. package/dist/libraries/html-ui-kit/src/components.js +219 -0
  521. package/dist/libraries/html-ui-kit/src/index.js +17 -0
  522. package/dist/libraries/html-ui-kit/src/nav/nav-controller.js +215 -0
  523. package/dist/libraries/html-ui-kit/src/nav/nav-input.js +138 -0
  524. package/dist/libraries/html-ui-kit/src/nav/osk.js +135 -0
  525. package/dist/libraries/html-ui-kit/src/nav/router.js +152 -0
  526. package/dist/libraries/html-ui-kit/src/nav/vcursor.js +177 -0
  527. package/dist/libraries/html-ui-kit/src/ten-foot.js +138 -0
  528. package/dist/libraries/html-ui-kit/src/theme.js +235 -0
  529. package/dist/libraries/inspectable/src/index.js +6 -0
  530. package/dist/libraries/inspectable/src/inspectable.js +205 -0
  531. package/dist/libraries/lighting/src/index.js +4 -0
  532. package/dist/libraries/lighting/src/library.js +48 -0
  533. package/dist/libraries/lighting/src/light-system.js +395 -0
  534. package/dist/libraries/lighting/src/lighting-system.js +57 -0
  535. package/dist/libraries/lighting/src/shaders/light-debug.wgsl +30 -0
  536. package/dist/libraries/marching-cubes/src/chunked-field.js +130 -0
  537. package/dist/libraries/marching-cubes/src/deformation.js +41 -0
  538. package/dist/libraries/marching-cubes/src/generator.js +356 -0
  539. package/dist/libraries/marching-cubes/src/index.js +13 -0
  540. package/dist/libraries/marching-cubes/src/library.js +54 -0
  541. package/dist/libraries/marching-cubes/src/lod.js +95 -0
  542. package/dist/libraries/marching-cubes/src/marching-tetrahedra.js +261 -0
  543. package/dist/libraries/marching-cubes/src/sab.js +40 -0
  544. package/dist/libraries/marching-cubes/src/streaming-config.js +28 -0
  545. package/dist/libraries/marching-cubes/src/streaming-manager.js +490 -0
  546. package/dist/libraries/marching-cubes/src/tables.js +314 -0
  547. package/dist/libraries/marching-cubes/src/types.js +1 -0
  548. package/dist/libraries/models/src/bake-node-transforms.js +146 -0
  549. package/dist/libraries/models/src/bind-unskinned-meshes.js +145 -0
  550. package/dist/libraries/models/src/codecs/basisu-codec.js +134 -0
  551. package/dist/libraries/models/src/codecs/draco-codec.js +236 -0
  552. package/dist/libraries/models/src/codecs/draco3dgltf.d.ts +40 -0
  553. package/dist/libraries/models/src/codecs/index.js +5 -0
  554. package/dist/libraries/models/src/codecs/meshopt-codec.js +59 -0
  555. package/dist/libraries/models/src/codecs/registry.js +111 -0
  556. package/dist/libraries/models/src/dae.js +665 -0
  557. package/dist/libraries/models/src/default-part-selection.js +58 -0
  558. package/dist/libraries/models/src/dxf.js +235 -0
  559. package/dist/libraries/models/src/fbx/index.js +438 -0
  560. package/dist/libraries/models/src/fbx/interpreter/animation.js +369 -0
  561. package/dist/libraries/models/src/fbx/interpreter/blend-shapes.js +283 -0
  562. package/dist/libraries/models/src/fbx/interpreter/connections.js +158 -0
  563. package/dist/libraries/models/src/fbx/interpreter/diagnostics.js +48 -0
  564. package/dist/libraries/models/src/fbx/interpreter/geometry.js +430 -0
  565. package/dist/libraries/models/src/fbx/interpreter/global-settings.js +77 -0
  566. package/dist/libraries/models/src/fbx/interpreter/materials.js +231 -0
  567. package/dist/libraries/models/src/fbx/interpreter/nodes.js +168 -0
  568. package/dist/libraries/models/src/fbx/interpreter/skeleton.js +454 -0
  569. package/dist/libraries/models/src/fbx/parsers/binary-parser.js +217 -0
  570. package/dist/libraries/models/src/fbx/types.js +88 -0
  571. package/dist/libraries/models/src/gltf-extensions.js +121 -0
  572. package/dist/libraries/models/src/gltf.js +724 -0
  573. package/dist/libraries/models/src/index.js +46 -0
  574. package/dist/libraries/models/src/library.js +44 -0
  575. package/dist/libraries/models/src/loader.js +218 -0
  576. package/dist/libraries/models/src/material-adapter.js +82 -0
  577. package/dist/libraries/models/src/mini-xml.js +145 -0
  578. package/dist/libraries/models/src/normalize.js +168 -0
  579. package/dist/libraries/models/src/obj.js +247 -0
  580. package/dist/libraries/models/src/off.js +94 -0
  581. package/dist/libraries/models/src/ply.js +329 -0
  582. package/dist/libraries/models/src/pose-sampler.js +183 -0
  583. package/dist/libraries/models/src/sidecar/blender-extras.js +32 -0
  584. package/dist/libraries/models/src/sidecar/ddmeta.js +98 -0
  585. package/dist/libraries/models/src/sidecar/godot-import.js +76 -0
  586. package/dist/libraries/models/src/sidecar/resolver.js +112 -0
  587. package/dist/libraries/models/src/sidecar/types.js +8 -0
  588. package/dist/libraries/models/src/sidecar/unity-meta.js +46 -0
  589. package/dist/libraries/models/src/skeleton-synthesis.js +122 -0
  590. package/dist/libraries/models/src/stl.js +129 -0
  591. package/dist/libraries/models/src/threeds.js +312 -0
  592. package/dist/libraries/models/src/threemf.js +203 -0
  593. package/dist/libraries/models/src/types.js +33 -0
  594. package/dist/libraries/models/src/vtk.js +242 -0
  595. package/dist/libraries/navmesh/src/crowd-system.js +207 -0
  596. package/dist/libraries/navmesh/src/debug-viz.js +52 -0
  597. package/dist/libraries/navmesh/src/index.js +7 -0
  598. package/dist/libraries/navmesh/src/library.js +47 -0
  599. package/dist/libraries/navmesh/src/navmesh-generator.js +364 -0
  600. package/dist/libraries/navmesh/src/navmesh.js +141 -0
  601. package/dist/libraries/navmesh/src/pathfinder.js +221 -0
  602. package/dist/libraries/navmesh/src/types.js +1 -0
  603. package/dist/libraries/networking/src/authority.js +107 -0
  604. package/dist/libraries/networking/src/connection.js +107 -0
  605. package/dist/libraries/networking/src/discovery.js +314 -0
  606. package/dist/libraries/networking/src/enhanced-replication.js +282 -0
  607. package/dist/libraries/networking/src/epic-adapter.js +101 -0
  608. package/dist/libraries/networking/src/index.js +16 -0
  609. package/dist/libraries/networking/src/library.js +45 -0
  610. package/dist/libraries/networking/src/lobby.js +84 -0
  611. package/dist/libraries/networking/src/platform-adapter.js +92 -0
  612. package/dist/libraries/networking/src/rcs-adapter.js +100 -0
  613. package/dist/libraries/networking/src/remote-input.js +162 -0
  614. package/dist/libraries/networking/src/replication.js +273 -0
  615. package/dist/libraries/networking/src/rpc.js +172 -0
  616. package/dist/libraries/networking/src/session.js +129 -0
  617. package/dist/libraries/networking/src/transport.js +156 -0
  618. package/dist/libraries/networking/src/webrtc.js +266 -0
  619. package/dist/libraries/pathfinding-2d/src/astar-grid.js +255 -0
  620. package/dist/libraries/pathfinding-2d/src/index.js +9 -0
  621. package/dist/libraries/persistence/src/autosave-manager.js +94 -0
  622. package/dist/libraries/persistence/src/binary-record-store.js +205 -0
  623. package/dist/libraries/persistence/src/browser.js +16 -0
  624. package/dist/libraries/persistence/src/file-save-store.js +507 -0
  625. package/dist/libraries/persistence/src/hash-utils.js +54 -0
  626. package/dist/libraries/persistence/src/index.js +17 -0
  627. package/dist/libraries/persistence/src/library.js +51 -0
  628. package/dist/libraries/persistence/src/mock-opfs.js +114 -0
  629. package/dist/libraries/persistence/src/node-fs-directory-handle.js +168 -0
  630. package/dist/libraries/persistence/src/opfs-save-store.js +584 -0
  631. package/dist/libraries/persistence/src/save-worker-proxy.js +96 -0
  632. package/dist/libraries/persistence/src/save-worker.js +76 -0
  633. package/dist/libraries/persistence/src/xxh3-ts.d.ts +10 -0
  634. package/dist/libraries/physics-native/src/backend.js +960 -0
  635. package/dist/libraries/physics-native/src/broadphase.js +79 -0
  636. package/dist/libraries/physics-native/src/index.js +6 -0
  637. package/dist/libraries/physics-native/src/library.js +57 -0
  638. package/dist/libraries/physics-native/src/narrowphase-shapes.js +348 -0
  639. package/dist/libraries/physics-native/src/narrowphase.js +60 -0
  640. package/dist/libraries/physics-native/src/solver.js +105 -0
  641. package/dist/libraries/physics-native/src/types.js +4 -0
  642. package/dist/libraries/physics-rapier/src/api.js +352 -0
  643. package/dist/libraries/physics-rapier/src/auto-backend.js +54 -0
  644. package/dist/libraries/physics-rapier/src/backend.js +1066 -0
  645. package/dist/libraries/physics-rapier/src/bulk-ops.js +46 -0
  646. package/dist/libraries/physics-rapier/src/ffi-backend.js +17 -0
  647. package/dist/libraries/physics-rapier/src/ffi-lib.js +605 -0
  648. package/dist/libraries/physics-rapier/src/index.js +9 -0
  649. package/dist/libraries/physics-rapier/src/library.js +71 -0
  650. package/dist/libraries/physics-rapier/src/rapier-backend.js +1102 -0
  651. package/dist/libraries/physics-rapier/src/realm-worker-script.js +233 -0
  652. package/dist/libraries/postfx/src/index.js +14 -0
  653. package/dist/libraries/postfx/src/library.js +207 -0
  654. package/dist/libraries/postfx/src/post-process-stack.js +1641 -0
  655. package/dist/libraries/postfx/src/shaders/post-process/afterimage.wgsl +14 -0
  656. package/dist/libraries/postfx/src/shaders/post-process/ascii.wgsl +24 -0
  657. package/dist/libraries/postfx/src/shaders/post-process/blit.wgsl +12 -0
  658. package/dist/libraries/postfx/src/shaders/post-process/bloom-blur.wgsl +21 -0
  659. package/dist/libraries/postfx/src/shaders/post-process/bloom-bright.wgsl +15 -0
  660. package/dist/libraries/postfx/src/shaders/post-process/bloom-composite.wgsl +14 -0
  661. package/dist/libraries/postfx/src/shaders/post-process/bloom-downsample.wgsl +60 -0
  662. package/dist/libraries/postfx/src/shaders/post-process/bloom-soft.wgsl +46 -0
  663. package/dist/libraries/postfx/src/shaders/post-process/bloom-upsample.wgsl +51 -0
  664. package/dist/libraries/postfx/src/shaders/post-process/channel-mixer.wgsl +36 -0
  665. package/dist/libraries/postfx/src/shaders/post-process/chromatic-aberration.wgsl +37 -0
  666. package/dist/libraries/postfx/src/shaders/post-process/dithering.wgsl +64 -0
  667. package/dist/libraries/postfx/src/shaders/post-process/dof.wgsl +131 -0
  668. package/dist/libraries/postfx/src/shaders/post-process/edges.wgsl +45 -0
  669. package/dist/libraries/postfx/src/shaders/post-process/fullscreen-vs.wgsl +15 -0
  670. package/dist/libraries/postfx/src/shaders/post-process/fxaa.wgsl +102 -0
  671. package/dist/libraries/postfx/src/shaders/post-process/gaussian-blur.wgsl +37 -0
  672. package/dist/libraries/postfx/src/shaders/post-process/glow-blur.wgsl +33 -0
  673. package/dist/libraries/postfx/src/shaders/post-process/glow-composite.wgsl +25 -0
  674. package/dist/libraries/postfx/src/shaders/post-process/grain.wgsl +37 -0
  675. package/dist/libraries/postfx/src/shaders/post-process/halftone.wgsl +80 -0
  676. package/dist/libraries/postfx/src/shaders/post-process/highlight-blur.wgsl +33 -0
  677. package/dist/libraries/postfx/src/shaders/post-process/highlight-composite.wgsl +32 -0
  678. package/dist/libraries/postfx/src/shaders/post-process/lens-distortion.wgsl +43 -0
  679. package/dist/libraries/postfx/src/shaders/post-process/lens-flare.wgsl +68 -0
  680. package/dist/libraries/postfx/src/shaders/post-process/lut.wgsl +30 -0
  681. package/dist/libraries/postfx/src/shaders/post-process/motion-blur.wgsl +55 -0
  682. package/dist/libraries/postfx/src/shaders/post-process/occluder-chunk.wgsl +28 -0
  683. package/dist/libraries/postfx/src/shaders/post-process/outline.wgsl +51 -0
  684. package/dist/libraries/postfx/src/shaders/post-process/pixelation.wgsl +47 -0
  685. package/dist/libraries/postfx/src/shaders/post-process/sharpen.wgsl +32 -0
  686. package/dist/libraries/postfx/src/shaders/post-process/sobel.wgsl +26 -0
  687. package/dist/libraries/postfx/src/shaders/post-process/split-tone.wgsl +36 -0
  688. package/dist/libraries/postfx/src/shaders/post-process/ssao-blur.wgsl +38 -0
  689. package/dist/libraries/postfx/src/shaders/post-process/ssao-composite.wgsl +25 -0
  690. package/dist/libraries/postfx/src/shaders/post-process/ssao.wgsl +147 -0
  691. package/dist/libraries/postfx/src/shaders/post-process/ssr.wgsl +155 -0
  692. package/dist/libraries/postfx/src/shaders/post-process/taa.wgsl +98 -0
  693. package/dist/libraries/postfx/src/shaders/post-process/tonemap.wgsl +40 -0
  694. package/dist/libraries/postfx/src/shaders/post-process/watercolor.wgsl +82 -0
  695. package/dist/libraries/postfx/src/shaders/post-process/white-balance.wgsl +41 -0
  696. package/dist/libraries/recast/src/backend.js +124 -0
  697. package/dist/libraries/recast/src/crowd-system.js +310 -0
  698. package/dist/libraries/recast/src/index.js +4 -0
  699. package/dist/libraries/recast/src/library.js +59 -0
  700. package/dist/libraries/recast/src/types.js +4 -0
  701. package/dist/libraries/sand/src/cell.js +32 -0
  702. package/dist/libraries/sand/src/fields.js +27 -0
  703. package/dist/libraries/sand/src/fluid-grid.js +267 -0
  704. package/dist/libraries/sand/src/grid-dims.js +47 -0
  705. package/dist/libraries/sand/src/grid-sim-buffer.js +184 -0
  706. package/dist/libraries/sand/src/index.js +20 -0
  707. package/dist/libraries/sand/src/library.js +67 -0
  708. package/dist/libraries/sand/src/materials.js +437 -0
  709. package/dist/libraries/sand/src/palette.js +87 -0
  710. package/dist/libraries/sand/src/particles.js +163 -0
  711. package/dist/libraries/sand/src/render/sand-grid-pass.js +377 -0
  712. package/dist/libraries/sand/src/rng.js +44 -0
  713. package/dist/libraries/sand/src/rules/builtin-rules.js +125 -0
  714. package/dist/libraries/sand/src/rules/rule-compiler.js +164 -0
  715. package/dist/libraries/sand/src/rules/rule-engine.js +210 -0
  716. package/dist/libraries/sand/src/rules/rule-types.js +27 -0
  717. package/dist/libraries/sand/src/sand-step-pool.js +458 -0
  718. package/dist/libraries/sand/src/sand-step-worker.js +101 -0
  719. package/dist/libraries/sand/src/sand-world.js +3382 -0
  720. package/dist/libraries/stickman/src/index.js +7 -0
  721. package/dist/libraries/stickman/src/library.js +44 -0
  722. package/dist/libraries/stickman/src/proportions.js +40 -0
  723. package/dist/libraries/stickman/src/shader.js +113 -0
  724. package/dist/libraries/stickman/src/skeleton.js +163 -0
  725. package/dist/libraries/stickman/src/stickman-pass.js +210 -0
  726. package/dist/libraries/stickman/src/thick-line.js +120 -0
  727. package/dist/libraries/surface-nets/src/chunked-field.js +5 -0
  728. package/dist/libraries/surface-nets/src/deformation.js +29 -0
  729. package/dist/libraries/surface-nets/src/index.js +15 -0
  730. package/dist/libraries/surface-nets/src/library.js +41 -0
  731. package/dist/libraries/surface-nets/src/lod.js +6 -0
  732. package/dist/libraries/surface-nets/src/sab.js +4 -0
  733. package/dist/libraries/surface-nets/src/streaming-config.js +4 -0
  734. package/dist/libraries/surface-nets/src/streaming-manager.js +9 -0
  735. package/dist/libraries/surface-nets/src/surface-nets.js +361 -0
  736. package/dist/libraries/surface-nets/src/types.js +1 -0
  737. package/dist/libraries/water/src/buoyancy.js +80 -0
  738. package/dist/libraries/water/src/index.js +12 -0
  739. package/dist/libraries/water/src/library.js +65 -0
  740. package/dist/libraries/water/src/shore-damping.js +70 -0
  741. package/dist/libraries/water/src/water-buffer.js +78 -0
  742. package/dist/libraries/water/src/water-chunks.js +5 -0
  743. package/dist/libraries/water/src/water-physics.js +315 -0
  744. package/dist/libraries/water/src/water-renderer.js +736 -0
  745. package/dist/libraries/water/src/water-sab.js +138 -0
  746. package/dist/libraries/water/src/wave-sources.js +45 -0
  747. package/dist/libraries/weather/src/index.js +5 -0
  748. package/dist/libraries/weather/src/library.js +48 -0
  749. package/dist/libraries/weather/src/types.js +29 -0
  750. package/dist/libraries/weather/src/weather-blend.js +108 -0
  751. package/dist/libraries/weather/src/weather-system.js +275 -0
  752. package/dist/libraries/weatherfx/src/cloud-provider.js +5 -0
  753. package/dist/libraries/weatherfx/src/cloud-system.js +294 -0
  754. package/dist/libraries/weatherfx/src/index.js +4 -0
  755. package/dist/libraries/weatherfx/src/library.js +41 -0
  756. package/dist/libraries/weatherfx/src/particle-system.js +350 -0
  757. package/dist/libraries/weatherfx/src/shaders/cloud.wgsl +111 -0
  758. package/dist/libraries/weatherfx/src/shaders/particle-compute.wgsl +187 -0
  759. package/dist/libraries/weatherfx/src/shaders/particle-render.wgsl +95 -0
  760. package/dist/mcp/src/client.js +669 -0
  761. package/dist/mcp/src/engine-context.js +99 -0
  762. package/dist/mcp/src/http-transport.js +423 -0
  763. package/dist/mcp/src/index.js +5 -0
  764. package/dist/mcp/src/prompts/add-entity.js +39 -0
  765. package/dist/mcp/src/prompts/create-scene.js +41 -0
  766. package/dist/mcp/src/prompts/debug-frame.js +36 -0
  767. package/dist/mcp/src/prompts/index.js +10 -0
  768. package/dist/mcp/src/resources/asset-list.js +28 -0
  769. package/dist/mcp/src/resources/checkpoint-list.js +29 -0
  770. package/dist/mcp/src/resources/entity-state.js +45 -0
  771. package/dist/mcp/src/resources/gpu-info.js +90 -0
  772. package/dist/mcp/src/resources/index.js +51 -0
  773. package/dist/mcp/src/resources/performance.js +33 -0
  774. package/dist/mcp/src/resources/scene-tree.js +37 -0
  775. package/dist/mcp/src/server.js +307 -0
  776. package/dist/mcp/src/tools/animation.js +102 -0
  777. package/dist/mcp/src/tools/asset.js +146 -0
  778. package/dist/mcp/src/tools/audio.js +80 -0
  779. package/dist/mcp/src/tools/build.js +128 -0
  780. package/dist/mcp/src/tools/camera.js +157 -0
  781. package/dist/mcp/src/tools/checkpoint.js +90 -0
  782. package/dist/mcp/src/tools/component.js +176 -0
  783. package/dist/mcp/src/tools/debug.js +273 -0
  784. package/dist/mcp/src/tools/entity.js +309 -0
  785. package/dist/mcp/src/tools/inspect.js +192 -0
  786. package/dist/mcp/src/tools/lighting.js +239 -0
  787. package/dist/mcp/src/tools/material.js +225 -0
  788. package/dist/mcp/src/tools/mesh.js +210 -0
  789. package/dist/mcp/src/tools/physics.js +251 -0
  790. package/dist/mcp/src/tools/scene.js +139 -0
  791. package/dist/mcp/src/tools/script.js +114 -0
  792. package/dist/mcp/src/types.js +9 -0
  793. package/dist/mcp/src/undo-redo.js +64 -0
  794. package/dist/modules/camera-controls/src/index.js +116 -0
  795. package/dist/modules/controller-ui/src/index.js +149 -0
  796. package/dist/modules/devtools/src/api.js +317 -0
  797. package/dist/modules/devtools/src/asset-utils.js +102 -0
  798. package/dist/modules/devtools/src/bind-debug-store.js +34 -0
  799. package/dist/modules/devtools/src/blitz/host.js +391 -0
  800. package/dist/modules/devtools/src/blitz/module.js +65 -0
  801. package/dist/modules/devtools/src/blitz/panels/console.js +217 -0
  802. package/dist/modules/devtools/src/blitz/panels/elements.js +79 -0
  803. package/dist/modules/devtools/src/blitz/panels/gpu.js +61 -0
  804. package/dist/modules/devtools/src/blitz/panels/performance.js +113 -0
  805. package/dist/modules/devtools/src/blitz/panels/snapshot.js +141 -0
  806. package/dist/modules/devtools/src/blitz/panels/types.js +55 -0
  807. package/dist/modules/devtools/src/blitz/theme.js +167 -0
  808. package/dist/modules/devtools/src/data-bridge.js +247 -0
  809. package/dist/modules/devtools/src/debug-overlay.js +181 -0
  810. package/dist/modules/devtools/src/debug-raycast.js +296 -0
  811. package/dist/modules/devtools/src/debug-store.js +28 -0
  812. package/dist/modules/devtools/src/debug-view-descriptors.js +24 -0
  813. package/dist/modules/devtools/src/doctor-panel.js +163 -0
  814. package/dist/modules/devtools/src/gizmo-module.js +95 -0
  815. package/dist/modules/devtools/src/graph-model.js +387 -0
  816. package/dist/modules/devtools/src/grid-renderer.js +145 -0
  817. package/dist/modules/devtools/src/height-ruler-renderer.js +189 -0
  818. package/dist/modules/devtools/src/index.js +46 -0
  819. package/dist/modules/devtools/src/init.js +204 -0
  820. package/dist/modules/devtools/src/label-overlay.js +129 -0
  821. package/dist/modules/devtools/src/material-stats-panel.js +171 -0
  822. package/dist/modules/devtools/src/profiling-bridge.js +288 -0
  823. package/dist/modules/devtools/src/profiling-hooks.js +63 -0
  824. package/dist/modules/devtools/src/renderer-adapter.js +61 -0
  825. package/dist/modules/devtools/src/scene-inspector.js +571 -0
  826. package/dist/modules/devtools/src/scene-store.js +212 -0
  827. package/dist/modules/devtools/src/scene-sync.js +92 -0
  828. package/dist/modules/devtools/src/shaders/transform-gizmo.wgsl +38 -0
  829. package/dist/modules/devtools/src/sim-stats-panel.js +250 -0
  830. package/dist/modules/devtools/src/sim-stats-provider.js +73 -0
  831. package/dist/modules/devtools/src/skeleton-renderer.js +326 -0
  832. package/dist/modules/devtools/src/transform-gizmo.js +677 -0
  833. package/dist/modules/devtools/src/types.js +5 -0
  834. package/dist/modules/devtools/src/worker-expose.js +59 -0
  835. package/dist/modules/devtools/src/worker-sync.js +115 -0
  836. package/dist/modules/editor/src/commands/component.js +151 -0
  837. package/dist/modules/editor/src/commands/entity.js +253 -0
  838. package/dist/modules/editor/src/commands/hierarchy.js +79 -0
  839. package/dist/modules/editor/src/commands/index.js +57 -0
  840. package/dist/modules/editor/src/commands/prefab.js +149 -0
  841. package/dist/modules/editor/src/commands/registry.js +246 -0
  842. package/dist/modules/editor/src/commands/scene-io.js +206 -0
  843. package/dist/modules/editor/src/commands/selection.js +71 -0
  844. package/dist/modules/editor/src/commands/transform.js +88 -0
  845. package/dist/modules/editor/src/ddscene.js +189 -0
  846. package/dist/modules/editor/src/document.js +96 -0
  847. package/dist/modules/editor/src/editor-context.js +115 -0
  848. package/dist/modules/editor/src/index.js +11 -0
  849. package/dist/modules/editor/src/mcp.js +91 -0
  850. package/dist/modules/editor/src/module.js +115 -0
  851. package/dist/modules/editor/src/selection.js +60 -0
  852. package/dist/modules/editor/src/shell.js +397 -0
  853. package/dist/modules/editor/src/viewport.js +186 -0
  854. package/dist/modules/html-ui/src/composite.js +116 -0
  855. package/dist/modules/html-ui/src/create-html-ui.js +137 -0
  856. package/dist/modules/html-ui/src/doc-backend.js +518 -0
  857. package/dist/modules/html-ui/src/host.js +819 -0
  858. package/dist/modules/html-ui/src/index.js +5 -0
  859. package/dist/modules/html-ui/src/jsx-dev-runtime.js +9 -0
  860. package/dist/modules/html-ui/src/jsx-runtime.js +121 -0
  861. package/dist/modules/html-ui/src/protocol.js +6 -0
  862. package/dist/modules/html-ui/src/ui-worker.js +10 -0
  863. package/dist/modules/mcp/src/index.js +62 -0
  864. package/dist/modules/movement-2d/src/grid-character.js +345 -0
  865. package/dist/modules/movement-2d/src/index.js +27 -0
  866. package/dist/modules/movement-3d/src/character-motor.js +166 -0
  867. package/dist/modules/movement-3d/src/index.js +27 -0
  868. package/dist/modules/native-osr/src/index.js +12 -0
  869. package/dist/modules/native-osr/src/input-router.js +335 -0
  870. package/dist/modules/native-osr/src/native-osr-manager.js +210 -0
  871. package/dist/modules/native-osr/src/native-texture-source.js +66 -0
  872. package/dist/modules/native-osr/src/types.js +8 -0
  873. package/dist/modules/native-osr/src/world-space-ui-pass.js +313 -0
  874. package/dist/modules/sailing/src/index.js +39 -0
  875. package/dist/modules/terrain/src/index.js +44 -0
  876. package/dist/modules/vitals/src/index.js +25 -0
  877. package/dist/modules/vitals/src/vitals.js +195 -0
  878. package/dist/modules/xr/src/camera-rig.js +119 -0
  879. package/dist/modules/xr/src/debug.js +45 -0
  880. package/dist/modules/xr/src/frame-loop.js +139 -0
  881. package/dist/modules/xr/src/index.js +10 -0
  882. package/dist/modules/xr/src/input.js +164 -0
  883. package/dist/modules/xr/src/layer.js +100 -0
  884. package/dist/modules/xr/src/session.js +133 -0
  885. package/dist/modules/xr/src/sim-module.js +21 -0
  886. package/dist/modules/xr/src/types.js +4 -0
  887. package/dist/modules/xr/src/webxr.d.ts +182 -0
  888. package/dist/modules/xr/src/xr-module.js +134 -0
  889. package/dist/shader-graph/src/chunks.js +340 -0
  890. package/dist/shader-graph/src/compiler.js +639 -0
  891. package/dist/shader-graph/src/compute-compiler.js +384 -0
  892. package/dist/shader-graph/src/compute-graph.js +55 -0
  893. package/dist/shader-graph/src/compute-profiles.js +39 -0
  894. package/dist/shader-graph/src/graph.js +38 -0
  895. package/dist/shader-graph/src/index.js +15 -0
  896. package/dist/shader-graph/src/profiles.js +305 -0
  897. package/dist/shader-graph/src/validator.js +42 -0
  898. package/dist/shader-graph/src/wgsl-binding-validator.js +110 -0
  899. package/dist/shader-graph/src/wgsl-struct-validator.js +222 -0
  900. package/dist/shader-graph/src/wgsl-struct.js +251 -0
  901. package/dist/test/src/index.js +1 -0
  902. package/dist/test/src/vision-test.js +228 -0
  903. package/libraries/asset-browser/src/software-thumbnails.ts +2 -2
  904. package/libraries/audio-kira/src/backend.ts +2 -1
  905. package/libraries/blitz-ui/native/src/shell.rs +35 -1
  906. package/libraries/blitz-ui/native-osr/Cargo.toml +8 -0
  907. package/libraries/blitz-ui/native-osr/src/lib.rs +213 -22
  908. package/libraries/blitz-ui/native-osr/src/mutate.rs +109 -14
  909. package/libraries/blitz-ui/src/native-osr-ffi.ts +71 -8
  910. package/libraries/blitz-ui/src/router.ts +3 -1
  911. package/libraries/blitz-ui/src/ui-blit-pass.ts +1 -1
  912. package/libraries/character/src/character-animator.ts +1 -1
  913. package/libraries/character/src/customization.ts +513 -0
  914. package/libraries/character/src/index.ts +6 -0
  915. package/libraries/character/src/inspectable.ts +111 -0
  916. package/libraries/character/src/loader.ts +38 -13
  917. package/libraries/character/src/locomotion.ts +13 -1
  918. package/libraries/character/src/preview.ts +94 -24
  919. package/libraries/devtools/README.md +16 -18
  920. package/libraries/devtools/src/backend.ts +505 -0
  921. package/libraries/devtools/src/cdp-bridge.ts +8 -8
  922. package/libraries/devtools/src/collectors.ts +41 -37
  923. package/libraries/devtools/src/index.ts +32 -14
  924. package/libraries/devtools/src/native-providers.ts +20 -12
  925. package/libraries/devtools/src/snapshot.ts +77 -0
  926. package/libraries/devtools/src/web/host.ts +11 -12
  927. package/libraries/devtools/src/web/mirror.ts +14 -405
  928. package/libraries/devtools/src/web/server.ts +4 -3
  929. package/libraries/entities/src/model-renderer.ts +96 -23
  930. package/libraries/gamepad/src/library.ts +2 -1
  931. package/libraries/inspectable/src/index.ts +11 -0
  932. package/libraries/inspectable/src/inspectable.ts +277 -0
  933. package/libraries/marching-cubes/src/streaming-manager.ts +4 -4
  934. package/libraries/models/src/bind-unskinned-meshes.ts +131 -0
  935. package/libraries/models/src/index.ts +1 -0
  936. package/libraries/models/src/types.ts +22 -0
  937. package/libraries/persistence/src/autosave-manager.ts +1 -1
  938. package/libraries/persistence/src/binary-record-store.ts +1 -1
  939. package/libraries/persistence/src/file-save-store.ts +4 -4
  940. package/libraries/persistence/src/library.ts +1 -1
  941. package/libraries/persistence/src/opfs-save-store.ts +5 -5
  942. package/libraries/persistence/src/save-worker.ts +13 -14
  943. package/libraries/physics-rapier/src/ffi-lib.ts +2 -1
  944. package/libraries/postfx/src/post-process-stack.ts +1 -1
  945. package/libraries/sand/src/sand-step-pool.ts +5 -0
  946. package/libraries/water/src/water-renderer.ts +1 -1
  947. package/libraries/weatherfx/src/cloud-system.ts +3 -3
  948. package/mcp/README.md +20 -0
  949. package/mcp/src/client.ts +75 -22
  950. package/mcp/src/undo-redo.ts +2 -2
  951. package/modules/devtools/src/blitz/host.ts +430 -0
  952. package/modules/devtools/src/blitz/module.ts +101 -0
  953. package/modules/devtools/src/blitz/panels/console.ts +223 -0
  954. package/modules/devtools/src/blitz/panels/elements.ts +92 -0
  955. package/modules/devtools/src/blitz/panels/gpu.ts +70 -0
  956. package/modules/devtools/src/blitz/panels/performance.ts +120 -0
  957. package/modules/devtools/src/blitz/panels/snapshot.ts +152 -0
  958. package/modules/devtools/src/blitz/panels/types.ts +120 -0
  959. package/modules/devtools/src/blitz/theme.ts +168 -0
  960. package/modules/devtools/src/data-bridge.ts +1 -1
  961. package/modules/devtools/src/index.ts +6 -0
  962. package/modules/devtools/src/profiling-bridge.ts +17 -13
  963. package/modules/devtools/src/profiling-hooks.ts +22 -13
  964. package/modules/devtools/src/scene-inspector.ts +1 -1
  965. package/modules/devtools/src/worker-sync.ts +9 -1
  966. package/modules/editor/src/commands/registry.ts +2 -2
  967. package/modules/editor/src/module.ts +1 -1
  968. package/modules/html-ui/src/composite.ts +1 -1
  969. package/modules/html-ui/src/create-html-ui.ts +21 -9
  970. package/modules/html-ui/src/doc-backend.ts +189 -10
  971. package/modules/html-ui/src/host.ts +354 -40
  972. package/modules/html-ui/src/index.ts +1 -1
  973. package/modules/html-ui/src/jsx-runtime.ts +1 -1
  974. package/modules/html-ui/src/protocol.ts +53 -6
  975. package/modules/mcp/README.md +6 -0
  976. package/modules/mcp/src/index.ts +70 -3
  977. package/modules/movement-3d/src/character-motor.ts +83 -10
  978. package/package.json +838 -165
  979. package/shader-graph/README.md +25 -0
  980. package/test/README.md +16 -0
  981. package/libraries/blitz-ui/native-osr-spike.ts +0 -70
  982. package/libraries/devtools/native/Cargo.toml +0 -12
  983. package/libraries/devtools/native/src/lib.rs +0 -1646
  984. package/libraries/devtools/native/src/panels/console.rs +0 -338
  985. package/libraries/devtools/native/src/panels/dom_tree.rs +0 -47
  986. package/libraries/devtools/native/src/panels/generic.rs +0 -317
  987. package/libraries/devtools/native/src/panels/gpu.rs +0 -107
  988. package/libraries/devtools/native/src/panels/input.rs +0 -88
  989. package/libraries/devtools/native/src/panels/mod.rs +0 -154
  990. package/libraries/devtools/native/src/panels/perf_metrics.rs +0 -91
  991. package/libraries/devtools/native/src/panels/perf_recorder.rs +0 -158
  992. package/libraries/devtools/native/src/panels/scene.rs +0 -72
  993. package/libraries/devtools/native/src/state.rs +0 -394
  994. package/libraries/devtools/src/egui-ffi.ts +0 -804
  995. package/libraries/devtools/src/egui-renderer.ts +0 -407
  996. package/libraries/devtools/src/host.ts +0 -363
  997. package/libraries/devtools/src/mirror.ts +0 -794
  998. package/libraries/models/test-fixtures/fbx/LICENSE-notice.txt +0 -24
  999. package/libraries/models/test-fixtures/fbx/README.md +0 -46
  1000. package/libraries/models/test-fixtures/fbx/m01_cube_phong.fbx +0 -0
  1001. package/libraries/models/test-fixtures/fbx/m02_geo_ngons.fbx +0 -0
  1002. package/libraries/models/test-fixtures/fbx/m03_normals.fbx +0 -0
  1003. package/libraries/models/test-fixtures/fbx/m04_material_properties.fbx +0 -0
  1004. package/libraries/models/test-fixtures/fbx/m05_external_diffuse.png +0 -0
  1005. package/libraries/models/test-fixtures/fbx/m05_textures.fbx +0 -0
  1006. package/libraries/models/test-fixtures/fbx/m06_uv_transform.fbx +0 -0
  1007. package/libraries/models/test-fixtures/fbx/m07_multimaterial.fbx +0 -0
  1008. package/libraries/models/test-fixtures/fbx/m08_transforms.fbx +0 -0
  1009. package/libraries/models/test-fixtures/fbx/m09_skinning.fbx +0 -0
  1010. package/libraries/models/test-fixtures/fbx/m10_morph.fbx +0 -0
  1011. package/libraries/models/test-fixtures/fbx/m11_node_anim.fbx +0 -0
  1012. package/libraries/models/test-fixtures/fbx/m12_skeletal_anim.fbx +0 -0
  1013. package/libraries/models/test-fixtures/fbx/m13_morph_anim.fbx +0 -0
  1014. package/libraries/models/test-fixtures/fbx/m14_multiclip.fbx +0 -0
  1015. package/libraries/models/test-fixtures/fbx/m15_camera_lights.fbx +0 -0
  1016. package/libraries/models/test-fixtures/fbx/m16_axis_yup.fbx +0 -0
  1017. package/libraries/models/test-fixtures/fbx/m16_axis_zup.fbx +0 -0
  1018. package/libraries/models/test-fixtures/fbx/m16_units_254.fbx +0 -0
  1019. package/libraries/physics-native/src/ffi-spike-worker.ts +0 -71
  1020. package/libraries/physics-rapier/bench/ffi-bench.ts +0 -79
  1021. package/libraries/physics-rapier/bench/wasm-baseline.ts +0 -90
@@ -11,17 +11,18 @@
11
11
  //! buffer) or `dd_osr_frame_into` (copy into a host-bound SharedArrayBuffer —
12
12
  //! the zero-copy path used by the html-ui worker channel).
13
13
 
14
+ use std::collections::HashSet;
14
15
  use std::os::raw::c_int;
15
16
  use std::panic::{catch_unwind, AssertUnwindSafe};
16
17
  use std::str::FromStr;
17
18
  use std::sync::atomic::{AtomicBool, Ordering};
18
- use std::sync::Arc;
19
+ use std::sync::{Arc, Mutex, OnceLock};
19
20
  use std::time::Instant;
20
21
 
21
22
  use anyrender::ImageRenderer;
22
23
  use anyrender_vello_cpu::VelloCpuImageRenderer;
23
24
  use atomic_refcell::AtomicRefCell;
24
- use blitz_dom::{Document, DocumentConfig, EventDriver, FontContext};
25
+ use blitz_dom::{BaseDocument, Document, DocumentConfig, EventDriver, FontContext};
25
26
  use blitz_html::HtmlDocument;
26
27
  use blitz_paint::paint_scene;
27
28
  use blitz_traits::events::{
@@ -92,6 +93,35 @@ impl ShellProvider for FlagShell {
92
93
  fn request_redraw(&self) {
93
94
  self.flag.store(true, Ordering::Relaxed);
94
95
  }
96
+
97
+ #[cfg(not(target_os = "android"))]
98
+ fn get_clipboard_text(&self) -> Result<String, blitz_traits::shell::ClipboardError> {
99
+ clipboard()
100
+ .and_then(|mut cb| cb.get_text().ok())
101
+ .ok_or(blitz_traits::shell::ClipboardError)
102
+ }
103
+
104
+ #[cfg(not(target_os = "android"))]
105
+ fn set_clipboard_text(&self, text: String) -> Result<(), blitz_traits::shell::ClipboardError> {
106
+ clipboard()
107
+ .and_then(|mut cb| cb.set_text(text).ok())
108
+ .ok_or(blitz_traits::shell::ClipboardError)
109
+ }
110
+ }
111
+
112
+ /// Long-lived process clipboard. On X11 the clipboard owner must keep serving
113
+ /// selection requests while it owns the selection, so a fresh `Clipboard` per
114
+ /// call is wrong: its `Drop` hands contents to the clipboard manager and
115
+ /// destroys the server window, which races requesters and can leave stale or
116
+ /// empty contents. Klipper already snapshots content on ownership changes, so
117
+ /// keeping the context alive for the process is the normal-app pattern.
118
+ #[cfg(not(target_os = "android"))]
119
+ fn clipboard() -> Option<std::sync::MutexGuard<'static, arboard::Clipboard>> {
120
+ static CB: std::sync::OnceLock<Option<std::sync::Mutex<arboard::Clipboard>>> =
121
+ std::sync::OnceLock::new();
122
+ CB.get_or_init(|| arboard::Clipboard::new().ok().map(std::sync::Mutex::new))
123
+ .as_ref()
124
+ .and_then(|m| m.lock().ok())
95
125
  }
96
126
 
97
127
  fn build_doc(
@@ -167,6 +197,67 @@ pub struct OsrDoc {
167
197
  pub(crate) rect_buf: [f64; 4],
168
198
  /// Owned node-id list written by dd_osr_query_all.
169
199
  pub(crate) query_buf: Vec<u64>,
200
+ /// Serialization flag — set for the duration of each FFI call. The ABI
201
+ /// exposes a raw `*mut OsrDoc`, so nothing prevents a host from calling
202
+ /// the same doc from two threads at once (which would alias `&mut` and
203
+ /// corrupt the DOM instantly). Callers that arrive while busy get -1.
204
+ busy: AtomicBool,
205
+ }
206
+
207
+ // ── Handle registry + per-doc call serialization ──
208
+ //
209
+ // Every handle handed out by dd_osr_init is registered here and removed by
210
+ // dd_osr_destroy *before* the Box is freed, so FFI entry points can tell a
211
+ // live handle from a stale/garbage pointer without dereferencing it. The
212
+ // `busy` flag is then swapped under the registry lock so the
213
+ // contains-check → claim sequence is atomic against destroy: after a doc
214
+ // leaves the registry no thread can newly enter it, and destroy only frees
215
+ // the Box once it owns `busy` (no in-flight call).
216
+ static DOCS: OnceLock<Mutex<HashSet<usize>>> = OnceLock::new();
217
+
218
+ fn docs() -> Option<&'static Mutex<HashSet<usize>>> {
219
+ // Mutex poisoning turns into a permanent OSR outage if a call ever panics
220
+ // while holding it — treat a poisoned/lock failure as "unknown handle".
221
+ DOCS.get_or_init(|| Mutex::new(HashSet::new())).into()
222
+ }
223
+
224
+ /// RAII claim on a live doc — releases `busy` on drop (including unwind).
225
+ pub(crate) struct DocGuard {
226
+ doc: *mut OsrDoc,
227
+ }
228
+
229
+ impl DocGuard {
230
+ /// Safety: registry membership keeps the Box alive (destroy removes the
231
+ /// handle before freeing) and `busy` guarantees exclusive access.
232
+ pub(crate) fn get(&mut self) -> &mut OsrDoc {
233
+ unsafe { &mut *self.doc }
234
+ }
235
+ }
236
+
237
+ impl Drop for DocGuard {
238
+ fn drop(&mut self) {
239
+ unsafe { (*self.doc).busy.store(false, Ordering::Release) };
240
+ }
241
+ }
242
+
243
+ /// Validate `handle` against the live-doc registry and claim exclusive
244
+ /// access to it. Returns None for null/stale handles or a doc already
245
+ /// inside an FFI call.
246
+ pub(crate) fn doc_enter(handle: *mut OsrDoc) -> Option<DocGuard> {
247
+ if handle.is_null() {
248
+ return None;
249
+ }
250
+ let key = handle as usize;
251
+ let reg = docs()?.lock().ok()?;
252
+ if !reg.contains(&key) {
253
+ return None;
254
+ }
255
+ // SAFETY: still under the registry lock — the doc cannot be freed here.
256
+ let d = unsafe { &*handle };
257
+ if d.busy.swap(true, Ordering::Acquire) {
258
+ return None;
259
+ }
260
+ Some(DocGuard { doc: handle })
170
261
  }
171
262
 
172
263
  /// O(1) "did anything change" check: Blitz propagates a damaged_descendants
@@ -269,6 +360,13 @@ pub extern "C" fn dd_osr_init(
269
360
  html_len: usize,
270
361
  ) -> *mut OsrDoc {
271
362
  ffi(std::ptr::null_mut(), || {
363
+ static LOG_INIT: std::sync::Once = std::sync::Once::new();
364
+ LOG_INIT.call_once(|| {
365
+ let _ = env_logger::Builder::from_env(
366
+ env_logger::Env::default().default_filter_or("off"),
367
+ )
368
+ .try_init();
369
+ });
272
370
  let Some(html) = (unsafe { read_str(html_ptr, html_len) }) else {
273
371
  return std::ptr::null_mut();
274
372
  };
@@ -294,8 +392,20 @@ pub extern "C" fn dd_osr_init(
294
392
  out_buf: Vec::new(),
295
393
  rect_buf: [0.0; 4],
296
394
  query_buf: Vec::new(),
395
+ busy: AtomicBool::new(false),
297
396
  };
298
- Box::into_raw(Box::new(doc))
397
+ let handle = Box::into_raw(Box::new(doc));
398
+ match docs().and_then(|m| m.lock().ok()) {
399
+ Some(mut reg) => {
400
+ reg.insert(handle as usize);
401
+ handle
402
+ }
403
+ // Registry unavailable — don't hand out an untracked handle.
404
+ None => {
405
+ drop(unsafe { Box::from_raw(handle) });
406
+ std::ptr::null_mut()
407
+ }
408
+ }
299
409
  })
300
410
  }
301
411
 
@@ -305,9 +415,10 @@ pub extern "C" fn dd_osr_init(
305
415
  #[no_mangle]
306
416
  pub extern "C" fn dd_osr_set_html(handle: *mut OsrDoc, html_ptr: *const u8, html_len: usize) -> c_int {
307
417
  ffi(-1, || {
308
- let Some(d) = (unsafe { handle.as_mut() }) else {
418
+ let Some(mut g) = doc_enter(handle) else {
309
419
  return -1;
310
420
  };
421
+ let d = g.get();
311
422
  let Some(html) = (unsafe { read_str(html_ptr, html_len) }) else {
312
423
  return -2;
313
424
  };
@@ -323,6 +434,39 @@ pub extern "C" fn dd_osr_set_html(handle: *mut OsrDoc, html_ptr: *const u8, html
323
434
  })
324
435
  }
325
436
 
437
+ /// taffy's `round_layout` snaps each border side to whole layout units via
438
+ /// `round(c + w) - round(c)`, so a sub-unit border side (a 1px border at
439
+ /// zoom 1.25 computes as 0.8px) can round to 0 depending on the node's
440
+ /// cumulative position. A zero side makes blitz-paint's corner-split math
441
+ /// divide by zero and emit NaN border paths — the adjacent edges (e.g. the
442
+ /// left border) then paint nothing. Restore any side taffy collapsed that
443
+ /// layout says is nonzero.
444
+ fn restore_collapsed_borders(doc: &mut BaseDocument) {
445
+ let root = doc.root_element().id;
446
+ doc.iter_subtree_mut(root, |id, doc| {
447
+ let Some(node) = doc.get_node_mut(id) else {
448
+ return;
449
+ };
450
+ let Some(ld) = node.try_layout_data_mut() else {
451
+ return;
452
+ };
453
+ let ub = ld.unrounded_layout.border;
454
+ let fb = &mut ld.final_layout.border;
455
+ if fb.left == 0.0 && ub.left > 0.0 {
456
+ fb.left = ub.left;
457
+ }
458
+ if fb.right == 0.0 && ub.right > 0.0 {
459
+ fb.right = ub.right;
460
+ }
461
+ if fb.top == 0.0 && ub.top > 0.0 {
462
+ fb.top = ub.top;
463
+ }
464
+ if fb.bottom == 0.0 && ub.bottom > 0.0 {
465
+ fb.bottom = ub.bottom;
466
+ }
467
+ });
468
+ }
469
+
326
470
  /// Resolve + rasterize + diff when dirty. Returns Some(rect) when the pixel
327
471
  /// buffer changed (rect = pixel-space dirty region), None when clean or
328
472
  /// identical. Writes per-call timings into d.stats.
@@ -334,6 +478,7 @@ fn raster_if_dirty(d: &mut OsrDoc) -> Option<[u32; 4]> {
334
478
  let t0 = Instant::now();
335
479
  let mut inner = d.doc.inner_mut();
336
480
  inner.resolve(0.0);
481
+ restore_collapsed_borders(&mut inner);
337
482
  let (w, h) = inner.viewport().window_size;
338
483
  let scale = inner.viewport().scale_f64();
339
484
  if inner.has_pending_critical_resources() {
@@ -389,9 +534,10 @@ fn raster_if_dirty(d: &mut OsrDoc) -> Option<[u32; 4]> {
389
534
  #[no_mangle]
390
535
  pub extern "C" fn dd_osr_frame(handle: *mut OsrDoc) -> *const u8 {
391
536
  ffi(std::ptr::null(), || {
392
- let Some(d) = (unsafe { handle.as_mut() }) else {
537
+ let Some(mut g) = doc_enter(handle) else {
393
538
  return std::ptr::null();
394
539
  };
540
+ let d = g.get();
395
541
  if raster_if_dirty(d).is_none() {
396
542
  return std::ptr::null();
397
543
  }
@@ -409,9 +555,10 @@ fn needed_buf_len(d: &OsrDoc) -> usize {
409
555
  #[no_mangle]
410
556
  pub extern "C" fn dd_osr_buf_needed(handle: *mut OsrDoc) -> usize {
411
557
  ffi(0, || {
412
- let Some(d) = (unsafe { handle.as_ref() }) else {
558
+ let Some(mut g) = doc_enter(handle) else {
413
559
  return 0;
414
560
  };
561
+ let d = g.get();
415
562
  needed_buf_len(d)
416
563
  })
417
564
  }
@@ -422,9 +569,10 @@ pub extern "C" fn dd_osr_buf_needed(handle: *mut OsrDoc) -> usize {
422
569
  #[no_mangle]
423
570
  pub extern "C" fn dd_osr_bind_frame_buf(handle: *mut OsrDoc, ptr: *mut u8, len: usize) -> c_int {
424
571
  ffi(-1, || {
425
- let Some(d) = (unsafe { handle.as_mut() }) else {
572
+ let Some(mut g) = doc_enter(handle) else {
426
573
  return -1;
427
574
  };
575
+ let d = g.get();
428
576
  if ptr.is_null() || len < needed_buf_len(d) {
429
577
  return -2;
430
578
  }
@@ -475,9 +623,10 @@ fn write_bound_frame(d: &mut OsrDoc, rect: [u32; 4]) -> c_int {
475
623
  #[no_mangle]
476
624
  pub extern "C" fn dd_osr_frame_into(handle: *mut OsrDoc) -> c_int {
477
625
  ffi(-1, || {
478
- let Some(d) = (unsafe { handle.as_mut() }) else {
626
+ let Some(mut g) = doc_enter(handle) else {
479
627
  return -1;
480
628
  };
629
+ let d = g.get();
481
630
  let Some(buf) = d.frame_buf.as_ref() else {
482
631
  return -3;
483
632
  };
@@ -499,9 +648,10 @@ pub extern "C" fn dd_osr_frame_into(handle: *mut OsrDoc) -> c_int {
499
648
  #[no_mangle]
500
649
  pub extern "C" fn dd_osr_refresh_into(handle: *mut OsrDoc) -> c_int {
501
650
  ffi(-1, || {
502
- let Some(d) = (unsafe { handle.as_mut() }) else {
651
+ let Some(mut g) = doc_enter(handle) else {
503
652
  return -1;
504
653
  };
654
+ let d = g.get();
505
655
  let Some(buf) = d.frame_buf.as_ref() else {
506
656
  return -3;
507
657
  };
@@ -523,9 +673,10 @@ pub extern "C" fn dd_osr_refresh_into(handle: *mut OsrDoc) -> c_int {
523
673
  #[no_mangle]
524
674
  pub extern "C" fn dd_osr_last_stats(handle: *mut OsrDoc) -> *const f64 {
525
675
  ffi(std::ptr::null(), || {
526
- let Some(d) = (unsafe { handle.as_ref() }) else {
676
+ let Some(mut g) = doc_enter(handle) else {
527
677
  return std::ptr::null();
528
678
  };
679
+ let d = g.get();
529
680
  d.stats.as_ptr()
530
681
  })
531
682
  }
@@ -535,9 +686,10 @@ pub extern "C" fn dd_osr_last_stats(handle: *mut OsrDoc) -> *const f64 {
535
686
  #[no_mangle]
536
687
  pub extern "C" fn dd_osr_pixels_len(handle: *mut OsrDoc) -> usize {
537
688
  ffi(0, || {
538
- let Some(d) = (unsafe { handle.as_ref() }) else {
689
+ let Some(mut g) = doc_enter(handle) else {
539
690
  return 0;
540
691
  };
692
+ let d = g.get();
541
693
  d.pixels.len()
542
694
  })
543
695
  }
@@ -546,9 +698,10 @@ pub extern "C" fn dd_osr_pixels_len(handle: *mut OsrDoc) -> usize {
546
698
  #[no_mangle]
547
699
  pub extern "C" fn dd_osr_resize(handle: *mut OsrDoc, width: f64, height: f64, scale: f64) -> c_int {
548
700
  ffi(-1, || {
549
- let Some(d) = (unsafe { handle.as_mut() }) else {
701
+ let Some(mut g) = doc_enter(handle) else {
550
702
  return -1;
551
703
  };
704
+ let d = g.get();
552
705
  let w = width.max(1.0) as u32;
553
706
  let h = height.max(1.0) as u32;
554
707
  {
@@ -618,9 +771,10 @@ pub extern "C" fn dd_osr_pointer(
618
771
  mods: u32,
619
772
  ) -> c_int {
620
773
  ffi(-1, || {
621
- let Some(d) = (unsafe { handle.as_mut() }) else {
774
+ let Some(mut g) = doc_enter(handle) else {
622
775
  return -1;
623
776
  };
777
+ let d = g.get();
624
778
  d.pointer_pos = (x, y);
625
779
  let mut event = make_pointer_event(d, x, y, dom_button(button));
626
780
  event.mods = kbt_modifiers(mods);
@@ -631,7 +785,10 @@ pub extern "C" fn dd_osr_pointer(
631
785
  UiEvent::PointerDown(event)
632
786
  }
633
787
  2 => {
634
- d.buttons ^= event.button.into();
788
+ // Release clears the bit — XOR would toggle it back on for a
789
+ // button-up that never had a matching down (double-up races,
790
+ // focus-loss sequences), leaving a phantom pressed state.
791
+ d.buttons &= !MouseEventButtons::from(event.button);
635
792
  event.buttons = d.buttons;
636
793
  UiEvent::PointerUp(event)
637
794
  }
@@ -643,7 +800,9 @@ pub extern "C" fn dd_osr_pointer(
643
800
  })
644
801
  }
645
802
 
646
- /// Wheel event at the last pointer position. Deltas are in pixels.
803
+ /// Wheel event at the last pointer position. Deltas are in pixels using
804
+ /// Blitz/winit semantics (+y = scroll up); the JS wrapper negates DOM
805
+ /// WheelEvent deltas before crossing the FFI.
647
806
  #[no_mangle]
648
807
  pub extern "C" fn dd_osr_wheel(
649
808
  handle: *mut OsrDoc,
@@ -654,9 +813,10 @@ pub extern "C" fn dd_osr_wheel(
654
813
  mods: u32,
655
814
  ) -> c_int {
656
815
  ffi(-1, || {
657
- let Some(d) = (unsafe { handle.as_mut() }) else {
816
+ let Some(mut g) = doc_enter(handle) else {
658
817
  return -1;
659
818
  };
819
+ let d = g.get();
660
820
  let event = BlitzWheelEvent {
661
821
  delta: BlitzWheelDelta::Pixels(delta_x, delta_y),
662
822
  coords: pointer_coords(d, x, y),
@@ -686,9 +846,10 @@ pub extern "C" fn dd_osr_key(
686
846
  mods: u32,
687
847
  ) -> c_int {
688
848
  ffi(-1, || {
689
- let Some(d) = (unsafe { handle.as_mut() }) else {
849
+ let Some(mut g) = doc_enter(handle) else {
690
850
  return -1;
691
851
  };
852
+ let d = g.get();
692
853
  let key_s = unsafe { read_str(key_ptr, key_len) }.unwrap_or("Unidentified");
693
854
  let code_s = unsafe { read_str(code_ptr, code_len) }.unwrap_or("");
694
855
  let key = Key::from_str(key_s).unwrap_or(Key::Unidentified);
@@ -724,9 +885,10 @@ pub extern "C" fn dd_osr_key(
724
885
  #[no_mangle]
725
886
  pub extern "C" fn dd_osr_hit_test(handle: *mut OsrDoc, x: f64, y: f64) -> c_int {
726
887
  ffi(0, || {
727
- let Some(d) = (unsafe { handle.as_mut() }) else {
888
+ let Some(mut g) = doc_enter(handle) else {
728
889
  return 0;
729
890
  };
891
+ let d = g.get();
730
892
  let doc = d.doc.inner();
731
893
  let scale = doc.viewport().scale_f64();
732
894
  let lx = (x / scale) as f32;
@@ -747,9 +909,10 @@ pub extern "C" fn dd_osr_hit_test(handle: *mut OsrDoc, x: f64, y: f64) -> c_int
747
909
  #[no_mangle]
748
910
  pub extern "C" fn dd_osr_frame_rect(handle: *mut OsrDoc) -> u64 {
749
911
  ffi(0, || {
750
- let Some(d) = (unsafe { handle.as_ref() }) else {
912
+ let Some(mut g) = doc_enter(handle) else {
751
913
  return 0;
752
914
  };
915
+ let d = g.get();
753
916
  let [x, y, w, h] = d.dirty_rect;
754
917
  ((x as u64) << 48) | ((y as u64) << 32) | ((w as u64) << 16) | h as u64
755
918
  })
@@ -761,9 +924,10 @@ pub extern "C" fn dd_osr_frame_rect(handle: *mut OsrDoc) -> u64 {
761
924
  #[no_mangle]
762
925
  pub extern "C" fn dd_osr_pending(handle: *mut OsrDoc) -> c_int {
763
926
  ffi(0, || {
764
- let Some(d) = (unsafe { handle.as_mut() }) else {
927
+ let Some(mut g) = doc_enter(handle) else {
765
928
  return 0;
766
929
  };
930
+ let d = g.get();
767
931
  fold_redraw(d);
768
932
  if d.dirty || d.doc.inner().is_animating() {
769
933
  1
@@ -778,9 +942,10 @@ pub extern "C" fn dd_osr_pending(handle: *mut OsrDoc) -> c_int {
778
942
  #[no_mangle]
779
943
  pub extern "C" fn dd_osr_poll_events(handle: *mut OsrDoc) -> *const u8 {
780
944
  ffi(std::ptr::null(), || {
781
- let Some(d) = (unsafe { handle.as_mut() }) else {
945
+ let Some(mut g) = doc_enter(handle) else {
782
946
  return std::ptr::null();
783
947
  };
948
+ let d = g.get();
784
949
  let mut q = d.events.borrow_mut();
785
950
  if q.is_empty() {
786
951
  return std::ptr::null();
@@ -804,9 +969,10 @@ pub extern "C" fn dd_osr_poll_events(handle: *mut OsrDoc) -> *const u8 {
804
969
  #[no_mangle]
805
970
  pub extern "C" fn dd_osr_events_len(handle: *mut OsrDoc) -> usize {
806
971
  ffi(0, || {
807
- let Some(d) = (unsafe { handle.as_ref() }) else {
972
+ let Some(mut g) = doc_enter(handle) else {
808
973
  return 0;
809
974
  };
975
+ let d = g.get();
810
976
  d.events_buf.len()
811
977
  })
812
978
  }
@@ -840,6 +1006,31 @@ pub extern "C" fn dd_osr_destroy(handle: *mut OsrDoc) -> c_int {
840
1006
  if handle.is_null() {
841
1007
  return -1;
842
1008
  }
1009
+ let key = handle as usize;
1010
+ let Some(reg_mutex) = docs() else { return -1 };
1011
+ let mut reg = match reg_mutex.lock() {
1012
+ Ok(r) => r,
1013
+ Err(_) => return -1,
1014
+ };
1015
+ if !reg.contains(&key) {
1016
+ return -1; // stale or double destroy — never touch the memory
1017
+ }
1018
+ // Claim the doc while still holding the registry lock: a thread that
1019
+ // passed doc_enter earlier is either holding busy (we spin for it —
1020
+ // FFI calls are µs-scale) or can no longer get in.
1021
+ let d = unsafe { &*handle };
1022
+ let mut spins = 0u32;
1023
+ while d.busy.swap(true, Ordering::Acquire) {
1024
+ spins += 1;
1025
+ if spins > 100_000 {
1026
+ // A caller is stuck inside the doc — refuse to free live
1027
+ // memory. -2 = "busy"; the host may retry.
1028
+ return -2;
1029
+ }
1030
+ std::hint::spin_loop();
1031
+ }
1032
+ reg.remove(&key);
1033
+ drop(reg);
843
1034
  drop(unsafe { Box::from_raw(handle) });
844
1035
  0
845
1036
  })
@@ -10,7 +10,7 @@ use blitz_dom::{
10
10
  ns,
11
11
  };
12
12
 
13
- use crate::{OsrDoc, ffi, read_str};
13
+ use crate::{OsrDoc, doc_enter, ffi, read_str};
14
14
 
15
15
  fn attr_qname(name: &str) -> QualName {
16
16
  QualName::new(None, ns!(), LocalName::from(name))
@@ -33,9 +33,10 @@ fn with_node_mutator(
33
33
  }
34
34
  let id = node_id(node);
35
35
  ffi(-1, || {
36
- let Some(d) = (unsafe { handle.as_mut() }) else {
36
+ let Some(mut g) = doc_enter(handle) else {
37
37
  return -1;
38
38
  };
39
+ let d = g.get();
39
40
  if d.doc.inner().get_node(id).is_none() {
40
41
  return -1; // stale/missing node — no-op
41
42
  }
@@ -53,9 +54,10 @@ fn with_node_mutator(
53
54
  #[no_mangle]
54
55
  pub extern "C" fn dd_osr_query(handle: *mut OsrDoc, sel_ptr: *const u8, sel_len: usize) -> u64 {
55
56
  ffi(0, || {
56
- let Some(d) = (unsafe { handle.as_mut() }) else {
57
+ let Some(mut g) = doc_enter(handle) else {
57
58
  return 0;
58
59
  };
60
+ let d = g.get();
59
61
  let Some(sel) = (unsafe { read_str(sel_ptr, sel_len) }) else {
60
62
  return 0;
61
63
  };
@@ -167,6 +169,52 @@ pub extern "C" fn dd_osr_set_inner_html(
167
169
  })
168
170
  }
169
171
 
172
+ /// Parse an HTML fragment and append it as the node's last children —
173
+ /// `innerHTML +=` semantics. Unlike set_inner_html the existing children
174
+ /// survive, so streaming views (the devtools console) can append rows
175
+ /// without reparsing the whole list. Requires the HtmlProvider set in
176
+ /// build_doc — same parser path as set_inner_html.
177
+ #[no_mangle]
178
+ pub extern "C" fn dd_osr_append_html(
179
+ handle: *mut OsrDoc,
180
+ node: u64,
181
+ html_ptr: *const u8,
182
+ html_len: usize,
183
+ ) -> c_int {
184
+ with_node_mutator(handle, node, |m, id| {
185
+ let Some(html) = (unsafe { read_str(html_ptr, html_len) }) else {
186
+ return -1;
187
+ };
188
+ let provider = m.doc.html_parser_provider.clone();
189
+ provider.parse_inner_html(m, id, html);
190
+ 0
191
+ })
192
+ }
193
+
194
+ /// Drop all but the last `keep` children of `node` — lets a streaming view
195
+ /// bound the DOM size without an innerHTML rebuild.
196
+ #[no_mangle]
197
+ pub extern "C" fn dd_osr_trim_children(
198
+ handle: *mut OsrDoc,
199
+ node: u64,
200
+ keep: u64,
201
+ ) -> c_int {
202
+ with_node_mutator(handle, node, |m, id| {
203
+ let kids: Vec<NodeId> = {
204
+ let Some(n) = m.doc.get_node(id) else {
205
+ return -1;
206
+ };
207
+ n.children.iter().copied().collect()
208
+ };
209
+ let keep = keep as usize;
210
+ let drop_n = kids.len().saturating_sub(keep);
211
+ for cid in kids.into_iter().take(drop_n) {
212
+ m.remove_and_drop_node(cid);
213
+ }
214
+ 0
215
+ })
216
+ }
217
+
170
218
  /// Get an attribute's value (or input's current text for <input>/<textarea>)
171
219
  /// into the doc's out-buffer. Read `dd_osr_out_len` for the byte length.
172
220
  /// NULL when the node/attr is absent.
@@ -178,9 +226,10 @@ pub extern "C" fn dd_osr_get_attr(
178
226
  name_len: usize,
179
227
  ) -> *const u8 {
180
228
  ffi(std::ptr::null(), || {
181
- let Some(d) = (unsafe { handle.as_mut() }) else {
229
+ let Some(mut g) = doc_enter(handle) else {
182
230
  return std::ptr::null();
183
231
  };
232
+ let d = g.get();
184
233
  let Some(name) = (unsafe { read_str(name_ptr, name_len) }) else {
185
234
  return std::ptr::null();
186
235
  };
@@ -213,9 +262,10 @@ pub extern "C" fn dd_osr_get_attr(
213
262
  #[no_mangle]
214
263
  pub extern "C" fn dd_osr_node_rect(handle: *mut OsrDoc, node: u64) -> *const f64 {
215
264
  ffi(std::ptr::null(), || {
216
- let Some(d) = (unsafe { handle.as_mut() }) else {
265
+ let Some(mut g) = doc_enter(handle) else {
217
266
  return std::ptr::null();
218
267
  };
268
+ let d = g.get();
219
269
  if node == 0 {
220
270
  return std::ptr::null();
221
271
  }
@@ -237,9 +287,10 @@ pub extern "C" fn dd_osr_node_rect(handle: *mut OsrDoc, node: u64) -> *const f64
237
287
  #[no_mangle]
238
288
  pub extern "C" fn dd_osr_out_len(handle: *mut OsrDoc) -> usize {
239
289
  ffi(0, || {
240
- let Some(d) = (unsafe { handle.as_ref() }) else {
290
+ let Some(mut g) = doc_enter(handle) else {
241
291
  return 0;
242
292
  };
293
+ let d = g.get();
243
294
  d.out_buf.len()
244
295
  })
245
296
  }
@@ -248,9 +299,10 @@ pub extern "C" fn dd_osr_out_len(handle: *mut OsrDoc) -> usize {
248
299
  #[no_mangle]
249
300
  pub extern "C" fn dd_osr_focus(handle: *mut OsrDoc, node: u64) -> c_int {
250
301
  ffi(-1, || {
251
- let Some(d) = (unsafe { handle.as_mut() }) else {
302
+ let Some(mut g) = doc_enter(handle) else {
252
303
  return -1;
253
304
  };
305
+ let d = g.get();
254
306
  let mut doc = d.doc.inner_mut();
255
307
  if node == 0 {
256
308
  doc.clear_focus();
@@ -277,9 +329,10 @@ pub extern "C" fn dd_osr_query_all(
277
329
  sel_len: usize,
278
330
  ) -> *const u64 {
279
331
  ffi(std::ptr::null(), || {
280
- let Some(d) = (unsafe { handle.as_mut() }) else {
332
+ let Some(mut g) = doc_enter(handle) else {
281
333
  return std::ptr::null();
282
334
  };
335
+ let d = g.get();
283
336
  let Some(sel) = (unsafe { read_str(sel_ptr, sel_len) }) else {
284
337
  return std::ptr::null();
285
338
  };
@@ -296,13 +349,50 @@ pub extern "C" fn dd_osr_query_all(
296
349
  #[no_mangle]
297
350
  pub extern "C" fn dd_osr_query_all_len(handle: *mut OsrDoc) -> usize {
298
351
  ffi(0, || {
299
- let Some(d) = (unsafe { handle.as_ref() }) else {
352
+ let Some(mut g) = doc_enter(handle) else {
300
353
  return 0;
301
354
  };
355
+ let d = g.get();
302
356
  d.query_buf.len()
303
357
  })
304
358
  }
305
359
 
360
+ /// Scroll a specific node (a scroll container) to absolute (x, y) offsets.
361
+ /// Unlike scroll_into_view — which at this Blitz rev only scrolls the root
362
+ /// viewport — this reaches nested scrollports; offsets clamp to the node's
363
+ /// scroll range, so y=1e9 pins a log view to its bottom.
364
+ /// behavior: 0 = instant, 1 = smooth
365
+ #[no_mangle]
366
+ pub extern "C" fn dd_osr_scroll_to(
367
+ handle: *mut OsrDoc,
368
+ node: u64,
369
+ x: f64,
370
+ y: f64,
371
+ behavior: c_int,
372
+ ) -> c_int {
373
+ ffi(-1, || {
374
+ let Some(mut g) = doc_enter(handle) else {
375
+ return -1;
376
+ };
377
+ let d = g.get();
378
+ let id = node_id(node);
379
+ {
380
+ let doc = d.doc.inner();
381
+ if node == 0 || doc.get_node(id).is_none() {
382
+ return -1;
383
+ }
384
+ }
385
+ d.doc.inner_mut().scroll_to(
386
+ id,
387
+ x,
388
+ y,
389
+ if behavior == 1 { ScrollBehavior::Smooth } else { ScrollBehavior::Instant },
390
+ );
391
+ d.dirty = true;
392
+ 0
393
+ })
394
+ }
395
+
306
396
  /// Scroll the viewport so that `node` is visible.
307
397
  /// behavior: 0 = instant, 1 = smooth
308
398
  /// v_align/h_align: 0 = start, 1 = center, 2 = end, 3 = nearest
@@ -323,9 +413,10 @@ pub extern "C" fn dd_osr_scroll_into_view(
323
413
  }
324
414
  }
325
415
  ffi(-1, || {
326
- let Some(d) = (unsafe { handle.as_mut() }) else {
416
+ let Some(mut g) = doc_enter(handle) else {
327
417
  return -1;
328
418
  };
419
+ let d = g.get();
329
420
  let id = node_id(node);
330
421
  {
331
422
  let doc = d.doc.inner();
@@ -354,9 +445,10 @@ pub extern "C" fn dd_osr_closest(
354
445
  sel_len: usize,
355
446
  ) -> u64 {
356
447
  ffi(0, || {
357
- let Some(d) = (unsafe { handle.as_mut() }) else {
448
+ let Some(mut g) = doc_enter(handle) else {
358
449
  return 0;
359
450
  };
451
+ let d = g.get();
360
452
  let Some(sel) = (unsafe { read_str(sel_ptr, sel_len) }) else {
361
453
  return 0;
362
454
  };
@@ -373,13 +465,16 @@ pub extern "C" fn dd_osr_closest(
373
465
  #[no_mangle]
374
466
  pub extern "C" fn dd_osr_focused_node(handle: *mut OsrDoc) -> u64 {
375
467
  ffi(0, || {
376
- let Some(d) = (unsafe { handle.as_ref() }) else {
468
+ let Some(mut g) = doc_enter(handle) else {
377
469
  return 0;
378
470
  };
379
- d.doc
471
+ let d = g.get();
472
+ let focused = d
473
+ .doc
380
474
  .inner()
381
475
  .get_focussed_node_id()
382
476
  .map(|id| id.as_u64())
383
- .unwrap_or(0)
477
+ .unwrap_or(0);
478
+ focused
384
479
  })
385
480
  }