@motion-core/motion-gpu 0.4.1 → 0.5.0

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 (228) hide show
  1. package/README.md +99 -0
  2. package/dist/advanced.d.ts +1 -0
  3. package/dist/advanced.d.ts.map +1 -0
  4. package/dist/advanced.js +14 -6
  5. package/dist/core/advanced.d.ts +1 -0
  6. package/dist/core/advanced.d.ts.map +1 -0
  7. package/dist/core/advanced.js +14 -5
  8. package/dist/core/compute-shader.d.ts +87 -0
  9. package/dist/core/compute-shader.d.ts.map +1 -0
  10. package/dist/core/compute-shader.js +205 -0
  11. package/dist/core/compute-shader.js.map +1 -0
  12. package/dist/core/current-value.d.ts +1 -0
  13. package/dist/core/current-value.d.ts.map +1 -0
  14. package/dist/core/current-value.js +35 -34
  15. package/dist/core/current-value.js.map +1 -0
  16. package/dist/core/error-diagnostics.d.ts +1 -0
  17. package/dist/core/error-diagnostics.d.ts.map +1 -0
  18. package/dist/core/error-diagnostics.js +70 -137
  19. package/dist/core/error-diagnostics.js.map +1 -0
  20. package/dist/core/error-report.d.ts +2 -1
  21. package/dist/core/error-report.d.ts.map +1 -0
  22. package/dist/core/error-report.js +247 -233
  23. package/dist/core/error-report.js.map +1 -0
  24. package/dist/core/frame-registry.d.ts +1 -0
  25. package/dist/core/frame-registry.d.ts.map +1 -0
  26. package/dist/core/frame-registry.js +546 -662
  27. package/dist/core/frame-registry.js.map +1 -0
  28. package/dist/core/index.d.ts +6 -2
  29. package/dist/core/index.d.ts.map +1 -0
  30. package/dist/core/index.js +13 -12
  31. package/dist/core/material-preprocess.d.ts +1 -0
  32. package/dist/core/material-preprocess.d.ts.map +1 -0
  33. package/dist/core/material-preprocess.js +131 -152
  34. package/dist/core/material-preprocess.js.map +1 -0
  35. package/dist/core/material.d.ts +23 -6
  36. package/dist/core/material.d.ts.map +1 -0
  37. package/dist/core/material.js +290 -317
  38. package/dist/core/material.js.map +1 -0
  39. package/dist/core/recompile-policy.d.ts +1 -0
  40. package/dist/core/recompile-policy.d.ts.map +1 -0
  41. package/dist/core/recompile-policy.js +18 -13
  42. package/dist/core/recompile-policy.js.map +1 -0
  43. package/dist/core/render-graph.d.ts +8 -3
  44. package/dist/core/render-graph.d.ts.map +1 -0
  45. package/dist/core/render-graph.js +77 -68
  46. package/dist/core/render-graph.js.map +1 -0
  47. package/dist/core/render-targets.d.ts +1 -0
  48. package/dist/core/render-targets.d.ts.map +1 -0
  49. package/dist/core/render-targets.js +52 -53
  50. package/dist/core/render-targets.js.map +1 -0
  51. package/dist/core/renderer.d.ts +1 -0
  52. package/dist/core/renderer.d.ts.map +1 -0
  53. package/dist/core/renderer.js +1337 -1081
  54. package/dist/core/renderer.js.map +1 -0
  55. package/dist/core/runtime-loop.d.ts +3 -2
  56. package/dist/core/runtime-loop.d.ts.map +1 -0
  57. package/dist/core/runtime-loop.js +353 -362
  58. package/dist/core/runtime-loop.js.map +1 -0
  59. package/dist/core/scheduler-helpers.d.ts +1 -0
  60. package/dist/core/scheduler-helpers.d.ts.map +1 -0
  61. package/dist/core/scheduler-helpers.js +52 -51
  62. package/dist/core/scheduler-helpers.js.map +1 -0
  63. package/dist/core/shader.d.ts +10 -1
  64. package/dist/core/shader.d.ts.map +1 -0
  65. package/dist/core/shader.js +109 -115
  66. package/dist/core/shader.js.map +1 -0
  67. package/dist/core/storage-buffers.d.ts +37 -0
  68. package/dist/core/storage-buffers.d.ts.map +1 -0
  69. package/dist/core/storage-buffers.js +95 -0
  70. package/dist/core/storage-buffers.js.map +1 -0
  71. package/dist/core/texture-loader.d.ts +1 -0
  72. package/dist/core/texture-loader.d.ts.map +1 -0
  73. package/dist/core/texture-loader.js +209 -273
  74. package/dist/core/texture-loader.js.map +1 -0
  75. package/dist/core/textures.d.ts +13 -0
  76. package/dist/core/textures.d.ts.map +1 -0
  77. package/dist/core/textures.js +111 -116
  78. package/dist/core/textures.js.map +1 -0
  79. package/dist/core/types.d.ts +147 -4
  80. package/dist/core/types.d.ts.map +1 -0
  81. package/dist/core/types.js +0 -4
  82. package/dist/core/uniforms.d.ts +1 -0
  83. package/dist/core/uniforms.d.ts.map +1 -0
  84. package/dist/core/uniforms.js +170 -191
  85. package/dist/core/uniforms.js.map +1 -0
  86. package/dist/index.d.ts +1 -0
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/index.js +13 -6
  89. package/dist/passes/BlitPass.d.ts +1 -0
  90. package/dist/passes/BlitPass.d.ts.map +1 -0
  91. package/dist/passes/BlitPass.js +23 -18
  92. package/dist/passes/BlitPass.js.map +1 -0
  93. package/dist/passes/ComputePass.d.ts +83 -0
  94. package/dist/passes/ComputePass.d.ts.map +1 -0
  95. package/dist/passes/ComputePass.js +92 -0
  96. package/dist/passes/ComputePass.js.map +1 -0
  97. package/dist/passes/CopyPass.d.ts +1 -0
  98. package/dist/passes/CopyPass.d.ts.map +1 -0
  99. package/dist/passes/CopyPass.js +58 -52
  100. package/dist/passes/CopyPass.js.map +1 -0
  101. package/dist/passes/FullscreenPass.d.ts +1 -0
  102. package/dist/passes/FullscreenPass.d.ts.map +1 -0
  103. package/dist/passes/FullscreenPass.js +127 -130
  104. package/dist/passes/FullscreenPass.js.map +1 -0
  105. package/dist/passes/PingPongComputePass.d.ts +104 -0
  106. package/dist/passes/PingPongComputePass.d.ts.map +1 -0
  107. package/dist/passes/PingPongComputePass.js +132 -0
  108. package/dist/passes/PingPongComputePass.js.map +1 -0
  109. package/dist/passes/ShaderPass.d.ts +1 -0
  110. package/dist/passes/ShaderPass.d.ts.map +1 -0
  111. package/dist/passes/ShaderPass.js +41 -37
  112. package/dist/passes/ShaderPass.js.map +1 -0
  113. package/dist/passes/index.d.ts +3 -0
  114. package/dist/passes/index.d.ts.map +1 -0
  115. package/dist/passes/index.js +6 -3
  116. package/dist/react/FragCanvas.d.ts +3 -2
  117. package/dist/react/FragCanvas.d.ts.map +1 -0
  118. package/dist/react/FragCanvas.js +234 -211
  119. package/dist/react/FragCanvas.js.map +1 -0
  120. package/dist/react/MotionGPUErrorOverlay.d.ts +1 -0
  121. package/dist/react/MotionGPUErrorOverlay.d.ts.map +1 -0
  122. package/dist/react/MotionGPUErrorOverlay.js +200 -14
  123. package/dist/react/MotionGPUErrorOverlay.js.map +1 -0
  124. package/dist/react/Portal.d.ts +1 -0
  125. package/dist/react/Portal.d.ts.map +1 -0
  126. package/dist/react/Portal.js +18 -21
  127. package/dist/react/Portal.js.map +1 -0
  128. package/dist/react/advanced.d.ts +1 -0
  129. package/dist/react/advanced.d.ts.map +1 -0
  130. package/dist/react/advanced.js +14 -6
  131. package/dist/react/frame-context.d.ts +1 -0
  132. package/dist/react/frame-context.d.ts.map +1 -0
  133. package/dist/react/frame-context.js +88 -94
  134. package/dist/react/frame-context.js.map +1 -0
  135. package/dist/react/index.d.ts +6 -2
  136. package/dist/react/index.d.ts.map +1 -0
  137. package/dist/react/index.js +12 -9
  138. package/dist/react/motiongpu-context.d.ts +1 -0
  139. package/dist/react/motiongpu-context.d.ts.map +1 -0
  140. package/dist/react/motiongpu-context.js +18 -15
  141. package/dist/react/motiongpu-context.js.map +1 -0
  142. package/dist/react/use-motiongpu-user-context.d.ts +1 -0
  143. package/dist/react/use-motiongpu-user-context.d.ts.map +1 -0
  144. package/dist/react/use-motiongpu-user-context.js +83 -82
  145. package/dist/react/use-motiongpu-user-context.js.map +1 -0
  146. package/dist/react/use-texture.d.ts +1 -0
  147. package/dist/react/use-texture.d.ts.map +1 -0
  148. package/dist/react/use-texture.js +132 -152
  149. package/dist/react/use-texture.js.map +1 -0
  150. package/dist/svelte/FragCanvas.svelte +2 -2
  151. package/dist/svelte/FragCanvas.svelte.d.ts +3 -2
  152. package/dist/svelte/FragCanvas.svelte.d.ts.map +1 -0
  153. package/dist/svelte/MotionGPUErrorOverlay.svelte +137 -7
  154. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts +1 -0
  155. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts.map +1 -0
  156. package/dist/svelte/Portal.svelte.d.ts +1 -0
  157. package/dist/svelte/Portal.svelte.d.ts.map +1 -0
  158. package/dist/svelte/advanced.d.ts +1 -0
  159. package/dist/svelte/advanced.d.ts.map +1 -0
  160. package/dist/svelte/advanced.js +13 -6
  161. package/dist/svelte/frame-context.d.ts +1 -0
  162. package/dist/svelte/frame-context.d.ts.map +1 -0
  163. package/dist/svelte/frame-context.js +27 -27
  164. package/dist/svelte/frame-context.js.map +1 -0
  165. package/dist/svelte/index.d.ts +6 -2
  166. package/dist/svelte/index.d.ts.map +1 -0
  167. package/dist/svelte/index.js +12 -9
  168. package/dist/svelte/motiongpu-context.d.ts +1 -0
  169. package/dist/svelte/motiongpu-context.d.ts.map +1 -0
  170. package/dist/svelte/motiongpu-context.js +24 -21
  171. package/dist/svelte/motiongpu-context.js.map +1 -0
  172. package/dist/svelte/use-motiongpu-user-context.d.ts +1 -0
  173. package/dist/svelte/use-motiongpu-user-context.d.ts.map +1 -0
  174. package/dist/svelte/use-motiongpu-user-context.js +69 -70
  175. package/dist/svelte/use-motiongpu-user-context.js.map +1 -0
  176. package/dist/svelte/use-texture.d.ts +1 -0
  177. package/dist/svelte/use-texture.d.ts.map +1 -0
  178. package/dist/svelte/use-texture.js +125 -147
  179. package/dist/svelte/use-texture.js.map +1 -0
  180. package/package.json +12 -7
  181. package/src/lib/advanced.ts +6 -0
  182. package/src/lib/core/advanced.ts +12 -0
  183. package/src/lib/core/compute-shader.ts +326 -0
  184. package/src/lib/core/current-value.ts +64 -0
  185. package/src/lib/core/error-diagnostics.ts +236 -0
  186. package/src/lib/core/error-report.ts +535 -0
  187. package/src/lib/core/frame-registry.ts +1190 -0
  188. package/src/lib/core/index.ts +94 -0
  189. package/src/lib/core/material-preprocess.ts +295 -0
  190. package/src/lib/core/material.ts +748 -0
  191. package/src/lib/core/recompile-policy.ts +31 -0
  192. package/src/lib/core/render-graph.ts +173 -0
  193. package/src/lib/core/render-targets.ts +107 -0
  194. package/src/lib/core/renderer.ts +2161 -0
  195. package/src/lib/core/runtime-loop.ts +537 -0
  196. package/src/lib/core/scheduler-helpers.ts +136 -0
  197. package/src/lib/core/shader.ts +301 -0
  198. package/src/lib/core/storage-buffers.ts +142 -0
  199. package/src/lib/core/texture-loader.ts +482 -0
  200. package/src/lib/core/textures.ts +257 -0
  201. package/src/lib/core/types.ts +743 -0
  202. package/src/lib/core/uniforms.ts +282 -0
  203. package/src/lib/index.ts +6 -0
  204. package/src/lib/passes/BlitPass.ts +54 -0
  205. package/src/lib/passes/ComputePass.ts +136 -0
  206. package/src/lib/passes/CopyPass.ts +80 -0
  207. package/src/lib/passes/FullscreenPass.ts +173 -0
  208. package/src/lib/passes/PingPongComputePass.ts +180 -0
  209. package/src/lib/passes/ShaderPass.ts +89 -0
  210. package/src/lib/passes/index.ts +9 -0
  211. package/src/lib/react/FragCanvas.tsx +345 -0
  212. package/src/lib/react/MotionGPUErrorOverlay.tsx +524 -0
  213. package/src/lib/react/Portal.tsx +34 -0
  214. package/src/lib/react/advanced.ts +36 -0
  215. package/src/lib/react/frame-context.ts +169 -0
  216. package/src/lib/react/index.ts +68 -0
  217. package/src/lib/react/motiongpu-context.ts +88 -0
  218. package/src/lib/react/use-motiongpu-user-context.ts +186 -0
  219. package/src/lib/react/use-texture.ts +233 -0
  220. package/src/lib/svelte/FragCanvas.svelte +249 -0
  221. package/src/lib/svelte/MotionGPUErrorOverlay.svelte +512 -0
  222. package/src/lib/svelte/Portal.svelte +31 -0
  223. package/src/lib/svelte/advanced.ts +32 -0
  224. package/src/lib/svelte/frame-context.ts +87 -0
  225. package/src/lib/svelte/index.ts +68 -0
  226. package/src/lib/svelte/motiongpu-context.ts +97 -0
  227. package/src/lib/svelte/use-motiongpu-user-context.ts +145 -0
  228. package/src/lib/svelte/use-texture.ts +232 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-registry.js","names":[],"sources":["../../src/lib/core/frame-registry.ts"],"sourcesContent":["import { createCurrentWritable, type CurrentWritable, type Subscribable } from './current-value.js';\nimport type { FrameInvalidationToken, FrameState, RenderMode } from './types.js';\n\n/**\n * Per-frame callback executed by the frame scheduler.\n */\nexport type FrameCallback = (state: FrameState) => void;\n\n/**\n * Stable key type used to identify frame tasks and stages.\n */\nexport type FrameKey = string | symbol;\n\n/**\n * Public metadata describing a registered frame task.\n */\nexport interface FrameTask {\n\tkey: FrameKey;\n\tstage: FrameKey;\n}\n\n/**\n * Public metadata describing a frame stage.\n */\nexport interface FrameStage {\n\tkey: FrameKey;\n}\n\n/**\n * Stage callback allowing custom orchestration around task execution.\n */\nexport type FrameStageCallback = (state: FrameState, runTasks: () => void) => void;\n\n/**\n * Options controlling task registration and scheduling behavior.\n */\nexport interface UseFrameOptions {\n\t/**\n\t * Whether task starts in active state.\n\t *\n\t * @default true\n\t */\n\tautoStart?: boolean;\n\t/**\n\t * Whether task execution invalidates frame automatically.\n\t *\n\t * @default true\n\t */\n\tautoInvalidate?: boolean;\n\t/**\n\t * Explicit task invalidation policy.\n\t */\n\tinvalidation?: FrameTaskInvalidation;\n\t/**\n\t * Stage to register task in.\n\t *\n\t * If omitted, main stage is used unless inferred from task dependencies.\n\t */\n\tstage?: FrameKey | FrameStage;\n\t/**\n\t * Task dependencies that should run after this task.\n\t */\n\tbefore?: (FrameKey | FrameTask) | (FrameKey | FrameTask)[];\n\t/**\n\t * Task dependencies that should run before this task.\n\t */\n\tafter?: (FrameKey | FrameTask) | (FrameKey | FrameTask)[];\n\t/**\n\t * Dynamic predicate controlling whether the task is currently active.\n\t */\n\trunning?: () => boolean;\n}\n\n/**\n * Invalidation token value or resolver.\n */\nexport type FrameTaskInvalidationToken =\n\t| FrameInvalidationToken\n\t| (() => FrameInvalidationToken | null | undefined);\n\n/**\n * Explicit task invalidation policy.\n */\nexport type FrameTaskInvalidation =\n\t| 'never'\n\t| 'always'\n\t| {\n\t\t\tmode?: 'never' | 'always';\n\t\t\ttoken?: FrameTaskInvalidationToken;\n\t }\n\t| {\n\t\t\tmode: 'on-change';\n\t\t\ttoken: FrameTaskInvalidationToken;\n\t };\n\n/**\n * Handle returned by `useFrame` registration.\n */\nexport interface UseFrameResult {\n\t/**\n\t * Registered task metadata.\n\t */\n\ttask: FrameTask;\n\t/**\n\t * Starts task execution.\n\t */\n\tstart: () => void;\n\t/**\n\t * Stops task execution.\n\t */\n\tstop: () => void;\n\t/**\n\t * Readable flag representing effective running state.\n\t */\n\tstarted: Subscribable<boolean>;\n}\n\n/**\n * Snapshot of the resolved stage/task execution order.\n */\nexport interface FrameScheduleSnapshot {\n\tstages: Array<{\n\t\tkey: string;\n\t\ttasks: string[];\n\t}>;\n}\n\n/**\n * Optional scheduler diagnostics payload captured for the last run.\n */\nexport interface FrameRunTimings {\n\ttotal: number;\n\tstages: Record<\n\t\tstring,\n\t\t{\n\t\t\tduration: number;\n\t\t\ttasks: Record<string, number>;\n\t\t}\n\t>;\n}\n\n/**\n * Aggregated timing statistics for stage/task profiling.\n */\nexport interface FrameTimingStats {\n\tlast: number;\n\tavg: number;\n\tmin: number;\n\tmax: number;\n\tcount: number;\n}\n\n/**\n * Profiling snapshot aggregated from the configured history window.\n */\nexport interface FrameProfilingSnapshot {\n\twindow: number;\n\tframeCount: number;\n\tlastFrame: FrameRunTimings | null;\n\ttotal: FrameTimingStats;\n\tstages: Record<\n\t\tstring,\n\t\t{\n\t\t\ttimings: FrameTimingStats;\n\t\t\ttasks: Record<string, FrameTimingStats>;\n\t\t}\n\t>;\n}\n\n/**\n * Internal registration payload including unsubscribe callback.\n */\ninterface RegisteredFrameTask extends UseFrameResult {\n\tunsubscribe: () => void;\n}\n\n/**\n * Internal mutable task descriptor used by scheduler runtime.\n */\ninterface InternalTask {\n\ttask: FrameTask;\n\tcallback: FrameCallback;\n\torder: number;\n\tstarted: boolean;\n\tlastRunning: boolean;\n\tstartedStoreSet: (value: boolean) => void;\n\tstartedStore: Subscribable<boolean>;\n\tbefore: Set<FrameKey>;\n\tafter: Set<FrameKey>;\n\tinvalidation: {\n\t\tmode: 'never' | 'always' | 'on-change';\n\t\ttoken?: FrameTaskInvalidationToken;\n\t\tlastToken: FrameInvalidationToken | null;\n\t\thasToken: boolean;\n\t};\n\trunning?: () => boolean;\n}\n\n/**\n * Internal mutable stage descriptor used by scheduler runtime.\n */\ninterface InternalStage {\n\tkey: FrameKey;\n\torder: number;\n\tstarted: boolean;\n\tbefore: Set<FrameKey>;\n\tafter: Set<FrameKey>;\n\tcallback: FrameStageCallback;\n\ttasks: Map<FrameKey, InternalTask>;\n}\n\n/**\n * Default stage key used when task stage is not explicitly specified.\n */\nconst MAIN_STAGE_KEY = Symbol('motiongpu-main-stage');\nconst RENDER_MODE_INVALIDATION_TOKEN = Symbol('motiongpu-render-mode-change');\n\n/**\n * Default stage callback that runs tasks immediately.\n */\nconst DEFAULT_STAGE_CALLBACK: FrameStageCallback = (_state, runTasks) => runTasks();\n\n/**\n * Normalizes scalar-or-array options to array form.\n */\nfunction asArray<T>(value: T | T[] | undefined): T[] {\n\tif (!value) {\n\t\treturn [];\n\t}\n\n\treturn Array.isArray(value) ? value : [value];\n}\n\n/**\n * Normalizes frame keys to readable string labels.\n */\nfunction frameKeyToString(key: FrameKey): string {\n\treturn typeof key === 'symbol' ? key.toString() : key;\n}\n\n/**\n * Extracts task key from either direct key or task reference.\n */\nfunction toTaskKey(reference: FrameKey | FrameTask): FrameKey {\n\tif (typeof reference === 'string' || typeof reference === 'symbol') {\n\t\treturn reference;\n\t}\n\n\treturn reference.key;\n}\n\n/**\n * Extracts stage key from either direct key or stage reference.\n */\nfunction toStageKey(reference: FrameKey | FrameStage): FrameKey {\n\tif (typeof reference === 'string' || typeof reference === 'symbol') {\n\t\treturn reference;\n\t}\n\n\treturn reference.key;\n}\n\n/**\n * Resolves invalidation token from static value or resolver callback.\n */\nfunction resolveInvalidationToken(\n\ttoken: FrameTaskInvalidationToken | undefined\n): FrameInvalidationToken | null {\n\tif (token === undefined) {\n\t\treturn null;\n\t}\n\n\tconst resolved = typeof token === 'function' ? token() : token;\n\tif (resolved === null || resolved === undefined) {\n\t\treturn null;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Normalizes task invalidation options to runtime representation.\n */\nfunction normalizeTaskInvalidation(\n\tkey: FrameKey,\n\toptions: UseFrameOptions\n): InternalTask['invalidation'] {\n\tconst explicit = options.invalidation;\n\tif (explicit === undefined) {\n\t\tif (options.autoInvalidate === false) {\n\t\t\treturn {\n\t\t\t\tmode: 'never',\n\t\t\t\tlastToken: null,\n\t\t\t\thasToken: false\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tmode: 'always',\n\t\t\ttoken: key,\n\t\t\tlastToken: null,\n\t\t\thasToken: false\n\t\t};\n\t}\n\n\tif (explicit === 'never' || explicit === 'always') {\n\t\tif (explicit === 'never') {\n\t\t\treturn {\n\t\t\t\tmode: explicit,\n\t\t\t\tlastToken: null,\n\t\t\t\thasToken: false\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tmode: explicit,\n\t\t\ttoken: key,\n\t\t\tlastToken: null,\n\t\t\thasToken: false\n\t\t};\n\t}\n\n\tconst mode = explicit.mode ?? 'always';\n\tconst token = explicit.token;\n\tif (mode === 'on-change' && token === undefined) {\n\t\tthrow new Error('Task invalidation mode \"on-change\" requires a token');\n\t}\n\n\tif (mode === 'never') {\n\t\treturn {\n\t\t\tmode,\n\t\t\tlastToken: null,\n\t\t\thasToken: false\n\t\t};\n\t}\n\n\tif (mode === 'on-change') {\n\t\treturn {\n\t\t\tmode,\n\t\t\ttoken: token as FrameTaskInvalidationToken,\n\t\t\tlastToken: null,\n\t\t\thasToken: false\n\t\t};\n\t}\n\n\treturn {\n\t\tmode,\n\t\ttoken: token ?? key,\n\t\tlastToken: null,\n\t\thasToken: false\n\t};\n}\n\n/**\n * Computes aggregate timing stats from sampled durations.\n */\nfunction buildTimingStats(samples: number[], last: number): FrameTimingStats {\n\tif (samples.length === 0) {\n\t\treturn {\n\t\t\tlast,\n\t\t\tavg: 0,\n\t\t\tmin: 0,\n\t\t\tmax: 0,\n\t\t\tcount: 0\n\t\t};\n\t}\n\n\tlet sum = 0;\n\tlet min = Number.POSITIVE_INFINITY;\n\tlet max = Number.NEGATIVE_INFINITY;\n\n\tfor (const value of samples) {\n\t\tsum += value;\n\t\tif (value < min) {\n\t\t\tmin = value;\n\t\t}\n\t\tif (value > max) {\n\t\t\tmax = value;\n\t\t}\n\t}\n\n\treturn {\n\t\tlast,\n\t\tavg: sum / samples.length,\n\t\tmin,\n\t\tmax,\n\t\tcount: samples.length\n\t};\n}\n\n/**\n * Dependency graph sorting options used for diagnostics labels.\n */\ninterface SortDependenciesOptions<T extends { key: FrameKey; order: number }> {\n\tgraphName: string;\n\tgetItemLabel: (item: T) => string;\n\tisKnownExternalDependency?: (key: FrameKey) => boolean;\n}\n\n/**\n * Deterministically sorts dependency keys for stable traversal and diagnostics.\n */\nfunction sortDependencyKeys(keys: Iterable<FrameKey>): FrameKey[] {\n\treturn Array.from(keys).sort((a, b) => frameKeyToString(a).localeCompare(frameKeyToString(b)));\n}\n\n/**\n * Finds one deterministic cycle path in the directed dependency graph.\n */\nfunction findDependencyCycle<T extends { key: FrameKey; order: number }>(\n\titems: T[],\n\tedges: ReadonlyMap<FrameKey, ReadonlySet<FrameKey>>\n): FrameKey[] | null {\n\tconst visitState = new Map<FrameKey, 0 | 1 | 2>();\n\tconst stack: FrameKey[] = [];\n\tlet cycle: FrameKey[] | null = null;\n\tconst sortedItems = [...items].sort((a, b) => a.order - b.order);\n\n\tconst visit = (key: FrameKey): boolean => {\n\t\tvisitState.set(key, 1);\n\t\tstack.push(key);\n\n\t\tfor (const childKey of sortDependencyKeys(edges.get(key) ?? [])) {\n\t\t\tconst state = visitState.get(childKey) ?? 0;\n\t\t\tif (state === 0) {\n\t\t\t\tif (visit(childKey)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (state === 1) {\n\t\t\t\tconst cycleStartIndex = stack.findIndex((entry) => entry === childKey);\n\t\t\t\tconst cyclePath = cycleStartIndex === -1 ? [childKey] : stack.slice(cycleStartIndex);\n\t\t\t\tcycle = [...cyclePath, childKey];\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\tstack.pop();\n\t\tvisitState.set(key, 2);\n\t\treturn false;\n\t};\n\n\tfor (const item of sortedItems) {\n\t\tif ((visitState.get(item.key) ?? 0) !== 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (visit(item.key)) {\n\t\t\treturn cycle;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Topologically sorts items by `before`/`after` dependencies.\n *\n * Throws deterministic errors when dependencies are missing or cyclic.\n */\nfunction sortByDependencies<T extends { key: FrameKey; order: number }>(\n\titems: T[],\n\tgetBefore: (item: T) => Iterable<FrameKey>,\n\tgetAfter: (item: T) => Iterable<FrameKey>,\n\toptions: SortDependenciesOptions<T>\n): T[] {\n\tconst itemsByKey = new Map<FrameKey, T>();\n\tfor (const item of items) {\n\t\titemsByKey.set(item.key, item);\n\t}\n\n\tconst indegree = new Map<FrameKey, number>();\n\tconst edges = new Map<FrameKey, Set<FrameKey>>();\n\n\tfor (const item of items) {\n\t\tindegree.set(item.key, 0);\n\t\tedges.set(item.key, new Set());\n\t}\n\n\tfor (const item of items) {\n\t\tfor (const dependencyKey of getAfter(item)) {\n\t\t\tif (!itemsByKey.has(dependencyKey)) {\n\t\t\t\tif (options.isKnownExternalDependency?.(dependencyKey)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${options.graphName} dependency error: ${options.getItemLabel(item)} references missing dependency \"${frameKeyToString(dependencyKey)}\" in \"after\".`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tedges.get(dependencyKey)?.add(item.key);\n\t\t\tindegree.set(item.key, (indegree.get(item.key) ?? 0) + 1);\n\t\t}\n\n\t\tfor (const dependencyKey of getBefore(item)) {\n\t\t\tif (!itemsByKey.has(dependencyKey)) {\n\t\t\t\tif (options.isKnownExternalDependency?.(dependencyKey)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${options.graphName} dependency error: ${options.getItemLabel(item)} references missing dependency \"${frameKeyToString(dependencyKey)}\" in \"before\".`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tedges.get(item.key)?.add(dependencyKey);\n\t\t\tindegree.set(dependencyKey, (indegree.get(dependencyKey) ?? 0) + 1);\n\t\t}\n\t}\n\n\tconst queue = items.filter((item) => (indegree.get(item.key) ?? 0) === 0);\n\tqueue.sort((a, b) => a.order - b.order);\n\n\tconst ordered: T[] = [];\n\twhile (queue.length > 0) {\n\t\tconst current = queue.shift();\n\t\tif (!current) {\n\t\t\tbreak;\n\t\t}\n\n\t\tordered.push(current);\n\n\t\tfor (const childKey of edges.get(current.key) ?? []) {\n\t\t\tconst nextDegree = (indegree.get(childKey) ?? 0) - 1;\n\t\t\tindegree.set(childKey, nextDegree);\n\t\t\tif (nextDegree === 0) {\n\t\t\t\tconst child = itemsByKey.get(childKey);\n\t\t\t\tif (child) {\n\t\t\t\t\tqueue.push(child);\n\t\t\t\t\tqueue.sort((a, b) => a.order - b.order);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (ordered.length !== items.length) {\n\t\tconst cycle = findDependencyCycle(items, edges);\n\t\tif (cycle) {\n\t\t\tthrow new Error(\n\t\t\t\t`${options.graphName} dependency cycle detected: ${cycle.map((key) => frameKeyToString(key)).join(' -> ')}`\n\t\t\t);\n\t\t}\n\n\t\tthrow new Error(`${options.graphName} dependency resolution failed.`);\n\t}\n\n\treturn ordered;\n}\n\n/**\n * Runtime registry that stores frame tasks/stages and drives render scheduling.\n */\nexport interface FrameRegistry {\n\t/**\n\t * Registers a frame callback in the scheduler.\n\t */\n\tregister: (\n\t\tkeyOrCallback: FrameKey | FrameCallback,\n\t\tcallbackOrOptions?: FrameCallback | UseFrameOptions,\n\t\tmaybeOptions?: UseFrameOptions\n\t) => RegisteredFrameTask;\n\t/**\n\t * Executes one scheduler run.\n\t */\n\trun: (state: FrameState) => void;\n\t/**\n\t * Marks frame as invalidated for `on-demand` mode.\n\t */\n\tinvalidate: (token?: FrameInvalidationToken) => void;\n\t/**\n\t * Requests a single render in `manual` mode.\n\t */\n\tadvance: () => void;\n\t/**\n\t * Returns whether renderer should submit a frame now.\n\t */\n\tshouldRender: () => boolean;\n\t/**\n\t * Resets one-frame invalidation/advance flags.\n\t */\n\tendFrame: () => void;\n\t/**\n\t * Sets render scheduling mode.\n\t */\n\tsetRenderMode: (mode: RenderMode) => void;\n\t/**\n\t * Enables or disables automatic rendering entirely.\n\t */\n\tsetAutoRender: (enabled: boolean) => void;\n\t/**\n\t * Sets maximum allowed delta passed to frame tasks.\n\t */\n\tsetMaxDelta: (value: number) => void;\n\t/**\n\t * Enables/disables frame profiling.\n\t */\n\tsetProfilingEnabled: (enabled: boolean) => void;\n\t/**\n\t * Sets profiling history window (in frames).\n\t */\n\tsetProfilingWindow: (window: number) => void;\n\t/**\n\t * Clears collected profiling samples.\n\t */\n\tresetProfiling: () => void;\n\t/**\n\t * Enables/disables diagnostics capture.\n\t */\n\tsetDiagnosticsEnabled: (enabled: boolean) => void;\n\t/**\n\t * Returns current render mode.\n\t */\n\tgetRenderMode: () => RenderMode;\n\t/**\n\t * Returns whether automatic rendering is enabled.\n\t */\n\tgetAutoRender: () => boolean;\n\t/**\n\t * Returns current max delta clamp.\n\t */\n\tgetMaxDelta: () => number;\n\t/**\n\t * Returns profiling toggle state.\n\t */\n\tgetProfilingEnabled: () => boolean;\n\t/**\n\t * Returns active profiling history window (in frames).\n\t */\n\tgetProfilingWindow: () => number;\n\t/**\n\t * Returns aggregated profiling snapshot.\n\t */\n\tgetProfilingSnapshot: () => FrameProfilingSnapshot | null;\n\t/**\n\t * Returns diagnostics toggle state.\n\t */\n\tgetDiagnosticsEnabled: () => boolean;\n\t/**\n\t * Returns last run timings snapshot when diagnostics are enabled.\n\t */\n\tgetLastRunTimings: () => FrameRunTimings | null;\n\t/**\n\t * Returns dependency-sorted schedule snapshot.\n\t */\n\tgetSchedule: () => FrameScheduleSnapshot;\n\t/**\n\t * Creates or updates a stage.\n\t */\n\tcreateStage: (\n\t\tkey: FrameKey,\n\t\toptions?: {\n\t\t\tbefore?: (FrameKey | FrameStage) | (FrameKey | FrameStage)[];\n\t\t\tafter?: (FrameKey | FrameStage) | (FrameKey | FrameStage)[];\n\t\t\tcallback?: FrameStageCallback | null;\n\t\t}\n\t) => FrameStage;\n\t/**\n\t * Reads stage metadata by key.\n\t */\n\tgetStage: (key: FrameKey) => FrameStage | undefined;\n\t/**\n\t * Removes all tasks from all stages.\n\t */\n\tclear: () => void;\n}\n\n/**\n * Creates a frame registry used by `FragCanvas` and `useFrame`.\n *\n * @param options - Initial scheduler options.\n * @returns Mutable frame registry instance.\n */\nexport function createFrameRegistry(options?: {\n\trenderMode?: RenderMode;\n\tautoRender?: boolean;\n\tmaxDelta?: number;\n\tprofilingEnabled?: boolean;\n\tprofilingWindow?: number;\n\tdiagnosticsEnabled?: boolean;\n}): FrameRegistry {\n\tlet renderMode: RenderMode = options?.renderMode ?? 'always';\n\tlet autoRender = options?.autoRender ?? true;\n\tlet maxDelta = options?.maxDelta ?? 0.1;\n\tlet profilingEnabled = options?.profilingEnabled ?? options?.diagnosticsEnabled ?? false;\n\tlet profilingWindow = options?.profilingWindow ?? 120;\n\tlet lastRunTimings: FrameRunTimings | null = null;\n\tconst profilingHistory: FrameRunTimings[] = [];\n\tlet hasUntokenizedInvalidation = true;\n\tconst invalidationTokens = new Set<FrameInvalidationToken>();\n\tlet shouldAdvance = false;\n\tlet orderCounter = 0;\n\n\tconst assertMaxDelta = (value: number): number => {\n\t\tif (!Number.isFinite(value) || value <= 0) {\n\t\t\tthrow new Error('maxDelta must be a finite number greater than 0');\n\t\t}\n\t\treturn value;\n\t};\n\n\tconst assertProfilingWindow = (value: number): number => {\n\t\tif (!Number.isFinite(value) || value <= 0) {\n\t\t\tthrow new Error('profilingWindow must be a finite number greater than 0');\n\t\t}\n\t\treturn Math.floor(value);\n\t};\n\n\tmaxDelta = assertMaxDelta(maxDelta);\n\tprofilingWindow = assertProfilingWindow(profilingWindow);\n\n\tconst stages = new Map<FrameKey, InternalStage>();\n\tlet scheduleDirty = true;\n\tlet sortedStages: InternalStage[] = [];\n\tconst sortedTasksByStage = new Map<FrameKey, InternalTask[]>();\n\tlet scheduleSnapshot: FrameScheduleSnapshot = { stages: [] };\n\n\tconst markScheduleDirty = (): void => {\n\t\tscheduleDirty = true;\n\t};\n\n\tconst syncSchedule = (): void => {\n\t\tif (!scheduleDirty) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst stageList = sortByDependencies(\n\t\t\tArray.from(stages.values()),\n\t\t\t(stage) => stage.before,\n\t\t\t(stage) => stage.after,\n\t\t\t{\n\t\t\t\tgraphName: 'Frame stage graph',\n\t\t\t\tgetItemLabel: (stage) => `stage \"${frameKeyToString(stage.key)}\"`\n\t\t\t}\n\t\t);\n\t\tconst nextTasksByStage = new Map<FrameKey, InternalTask[]>();\n\t\tconst globalTaskKeys = new Set<FrameKey>();\n\t\tfor (const stage of stageList) {\n\t\t\tfor (const task of stage.tasks.values()) {\n\t\t\t\tglobalTaskKeys.add(task.task.key);\n\t\t\t}\n\t\t}\n\n\t\tfor (const stage of stageList) {\n\t\t\tconst taskList = sortByDependencies(\n\t\t\t\tArray.from(stage.tasks.values()).map((task) => ({\n\t\t\t\t\tkey: task.task.key,\n\t\t\t\t\torder: task.order,\n\t\t\t\t\ttask\n\t\t\t\t})),\n\t\t\t\t(task) => task.task.before,\n\t\t\t\t(task) => task.task.after,\n\t\t\t\t{\n\t\t\t\t\tgraphName: `Frame task graph for stage \"${frameKeyToString(stage.key)}\"`,\n\t\t\t\t\tgetItemLabel: (task) => `task \"${frameKeyToString(task.key)}\"`,\n\t\t\t\t\tisKnownExternalDependency: (key) => globalTaskKeys.has(key)\n\t\t\t\t}\n\t\t\t).map((task) => task.task);\n\t\t\tnextTasksByStage.set(stage.key, taskList);\n\t\t}\n\n\t\tsortedStages = stageList;\n\t\tsortedTasksByStage.clear();\n\t\tfor (const [stageKey, taskList] of nextTasksByStage) {\n\t\t\tsortedTasksByStage.set(stageKey, taskList);\n\t\t}\n\n\t\tscheduleSnapshot = {\n\t\t\tstages: sortedStages.map((stage) => ({\n\t\t\t\tkey: frameKeyToString(stage.key),\n\t\t\t\ttasks: (sortedTasksByStage.get(stage.key) ?? []).map((task) =>\n\t\t\t\t\tframeKeyToString(task.task.key)\n\t\t\t\t)\n\t\t\t}))\n\t\t};\n\n\t\tscheduleDirty = false;\n\t};\n\n\tconst pushProfile = (timings: FrameRunTimings): void => {\n\t\tprofilingHistory.push(timings);\n\t\twhile (profilingHistory.length > profilingWindow) {\n\t\t\tprofilingHistory.shift();\n\t\t}\n\t};\n\n\tconst clearProfiling = (): void => {\n\t\tprofilingHistory.length = 0;\n\t\tlastRunTimings = null;\n\t};\n\n\tconst buildProfilingSnapshot = (): FrameProfilingSnapshot | null => {\n\t\tif (!profilingEnabled) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst stageBuckets = new Map<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tdurations: number[];\n\t\t\t\ttaskDurations: Map<string, number[]>;\n\t\t\t}\n\t\t>();\n\t\tconst totalDurations: number[] = [];\n\n\t\tfor (const frame of profilingHistory) {\n\t\t\ttotalDurations.push(frame.total);\n\t\t\tfor (const [stageKey, stageTiming] of Object.entries(frame.stages)) {\n\t\t\t\tconst stageBucket = stageBuckets.get(stageKey) ?? {\n\t\t\t\t\tdurations: [],\n\t\t\t\t\ttaskDurations: new Map<string, number[]>()\n\t\t\t\t};\n\t\t\t\tstageBucket.durations.push(stageTiming.duration);\n\n\t\t\t\tfor (const [taskKey, taskDuration] of Object.entries(stageTiming.tasks)) {\n\t\t\t\t\tconst bucket = stageBucket.taskDurations.get(taskKey) ?? [];\n\t\t\t\t\tbucket.push(taskDuration);\n\t\t\t\t\tstageBucket.taskDurations.set(taskKey, bucket);\n\t\t\t\t}\n\n\t\t\t\tstageBuckets.set(stageKey, stageBucket);\n\t\t\t}\n\t\t}\n\n\t\tconst stagesSnapshot: FrameProfilingSnapshot['stages'] = {};\n\t\tfor (const [stageKey, stageBucket] of stageBuckets) {\n\t\t\tconst lastStageDuration = lastRunTimings?.stages[stageKey]?.duration ?? 0;\n\t\t\tconst taskSnapshot: Record<string, FrameTimingStats> = {};\n\t\t\tfor (const [taskKey, taskDurations] of stageBucket.taskDurations) {\n\t\t\t\tconst lastTaskDuration = lastRunTimings?.stages[stageKey]?.tasks[taskKey] ?? 0;\n\t\t\t\ttaskSnapshot[taskKey] = buildTimingStats(taskDurations, lastTaskDuration);\n\t\t\t}\n\n\t\t\tstagesSnapshot[stageKey] = {\n\t\t\t\ttimings: buildTimingStats(stageBucket.durations, lastStageDuration),\n\t\t\t\ttasks: taskSnapshot\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\twindow: profilingWindow,\n\t\t\tframeCount: profilingHistory.length,\n\t\t\tlastFrame: lastRunTimings,\n\t\t\ttotal: buildTimingStats(totalDurations, lastRunTimings?.total ?? 0),\n\t\t\tstages: stagesSnapshot\n\t\t};\n\t};\n\n\tconst ensureStage = (\n\t\tstageReference: FrameKey | FrameStage,\n\t\tstageOptions?: {\n\t\t\tbefore?: (FrameKey | FrameStage)[];\n\t\t\tafter?: (FrameKey | FrameStage)[];\n\t\t\tcallback?: FrameStageCallback | null;\n\t\t}\n\t): InternalStage => {\n\t\tconst stageKey = toStageKey(stageReference);\n\t\tconst existing = stages.get(stageKey);\n\t\tif (existing) {\n\t\t\tif (stageOptions?.before !== undefined) {\n\t\t\t\texisting.before = new Set(stageOptions.before.map((entry) => toStageKey(entry)));\n\t\t\t\tmarkScheduleDirty();\n\t\t\t}\n\t\t\tif (stageOptions?.after !== undefined) {\n\t\t\t\texisting.after = new Set(stageOptions.after.map((entry) => toStageKey(entry)));\n\t\t\t\tmarkScheduleDirty();\n\t\t\t}\n\t\t\tif (stageOptions && Object.prototype.hasOwnProperty.call(stageOptions, 'callback')) {\n\t\t\t\texisting.callback = stageOptions.callback ?? DEFAULT_STAGE_CALLBACK;\n\t\t\t}\n\t\t\treturn existing;\n\t\t}\n\n\t\tconst stage: InternalStage = {\n\t\t\tkey: stageKey,\n\t\t\torder: orderCounter++,\n\t\t\tstarted: true,\n\t\t\tbefore: new Set((stageOptions?.before ?? []).map((entry) => toStageKey(entry))),\n\t\t\tafter: new Set((stageOptions?.after ?? []).map((entry) => toStageKey(entry))),\n\t\t\tcallback: stageOptions?.callback ?? DEFAULT_STAGE_CALLBACK,\n\t\t\ttasks: new Map()\n\t\t};\n\t\tstages.set(stageKey, stage);\n\t\tmarkScheduleDirty();\n\t\treturn stage;\n\t};\n\n\tensureStage(MAIN_STAGE_KEY);\n\n\tconst resolveEffectiveRunning = (task: InternalTask): boolean => {\n\t\tconst running = task.started && (task.running?.() ?? true);\n\t\tif (task.lastRunning !== running) {\n\t\t\ttask.lastRunning = running;\n\t\t\ttask.startedStoreSet(running);\n\t\t}\n\t\treturn running;\n\t};\n\n\tconst hasPendingInvalidation = (): boolean => {\n\t\treturn hasUntokenizedInvalidation || invalidationTokens.size > 0;\n\t};\n\n\tconst invalidateWithToken = (token?: FrameInvalidationToken): void => {\n\t\tif (token === undefined) {\n\t\t\thasUntokenizedInvalidation = true;\n\t\t\treturn;\n\t\t}\n\n\t\tinvalidationTokens.add(token);\n\t};\n\n\tconst applyTaskInvalidation = (task: InternalTask): void => {\n\t\tconst config = task.invalidation;\n\t\tif (config.mode === 'never') {\n\t\t\treturn;\n\t\t}\n\n\t\tif (config.mode === 'always') {\n\t\t\tconst token = resolveInvalidationToken(config.token);\n\t\t\tinvalidateWithToken(token ?? task.task.key);\n\t\t\treturn;\n\t\t}\n\n\t\tconst token = resolveInvalidationToken(config.token);\n\t\tif (token === null) {\n\t\t\tconfig.hasToken = false;\n\t\t\tconfig.lastToken = null;\n\t\t\treturn;\n\t\t}\n\n\t\tconst changed = !config.hasToken || config.lastToken !== token;\n\t\tconfig.hasToken = true;\n\t\tconfig.lastToken = token;\n\t\tif (changed) {\n\t\t\tinvalidateWithToken(token);\n\t\t}\n\t};\n\n\treturn {\n\t\tregister(keyOrCallback, callbackOrOptions, maybeOptions) {\n\t\t\tconst key =\n\t\t\t\ttypeof keyOrCallback === 'function'\n\t\t\t\t\t? (Symbol('motiongpu-task') as FrameKey)\n\t\t\t\t\t: (keyOrCallback as FrameKey);\n\t\t\tconst callback =\n\t\t\t\ttypeof keyOrCallback === 'function' ? keyOrCallback : (callbackOrOptions as FrameCallback);\n\t\t\tconst taskOptions =\n\t\t\t\ttypeof keyOrCallback === 'function'\n\t\t\t\t\t? ((callbackOrOptions as UseFrameOptions | undefined) ?? {})\n\t\t\t\t\t: (maybeOptions ?? {});\n\n\t\t\tif (typeof callback !== 'function') {\n\t\t\t\tthrow new Error('useFrame requires a callback');\n\t\t\t}\n\n\t\t\tconst before = asArray(taskOptions.before);\n\t\t\tconst after = asArray(taskOptions.after);\n\t\t\tconst inferredStage = [...before, ...after].find(\n\t\t\t\t(entry) => typeof entry === 'object' && entry !== null && 'stage' in entry\n\t\t\t) as FrameTask | undefined;\n\t\t\tconst stageKey = taskOptions.stage\n\t\t\t\t? toStageKey(taskOptions.stage)\n\t\t\t\t: (inferredStage?.stage ?? MAIN_STAGE_KEY);\n\n\t\t\tconst stage = ensureStage(stageKey);\n\t\t\tconst startedWritable: CurrentWritable<boolean> = createCurrentWritable(\n\t\t\t\ttaskOptions.autoStart ?? true\n\t\t\t);\n\n\t\t\tconst internalTask: InternalTask = {\n\t\t\t\ttask: { key, stage: stage.key },\n\t\t\t\tcallback,\n\t\t\t\torder: orderCounter++,\n\t\t\t\tstarted: taskOptions.autoStart ?? true,\n\t\t\t\tlastRunning: taskOptions.autoStart ?? true,\n\t\t\t\tstartedStoreSet: startedWritable.set,\n\t\t\t\tstartedStore: { subscribe: startedWritable.subscribe },\n\t\t\t\tbefore: new Set(before.map((entry) => toTaskKey(entry))),\n\t\t\t\tafter: new Set(after.map((entry) => toTaskKey(entry))),\n\t\t\t\tinvalidation: normalizeTaskInvalidation(key, taskOptions)\n\t\t\t};\n\n\t\t\tif (taskOptions.running) {\n\t\t\t\tinternalTask.running = taskOptions.running;\n\t\t\t}\n\n\t\t\tstage.tasks.set(key, internalTask);\n\t\t\tmarkScheduleDirty();\n\t\t\tinternalTask.startedStoreSet(resolveEffectiveRunning(internalTask));\n\n\t\t\tconst start = () => {\n\t\t\t\tinternalTask.started = true;\n\t\t\t\tresolveEffectiveRunning(internalTask);\n\t\t\t};\n\n\t\t\tconst stop = () => {\n\t\t\t\tinternalTask.started = false;\n\t\t\t\tresolveEffectiveRunning(internalTask);\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\ttask: internalTask.task,\n\t\t\t\tstart,\n\t\t\t\tstop,\n\t\t\t\tstarted: internalTask.startedStore,\n\t\t\t\tunsubscribe: () => {\n\t\t\t\t\tconst current = stage.tasks.get(key);\n\t\t\t\t\tif (current === internalTask && stage.tasks.delete(key)) {\n\t\t\t\t\t\tmarkScheduleDirty();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\trun(state) {\n\t\t\tconst clampedDelta = Math.min(state.delta, maxDelta);\n\t\t\tconst frameState =\n\t\t\t\tclampedDelta === state.delta\n\t\t\t\t\t? state\n\t\t\t\t\t: {\n\t\t\t\t\t\t\t...state,\n\t\t\t\t\t\t\tdelta: clampedDelta\n\t\t\t\t\t\t};\n\t\t\tsyncSchedule();\n\t\t\tconst frameStart = profilingEnabled ? performance.now() : 0;\n\t\t\tconst stageTimings: FrameRunTimings['stages'] = {};\n\n\t\t\tfor (const stage of sortedStages) {\n\t\t\t\tif (!stage.started) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst stageStart = profilingEnabled ? performance.now() : 0;\n\t\t\t\tconst taskTimings: Record<string, number> = {};\n\t\t\t\tconst taskList = sortedTasksByStage.get(stage.key) ?? [];\n\n\t\t\t\tstage.callback(frameState, () => {\n\t\t\t\t\tfor (const task of taskList) {\n\t\t\t\t\t\tif (!resolveEffectiveRunning(task)) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst taskStart = profilingEnabled ? performance.now() : 0;\n\n\t\t\t\t\t\ttask.callback(frameState);\n\t\t\t\t\t\tif (profilingEnabled) {\n\t\t\t\t\t\t\ttaskTimings[frameKeyToString(task.task.key)] = performance.now() - taskStart;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tapplyTaskInvalidation(task);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tif (profilingEnabled) {\n\t\t\t\t\tstageTimings[frameKeyToString(stage.key)] = {\n\t\t\t\t\t\tduration: performance.now() - stageStart,\n\t\t\t\t\t\ttasks: taskTimings\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (profilingEnabled) {\n\t\t\t\tconst timings = {\n\t\t\t\t\ttotal: performance.now() - frameStart,\n\t\t\t\t\tstages: stageTimings\n\t\t\t\t};\n\t\t\t\tlastRunTimings = timings;\n\t\t\t\tpushProfile(timings);\n\t\t\t}\n\t\t},\n\t\tinvalidate(token) {\n\t\t\tinvalidateWithToken(token);\n\t\t},\n\t\tadvance() {\n\t\t\tshouldAdvance = true;\n\t\t\tinvalidateWithToken();\n\t\t},\n\t\tshouldRender() {\n\t\t\tif (!autoRender) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (renderMode === 'always') {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (renderMode === 'on-demand') {\n\t\t\t\treturn shouldAdvance || hasPendingInvalidation();\n\t\t\t}\n\n\t\t\treturn shouldAdvance;\n\t\t},\n\t\tendFrame() {\n\t\t\thasUntokenizedInvalidation = false;\n\t\t\tinvalidationTokens.clear();\n\t\t\tshouldAdvance = false;\n\t\t},\n\t\tsetRenderMode(mode) {\n\t\t\tif (renderMode === mode) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\trenderMode = mode;\n\t\t\tshouldAdvance = false;\n\t\t\tif (mode === 'on-demand') {\n\t\t\t\tinvalidateWithToken(RENDER_MODE_INVALIDATION_TOKEN);\n\t\t\t}\n\t\t},\n\t\tsetAutoRender(enabled) {\n\t\t\tautoRender = enabled;\n\t\t},\n\t\tsetMaxDelta(value) {\n\t\t\tmaxDelta = assertMaxDelta(value);\n\t\t},\n\t\tsetProfilingEnabled(enabled) {\n\t\t\tprofilingEnabled = enabled;\n\t\t\tif (!enabled) {\n\t\t\t\tclearProfiling();\n\t\t\t}\n\t\t},\n\t\tsetProfilingWindow(window) {\n\t\t\tprofilingWindow = assertProfilingWindow(window);\n\t\t\twhile (profilingHistory.length > profilingWindow) {\n\t\t\t\tprofilingHistory.shift();\n\t\t\t}\n\t\t},\n\t\tresetProfiling() {\n\t\t\tclearProfiling();\n\t\t},\n\t\tsetDiagnosticsEnabled(enabled) {\n\t\t\tprofilingEnabled = enabled;\n\t\t\tif (!enabled) {\n\t\t\t\tclearProfiling();\n\t\t\t}\n\t\t},\n\t\tgetRenderMode() {\n\t\t\treturn renderMode;\n\t\t},\n\t\tgetAutoRender() {\n\t\t\treturn autoRender;\n\t\t},\n\t\tgetMaxDelta() {\n\t\t\treturn maxDelta;\n\t\t},\n\t\tgetProfilingEnabled() {\n\t\t\treturn profilingEnabled;\n\t\t},\n\t\tgetProfilingWindow() {\n\t\t\treturn profilingWindow;\n\t\t},\n\t\tgetProfilingSnapshot() {\n\t\t\treturn buildProfilingSnapshot();\n\t\t},\n\t\tgetDiagnosticsEnabled() {\n\t\t\treturn profilingEnabled;\n\t\t},\n\t\tgetLastRunTimings() {\n\t\t\treturn lastRunTimings;\n\t\t},\n\t\tgetSchedule() {\n\t\t\tsyncSchedule();\n\t\t\treturn scheduleSnapshot;\n\t\t},\n\t\tcreateStage(key, options) {\n\t\t\tconst stageOptions: Parameters<typeof ensureStage>[1] | undefined = options\n\t\t\t\t? {\n\t\t\t\t\t\t...(Object.prototype.hasOwnProperty.call(options, 'before')\n\t\t\t\t\t\t\t? { before: asArray(options.before) }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t...(Object.prototype.hasOwnProperty.call(options, 'after')\n\t\t\t\t\t\t\t? { after: asArray(options.after) }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t...(Object.prototype.hasOwnProperty.call(options, 'callback')\n\t\t\t\t\t\t\t? { callback: options.callback ?? null }\n\t\t\t\t\t\t\t: {})\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\t\t\tconst stage = ensureStage(key, stageOptions);\n\t\t\treturn { key: stage.key };\n\t\t},\n\t\tgetStage(key) {\n\t\t\tconst stage = stages.get(key);\n\t\t\tif (!stage) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\treturn { key: stage.key };\n\t\t},\n\t\tclear() {\n\t\t\tfor (const stage of stages.values()) {\n\t\t\t\tstage.tasks.clear();\n\t\t\t}\n\t\t\tmarkScheduleDirty();\n\t\t}\n\t};\n}\n"],"mappings":"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"}
@@ -9,11 +9,15 @@ export { createCurrentWritable } from './current-value.js';
9
9
  export { createFrameRegistry } from './frame-registry.js';
10
10
  export { createMotionGPURuntimeLoop } from './runtime-loop.js';
11
11
  export { loadTexturesFromUrls } from './texture-loader.js';
12
- export { BlitPass, CopyPass, ShaderPass } from '../passes/index.js';
12
+ export { BlitPass, CopyPass, ShaderPass, ComputePass, PingPongComputePass } from '../passes/index.js';
13
13
  export type { CurrentReadable, CurrentWritable, Subscribable } from './current-value.js';
14
14
  export type { MotionGPUErrorCode, MotionGPUErrorContext, MotionGPUErrorPhase, MotionGPUErrorReport, MotionGPUErrorSeverity, MotionGPUErrorSource, MotionGPUErrorSourceLine } from './error-report.js';
15
15
  export type { FrameCallback, FrameKey, FrameProfilingSnapshot, FrameRegistry, FrameRunTimings, FrameScheduleSnapshot, FrameStage, FrameStageCallback, FrameTask, FrameTaskInvalidation, FrameTaskInvalidationToken, FrameTimingStats, UseFrameOptions, UseFrameResult } from './frame-registry.js';
16
16
  export type { FragMaterial, FragMaterialInput, MaterialDefineValue, MaterialDefines, MaterialIncludes, ResolvedMaterial, TypedMaterialDefineValue } from './material.js';
17
17
  export type { MotionGPURuntimeLoop, MotionGPURuntimeLoopOptions } from './runtime-loop.js';
18
18
  export type { LoadedTexture, TextureDecodeOptions, TextureLoadOptions } from './texture-loader.js';
19
- export type { FrameInvalidationToken, FrameState, OutputColorSpace, RenderPass, RenderPassContext, RenderPassFlags, RenderPassInputSlot, RenderPassOutputSlot, RenderMode, RenderTarget, RenderTargetDefinition, RenderTargetDefinitionMap, TextureData, TextureDefinition, TextureDefinitionMap, TextureMap, TextureSource, TextureUpdateMode, TextureValue, TypedUniform, UniformLayout, UniformLayoutEntry, UniformMap, UniformMat4Value, UniformType, UniformValue } from './types.js';
19
+ export type { FrameInvalidationToken, FrameState, OutputColorSpace, AnyPass, ComputePassLike, RenderPass, RenderPassContext, RenderPassFlags, RenderPassInputSlot, RenderPassOutputSlot, RenderMode, RenderTarget, RenderTargetDefinition, RenderTargetDefinitionMap, TextureData, TextureDefinition, TextureDefinitionMap, TextureMap, TextureSource, TextureUpdateMode, TextureValue, TypedUniform, UniformLayout, UniformLayoutEntry, UniformMap, UniformMat4Value, UniformType, UniformValue } from './types.js';
20
+ export type { StorageBufferAccess, StorageBufferDefinition, StorageBufferDefinitionMap, StorageBufferType, ComputePassContext } from './types.js';
21
+ export type { ComputePassOptions, ComputeDispatchContext } from '../passes/ComputePass.js';
22
+ export type { PingPongComputePassOptions } from '../passes/PingPongComputePass.js';
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/core/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EACN,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACzF,YAAY,EACX,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,wBAAwB,EACxB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACX,aAAa,EACb,QAAQ,EACR,sBAAsB,EACtB,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,kBAAkB,EAClB,SAAS,EACT,qBAAqB,EACrB,0BAA0B,EAC1B,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACX,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,wBAAwB,EACxB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAC3F,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACnG,YAAY,EACX,sBAAsB,EACtB,UAAU,EACV,gBAAgB,EAChB,OAAO,EACP,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,UAAU,EACV,YAAY,EACZ,sBAAsB,EACtB,yBAAyB,EACzB,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EACX,mBAAmB,EACnB,uBAAuB,EACvB,0BAA0B,EAC1B,iBAAiB,EACjB,kBAAkB,EAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAC3F,YAAY,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC"}
@@ -1,12 +1,13 @@
1
- /**
2
- * Framework-agnostic MotionGPU core entrypoint.
3
- *
4
- * This surface is intended for building framework adapters (Svelte/React/Vue).
5
- */
6
- export { defineMaterial, resolveMaterial } from './material.js';
7
- export { toMotionGPUErrorReport } from './error-report.js';
8
- export { createCurrentWritable } from './current-value.js';
9
- export { createFrameRegistry } from './frame-registry.js';
10
- export { createMotionGPURuntimeLoop } from './runtime-loop.js';
11
- export { loadTexturesFromUrls } from './texture-loader.js';
12
- export { BlitPass, CopyPass, ShaderPass } from '../passes/index.js';
1
+ import { defineMaterial, resolveMaterial } from "./material.js";
2
+ import { toMotionGPUErrorReport } from "./error-report.js";
3
+ import { createCurrentWritable } from "./current-value.js";
4
+ import { createFrameRegistry } from "./frame-registry.js";
5
+ import { createMotionGPURuntimeLoop } from "./runtime-loop.js";
6
+ import { loadTexturesFromUrls } from "./texture-loader.js";
7
+ import { BlitPass } from "../passes/BlitPass.js";
8
+ import { CopyPass } from "../passes/CopyPass.js";
9
+ import { ShaderPass } from "../passes/ShaderPass.js";
10
+ import { ComputePass } from "../passes/ComputePass.js";
11
+ import { PingPongComputePass } from "../passes/PingPongComputePass.js";
12
+ import "../passes/index.js";
13
+ export { BlitPass, ComputePass, CopyPass, PingPongComputePass, ShaderPass, createCurrentWritable, createFrameRegistry, createMotionGPURuntimeLoop, defineMaterial, loadTexturesFromUrls, resolveMaterial, toMotionGPUErrorReport };
@@ -61,3 +61,4 @@ export declare function preprocessMaterialFragment<TDefineKey extends string, TI
61
61
  defines?: MaterialDefines<TDefineKey>;
62
62
  includes?: MaterialIncludes<TIncludeKey>;
63
63
  }): PreprocessedMaterialFragment;
64
+ //# sourceMappingURL=material-preprocess.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material-preprocess.d.ts","sourceRoot":"","sources":["../../src/lib/core/material-preprocess.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAEhB,MAAM,eAAe,CAAC;AAIvB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACtC;;OAEG;IACH,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IACxC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC5C;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAqCD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,SAAS,MAAM,EACzD,OAAO,EAAE,eAAe,CAAC,UAAU,CAAC,GAAG,SAAS,GAC9C,eAAe,CAAC,UAAU,CAAC,CA0B7B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,SAAS,MAAM,EAC3D,QAAQ,EAAE,gBAAgB,CAAC,WAAW,CAAC,GAAG,SAAS,GACjD,gBAAgB,CAAC,WAAW,CAAC,CAY/B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAyB5E;AAoED;;GAEG;AACH,wBAAgB,0BAA0B,CACzC,UAAU,SAAS,MAAM,EACzB,WAAW,SAAS,MAAM,EACzB,KAAK,EAAE;IACR,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACzC,GAAG,4BAA4B,CA8C/B"}
@@ -1,163 +1,142 @@
1
- import { assertUniformName } from './uniforms.js';
2
- const INCLUDE_DIRECTIVE_PATTERN = /^\s*#include\s+<([A-Za-z_][A-Za-z0-9_]*)>\s*$/;
1
+ import { assertUniformName } from "./uniforms.js";
2
+ //#region src/lib/core/material-preprocess.ts
3
+ var INCLUDE_DIRECTIVE_PATTERN = /^\s*#include\s+<([A-Za-z_][A-Za-z0-9_]*)>\s*$/;
3
4
  function normalizeTypedDefine(name, define) {
4
- const value = define.value;
5
- if (define.type === 'bool') {
6
- if (typeof value !== 'boolean') {
7
- throw new Error(`Invalid define value for "${name}". bool define requires boolean value.`);
8
- }
9
- return {
10
- type: 'bool',
11
- value
12
- };
13
- }
14
- if (typeof value !== 'number' || !Number.isFinite(value)) {
15
- throw new Error(`Invalid define value for "${name}". Numeric define must be finite.`);
16
- }
17
- if ((define.type === 'i32' || define.type === 'u32') && !Number.isInteger(value)) {
18
- throw new Error(`Invalid define value for "${name}". ${define.type} define requires integer.`);
19
- }
20
- if (define.type === 'u32' && value < 0) {
21
- throw new Error(`Invalid define value for "${name}". u32 define must be >= 0.`);
22
- }
23
- return {
24
- type: define.type,
25
- value
26
- };
5
+ const value = define.value;
6
+ if (define.type === "bool") {
7
+ if (typeof value !== "boolean") throw new Error(`Invalid define value for "${name}". bool define requires boolean value.`);
8
+ return {
9
+ type: "bool",
10
+ value
11
+ };
12
+ }
13
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`Invalid define value for "${name}". Numeric define must be finite.`);
14
+ if ((define.type === "i32" || define.type === "u32") && !Number.isInteger(value)) throw new Error(`Invalid define value for "${name}". ${define.type} define requires integer.`);
15
+ if (define.type === "u32" && value < 0) throw new Error(`Invalid define value for "${name}". u32 define must be >= 0.`);
16
+ return {
17
+ type: define.type,
18
+ value
19
+ };
27
20
  }
28
21
  /**
29
- * Validates and normalizes define entries.
30
- */
31
- export function normalizeDefines(defines) {
32
- const resolved = {};
33
- for (const [name, value] of Object.entries(defines ?? {})) {
34
- assertUniformName(name);
35
- if (typeof value === 'boolean') {
36
- resolved[name] = value;
37
- continue;
38
- }
39
- if (typeof value === 'number') {
40
- if (!Number.isFinite(value)) {
41
- throw new Error(`Invalid define value for "${name}". Define numbers must be finite.`);
42
- }
43
- resolved[name] = value;
44
- continue;
45
- }
46
- const normalized = normalizeTypedDefine(name, value);
47
- resolved[name] = Object.freeze(normalized);
48
- }
49
- return resolved;
22
+ * Validates and normalizes define entries.
23
+ */
24
+ function normalizeDefines(defines) {
25
+ const resolved = {};
26
+ for (const [name, value] of Object.entries(defines ?? {})) {
27
+ assertUniformName(name);
28
+ if (typeof value === "boolean") {
29
+ resolved[name] = value;
30
+ continue;
31
+ }
32
+ if (typeof value === "number") {
33
+ if (!Number.isFinite(value)) throw new Error(`Invalid define value for "${name}". Define numbers must be finite.`);
34
+ resolved[name] = value;
35
+ continue;
36
+ }
37
+ const normalized = normalizeTypedDefine(name, value);
38
+ resolved[name] = Object.freeze(normalized);
39
+ }
40
+ return resolved;
50
41
  }
51
42
  /**
52
- * Validates include map identifiers and source chunks.
53
- */
54
- export function normalizeIncludes(includes) {
55
- const resolved = {};
56
- for (const [name, source] of Object.entries(includes ?? {})) {
57
- assertUniformName(name);
58
- if (typeof source !== 'string' || source.trim().length === 0) {
59
- throw new Error(`Invalid include "${name}". Include source must be a non-empty WGSL string.`);
60
- }
61
- resolved[name] = source;
62
- }
63
- return resolved;
43
+ * Validates include map identifiers and source chunks.
44
+ */
45
+ function normalizeIncludes(includes) {
46
+ const resolved = {};
47
+ for (const [name, source] of Object.entries(includes ?? {})) {
48
+ assertUniformName(name);
49
+ if (typeof source !== "string" || source.trim().length === 0) throw new Error(`Invalid include "${name}". Include source must be a non-empty WGSL string.`);
50
+ resolved[name] = source;
51
+ }
52
+ return resolved;
64
53
  }
65
54
  /**
66
- * Converts one define declaration to WGSL `const`.
67
- */
68
- export function toDefineLine(key, value) {
69
- if (typeof value === 'boolean') {
70
- return `const ${key}: bool = ${value ? 'true' : 'false'};`;
71
- }
72
- if (typeof value === 'number') {
73
- const valueLiteral = Number.isInteger(value) ? `${value}.0` : `${value}`;
74
- return `const ${key}: f32 = ${valueLiteral};`;
75
- }
76
- if (value.type === 'bool') {
77
- return `const ${key}: bool = ${value.value ? 'true' : 'false'};`;
78
- }
79
- if (value.type === 'f32') {
80
- const numberValue = value.value;
81
- const valueLiteral = Number.isInteger(numberValue) ? `${numberValue}.0` : `${numberValue}`;
82
- return `const ${key}: f32 = ${valueLiteral};`;
83
- }
84
- if (value.type === 'i32') {
85
- return `const ${key}: i32 = ${value.value};`;
86
- }
87
- return `const ${key}: u32 = ${value.value}u;`;
55
+ * Converts one define declaration to WGSL `const`.
56
+ */
57
+ function toDefineLine(key, value) {
58
+ if (typeof value === "boolean") return `const ${key}: bool = ${value ? "true" : "false"};`;
59
+ if (typeof value === "number") return `const ${key}: f32 = ${Number.isInteger(value) ? `${value}.0` : `${value}`};`;
60
+ if (value.type === "bool") return `const ${key}: bool = ${value.value ? "true" : "false"};`;
61
+ if (value.type === "f32") {
62
+ const numberValue = value.value;
63
+ return `const ${key}: f32 = ${Number.isInteger(numberValue) ? `${numberValue}.0` : `${numberValue}`};`;
64
+ }
65
+ if (value.type === "i32") return `const ${key}: i32 = ${value.value};`;
66
+ return `const ${key}: u32 = ${value.value}u;`;
88
67
  }
89
- function expandChunk(source, kind, includeName, includes, stack) {
90
- const sourceLines = source.split('\n');
91
- const lines = [];
92
- const mapEntries = [];
93
- for (let index = 0; index < sourceLines.length; index += 1) {
94
- const sourceLine = sourceLines[index];
95
- if (sourceLine === undefined) {
96
- continue;
97
- }
98
- const includeMatch = sourceLine.match(INCLUDE_DIRECTIVE_PATTERN);
99
- if (!includeMatch) {
100
- lines.push(sourceLine);
101
- mapEntries.push({
102
- kind,
103
- line: index + 1,
104
- ...(kind === 'include' && includeName ? { include: includeName } : {})
105
- });
106
- continue;
107
- }
108
- const includeKey = includeMatch[1];
109
- if (!includeKey) {
110
- throw new Error('Invalid include directive in fragment shader.');
111
- }
112
- assertUniformName(includeKey);
113
- const includeSource = includes[includeKey];
114
- if (!includeSource) {
115
- throw new Error(`Unknown include "${includeKey}" referenced in fragment shader.`);
116
- }
117
- if (stack.includes(includeKey)) {
118
- throw new Error(`Circular include detected for "${includeKey}". Include stack: ${[...stack, includeKey].join(' -> ')}.`);
119
- }
120
- const nested = expandChunk(includeSource, 'include', includeKey, includes, [
121
- ...stack,
122
- includeKey
123
- ]);
124
- lines.push(...nested.lines);
125
- mapEntries.push(...nested.mapEntries);
126
- }
127
- return { lines, mapEntries };
68
+ function expandChunk(source, kind, includeName, includes, stack, expandedIncludes) {
69
+ const sourceLines = source.split("\n");
70
+ const lines = [];
71
+ const mapEntries = [];
72
+ for (let index = 0; index < sourceLines.length; index += 1) {
73
+ const sourceLine = sourceLines[index];
74
+ if (sourceLine === void 0) continue;
75
+ const includeMatch = sourceLine.match(INCLUDE_DIRECTIVE_PATTERN);
76
+ if (!includeMatch) {
77
+ lines.push(sourceLine);
78
+ mapEntries.push({
79
+ kind,
80
+ line: index + 1,
81
+ ...kind === "include" && includeName ? { include: includeName } : {}
82
+ });
83
+ continue;
84
+ }
85
+ const includeKey = includeMatch[1];
86
+ if (!includeKey) throw new Error("Invalid include directive in fragment shader.");
87
+ assertUniformName(includeKey);
88
+ const includeSource = includes[includeKey];
89
+ if (!includeSource) throw new Error(`Unknown include "${includeKey}" referenced in fragment shader.`);
90
+ if (stack.includes(includeKey)) throw new Error(`Circular include detected for "${includeKey}". Include stack: ${[...stack, includeKey].join(" -> ")}.`);
91
+ if (expandedIncludes.has(includeKey)) continue;
92
+ expandedIncludes.add(includeKey);
93
+ const nested = expandChunk(includeSource, "include", includeKey, includes, [...stack, includeKey], expandedIncludes);
94
+ lines.push(...nested.lines);
95
+ mapEntries.push(...nested.mapEntries);
96
+ }
97
+ return {
98
+ lines,
99
+ mapEntries
100
+ };
128
101
  }
129
102
  /**
130
- * Preprocesses material fragment with deterministic define/include expansion and line mapping.
131
- */
132
- export function preprocessMaterialFragment(input) {
133
- const normalizedDefines = normalizeDefines(input.defines);
134
- const normalizedIncludes = normalizeIncludes(input.includes);
135
- const fragmentExpanded = expandChunk(input.fragment, 'fragment', undefined, normalizedIncludes, []);
136
- const defineEntries = Object.entries(normalizedDefines).sort(([a], [b]) => a.localeCompare(b));
137
- const lines = [];
138
- const defineLines = [];
139
- const mapEntries = [];
140
- for (let index = 0; index < defineEntries.length; index += 1) {
141
- const entry = defineEntries[index];
142
- if (!entry) {
143
- continue;
144
- }
145
- const [name, value] = entry;
146
- const defineLine = toDefineLine(name, value);
147
- lines.push(defineLine);
148
- defineLines.push(defineLine);
149
- mapEntries.push({ kind: 'define', line: index + 1, define: name });
150
- }
151
- if (defineEntries.length > 0) {
152
- lines.push('');
153
- mapEntries.push(null);
154
- }
155
- lines.push(...fragmentExpanded.lines);
156
- mapEntries.push(...fragmentExpanded.mapEntries);
157
- const lineMap = [null, ...mapEntries];
158
- return {
159
- fragment: lines.join('\n'),
160
- lineMap,
161
- defineBlockSource: defineLines.join('\n')
162
- };
103
+ * Preprocesses material fragment with deterministic define/include expansion and line mapping.
104
+ */
105
+ function preprocessMaterialFragment(input) {
106
+ const normalizedDefines = normalizeDefines(input.defines);
107
+ const normalizedIncludes = normalizeIncludes(input.includes);
108
+ const fragmentExpanded = expandChunk(input.fragment, "fragment", void 0, normalizedIncludes, [], /* @__PURE__ */ new Set());
109
+ const defineEntries = Object.entries(normalizedDefines).sort(([a], [b]) => a.localeCompare(b));
110
+ const lines = [];
111
+ const defineLines = [];
112
+ const mapEntries = [];
113
+ for (let index = 0; index < defineEntries.length; index += 1) {
114
+ const entry = defineEntries[index];
115
+ if (!entry) continue;
116
+ const [name, value] = entry;
117
+ const defineLine = toDefineLine(name, value);
118
+ lines.push(defineLine);
119
+ defineLines.push(defineLine);
120
+ mapEntries.push({
121
+ kind: "define",
122
+ line: index + 1,
123
+ define: name
124
+ });
125
+ }
126
+ if (defineEntries.length > 0) {
127
+ lines.push("");
128
+ mapEntries.push(null);
129
+ }
130
+ lines.push(...fragmentExpanded.lines);
131
+ mapEntries.push(...fragmentExpanded.mapEntries);
132
+ const lineMap = [null, ...mapEntries];
133
+ return {
134
+ fragment: lines.join("\n"),
135
+ lineMap,
136
+ defineBlockSource: defineLines.join("\n")
137
+ };
163
138
  }
139
+ //#endregion
140
+ export { normalizeDefines, normalizeIncludes, preprocessMaterialFragment, toDefineLine };
141
+
142
+ //# sourceMappingURL=material-preprocess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material-preprocess.js","names":[],"sources":["../../src/lib/core/material-preprocess.ts"],"sourcesContent":["import { assertUniformName } from './uniforms.js';\nimport type {\n\tMaterialDefineValue,\n\tMaterialDefines,\n\tMaterialIncludes,\n\tTypedMaterialDefineValue\n} from './material.js';\n\nconst INCLUDE_DIRECTIVE_PATTERN = /^\\s*#include\\s+<([A-Za-z_][A-Za-z0-9_]*)>\\s*$/;\n\n/**\n * Source location metadata for one generated fragment line.\n */\nexport interface MaterialSourceLocation {\n\t/**\n\t * Origin category for this generated line.\n\t */\n\tkind: 'fragment' | 'include' | 'define';\n\t/**\n\t * 1-based line in the origin source.\n\t */\n\tline: number;\n\t/**\n\t * Include chunk identifier when `kind === \"include\"`.\n\t */\n\tinclude?: string;\n\t/**\n\t * Define identifier when `kind === \"define\"`.\n\t */\n\tdefine?: string;\n}\n\n/**\n * 1-based line map from generated fragment WGSL to user source locations.\n */\nexport type MaterialLineMap = Array<MaterialSourceLocation | null>;\n\n/**\n * Preprocess output used by material resolution and diagnostics mapping.\n */\nexport interface PreprocessedMaterialFragment {\n\t/**\n\t * Final fragment source after defines/include expansion.\n\t */\n\tfragment: string;\n\t/**\n\t * 1-based generated-line source map.\n\t */\n\tlineMap: MaterialLineMap;\n\t/**\n\t * Deterministic WGSL define block used to build the final fragment source.\n\t */\n\tdefineBlockSource: string;\n}\n\nfunction normalizeTypedDefine(\n\tname: string,\n\tdefine: TypedMaterialDefineValue\n): TypedMaterialDefineValue {\n\tconst value = define.value;\n\n\tif (define.type === 'bool') {\n\t\tif (typeof value !== 'boolean') {\n\t\t\tthrow new Error(`Invalid define value for \"${name}\". bool define requires boolean value.`);\n\t\t}\n\n\t\treturn {\n\t\t\ttype: 'bool',\n\t\t\tvalue\n\t\t};\n\t}\n\n\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\tthrow new Error(`Invalid define value for \"${name}\". Numeric define must be finite.`);\n\t}\n\n\tif ((define.type === 'i32' || define.type === 'u32') && !Number.isInteger(value)) {\n\t\tthrow new Error(`Invalid define value for \"${name}\". ${define.type} define requires integer.`);\n\t}\n\n\tif (define.type === 'u32' && value < 0) {\n\t\tthrow new Error(`Invalid define value for \"${name}\". u32 define must be >= 0.`);\n\t}\n\n\treturn {\n\t\ttype: define.type,\n\t\tvalue\n\t};\n}\n\n/**\n * Validates and normalizes define entries.\n */\nexport function normalizeDefines<TDefineKey extends string>(\n\tdefines: MaterialDefines<TDefineKey> | undefined\n): MaterialDefines<TDefineKey> {\n\tconst resolved: MaterialDefines<TDefineKey> = {} as MaterialDefines<TDefineKey>;\n\n\tfor (const [name, value] of Object.entries(defines ?? {}) as Array<\n\t\t[TDefineKey, MaterialDefineValue]\n\t>) {\n\t\tassertUniformName(name);\n\n\t\tif (typeof value === 'boolean') {\n\t\t\tresolved[name] = value;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (typeof value === 'number') {\n\t\t\tif (!Number.isFinite(value)) {\n\t\t\t\tthrow new Error(`Invalid define value for \"${name}\". Define numbers must be finite.`);\n\t\t\t}\n\t\t\tresolved[name] = value;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst normalized = normalizeTypedDefine(name, value);\n\t\tresolved[name] = Object.freeze(normalized);\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Validates include map identifiers and source chunks.\n */\nexport function normalizeIncludes<TIncludeKey extends string>(\n\tincludes: MaterialIncludes<TIncludeKey> | undefined\n): MaterialIncludes<TIncludeKey> {\n\tconst resolved: MaterialIncludes<TIncludeKey> = {} as MaterialIncludes<TIncludeKey>;\n\n\tfor (const [name, source] of Object.entries(includes ?? {}) as Array<[TIncludeKey, string]>) {\n\t\tassertUniformName(name);\n\t\tif (typeof source !== 'string' || source.trim().length === 0) {\n\t\t\tthrow new Error(`Invalid include \"${name}\". Include source must be a non-empty WGSL string.`);\n\t\t}\n\t\tresolved[name] = source;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Converts one define declaration to WGSL `const`.\n */\nexport function toDefineLine(key: string, value: MaterialDefineValue): string {\n\tif (typeof value === 'boolean') {\n\t\treturn `const ${key}: bool = ${value ? 'true' : 'false'};`;\n\t}\n\n\tif (typeof value === 'number') {\n\t\tconst valueLiteral = Number.isInteger(value) ? `${value}.0` : `${value}`;\n\t\treturn `const ${key}: f32 = ${valueLiteral};`;\n\t}\n\n\tif (value.type === 'bool') {\n\t\treturn `const ${key}: bool = ${value.value ? 'true' : 'false'};`;\n\t}\n\n\tif (value.type === 'f32') {\n\t\tconst numberValue = value.value as number;\n\t\tconst valueLiteral = Number.isInteger(numberValue) ? `${numberValue}.0` : `${numberValue}`;\n\t\treturn `const ${key}: f32 = ${valueLiteral};`;\n\t}\n\n\tif (value.type === 'i32') {\n\t\treturn `const ${key}: i32 = ${value.value};`;\n\t}\n\n\treturn `const ${key}: u32 = ${value.value}u;`;\n}\n\nfunction expandChunk(\n\tsource: string,\n\tkind: 'fragment' | 'include',\n\tincludeName: string | undefined,\n\tincludes: Record<string, string>,\n\tstack: string[],\n\texpandedIncludes: Set<string>\n): { lines: string[]; mapEntries: MaterialSourceLocation[] } {\n\tconst sourceLines = source.split('\\n');\n\tconst lines: string[] = [];\n\tconst mapEntries: MaterialSourceLocation[] = [];\n\n\tfor (let index = 0; index < sourceLines.length; index += 1) {\n\t\tconst sourceLine = sourceLines[index];\n\t\tif (sourceLine === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst includeMatch = sourceLine.match(INCLUDE_DIRECTIVE_PATTERN);\n\t\tif (!includeMatch) {\n\t\t\tlines.push(sourceLine);\n\t\t\tmapEntries.push({\n\t\t\t\tkind,\n\t\t\t\tline: index + 1,\n\t\t\t\t...(kind === 'include' && includeName ? { include: includeName } : {})\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst includeKey = includeMatch[1];\n\t\tif (!includeKey) {\n\t\t\tthrow new Error('Invalid include directive in fragment shader.');\n\t\t}\n\n\t\tassertUniformName(includeKey);\n\t\tconst includeSource = includes[includeKey];\n\t\tif (!includeSource) {\n\t\t\tthrow new Error(`Unknown include \"${includeKey}\" referenced in fragment shader.`);\n\t\t}\n\n\t\tif (stack.includes(includeKey)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Circular include detected for \"${includeKey}\". Include stack: ${[...stack, includeKey].join(' -> ')}.`\n\t\t\t);\n\t\t}\n\n\t\tif (expandedIncludes.has(includeKey)) {\n\t\t\tcontinue;\n\t\t}\n\t\texpandedIncludes.add(includeKey);\n\n\t\tconst nested = expandChunk(\n\t\t\tincludeSource,\n\t\t\t'include',\n\t\t\tincludeKey,\n\t\t\tincludes,\n\t\t\t[...stack, includeKey],\n\t\t\texpandedIncludes\n\t\t);\n\t\tlines.push(...nested.lines);\n\t\tmapEntries.push(...nested.mapEntries);\n\t}\n\n\treturn { lines, mapEntries };\n}\n\n/**\n * Preprocesses material fragment with deterministic define/include expansion and line mapping.\n */\nexport function preprocessMaterialFragment<\n\tTDefineKey extends string,\n\tTIncludeKey extends string\n>(input: {\n\tfragment: string;\n\tdefines?: MaterialDefines<TDefineKey>;\n\tincludes?: MaterialIncludes<TIncludeKey>;\n}): PreprocessedMaterialFragment {\n\tconst normalizedDefines = normalizeDefines(input.defines);\n\tconst normalizedIncludes = normalizeIncludes(input.includes);\n\n\tconst fragmentExpanded = expandChunk(\n\t\tinput.fragment,\n\t\t'fragment',\n\t\tundefined,\n\t\tnormalizedIncludes,\n\t\t[],\n\t\tnew Set()\n\t);\n\tconst defineEntries = (\n\t\tObject.entries(normalizedDefines) as Array<[TDefineKey, MaterialDefineValue]>\n\t).sort(([a], [b]) => a.localeCompare(b));\n\tconst lines: string[] = [];\n\tconst defineLines: string[] = [];\n\tconst mapEntries: Array<MaterialSourceLocation | null> = [];\n\n\tfor (let index = 0; index < defineEntries.length; index += 1) {\n\t\tconst entry = defineEntries[index];\n\t\tif (!entry) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst [name, value] = entry;\n\t\tconst defineLine = toDefineLine(name, value);\n\t\tlines.push(defineLine);\n\t\tdefineLines.push(defineLine);\n\t\tmapEntries.push({ kind: 'define', line: index + 1, define: name });\n\t}\n\n\tif (defineEntries.length > 0) {\n\t\tlines.push('');\n\t\tmapEntries.push(null);\n\t}\n\n\tlines.push(...fragmentExpanded.lines);\n\tmapEntries.push(...fragmentExpanded.mapEntries);\n\n\tconst lineMap: MaterialLineMap = [null, ...mapEntries];\n\treturn {\n\t\tfragment: lines.join('\\n'),\n\t\tlineMap,\n\t\tdefineBlockSource: defineLines.join('\\n')\n\t};\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import type { MaterialSourceMetadata } from './error-diagnostics.js';
2
2
  import { resolveUniformLayout } from './uniforms.js';
3
3
  import { type MaterialLineMap } from './material-preprocess.js';
4
- import type { TextureDefinitionMap, UniformMap } from './types.js';
4
+ import type { StorageBufferDefinitionMap, TextureDefinitionMap, UniformMap } from './types.js';
5
5
  /**
6
6
  * Typed compile-time define declaration.
7
7
  */
@@ -39,7 +39,7 @@ export type MaterialIncludes<TKey extends string = string> = Record<TKey, string
39
39
  /**
40
40
  * External material input accepted by {@link defineMaterial}.
41
41
  */
42
- export interface FragMaterialInput<TUniformKey extends string = string, TTextureKey extends string = string, TDefineKey extends string = string, TIncludeKey extends string = string> {
42
+ export interface FragMaterialInput<TUniformKey extends string = string, TTextureKey extends string = string, TDefineKey extends string = string, TIncludeKey extends string = string, TStorageBufferKey extends string = string> {
43
43
  /**
44
44
  * User WGSL source containing `frag(uv: vec2f) -> vec4f`.
45
45
  */
@@ -60,11 +60,15 @@ export interface FragMaterialInput<TUniformKey extends string = string, TTexture
60
60
  * Optional WGSL include chunks used by `#include <name>` directives.
61
61
  */
62
62
  includes?: MaterialIncludes<TIncludeKey>;
63
+ /**
64
+ * Optional storage buffer definitions for compute shaders.
65
+ */
66
+ storageBuffers?: StorageBufferDefinitionMap<TStorageBufferKey>;
63
67
  }
64
68
  /**
65
69
  * Normalized and immutable material declaration consumed by `FragCanvas`.
66
70
  */
67
- export interface FragMaterial<TUniformKey extends string = string, TTextureKey extends string = string, TDefineKey extends string = string, TIncludeKey extends string = string> {
71
+ export interface FragMaterial<TUniformKey extends string = string, TTextureKey extends string = string, TDefineKey extends string = string, TIncludeKey extends string = string, TStorageBufferKey extends string = string> {
68
72
  /**
69
73
  * User WGSL source containing `frag(uv: vec2f) -> vec4f`.
70
74
  */
@@ -85,11 +89,15 @@ export interface FragMaterial<TUniformKey extends string = string, TTextureKey e
85
89
  * Optional WGSL include chunks used by `#include <name>` directives.
86
90
  */
87
91
  readonly includes: Readonly<MaterialIncludes<TIncludeKey>>;
92
+ /**
93
+ * Storage buffer definitions for compute shaders. Empty when not provided.
94
+ */
95
+ readonly storageBuffers: Readonly<StorageBufferDefinitionMap<TStorageBufferKey>>;
88
96
  }
89
97
  /**
90
98
  * Fully resolved, immutable material snapshot used for renderer creation/caching.
91
99
  */
92
- export interface ResolvedMaterial<TUniformKey extends string = string, TTextureKey extends string = string, TIncludeKey extends string = string> {
100
+ export interface ResolvedMaterial<TUniformKey extends string = string, TTextureKey extends string = string, TIncludeKey extends string = string, TStorageBufferKey extends string = string> {
93
101
  /**
94
102
  * Final fragment WGSL after define injection.
95
103
  */
@@ -134,6 +142,14 @@ export interface ResolvedMaterial<TUniformKey extends string = string, TTextureK
134
142
  * Source metadata used for diagnostics.
135
143
  */
136
144
  source: Readonly<MaterialSourceMetadata> | null;
145
+ /**
146
+ * Sorted storage buffer keys. Empty array when no storage buffers declared.
147
+ */
148
+ storageBufferKeys: TStorageBufferKey[];
149
+ /**
150
+ * Sorted storage texture keys (textures with storage: true).
151
+ */
152
+ storageTextureKeys: TTextureKey[];
137
153
  }
138
154
  /**
139
155
  * Creates a stable WGSL define block from the provided map.
@@ -156,11 +172,12 @@ export declare function applyMaterialDefines(fragment: string, defines: Material
156
172
  * @param input - User material declaration.
157
173
  * @returns Frozen material object safe to share and cache.
158
174
  */
159
- export declare function defineMaterial<TUniformKey extends string = string, TTextureKey extends string = string, TDefineKey extends string = string, TIncludeKey extends string = string>(input: FragMaterialInput<TUniformKey, TTextureKey, TDefineKey, TIncludeKey>): FragMaterial<TUniformKey, TTextureKey, TDefineKey, TIncludeKey>;
175
+ export declare function defineMaterial<TUniformKey extends string = string, TTextureKey extends string = string, TDefineKey extends string = string, TIncludeKey extends string = string, TStorageBufferKey extends string = string>(input: FragMaterialInput<TUniformKey, TTextureKey, TDefineKey, TIncludeKey, TStorageBufferKey>): FragMaterial<TUniformKey, TTextureKey, TDefineKey, TIncludeKey, TStorageBufferKey>;
160
176
  /**
161
177
  * Resolves a material to renderer-ready data and a deterministic signature.
162
178
  *
163
179
  * @param material - Material input created via {@link defineMaterial}.
164
180
  * @returns Resolved material with packed uniform layout, sorted texture keys and cache signature.
165
181
  */
166
- export declare function resolveMaterial<TUniformKey extends string = string, TTextureKey extends string = string, TDefineKey extends string = string, TIncludeKey extends string = string>(material: FragMaterial<TUniformKey, TTextureKey, TDefineKey, TIncludeKey>): ResolvedMaterial<TUniformKey, TTextureKey, TIncludeKey>;
182
+ export declare function resolveMaterial<TUniformKey extends string = string, TTextureKey extends string = string, TDefineKey extends string = string, TIncludeKey extends string = string, TStorageBufferKey extends string = string>(material: FragMaterial<TUniformKey, TTextureKey, TDefineKey, TIncludeKey, TStorageBufferKey>): ResolvedMaterial<TUniformKey, TTextureKey, TIncludeKey, TStorageBufferKey>;
183
+ //# sourceMappingURL=material.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../../src/lib/core/material.ts"],"names":[],"mappings":"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"}