@photivra/engine 1.5.0 → 2.1.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 (1085) hide show
  1. package/CHANGELOG.md +414 -6
  2. package/CITATION.cff +1 -1
  3. package/NODE_SUPPORT.md +64 -12
  4. package/README.md +301 -182
  5. package/SECURITY.md +37 -28
  6. package/THIRD_PARTY.md +148 -4
  7. package/dist/camera/equivalent-focal-length.d.ts +13 -14
  8. package/dist/camera/equivalent-focal-length.js +15 -13
  9. package/dist/camera/equivalent-focal-length.js.map +1 -1
  10. package/dist/camera/field-of-view.d.ts +30 -19
  11. package/dist/camera/field-of-view.js +67 -18
  12. package/dist/camera/field-of-view.js.map +1 -1
  13. package/dist/camera/lens-projection.d.ts +170 -0
  14. package/dist/camera/lens-projection.js +444 -0
  15. package/dist/camera/lens-projection.js.map +1 -0
  16. package/dist/camera/projected-object-size.d.ts +10 -11
  17. package/dist/camera/projected-object-size.js +12 -10
  18. package/dist/camera/projected-object-size.js.map +1 -1
  19. package/dist/capture/capture-export-metadata.d.ts +9 -10
  20. package/dist/capture/capture-export-metadata.js +8 -5
  21. package/dist/capture/capture-export-metadata.js.map +1 -1
  22. package/dist/capture/dng-import.d.ts +91 -0
  23. package/dist/capture/dng-import.js +343 -0
  24. package/dist/capture/dng-import.js.map +1 -0
  25. package/dist/capture/environment-raw-producer.d.ts +37 -17
  26. package/dist/capture/environment-raw-producer.js +43 -19
  27. package/dist/capture/environment-raw-producer.js.map +1 -1
  28. package/dist/capture/export-jpeg.d.ts +35 -4
  29. package/dist/capture/export-jpeg.js +133 -47
  30. package/dist/capture/export-jpeg.js.map +1 -1
  31. package/dist/capture/export-tiff.d.ts +48 -24
  32. package/dist/capture/export-tiff.js +91 -31
  33. package/dist/capture/export-tiff.js.map +1 -1
  34. package/dist/capture/focus-control.d.ts +42 -65
  35. package/dist/capture/focus-control.js +56 -75
  36. package/dist/capture/focus-control.js.map +1 -1
  37. package/dist/capture/host-yield-cadence.d.ts +25 -0
  38. package/dist/capture/host-yield-cadence.js +25 -0
  39. package/dist/capture/host-yield-cadence.js.map +1 -0
  40. package/dist/capture/linear-encoding.d.ts +14 -12
  41. package/dist/capture/linear-encoding.js +14 -13
  42. package/dist/capture/linear-encoding.js.map +1 -1
  43. package/dist/capture/lossless-jpeg.d.ts +27 -0
  44. package/dist/capture/lossless-jpeg.js +237 -0
  45. package/dist/capture/lossless-jpeg.js.map +1 -0
  46. package/dist/capture/native-environment-lean.d.ts +227 -0
  47. package/dist/capture/native-environment-lean.js +974 -0
  48. package/dist/capture/native-environment-lean.js.map +1 -0
  49. package/dist/capture/native-environment-optical-stage.d.ts +97 -0
  50. package/dist/capture/native-environment-optical-stage.js +340 -0
  51. package/dist/capture/native-environment-optical-stage.js.map +1 -0
  52. package/dist/capture/native-environment-raw.d.ts +140 -6
  53. package/dist/capture/native-environment-raw.js +435 -34
  54. package/dist/capture/native-environment-raw.js.map +1 -1
  55. package/dist/capture/native-raw-development.d.ts +116 -9
  56. package/dist/capture/native-raw-development.js +221 -62
  57. package/dist/capture/native-raw-development.js.map +1 -1
  58. package/dist/capture/native-raw-dng.d.ts +60 -0
  59. package/dist/capture/native-raw-dng.js +167 -0
  60. package/dist/capture/native-raw-dng.js.map +1 -0
  61. package/dist/capture/native-raw.d.ts +65 -12
  62. package/dist/capture/native-raw.js +81 -19
  63. package/dist/capture/native-raw.js.map +1 -1
  64. package/dist/capture/packed-sensor-raw.d.ts +160 -0
  65. package/dist/capture/packed-sensor-raw.js +221 -0
  66. package/dist/capture/packed-sensor-raw.js.map +1 -0
  67. package/dist/capture/photographic-export.d.ts +58 -35
  68. package/dist/capture/photographic-export.js +177 -70
  69. package/dist/capture/photographic-export.js.map +1 -1
  70. package/dist/capture/raw-development-kernel.d.ts +52 -0
  71. package/dist/capture/raw-development-kernel.js +88 -0
  72. package/dist/capture/raw-development-kernel.js.map +1 -0
  73. package/dist/capture/raw-frame-limits.d.ts +7 -7
  74. package/dist/capture/raw-frame-limits.js +7 -6
  75. package/dist/capture/raw-frame-limits.js.map +1 -1
  76. package/dist/capture/raw-frame-reconstruction.d.ts +8 -9
  77. package/dist/capture/raw-frame-reconstruction.js +9 -8
  78. package/dist/capture/raw-frame-reconstruction.js.map +1 -1
  79. package/dist/capture/raw-white-level.d.ts +55 -0
  80. package/dist/capture/raw-white-level.js +165 -0
  81. package/dist/capture/raw-white-level.js.map +1 -0
  82. package/dist/capture/release-sequence.d.ts +5 -7
  83. package/dist/capture/release-sequence.js +15 -13
  84. package/dist/capture/release-sequence.js.map +1 -1
  85. package/dist/capture/sensor-raw-frame.d.ts +5 -6
  86. package/dist/capture/sensor-raw-frame.js +26 -9
  87. package/dist/capture/sensor-raw-frame.js.map +1 -1
  88. package/dist/capture/sensor-raw-producer.d.ts +21 -13
  89. package/dist/capture/sensor-raw-producer.js +86 -25
  90. package/dist/capture/sensor-raw-producer.js.map +1 -1
  91. package/dist/capture/simulated-capture.d.ts +15 -16
  92. package/dist/capture/simulated-capture.js +22 -12
  93. package/dist/capture/simulated-capture.js.map +1 -1
  94. package/dist/color/camera-color-matrix.d.ts +69 -0
  95. package/dist/color/camera-color-matrix.js +132 -0
  96. package/dist/color/camera-color-matrix.js.map +1 -0
  97. package/dist/color/capture-color.d.ts +17 -10
  98. package/dist/color/capture-color.js +50 -17
  99. package/dist/color/capture-color.js.map +1 -1
  100. package/dist/color/chromatic-adaptation.d.ts +63 -0
  101. package/dist/color/chromatic-adaptation.js +91 -0
  102. package/dist/color/chromatic-adaptation.js.map +1 -0
  103. package/dist/color/color-difference.d.ts +104 -0
  104. package/dist/color/color-difference.js +205 -0
  105. package/dist/color/color-difference.js.map +1 -0
  106. package/dist/color/color-matching-functions.d.ts +168 -0
  107. package/dist/color/color-matching-functions.js +309 -0
  108. package/dist/color/color-matching-functions.js.map +1 -0
  109. package/dist/color/colorimetry-math.d.ts +52 -0
  110. package/dist/color/colorimetry-math.js +144 -0
  111. package/dist/color/colorimetry-math.js.map +1 -0
  112. package/dist/color/gamut-mapping.d.ts +54 -0
  113. package/dist/color/gamut-mapping.js +107 -0
  114. package/dist/color/gamut-mapping.js.map +1 -0
  115. package/dist/color/illuminants.d.ts +182 -0
  116. package/dist/color/illuminants.js +434 -0
  117. package/dist/color/illuminants.js.map +1 -0
  118. package/dist/color/rgb-color-spaces.d.ts +79 -0
  119. package/dist/color/rgb-color-spaces.js +115 -0
  120. package/dist/color/rgb-color-spaces.js.map +1 -0
  121. package/dist/color/sensor-color-development.d.ts +33 -11
  122. package/dist/color/sensor-color-development.js +104 -30
  123. package/dist/color/sensor-color-development.js.map +1 -1
  124. package/dist/color/srgb-icc.d.ts +9 -2
  125. package/dist/color/srgb-icc.js +16 -5
  126. package/dist/color/srgb-icc.js.map +1 -1
  127. package/dist/color/srgb-transfer.d.ts +1 -2
  128. package/dist/color/srgb-transfer.js +1 -1
  129. package/dist/color/srgb-transfer.js.map +1 -1
  130. package/dist/color/white-balance.d.ts +68 -19
  131. package/dist/color/white-balance.js +168 -35
  132. package/dist/color/white-balance.js.map +1 -1
  133. package/dist/composition/image-formation-plan.d.ts +152 -128
  134. package/dist/composition/image-formation-plan.js +292 -138
  135. package/dist/composition/image-formation-plan.js.map +1 -1
  136. package/dist/composition/plan-consumer.d.ts +6 -7
  137. package/dist/composition/plan-consumer.js +14 -11
  138. package/dist/composition/plan-consumer.js.map +1 -1
  139. package/dist/core/calculation-result.d.ts +21 -14
  140. package/dist/core/calculation-result.js +209 -11
  141. package/dist/core/calculation-result.js.map +1 -1
  142. package/dist/core/canonical-json.d.ts +13 -8
  143. package/dist/core/canonical-json.js +34 -15
  144. package/dist/core/canonical-json.js.map +1 -1
  145. package/dist/core/configuration-error.d.ts +5 -4
  146. package/dist/core/configuration-error.js +5 -3
  147. package/dist/core/configuration-error.js.map +1 -1
  148. package/dist/core/evidence-provenance.d.ts +12 -12
  149. package/dist/core/evidence-provenance.js +10 -9
  150. package/dist/core/evidence-provenance.js.map +1 -1
  151. package/dist/core/image-formation.d.ts +11 -10
  152. package/dist/core/image-formation.js +11 -9
  153. package/dist/core/image-formation.js.map +1 -1
  154. package/dist/core/owned-data.d.ts +9 -17
  155. package/dist/core/owned-data.js +9 -16
  156. package/dist/core/owned-data.js.map +1 -1
  157. package/dist/core/portable-math.d.ts +15 -0
  158. package/dist/core/portable-math.js +56 -0
  159. package/dist/core/portable-math.js.map +1 -0
  160. package/dist/core/record-validation.d.ts +48 -9
  161. package/dist/core/record-validation.js +93 -19
  162. package/dist/core/record-validation.js.map +1 -1
  163. package/dist/core/scientific-assurance.d.ts +16 -14
  164. package/dist/core/scientific-assurance.js +22 -18
  165. package/dist/core/scientific-assurance.js.map +1 -1
  166. package/dist/core/spectral-composition.d.ts +13 -14
  167. package/dist/core/spectral-composition.js +30 -27
  168. package/dist/core/spectral-composition.js.map +1 -1
  169. package/dist/core/spectral.d.ts +5 -6
  170. package/dist/core/spectral.js +9 -7
  171. package/dist/core/spectral.js.map +1 -1
  172. package/dist/core/validation.d.ts +3 -6
  173. package/dist/core/validation.js +3 -5
  174. package/dist/core/validation.js.map +1 -1
  175. package/dist/core/version.d.ts +6 -6
  176. package/dist/core/version.js +6 -5
  177. package/dist/core/version.js.map +1 -1
  178. package/dist/equipment/exposure-capabilities.d.ts +10 -10
  179. package/dist/equipment/exposure-capabilities.js +40 -30
  180. package/dist/equipment/exposure-capabilities.js.map +1 -1
  181. package/dist/equipment/generic-tier-assets.d.ts +13 -6
  182. package/dist/equipment/generic-tier-assets.js +34 -15
  183. package/dist/equipment/generic-tier-assets.js.map +1 -1
  184. package/dist/equipment/generic-tier-presets.d.ts +5 -6
  185. package/dist/equipment/generic-tier-presets.js +15 -13
  186. package/dist/equipment/generic-tier-presets.js.map +1 -1
  187. package/dist/equipment/iso-capabilities.d.ts +21 -22
  188. package/dist/equipment/iso-capabilities.js +49 -44
  189. package/dist/equipment/iso-capabilities.js.map +1 -1
  190. package/dist/equipment/metering-capabilities.d.ts +5 -6
  191. package/dist/equipment/metering-capabilities.js +22 -19
  192. package/dist/equipment/metering-capabilities.js.map +1 -1
  193. package/dist/equipment/release-capabilities.d.ts +3 -4
  194. package/dist/equipment/release-capabilities.js +18 -14
  195. package/dist/equipment/release-capabilities.js.map +1 -1
  196. package/dist/exposure/exposure-duration-control.d.ts +19 -17
  197. package/dist/exposure/exposure-duration-control.js +27 -23
  198. package/dist/exposure/exposure-duration-control.js.map +1 -1
  199. package/dist/exposure/exposure-mode-resolver.d.ts +42 -39
  200. package/dist/exposure/exposure-mode-resolver.js +127 -82
  201. package/dist/exposure/exposure-mode-resolver.js.map +1 -1
  202. package/dist/exposure/exposure.d.ts +17 -16
  203. package/dist/exposure/exposure.js +22 -15
  204. package/dist/exposure/exposure.js.map +1 -1
  205. package/dist/exposure/flash-ttl.d.ts +135 -0
  206. package/dist/exposure/flash-ttl.js +193 -0
  207. package/dist/exposure/flash-ttl.js.map +1 -0
  208. package/dist/exposure/flash.d.ts +144 -36
  209. package/dist/exposure/flash.js +259 -59
  210. package/dist/exposure/flash.js.map +1 -1
  211. package/dist/exposure/metering-scene-radiance.d.ts +10 -10
  212. package/dist/exposure/metering-scene-radiance.js +42 -23
  213. package/dist/exposure/metering-scene-radiance.js.map +1 -1
  214. package/dist/exposure/metering-target.d.ts +8 -8
  215. package/dist/exposure/metering-target.js +30 -20
  216. package/dist/exposure/metering-target.js.map +1 -1
  217. package/dist/exposure/metering-temporal.d.ts +16 -15
  218. package/dist/exposure/metering-temporal.js +41 -19
  219. package/dist/exposure/metering-temporal.js.map +1 -1
  220. package/dist/exposure/metering.d.ts +64 -17
  221. package/dist/exposure/metering.js +159 -30
  222. package/dist/exposure/metering.js.map +1 -1
  223. package/dist/exposure/program-line.d.ts +5 -5
  224. package/dist/exposure/program-line.js +20 -13
  225. package/dist/exposure/program-line.js.map +1 -1
  226. package/dist/facade/camera-preset.d.ts +8 -0
  227. package/dist/facade/camera-preset.js +102 -0
  228. package/dist/facade/camera-preset.js.map +1 -0
  229. package/dist/facade/chart-radiance-batch.d.ts +57 -0
  230. package/dist/facade/chart-radiance-batch.js +121 -0
  231. package/dist/facade/chart-radiance-batch.js.map +1 -0
  232. package/dist/facade/chart-scenes.d.ts +177 -0
  233. package/dist/facade/chart-scenes.js +232 -0
  234. package/dist/facade/chart-scenes.js.map +1 -0
  235. package/dist/facade/diffraction-provider.d.ts +30 -0
  236. package/dist/facade/diffraction-provider.js +127 -0
  237. package/dist/facade/diffraction-provider.js.map +1 -0
  238. package/dist/facade/host-yield.d.ts +7 -0
  239. package/dist/facade/host-yield.js +19 -0
  240. package/dist/facade/host-yield.js.map +1 -0
  241. package/dist/facade/scene-radiance.d.ts +117 -0
  242. package/dist/facade/scene-radiance.js +205 -0
  243. package/dist/facade/scene-radiance.js.map +1 -0
  244. package/dist/facade/simulate-capture.d.ts +363 -0
  245. package/dist/facade/simulate-capture.js +1281 -0
  246. package/dist/facade/simulate-capture.js.map +1 -0
  247. package/dist/gpu/chart-radiance-gpu.d.ts +17 -0
  248. package/dist/gpu/chart-radiance-gpu.js +176 -0
  249. package/dist/gpu/chart-radiance-gpu.js.map +1 -0
  250. package/dist/gpu/image-kernel-accelerator.d.ts +132 -0
  251. package/dist/gpu/image-kernel-accelerator.js +720 -0
  252. package/dist/gpu/image-kernel-accelerator.js.map +1 -0
  253. package/dist/gpu/image-kernel-execution.d.ts +92 -0
  254. package/dist/gpu/image-kernel-execution.js +84 -0
  255. package/dist/gpu/image-kernel-execution.js.map +1 -0
  256. package/dist/gpu/sensor-stage-gpu.d.ts +44 -0
  257. package/dist/gpu/sensor-stage-gpu.js +317 -0
  258. package/dist/gpu/sensor-stage-gpu.js.map +1 -0
  259. package/dist/gpu/temporal-sum-gpu.d.ts +23 -0
  260. package/dist/gpu/temporal-sum-gpu.js +150 -0
  261. package/dist/gpu/temporal-sum-gpu.js.map +1 -0
  262. package/dist/gpu/webgpu-runtime.d.ts +63 -0
  263. package/dist/gpu/webgpu-runtime.js +215 -0
  264. package/dist/gpu/webgpu-runtime.js.map +1 -0
  265. package/dist/gpu/wgsl-chart-kernel.d.ts +30 -0
  266. package/dist/gpu/wgsl-chart-kernel.js +165 -0
  267. package/dist/gpu/wgsl-chart-kernel.js.map +1 -0
  268. package/dist/gpu/wgsl-kernels.d.ts +53 -0
  269. package/dist/gpu/wgsl-kernels.js +365 -0
  270. package/dist/gpu/wgsl-kernels.js.map +1 -0
  271. package/dist/gpu/wgsl-sensor-kernel.d.ts +64 -0
  272. package/dist/gpu/wgsl-sensor-kernel.js +409 -0
  273. package/dist/gpu/wgsl-sensor-kernel.js.map +1 -0
  274. package/dist/index.d.ts +91 -25
  275. package/dist/index.js +60 -15
  276. package/dist/index.js.map +1 -1
  277. package/dist/motion/camera-rotation.d.ts +92 -40
  278. package/dist/motion/camera-rotation.js +84 -47
  279. package/dist/motion/camera-rotation.js.map +1 -1
  280. package/dist/motion/capture-rotation-inverse-mapping.d.ts +37 -34
  281. package/dist/motion/capture-rotation-inverse-mapping.js +32 -24
  282. package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
  283. package/dist/motion/capture-rotation-temporal-quadrature.d.ts +39 -35
  284. package/dist/motion/capture-rotation-temporal-quadrature.js +37 -28
  285. package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
  286. package/dist/motion/capture-rotation-trajectory.d.ts +32 -28
  287. package/dist/motion/capture-rotation-trajectory.js +36 -26
  288. package/dist/motion/capture-rotation-trajectory.js.map +1 -1
  289. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +23 -21
  290. package/dist/motion/capture-translation-parallax-temporal-quadrature.js +33 -14
  291. package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
  292. package/dist/motion/extended-object-projection.d.ts +19 -16
  293. package/dist/motion/extended-object-projection.js +38 -18
  294. package/dist/motion/extended-object-projection.js.map +1 -1
  295. package/dist/motion/projected-motion.d.ts +18 -17
  296. package/dist/motion/projected-motion.js +25 -17
  297. package/dist/motion/projected-motion.js.map +1 -1
  298. package/dist/motion/temporal-exposure-sum.d.ts +55 -0
  299. package/dist/motion/temporal-exposure-sum.js +141 -0
  300. package/dist/motion/temporal-exposure-sum.js.map +1 -0
  301. package/dist/motion/video-sequence.d.ts +111 -0
  302. package/dist/motion/video-sequence.js +179 -0
  303. package/dist/motion/video-sequence.js.map +1 -0
  304. package/dist/optics/aperture.d.ts +14 -15
  305. package/dist/optics/aperture.js +13 -11
  306. package/dist/optics/aperture.js.map +1 -1
  307. package/dist/optics/atmospheric-haze.d.ts +83 -0
  308. package/dist/optics/atmospheric-haze.js +113 -0
  309. package/dist/optics/atmospheric-haze.js.map +1 -0
  310. package/dist/optics/brown-conrady-distortion.d.ts +116 -0
  311. package/dist/optics/brown-conrady-distortion.js +291 -0
  312. package/dist/optics/brown-conrady-distortion.js.map +1 -0
  313. package/dist/optics/circle-of-confusion.d.ts +10 -10
  314. package/dist/optics/circle-of-confusion.js +15 -11
  315. package/dist/optics/circle-of-confusion.js.map +1 -1
  316. package/dist/optics/complex-pupil-psf.d.ts +64 -33
  317. package/dist/optics/complex-pupil-psf.js +190 -98
  318. package/dist/optics/complex-pupil-psf.js.map +1 -1
  319. package/dist/optics/depth-of-field.d.ts +25 -15
  320. package/dist/optics/depth-of-field.js +67 -27
  321. package/dist/optics/depth-of-field.js.map +1 -1
  322. package/dist/optics/diffraction-psf-profile.d.ts +118 -0
  323. package/dist/optics/diffraction-psf-profile.js +252 -0
  324. package/dist/optics/diffraction-psf-profile.js.map +1 -0
  325. package/dist/optics/diffraction.d.ts +14 -13
  326. package/dist/optics/diffraction.js +14 -10
  327. package/dist/optics/diffraction.js.map +1 -1
  328. package/dist/optics/focus-breathing.d.ts +88 -27
  329. package/dist/optics/focus-breathing.js +114 -23
  330. package/dist/optics/focus-breathing.js.map +1 -1
  331. package/dist/optics/focus-state.d.ts +18 -18
  332. package/dist/optics/focus-state.js +21 -15
  333. package/dist/optics/focus-state.js.map +1 -1
  334. package/dist/optics/front-of-lens-filter.d.ts +45 -14
  335. package/dist/optics/front-of-lens-filter.js +259 -88
  336. package/dist/optics/front-of-lens-filter.js.map +1 -1
  337. package/dist/optics/illumination-vignetting.d.ts +16 -17
  338. package/dist/optics/illumination-vignetting.js +40 -17
  339. package/dist/optics/illumination-vignetting.js.map +1 -1
  340. package/dist/optics/irradiance-convolution.d.ts +59 -0
  341. package/dist/optics/irradiance-convolution.js +138 -0
  342. package/dist/optics/irradiance-convolution.js.map +1 -0
  343. package/dist/optics/lateral-chromatic-aberration.d.ts +33 -30
  344. package/dist/optics/lateral-chromatic-aberration.js +33 -23
  345. package/dist/optics/lateral-chromatic-aberration.js.map +1 -1
  346. package/dist/optics/lens-psf-kernels.d.ts +89 -0
  347. package/dist/optics/lens-psf-kernels.js +175 -0
  348. package/dist/optics/lens-psf-kernels.js.map +1 -0
  349. package/dist/optics/lens-psf-profile.d.ts +78 -46
  350. package/dist/optics/lens-psf-profile.js +335 -124
  351. package/dist/optics/lens-psf-profile.js.map +1 -1
  352. package/dist/optics/longitudinal-chromatic-aberration.d.ts +102 -0
  353. package/dist/optics/longitudinal-chromatic-aberration.js +210 -0
  354. package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -0
  355. package/dist/optics/polygon-diffraction.d.ts +80 -23
  356. package/dist/optics/polygon-diffraction.js +130 -25
  357. package/dist/optics/polygon-diffraction.js.map +1 -1
  358. package/dist/optics/profile-contract.d.ts +5 -6
  359. package/dist/optics/profile-contract.js +14 -11
  360. package/dist/optics/profile-contract.js.map +1 -1
  361. package/dist/optics/psf-foundation.d.ts +23 -23
  362. package/dist/optics/psf-foundation.js +24 -21
  363. package/dist/optics/psf-foundation.js.map +1 -1
  364. package/dist/optics/pupil-vignetting.d.ts +118 -0
  365. package/dist/optics/pupil-vignetting.js +264 -0
  366. package/dist/optics/pupil-vignetting.js.map +1 -0
  367. package/dist/optics/radial-distortion.d.ts +34 -33
  368. package/dist/optics/radial-distortion.js +37 -30
  369. package/dist/optics/radial-distortion.js.map +1 -1
  370. package/dist/optics/scene-to-sensor-irradiance.d.ts +47 -33
  371. package/dist/optics/scene-to-sensor-irradiance.js +73 -45
  372. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
  373. package/dist/optics/scene-to-sensor-quadrature.d.ts +23 -18
  374. package/dist/optics/scene-to-sensor-quadrature.js +16 -11
  375. package/dist/optics/scene-to-sensor-quadrature.js.map +1 -1
  376. package/dist/optics/sensor-aperture-rays.d.ts +20 -4
  377. package/dist/optics/sensor-aperture-rays.js +32 -14
  378. package/dist/optics/sensor-aperture-rays.js.map +1 -1
  379. package/dist/optics/sensor-environment-query.d.ts +81 -16
  380. package/dist/optics/sensor-environment-query.js +145 -12
  381. package/dist/optics/sensor-environment-query.js.map +1 -1
  382. package/dist/optics/sensor-psf-quadrature.d.ts +12 -10
  383. package/dist/optics/sensor-psf-quadrature.js +18 -11
  384. package/dist/optics/sensor-psf-quadrature.js.map +1 -1
  385. package/dist/optics/sensor-psf-support.d.ts +8 -6
  386. package/dist/optics/sensor-psf-support.js +8 -5
  387. package/dist/optics/sensor-psf-support.js.map +1 -1
  388. package/dist/optics/stray-light.d.ts +22 -19
  389. package/dist/optics/stray-light.js +18 -12
  390. package/dist/optics/stray-light.js.map +1 -1
  391. package/dist/optics/thin-lens.d.ts +10 -9
  392. package/dist/optics/thin-lens.js +12 -8
  393. package/dist/optics/thin-lens.js.map +1 -1
  394. package/dist/optics/zernike-wavefront.d.ts +154 -0
  395. package/dist/optics/zernike-wavefront.js +352 -0
  396. package/dist/optics/zernike-wavefront.js.map +1 -0
  397. package/dist/output/capture-corrected-sdr.d.ts +16 -8
  398. package/dist/output/capture-corrected-sdr.js +16 -8
  399. package/dist/output/capture-corrected-sdr.js.map +1 -1
  400. package/dist/output/capture-geometry.d.ts +34 -36
  401. package/dist/output/capture-geometry.js +52 -32
  402. package/dist/output/capture-geometry.js.map +1 -1
  403. package/dist/output/capture-sdr.d.ts +7 -6
  404. package/dist/output/capture-sdr.js +11 -8
  405. package/dist/output/capture-sdr.js.map +1 -1
  406. package/dist/output/crop.d.ts +22 -6
  407. package/dist/output/crop.js +40 -6
  408. package/dist/output/crop.js.map +1 -1
  409. package/dist/output/geometric-transforms.d.ts +60 -23
  410. package/dist/output/geometric-transforms.js +111 -24
  411. package/dist/output/geometric-transforms.js.map +1 -1
  412. package/dist/output/lens-corrections.d.ts +27 -19
  413. package/dist/output/lens-corrections.js +29 -13
  414. package/dist/output/lens-corrections.js.map +1 -1
  415. package/dist/output/native-capture-sdr.d.ts +71 -16
  416. package/dist/output/native-capture-sdr.js +190 -33
  417. package/dist/output/native-capture-sdr.js.map +1 -1
  418. package/dist/output/png-encoder.d.ts +65 -0
  419. package/dist/output/png-encoder.js +461 -0
  420. package/dist/output/png-encoder.js.map +1 -0
  421. package/dist/output/print-contrast-reference.d.ts +10 -9
  422. package/dist/output/print-contrast-reference.js +10 -8
  423. package/dist/output/print-contrast-reference.js.map +1 -1
  424. package/dist/output/print-detail.d.ts +18 -17
  425. package/dist/output/print-detail.js +12 -10
  426. package/dist/output/print-detail.js.map +1 -1
  427. package/dist/output/print-jpeg.d.ts +26 -5
  428. package/dist/output/print-jpeg.js +117 -50
  429. package/dist/output/print-jpeg.js.map +1 -1
  430. package/dist/output/print-plan.d.ts +19 -19
  431. package/dist/output/print-plan.js +11 -10
  432. package/dist/output/print-plan.js.map +1 -1
  433. package/dist/output/print-region-statistics.d.ts +14 -15
  434. package/dist/output/print-region-statistics.js +11 -11
  435. package/dist/output/print-region-statistics.js.map +1 -1
  436. package/dist/output/sdr-rendering.d.ts +48 -10
  437. package/dist/output/sdr-rendering.js +114 -25
  438. package/dist/output/sdr-rendering.js.map +1 -1
  439. package/dist/output/subject-framing-crop.d.ts +6 -10
  440. package/dist/output/subject-framing-crop.js +23 -13
  441. package/dist/output/subject-framing-crop.js.map +1 -1
  442. package/dist/processing/demosaic.d.ts +90 -0
  443. package/dist/processing/demosaic.js +275 -0
  444. package/dist/processing/demosaic.js.map +1 -0
  445. package/dist/processing/denoise.d.ts +68 -0
  446. package/dist/processing/denoise.js +214 -0
  447. package/dist/processing/denoise.js.map +1 -0
  448. package/dist/processing/focus-stacking.d.ts +17 -0
  449. package/dist/processing/focus-stacking.js +80 -0
  450. package/dist/processing/focus-stacking.js.map +1 -0
  451. package/dist/processing/hdr.d.ts +54 -0
  452. package/dist/processing/hdr.js +172 -0
  453. package/dist/processing/hdr.js.map +1 -0
  454. package/dist/processing/image-ops.d.ts +66 -0
  455. package/dist/processing/image-ops.js +192 -0
  456. package/dist/processing/image-ops.js.map +1 -0
  457. package/dist/processing/panorama.d.ts +51 -0
  458. package/dist/processing/panorama.js +305 -0
  459. package/dist/processing/panorama.js.map +1 -0
  460. package/dist/processing/processing-task.d.ts +85 -0
  461. package/dist/processing/processing-task.js +164 -0
  462. package/dist/processing/processing-task.js.map +1 -0
  463. package/dist/processing/tone-mapping.d.ts +69 -0
  464. package/dist/processing/tone-mapping.js +310 -0
  465. package/dist/processing/tone-mapping.js.map +1 -0
  466. package/dist/schema/camera.d.ts +5 -4
  467. package/dist/schema/illumination-spectral.d.ts +13 -19
  468. package/dist/schema/illumination-spectral.js +23 -19
  469. package/dist/schema/illumination-spectral.js.map +1 -1
  470. package/dist/schema/illumination-temporal.d.ts +12 -15
  471. package/dist/schema/illumination-temporal.js +43 -28
  472. package/dist/schema/illumination-temporal.js.map +1 -1
  473. package/dist/schema/illumination.d.ts +5 -4
  474. package/dist/schema/illumination.js +55 -20
  475. package/dist/schema/illumination.js.map +1 -1
  476. package/dist/schema/scene-radiance-temporal.d.ts +9 -11
  477. package/dist/schema/scene-radiance-temporal.js +26 -23
  478. package/dist/schema/scene-radiance-temporal.js.map +1 -1
  479. package/dist/schema/scene-radiance.d.ts +17 -17
  480. package/dist/schema/scene-radiance.js +56 -34
  481. package/dist/schema/scene-radiance.js.map +1 -1
  482. package/dist/schema/scene.d.ts +14 -13
  483. package/dist/schema/validation.d.ts +0 -1
  484. package/dist/schema/validation.js +17 -15
  485. package/dist/schema/validation.js.map +1 -1
  486. package/dist/sensor/accumulated-charge.d.ts +45 -64
  487. package/dist/sensor/accumulated-charge.js +41 -47
  488. package/dist/sensor/accumulated-charge.js.map +1 -1
  489. package/dist/sensor/architecture.d.ts +22 -25
  490. package/dist/sensor/architecture.js +17 -16
  491. package/dist/sensor/architecture.js.map +1 -1
  492. package/dist/sensor/camera-saturation-capacity.d.ts +21 -28
  493. package/dist/sensor/camera-saturation-capacity.js +36 -34
  494. package/dist/sensor/camera-saturation-capacity.js.map +1 -1
  495. package/dist/sensor/capture-color-sampling-binding.d.ts +46 -51
  496. package/dist/sensor/capture-color-sampling-binding.js +39 -41
  497. package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
  498. package/dist/sensor/capture-mode-timing.d.ts +8 -9
  499. package/dist/sensor/capture-mode-timing.js +24 -21
  500. package/dist/sensor/capture-mode-timing.js.map +1 -1
  501. package/dist/sensor/capture-mode.d.ts +28 -30
  502. package/dist/sensor/capture-mode.js +33 -31
  503. package/dist/sensor/capture-mode.js.map +1 -1
  504. package/dist/sensor/color-sampling.d.ts +30 -33
  505. package/dist/sensor/color-sampling.js +32 -37
  506. package/dist/sensor/color-sampling.js.map +1 -1
  507. package/dist/sensor/constant-rate-temporal-integration.d.ts +19 -23
  508. package/dist/sensor/constant-rate-temporal-integration.js +28 -26
  509. package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
  510. package/dist/sensor/dark-current.d.ts +53 -49
  511. package/dist/sensor/dark-current.js +87 -46
  512. package/dist/sensor/dark-current.js.map +1 -1
  513. package/dist/sensor/environment-photo-signal.d.ts +71 -30
  514. package/dist/sensor/environment-photo-signal.js +127 -46
  515. package/dist/sensor/environment-photo-signal.js.map +1 -1
  516. package/dist/sensor/eqe-electron-rate.d.ts +14 -13
  517. package/dist/sensor/eqe-electron-rate.js +34 -14
  518. package/dist/sensor/eqe-electron-rate.js.map +1 -1
  519. package/dist/sensor/eqe-local-exposure.d.ts +24 -24
  520. package/dist/sensor/eqe-local-exposure.js +15 -11
  521. package/dist/sensor/eqe-local-exposure.js.map +1 -1
  522. package/dist/sensor/eqe-temporal-exposure.d.ts +11 -11
  523. package/dist/sensor/eqe-temporal-exposure.js +15 -10
  524. package/dist/sensor/eqe-temporal-exposure.js.map +1 -1
  525. package/dist/sensor/exposure-window.d.ts +48 -34
  526. package/dist/sensor/exposure-window.js +77 -36
  527. package/dist/sensor/exposure-window.js.map +1 -1
  528. package/dist/sensor/fixed-pattern-noise.d.ts +108 -0
  529. package/dist/sensor/fixed-pattern-noise.js +166 -0
  530. package/dist/sensor/fixed-pattern-noise.js.map +1 -0
  531. package/dist/sensor/iso-gain.d.ts +44 -0
  532. package/dist/sensor/iso-gain.js +119 -0
  533. package/dist/sensor/iso-gain.js.map +1 -0
  534. package/dist/sensor/iso-signal-chain.d.ts +25 -48
  535. package/dist/sensor/iso-signal-chain.js +52 -66
  536. package/dist/sensor/iso-signal-chain.js.map +1 -1
  537. package/dist/sensor/local-exposure-binding.d.ts +21 -21
  538. package/dist/sensor/local-exposure-binding.js +22 -18
  539. package/dist/sensor/local-exposure-binding.js.map +1 -1
  540. package/dist/sensor/optical-stack.d.ts +36 -40
  541. package/dist/sensor/optical-stack.js +34 -37
  542. package/dist/sensor/optical-stack.js.map +1 -1
  543. package/dist/sensor/photon-energy.d.ts +22 -28
  544. package/dist/sensor/photon-energy.js +42 -34
  545. package/dist/sensor/photon-energy.js.map +1 -1
  546. package/dist/sensor/physical-charge-capacity.d.ts +20 -30
  547. package/dist/sensor/physical-charge-capacity.js +35 -36
  548. package/dist/sensor/physical-charge-capacity.js.map +1 -1
  549. package/dist/sensor/pixel-pitch.d.ts +2 -3
  550. package/dist/sensor/pixel-pitch.js +4 -2
  551. package/dist/sensor/pixel-pitch.js.map +1 -1
  552. package/dist/sensor/radiometry-readiness.d.ts +13 -15
  553. package/dist/sensor/radiometry-readiness.js +20 -17
  554. package/dist/sensor/radiometry-readiness.js.map +1 -1
  555. package/dist/sensor/raw-readout.d.ts +173 -83
  556. package/dist/sensor/raw-readout.js +425 -160
  557. package/dist/sensor/raw-readout.js.map +1 -1
  558. package/dist/sensor/raw-reconstruction.d.ts +112 -44
  559. package/dist/sensor/raw-reconstruction.js +200 -47
  560. package/dist/sensor/raw-reconstruction.js.map +1 -1
  561. package/dist/sensor/readout-exposure-linkage.d.ts +103 -34
  562. package/dist/sensor/readout-exposure-linkage.js +125 -27
  563. package/dist/sensor/readout-exposure-linkage.js.map +1 -1
  564. package/dist/sensor/readout-timing.d.ts +43 -44
  565. package/dist/sensor/readout-timing.js +38 -30
  566. package/dist/sensor/readout-timing.js.map +1 -1
  567. package/dist/sensor/response-application-compatibility.d.ts +21 -28
  568. package/dist/sensor/response-application-compatibility.js +35 -34
  569. package/dist/sensor/response-application-compatibility.js.map +1 -1
  570. package/dist/sensor/response-operating-range.d.ts +26 -35
  571. package/dist/sensor/response-operating-range.js +40 -39
  572. package/dist/sensor/response-operating-range.js.map +1 -1
  573. package/dist/sensor/responsivity-photocurrent.d.ts +21 -29
  574. package/dist/sensor/responsivity-photocurrent.js +57 -40
  575. package/dist/sensor/responsivity-photocurrent.js.map +1 -1
  576. package/dist/sensor/sampling-aperture.d.ts +21 -25
  577. package/dist/sensor/sampling-aperture.js +29 -28
  578. package/dist/sensor/sampling-aperture.js.map +1 -1
  579. package/dist/sensor/scene-eqe-temporal-exposure.d.ts +14 -12
  580. package/dist/sensor/scene-eqe-temporal-exposure.js +13 -8
  581. package/dist/sensor/scene-eqe-temporal-exposure.js.map +1 -1
  582. package/dist/sensor/sensor-geometry.d.ts +28 -32
  583. package/dist/sensor/sensor-geometry.js +35 -20
  584. package/dist/sensor/sensor-geometry.js.map +1 -1
  585. package/dist/sensor/signal-noise.d.ts +14 -16
  586. package/dist/sensor/signal-noise.js +15 -13
  587. package/dist/sensor/signal-noise.js.map +1 -1
  588. package/dist/sensor/spatial-sample-reduction.d.ts +45 -60
  589. package/dist/sensor/spatial-sample-reduction.js +39 -48
  590. package/dist/sensor/spatial-sample-reduction.js.map +1 -1
  591. package/dist/sensor/spatial-sampling-quadrature.d.ts +46 -54
  592. package/dist/sensor/spatial-sampling-quadrature.js +31 -36
  593. package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
  594. package/dist/sensor/spatio-spectral-reduction.d.ts +32 -42
  595. package/dist/sensor/spatio-spectral-reduction.js +24 -29
  596. package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
  597. package/dist/sensor/spectral-coverage.d.ts +6 -9
  598. package/dist/sensor/spectral-coverage.js +9 -6
  599. package/dist/sensor/spectral-coverage.js.map +1 -1
  600. package/dist/sensor/spectral-quadrature.d.ts +46 -60
  601. package/dist/sensor/spectral-quadrature.js +38 -48
  602. package/dist/sensor/spectral-quadrature.js.map +1 -1
  603. package/dist/sensor/spectral-response.d.ts +53 -41
  604. package/dist/sensor/spectral-response.js +80 -47
  605. package/dist/sensor/spectral-response.js.map +1 -1
  606. package/dist/sensor/stochastic-seed.d.ts +50 -0
  607. package/dist/sensor/stochastic-seed.js +123 -0
  608. package/dist/sensor/stochastic-seed.js.map +1 -0
  609. package/dist/sensor/temporal-eqe-sum.d.ts +2 -4
  610. package/dist/sensor/temporal-eqe-sum.js +5 -6
  611. package/dist/sensor/temporal-eqe-sum.js.map +1 -1
  612. package/dist/sensor/temporal-photo-signal.d.ts +5 -6
  613. package/dist/sensor/temporal-photo-signal.js +11 -10
  614. package/dist/sensor/temporal-photo-signal.js.map +1 -1
  615. package/dist/sensor/temporal-sample-binding.d.ts +1 -2
  616. package/dist/sensor/temporal-sample-binding.js +3 -3
  617. package/dist/sensor/temporal-sample-binding.js.map +1 -1
  618. package/dist/simulation/poc-simulation.d.ts +16 -16
  619. package/dist/simulation/poc-simulation.js +20 -15
  620. package/dist/simulation/poc-simulation.js.map +1 -1
  621. package/dist/stabilization/camera-shake.d.ts +42 -18
  622. package/dist/stabilization/camera-shake.js +43 -20
  623. package/dist/stabilization/camera-shake.js.map +1 -1
  624. package/dist/stabilization/system.d.ts +44 -41
  625. package/dist/stabilization/system.js +196 -108
  626. package/dist/stabilization/system.js.map +1 -1
  627. package/docs/AGENT_GUIDE.md +183 -0
  628. package/docs/API_REFERENCE.md +777 -2
  629. package/docs/QUICK_START.md +663 -0
  630. package/docs/USAGE.md +1719 -714
  631. package/docs/api/camera-equivalent-focal-length.md +6 -7
  632. package/docs/api/camera-field-of-view.md +16 -8
  633. package/docs/api/camera-lens-projection.md +246 -0
  634. package/docs/api/camera-projected-object-size.md +6 -5
  635. package/docs/api/capture-capture-export-metadata.md +10 -10
  636. package/docs/api/capture-dng-import.md +134 -0
  637. package/docs/api/capture-environment-raw-producer.md +17 -11
  638. package/docs/api/capture-export-jpeg.md +16 -0
  639. package/docs/api/capture-focus-control.md +25 -47
  640. package/docs/api/capture-linear-encoding.md +21 -12
  641. package/docs/api/capture-lossless-jpeg.md +49 -0
  642. package/docs/api/capture-native-environment-optical-stage.md +75 -0
  643. package/docs/api/capture-native-environment-raw.md +161 -4
  644. package/docs/api/capture-native-raw-development.md +69 -8
  645. package/docs/api/capture-native-raw-dng.md +84 -0
  646. package/docs/api/capture-native-raw.md +21 -10
  647. package/docs/api/capture-packed-sensor-raw.md +156 -0
  648. package/docs/api/capture-photographic-export.md +69 -31
  649. package/docs/api/capture-raw-frame-reconstruction.md +8 -8
  650. package/docs/api/capture-raw-white-level.md +37 -0
  651. package/docs/api/capture-release-sequence.md +6 -7
  652. package/docs/api/capture-sensor-raw-frame.md +6 -6
  653. package/docs/api/capture-sensor-raw-producer.md +17 -11
  654. package/docs/api/capture-simulated-capture.md +15 -15
  655. package/docs/api/color-camera-color-matrix.md +103 -0
  656. package/docs/api/color-capture-color.md +22 -11
  657. package/docs/api/color-chromatic-adaptation.md +82 -0
  658. package/docs/api/color-color-difference.md +134 -0
  659. package/docs/api/color-color-matching-functions.md +259 -0
  660. package/docs/api/color-colorimetry-math.md +54 -0
  661. package/docs/api/color-gamut-mapping.md +72 -0
  662. package/docs/api/color-illuminants.md +280 -0
  663. package/docs/api/color-rgb-color-spaces.md +151 -0
  664. package/docs/api/color-sensor-color-development.md +27 -0
  665. package/docs/api/color-srgb-icc.md +2 -4
  666. package/docs/api/color-white-balance.md +95 -19
  667. package/docs/api/composition-image-formation-plan.md +124 -95
  668. package/docs/api/composition-plan-consumer.md +7 -7
  669. package/docs/api/core-calculation-result.md +18 -14
  670. package/docs/api/core-configuration-error.md +1 -1
  671. package/docs/api/core-image-formation.md +7 -7
  672. package/docs/api/core-scientific-assurance.md +12 -10
  673. package/docs/api/core-spectral-composition.md +14 -14
  674. package/docs/api/core-spectral.md +6 -6
  675. package/docs/api/core-validation.md +3 -3
  676. package/docs/api/core-version.md +7 -6
  677. package/docs/api/equipment-exposure-capabilities.md +11 -10
  678. package/docs/api/equipment-generic-tier-assets.md +7 -2
  679. package/docs/api/equipment-generic-tier-presets.md +6 -6
  680. package/docs/api/equipment-iso-capabilities.md +18 -18
  681. package/docs/api/equipment-metering-capabilities.md +6 -6
  682. package/docs/api/equipment-release-capabilities.md +4 -4
  683. package/docs/api/exports.json +2253 -3
  684. package/docs/api/exposure-exposure-duration-control.md +9 -9
  685. package/docs/api/exposure-exposure-mode-resolver.md +35 -31
  686. package/docs/api/exposure-exposure.md +10 -10
  687. package/docs/api/exposure-flash-ttl.md +182 -0
  688. package/docs/api/exposure-flash.md +183 -28
  689. package/docs/api/exposure-metering-scene-radiance.md +11 -10
  690. package/docs/api/exposure-metering-target.md +9 -8
  691. package/docs/api/exposure-metering-temporal.md +8 -8
  692. package/docs/api/exposure-metering.md +69 -9
  693. package/docs/api/exposure-program-line.md +6 -5
  694. package/docs/api/facade-chart-radiance-batch.md +96 -0
  695. package/docs/api/facade-chart-scenes.md +240 -0
  696. package/docs/api/facade-scene-radiance.md +122 -0
  697. package/docs/api/facade-simulate-capture.md +397 -0
  698. package/docs/api/gpu-image-kernel-accelerator.md +157 -0
  699. package/docs/api/gpu-image-kernel-execution.md +152 -0
  700. package/docs/api/motion-camera-rotation.md +43 -26
  701. package/docs/api/motion-capture-rotation-inverse-mapping.md +24 -23
  702. package/docs/api/motion-capture-rotation-temporal-quadrature.md +22 -22
  703. package/docs/api/motion-capture-rotation-trajectory.md +15 -15
  704. package/docs/api/motion-capture-translation-parallax-temporal-quadrature.md +15 -14
  705. package/docs/api/motion-extended-object-projection.md +10 -8
  706. package/docs/api/motion-projected-motion.md +8 -8
  707. package/docs/api/motion-temporal-exposure-sum.md +98 -0
  708. package/docs/api/motion-video-sequence.md +159 -0
  709. package/docs/api/optics-aperture.md +8 -8
  710. package/docs/api/optics-atmospheric-haze.md +104 -0
  711. package/docs/api/optics-brown-conrady-distortion.md +123 -0
  712. package/docs/api/optics-circle-of-confusion.md +5 -4
  713. package/docs/api/optics-complex-pupil-psf.md +57 -16
  714. package/docs/api/optics-depth-of-field.md +12 -6
  715. package/docs/api/optics-diffraction-psf-profile.md +96 -0
  716. package/docs/api/optics-diffraction.md +8 -7
  717. package/docs/api/optics-focus-breathing.md +104 -16
  718. package/docs/api/optics-focus-state.md +9 -10
  719. package/docs/api/optics-front-of-lens-filter.md +72 -14
  720. package/docs/api/optics-illumination-vignetting.md +10 -10
  721. package/docs/api/optics-irradiance-convolution.md +95 -0
  722. package/docs/api/optics-lateral-chromatic-aberration.md +22 -21
  723. package/docs/api/optics-lens-psf-kernels.md +72 -0
  724. package/docs/api/optics-lens-psf-profile.md +48 -26
  725. package/docs/api/optics-longitudinal-chromatic-aberration.md +128 -0
  726. package/docs/api/optics-polygon-diffraction.md +78 -13
  727. package/docs/api/optics-profile-contract.md +4 -4
  728. package/docs/api/optics-psf-foundation.md +12 -12
  729. package/docs/api/optics-pupil-vignetting.md +132 -0
  730. package/docs/api/optics-radial-distortion.md +12 -12
  731. package/docs/api/optics-scene-to-sensor-irradiance.md +25 -14
  732. package/docs/api/optics-scene-to-sensor-quadrature.md +15 -12
  733. package/docs/api/optics-sensor-aperture-rays.md +3 -2
  734. package/docs/api/optics-sensor-environment-query.md +52 -9
  735. package/docs/api/optics-sensor-psf-quadrature.md +13 -10
  736. package/docs/api/optics-stray-light.md +12 -11
  737. package/docs/api/optics-thin-lens.md +4 -3
  738. package/docs/api/optics-zernike-wavefront.md +229 -0
  739. package/docs/api/output-capture-corrected-sdr.md +10 -7
  740. package/docs/api/output-capture-geometry.md +35 -36
  741. package/docs/api/output-capture-sdr.md +4 -4
  742. package/docs/api/output-crop.md +7 -4
  743. package/docs/api/output-geometric-transforms.md +65 -19
  744. package/docs/api/output-lens-corrections.md +17 -15
  745. package/docs/api/output-native-capture-sdr.md +26 -13
  746. package/docs/api/output-png-encoder.md +105 -0
  747. package/docs/api/output-print-contrast-reference.md +8 -8
  748. package/docs/api/output-print-detail.md +14 -14
  749. package/docs/api/output-print-jpeg.md +22 -5
  750. package/docs/api/output-print-plan.md +18 -18
  751. package/docs/api/output-print-region-statistics.md +14 -14
  752. package/docs/api/output-sdr-rendering.md +52 -10
  753. package/docs/api/output-subject-framing-crop.md +5 -6
  754. package/docs/api/processing-demosaic.md +120 -0
  755. package/docs/api/processing-denoise.md +148 -0
  756. package/docs/api/processing-focus-stacking.md +41 -0
  757. package/docs/api/processing-hdr.md +113 -0
  758. package/docs/api/processing-panorama.md +82 -0
  759. package/docs/api/processing-processing-task.md +107 -0
  760. package/docs/api/processing-tone-mapping.md +142 -0
  761. package/docs/api/schema-camera.md +6 -4
  762. package/docs/api/schema-illumination-spectral.md +10 -11
  763. package/docs/api/schema-illumination-temporal.md +13 -15
  764. package/docs/api/schema-illumination.md +4 -4
  765. package/docs/api/schema-scene-radiance-temporal.md +10 -11
  766. package/docs/api/schema-scene-radiance.md +18 -17
  767. package/docs/api/schema-scene.md +9 -9
  768. package/docs/api/schema-validation.md +1 -1
  769. package/docs/api/sensor-accumulated-charge.md +12 -20
  770. package/docs/api/sensor-architecture.md +15 -16
  771. package/docs/api/sensor-camera-saturation-capacity.md +9 -11
  772. package/docs/api/sensor-capture-color-sampling-binding.md +47 -51
  773. package/docs/api/sensor-capture-mode-timing.md +9 -9
  774. package/docs/api/sensor-capture-mode.md +29 -30
  775. package/docs/api/sensor-color-sampling.md +31 -33
  776. package/docs/api/sensor-constant-rate-temporal-integration.md +10 -11
  777. package/docs/api/sensor-dark-current.md +30 -14
  778. package/docs/api/sensor-environment-photo-signal.md +13 -6
  779. package/docs/api/sensor-eqe-electron-rate.md +9 -8
  780. package/docs/api/sensor-eqe-local-exposure.md +18 -17
  781. package/docs/api/sensor-eqe-temporal-exposure.md +12 -11
  782. package/docs/api/sensor-exposure-window.md +24 -24
  783. package/docs/api/sensor-fixed-pattern-noise.md +104 -0
  784. package/docs/api/sensor-iso-gain.md +63 -0
  785. package/docs/api/sensor-iso-signal-chain.md +13 -22
  786. package/docs/api/sensor-local-exposure-binding.md +12 -13
  787. package/docs/api/sensor-optical-stack.md +37 -40
  788. package/docs/api/sensor-photon-energy.md +10 -11
  789. package/docs/api/sensor-physical-charge-capacity.md +8 -13
  790. package/docs/api/sensor-pixel-pitch.md +1 -1
  791. package/docs/api/sensor-radiometry-readiness.md +9 -9
  792. package/docs/api/sensor-raw-readout.md +118 -52
  793. package/docs/api/sensor-raw-reconstruction.md +97 -20
  794. package/docs/api/sensor-readout-exposure-linkage.md +120 -24
  795. package/docs/api/sensor-readout-timing.md +33 -35
  796. package/docs/api/sensor-response-application-compatibility.md +9 -11
  797. package/docs/api/sensor-response-operating-range.md +14 -18
  798. package/docs/api/sensor-responsivity-photocurrent.md +9 -12
  799. package/docs/api/sensor-sampling-aperture.md +22 -25
  800. package/docs/api/sensor-scene-eqe-temporal-exposure.md +9 -8
  801. package/docs/api/sensor-sensor-geometry.md +23 -24
  802. package/docs/api/sensor-signal-noise.md +10 -10
  803. package/docs/api/sensor-spatial-sample-reduction.md +27 -30
  804. package/docs/api/sensor-spatial-sampling-quadrature.md +37 -39
  805. package/docs/api/sensor-spatio-spectral-reduction.md +27 -29
  806. package/docs/api/sensor-spectral-coverage.md +5 -5
  807. package/docs/api/sensor-spectral-quadrature.md +33 -35
  808. package/docs/api/sensor-spectral-response.md +28 -16
  809. package/docs/api/sensor-temporal-photo-signal.md +6 -6
  810. package/docs/api/simulation-poc-simulation.md +17 -16
  811. package/docs/api/stabilization-camera-shake.md +29 -10
  812. package/docs/api/stabilization-system.md +25 -21
  813. package/docs/examples/production-request.json +3821 -2157
  814. package/docs/examples/simulate-capture.mjs +14 -0
  815. package/llms.txt +35 -0
  816. package/package.json +32 -11
  817. package/AGENTS.md +0 -674
  818. package/CONTRIBUTING.md +0 -76
  819. package/DCO +0 -33
  820. package/dist/camera/equivalent-focal-length.d.ts.map +0 -1
  821. package/dist/camera/field-of-view.d.ts.map +0 -1
  822. package/dist/camera/projected-object-size.d.ts.map +0 -1
  823. package/dist/capture/capture-export-metadata.d.ts.map +0 -1
  824. package/dist/capture/environment-raw-producer.d.ts.map +0 -1
  825. package/dist/capture/export-jpeg.d.ts.map +0 -1
  826. package/dist/capture/export-tiff.d.ts.map +0 -1
  827. package/dist/capture/focus-control.d.ts.map +0 -1
  828. package/dist/capture/linear-encoding.d.ts.map +0 -1
  829. package/dist/capture/native-environment-raw.d.ts.map +0 -1
  830. package/dist/capture/native-raw-development.d.ts.map +0 -1
  831. package/dist/capture/native-raw.d.ts.map +0 -1
  832. package/dist/capture/photographic-export.d.ts.map +0 -1
  833. package/dist/capture/raw-frame-limits.d.ts.map +0 -1
  834. package/dist/capture/raw-frame-reconstruction.d.ts.map +0 -1
  835. package/dist/capture/release-sequence.d.ts.map +0 -1
  836. package/dist/capture/sensor-raw-frame.d.ts.map +0 -1
  837. package/dist/capture/sensor-raw-producer.d.ts.map +0 -1
  838. package/dist/capture/simulated-capture.d.ts.map +0 -1
  839. package/dist/color/capture-color.d.ts.map +0 -1
  840. package/dist/color/sensor-color-development.d.ts.map +0 -1
  841. package/dist/color/srgb-icc.d.ts.map +0 -1
  842. package/dist/color/srgb-transfer.d.ts.map +0 -1
  843. package/dist/color/white-balance.d.ts.map +0 -1
  844. package/dist/composition/image-formation-plan.d.ts.map +0 -1
  845. package/dist/composition/plan-consumer.d.ts.map +0 -1
  846. package/dist/core/calculation-result.d.ts.map +0 -1
  847. package/dist/core/canonical-json.d.ts.map +0 -1
  848. package/dist/core/configuration-error.d.ts.map +0 -1
  849. package/dist/core/evidence-provenance.d.ts.map +0 -1
  850. package/dist/core/image-formation.d.ts.map +0 -1
  851. package/dist/core/owned-data.d.ts.map +0 -1
  852. package/dist/core/record-validation.d.ts.map +0 -1
  853. package/dist/core/scientific-assurance.d.ts.map +0 -1
  854. package/dist/core/spectral-composition.d.ts.map +0 -1
  855. package/dist/core/spectral.d.ts.map +0 -1
  856. package/dist/core/validation.d.ts.map +0 -1
  857. package/dist/core/version.d.ts.map +0 -1
  858. package/dist/equipment/exposure-capabilities.d.ts.map +0 -1
  859. package/dist/equipment/generic-tier-assets.d.ts.map +0 -1
  860. package/dist/equipment/generic-tier-presets.d.ts.map +0 -1
  861. package/dist/equipment/iso-capabilities.d.ts.map +0 -1
  862. package/dist/equipment/metering-capabilities.d.ts.map +0 -1
  863. package/dist/equipment/release-capabilities.d.ts.map +0 -1
  864. package/dist/exposure/exposure-duration-control.d.ts.map +0 -1
  865. package/dist/exposure/exposure-mode-resolver.d.ts.map +0 -1
  866. package/dist/exposure/exposure.d.ts.map +0 -1
  867. package/dist/exposure/flash.d.ts.map +0 -1
  868. package/dist/exposure/metering-scene-radiance.d.ts.map +0 -1
  869. package/dist/exposure/metering-target.d.ts.map +0 -1
  870. package/dist/exposure/metering-temporal.d.ts.map +0 -1
  871. package/dist/exposure/metering.d.ts.map +0 -1
  872. package/dist/exposure/program-line.d.ts.map +0 -1
  873. package/dist/index.d.ts.map +0 -1
  874. package/dist/motion/camera-rotation.d.ts.map +0 -1
  875. package/dist/motion/capture-rotation-inverse-mapping.d.ts.map +0 -1
  876. package/dist/motion/capture-rotation-temporal-quadrature.d.ts.map +0 -1
  877. package/dist/motion/capture-rotation-trajectory.d.ts.map +0 -1
  878. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts.map +0 -1
  879. package/dist/motion/extended-object-projection.d.ts.map +0 -1
  880. package/dist/motion/projected-motion.d.ts.map +0 -1
  881. package/dist/optics/aperture.d.ts.map +0 -1
  882. package/dist/optics/circle-of-confusion.d.ts.map +0 -1
  883. package/dist/optics/complex-pupil-psf.d.ts.map +0 -1
  884. package/dist/optics/depth-of-field.d.ts.map +0 -1
  885. package/dist/optics/diffraction.d.ts.map +0 -1
  886. package/dist/optics/focus-breathing.d.ts.map +0 -1
  887. package/dist/optics/focus-state.d.ts.map +0 -1
  888. package/dist/optics/front-of-lens-filter.d.ts.map +0 -1
  889. package/dist/optics/illumination-vignetting.d.ts.map +0 -1
  890. package/dist/optics/lateral-chromatic-aberration.d.ts.map +0 -1
  891. package/dist/optics/lens-psf-profile.d.ts.map +0 -1
  892. package/dist/optics/polygon-diffraction.d.ts.map +0 -1
  893. package/dist/optics/profile-contract.d.ts.map +0 -1
  894. package/dist/optics/psf-foundation.d.ts.map +0 -1
  895. package/dist/optics/radial-distortion.d.ts.map +0 -1
  896. package/dist/optics/scene-to-sensor-irradiance.d.ts.map +0 -1
  897. package/dist/optics/scene-to-sensor-quadrature.d.ts.map +0 -1
  898. package/dist/optics/sensor-aperture-rays.d.ts.map +0 -1
  899. package/dist/optics/sensor-environment-query.d.ts.map +0 -1
  900. package/dist/optics/sensor-psf-quadrature.d.ts.map +0 -1
  901. package/dist/optics/sensor-psf-support.d.ts.map +0 -1
  902. package/dist/optics/stray-light.d.ts.map +0 -1
  903. package/dist/optics/thin-lens.d.ts.map +0 -1
  904. package/dist/output/capture-corrected-sdr.d.ts.map +0 -1
  905. package/dist/output/capture-geometry.d.ts.map +0 -1
  906. package/dist/output/capture-sdr.d.ts.map +0 -1
  907. package/dist/output/crop.d.ts.map +0 -1
  908. package/dist/output/geometric-transforms.d.ts.map +0 -1
  909. package/dist/output/lens-corrections.d.ts.map +0 -1
  910. package/dist/output/native-capture-sdr.d.ts.map +0 -1
  911. package/dist/output/print-contrast-reference.d.ts.map +0 -1
  912. package/dist/output/print-detail.d.ts.map +0 -1
  913. package/dist/output/print-jpeg.d.ts.map +0 -1
  914. package/dist/output/print-plan.d.ts.map +0 -1
  915. package/dist/output/print-region-statistics.d.ts.map +0 -1
  916. package/dist/output/sdr-rendering.d.ts.map +0 -1
  917. package/dist/output/subject-framing-crop.d.ts.map +0 -1
  918. package/dist/schema/camera.d.ts.map +0 -1
  919. package/dist/schema/camera.js +0 -3
  920. package/dist/schema/camera.js.map +0 -1
  921. package/dist/schema/illumination-spectral.d.ts.map +0 -1
  922. package/dist/schema/illumination-temporal.d.ts.map +0 -1
  923. package/dist/schema/illumination.d.ts.map +0 -1
  924. package/dist/schema/scene-radiance-temporal.d.ts.map +0 -1
  925. package/dist/schema/scene-radiance.d.ts.map +0 -1
  926. package/dist/schema/scene.d.ts.map +0 -1
  927. package/dist/schema/scene.js +0 -3
  928. package/dist/schema/scene.js.map +0 -1
  929. package/dist/schema/validation.d.ts.map +0 -1
  930. package/dist/sensor/accumulated-charge.d.ts.map +0 -1
  931. package/dist/sensor/architecture.d.ts.map +0 -1
  932. package/dist/sensor/camera-saturation-capacity.d.ts.map +0 -1
  933. package/dist/sensor/capture-color-sampling-binding.d.ts.map +0 -1
  934. package/dist/sensor/capture-mode-timing.d.ts.map +0 -1
  935. package/dist/sensor/capture-mode.d.ts.map +0 -1
  936. package/dist/sensor/color-sampling.d.ts.map +0 -1
  937. package/dist/sensor/constant-rate-temporal-integration.d.ts.map +0 -1
  938. package/dist/sensor/dark-current.d.ts.map +0 -1
  939. package/dist/sensor/environment-photo-signal.d.ts.map +0 -1
  940. package/dist/sensor/eqe-electron-rate.d.ts.map +0 -1
  941. package/dist/sensor/eqe-local-exposure.d.ts.map +0 -1
  942. package/dist/sensor/eqe-temporal-exposure.d.ts.map +0 -1
  943. package/dist/sensor/exposure-window.d.ts.map +0 -1
  944. package/dist/sensor/iso-signal-chain.d.ts.map +0 -1
  945. package/dist/sensor/local-exposure-binding.d.ts.map +0 -1
  946. package/dist/sensor/optical-stack.d.ts.map +0 -1
  947. package/dist/sensor/photon-energy.d.ts.map +0 -1
  948. package/dist/sensor/physical-charge-capacity.d.ts.map +0 -1
  949. package/dist/sensor/pixel-pitch.d.ts.map +0 -1
  950. package/dist/sensor/radiometry-readiness.d.ts.map +0 -1
  951. package/dist/sensor/raw-readout.d.ts.map +0 -1
  952. package/dist/sensor/raw-reconstruction.d.ts.map +0 -1
  953. package/dist/sensor/readout-exposure-linkage.d.ts.map +0 -1
  954. package/dist/sensor/readout-timing.d.ts.map +0 -1
  955. package/dist/sensor/response-application-compatibility.d.ts.map +0 -1
  956. package/dist/sensor/response-operating-range.d.ts.map +0 -1
  957. package/dist/sensor/responsivity-photocurrent.d.ts.map +0 -1
  958. package/dist/sensor/sampling-aperture.d.ts.map +0 -1
  959. package/dist/sensor/scene-eqe-temporal-exposure.d.ts.map +0 -1
  960. package/dist/sensor/sensor-geometry.d.ts.map +0 -1
  961. package/dist/sensor/signal-noise.d.ts.map +0 -1
  962. package/dist/sensor/spatial-sample-reduction.d.ts.map +0 -1
  963. package/dist/sensor/spatial-sampling-quadrature.d.ts.map +0 -1
  964. package/dist/sensor/spatio-spectral-reduction.d.ts.map +0 -1
  965. package/dist/sensor/spectral-coverage.d.ts.map +0 -1
  966. package/dist/sensor/spectral-quadrature.d.ts.map +0 -1
  967. package/dist/sensor/spectral-response.d.ts.map +0 -1
  968. package/dist/sensor/temporal-eqe-sum.d.ts.map +0 -1
  969. package/dist/sensor/temporal-photo-signal.d.ts.map +0 -1
  970. package/dist/sensor/temporal-sample-binding.d.ts.map +0 -1
  971. package/dist/simulation/poc-simulation.d.ts.map +0 -1
  972. package/dist/stabilization/camera-shake.d.ts.map +0 -1
  973. package/dist/stabilization/system.d.ts.map +0 -1
  974. package/docs/API_STYLE.md +0 -235
  975. package/docs/ARCHITECTURE.md +0 -356
  976. package/docs/AUTOMATION_COORDINATION.md +0 -190
  977. package/docs/CAPTURE_COLOR.md +0 -25
  978. package/docs/CAPTURE_CORRECTED_SDR.md +0 -25
  979. package/docs/CAPTURE_EXPORT_METADATA.md +0 -27
  980. package/docs/CAPTURE_SDR.md +0 -22
  981. package/docs/DENSE_PUPIL_QUALIFICATION.md +0 -121
  982. package/docs/DEVELOPERS.md +0 -68
  983. package/docs/DIGITAL_OPTICS_FOUNDATION.md +0 -69
  984. package/docs/ENVIRONMENT_RAW_CAPTURE.md +0 -208
  985. package/docs/EXPORT_ACCEPTANCE.md +0 -133
  986. package/docs/GENERIC_TIER_PRESETS.md +0 -269
  987. package/docs/GEOMETRIC_PREPARATION_REUSE.md +0 -141
  988. package/docs/IMAGE_FORMATION.md +0 -247
  989. package/docs/LINEAR_CAPTURE_ENCODING.md +0 -25
  990. package/docs/MOTION_AND_SIGNAL.md +0 -250
  991. package/docs/NATIVE_CAPTURE_SDR.md +0 -70
  992. package/docs/NATIVE_CAPTURE_SDR_REVIEW.md +0 -37
  993. package/docs/NATIVE_CAPTURE_SDR_VALIDATION.md +0 -34
  994. package/docs/NATIVE_RAW_AND_PRINT.md +0 -54
  995. package/docs/NUMERICAL_CORRECTNESS.md +0 -191
  996. package/docs/PERFORMANCE_BASELINE.md +0 -56
  997. package/docs/PHOTOGRAPHIC_EXPORT.md +0 -206
  998. package/docs/PHYSICS_FOUNDATION.md +0 -426
  999. package/docs/POC_API.md +0 -278
  1000. package/docs/POC_PROJECTION_PLATFORM_REFERENCE.md +0 -12
  1001. package/docs/POC_PROJECTION_REUSE.md +0 -124
  1002. package/docs/PRINT_195_196_REVIEW.md +0 -93
  1003. package/docs/PRINT_196_ENGINE_ACCEPTANCE.md +0 -45
  1004. package/docs/PRINT_CONTRAST_REFERENCE.md +0 -43
  1005. package/docs/PRINT_DETAIL_ASSESSMENT.md +0 -81
  1006. package/docs/PRINT_DETAIL_JPEG_EVIDENCE.md +0 -36
  1007. package/docs/PRINT_DETAIL_SDR_EVIDENCE.md +0 -29
  1008. package/docs/PRINT_DETAIL_VALIDATION.md +0 -36
  1009. package/docs/PRINT_PLANNING.md +0 -75
  1010. package/docs/PRINT_REGION_STATISTICS.md +0 -38
  1011. package/docs/PROCESSED_OUTPUT.md +0 -157
  1012. package/docs/PRODUCTION_COMPOSITION.md +0 -373
  1013. package/docs/PRODUCTION_ENVIRONMENT_CAPTURE.md +0 -131
  1014. package/docs/PROVENANCE.md +0 -115
  1015. package/docs/PSF_FOUNDATION.md +0 -165
  1016. package/docs/RAW_FRAME_ENVELOPE.md +0 -56
  1017. package/docs/RAW_FRAME_RECONSTRUCTION.md +0 -30
  1018. package/docs/RELEASE_1_0.md +0 -66
  1019. package/docs/RELEASE_1_0_1.md +0 -61
  1020. package/docs/RELEASE_1_1_0.md +0 -25
  1021. package/docs/RELEASE_1_2_0.md +0 -51
  1022. package/docs/RELEASE_1_3_0.md +0 -15
  1023. package/docs/RELEASE_1_4_0.md +0 -23
  1024. package/docs/RELEASE_1_5_0.md +0 -105
  1025. package/docs/RELEASE_AUDIT.md +0 -39
  1026. package/docs/SCENE_RADIANCE_AND_ILLUMINATION.md +0 -298
  1027. package/docs/SCENE_SENSOR_QUADRATURE.md +0 -98
  1028. package/docs/SCENE_SENSOR_TEMPORAL_EXPOSURE.md +0 -86
  1029. package/docs/SCIENTIFIC_ASSURANCE.md +0 -280
  1030. package/docs/SCIENTIFIC_CONFORMANCE.md +0 -83
  1031. package/docs/SDR_RENDERING.md +0 -33
  1032. package/docs/SENSOR_APERTURE_RAYS.md +0 -23
  1033. package/docs/SENSOR_ENVIRONMENT_QUERY.md +0 -86
  1034. package/docs/SENSOR_EQE_LOCAL_EXPOSURE.md +0 -104
  1035. package/docs/SENSOR_EQE_TEMPORAL_EXPOSURE.md +0 -74
  1036. package/docs/SENSOR_PSF_QUADRATURE.md +0 -90
  1037. package/docs/SENSOR_RAW_FRAME.md +0 -20
  1038. package/docs/SENSOR_RAW_PRODUCER.md +0 -77
  1039. package/docs/SEPARABLE_EMISSION_DRAFT.md +0 -103
  1040. package/docs/SIGNAL_CONFORMANCE.md +0 -23
  1041. package/docs/SIMULATED_CAPTURE.md +0 -65
  1042. package/docs/STABILIZATION.md +0 -234
  1043. package/docs/TEMPORAL_PHOTO_RAW.md +0 -83
  1044. package/docs/TIER_ACCEPTANCE.md +0 -129
  1045. package/docs/TIER_PRESET_ACCEPTANCE.md +0 -59
  1046. package/docs/V1_COMPOSITION_MAP.md +0 -123
  1047. package/docs/V1_HELPER_REUSE_REVIEW.md +0 -60
  1048. package/docs/V1_PERFORMANCE_DISPOSITION.md +0 -88
  1049. package/docs/benchmarks/2026-10-01-main-baseline.json +0 -694
  1050. package/docs/benchmarks/2026-10-02-geometric-preparation-reuse.json +0 -2190
  1051. package/docs/benchmarks/2026-10-02-poc-projection-reuse.json +0 -2423
  1052. package/docs/benchmarks/2026-10-02-v1-environment-gc-profile.json +0 -210
  1053. package/docs/benchmarks/2026-10-02-v1-environment-ordinary.json +0 -187
  1054. package/docs/benchmarks/2026-10-02-v1-geometry-gc-profile.json +0 -756
  1055. package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-1.json +0 -711
  1056. package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-2.json +0 -711
  1057. package/docs/benchmarks/2026-10-02-v1-poc-gc-profile.json +0 -885
  1058. package/docs/benchmarks/2026-10-02-v1-poc-ordinary-1.json +0 -868
  1059. package/docs/benchmarks/2026-10-02-v1-poc-ordinary-2.json +0 -868
  1060. package/docs/licenses/castleCSF-MIT.txt +0 -21
  1061. package/docs/validation/dense-pupil-2026-10-06/pilot.jsonl +0 -6
  1062. package/docs/validation/documentation-fragments.json +0 -212
  1063. package/docs/validation/native-capture-sdr-darwin-arm64-node26-review.jsonl +0 -4
  1064. package/docs/validation/native-capture-sdr-darwin-arm64.jsonl +0 -3
  1065. package/docs/validation/native-raw-print-2026-10-04/fractional-asymmetric-crop.jpg +0 -0
  1066. package/docs/validation/native-raw-print-2026-10-04/gray-ramp.jpg +0 -0
  1067. package/docs/validation/native-raw-print-2026-10-04/linear-area-checker.jpg +0 -0
  1068. package/docs/validation/native-raw-print-2026-10-04/manifest.json +0 -218
  1069. package/docs/validation/native-raw-print-2026-10-04/megapixel-native.jpg +0 -0
  1070. package/docs/validation/native-raw-print-2026-10-04/native-color.jpg +0 -0
  1071. package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel-validation.json +0 -9
  1072. package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json +0 -29
  1073. package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json.codes.u16le.gz +0 -0
  1074. package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json.jpg +0 -0
  1075. package/docs/validation/native-raw-print-2026-10-04/photivra-native-full-megapixel.json.rgb.gz +0 -0
  1076. package/docs/validation/native-raw-print-2026-10-04/srgb.icc +0 -0
  1077. package/docs/validation/native-raw-print-2026-10-04/validation.json +0 -41
  1078. package/docs/validation/print-196-candidate-capabilities.json +0 -28
  1079. package/docs/validation/print-196-candidate-evidence.json +0 -356
  1080. package/docs/validation/print-196-engine-acceptance.json +0 -81
  1081. package/docs/validation/print-detail-capabilities.json +0 -103
  1082. package/docs/validation/print-detail-jpeg-evidence.json +0 -116
  1083. package/docs/validation/print-detail-sdr-evidence.json +0 -81
  1084. package/docs/validation/release-audit-inventory.json +0 -1306
  1085. package/docs/validation/tier-acceptance-report-v1.json +0 -2538
@@ -0,0 +1,974 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import { InvalidConfigurationError } from "../core/configuration-error.js";
3
+ import { apertureRadianceQuery } from "../sensor/environment-photo-signal.js";
4
+ import { createSensorEqeTemporalPhotoSignal } from "../sensor/temporal-photo-signal.js";
5
+ import { parseSceneRadianceEvaluationResult, validateSceneRadianceEvaluationBindings } from "../schema/scene-radiance.js";
6
+ import { calculateSceneRadianceToSensorIrradiance } from "../optics/scene-to-sensor-irradiance.js";
7
+ import { calculateMappedSensorEnvironmentRadianceQuery, prepareEnvironmentLensFieldMapping } from "../optics/sensor-environment-query.js";
8
+ import { calculateSensorPsfIrradianceQuadrature } from "../optics/sensor-psf-quadrature.js";
9
+ import { sensorPsfSourcePoint } from "../optics/sensor-psf-support.js";
10
+ import { resolveLensSampledPsf, resolveLensSampledPsfKernel } from "../optics/lens-psf-profile.js";
11
+ import { sensorApertureRayValues } from "../optics/sensor-aperture-rays.js";
12
+ import { parseFocusPlane } from "../optics/focus-state.js";
13
+ import { calculateIlluminationVignetting } from "../optics/illumination-vignetting.js";
14
+ import { applyPhysicalCameraRotation, resolveProjectionDistanceMm } from "../motion/camera-rotation.js";
15
+ import { prepareCaptureExposureWindowSampler } from "../sensor/exposure-window.js";
16
+ import { isPublicOpaqueId } from "../core/record-validation.js";
17
+ import { freezeOwnedData } from "../core/owned-data.js";
18
+ import { composeNativeEnvironmentSensorSite } from "./native-environment-optical-stage.js";
19
+ import { calculateNativeRawSite, parseNativeRawProducerSite } from "./sensor-raw-producer.js";
20
+ import { calculateSiteEffectiveSaturationCode } from "./raw-white-level.js";
21
+ import { adcTransfer, resolveSensorReadoutRegime, samplePoisson } from "../sensor/raw-readout.js";
22
+ import { createDeterministicUniformStream, deriveNativeSiteStreamSeedUint32, sampleDeterministicStandardNormal, NATIVE_SITE_CHARGE_STREAM_ID, NATIVE_SITE_READ_NOISE_STREAM_ID } from "../sensor/stochastic-seed.js";
23
+ import { evaluateParsedFixedPatternSite } from "../sensor/fixed-pattern-noise.js";
24
+ /** Most distinct templates kept for one capture event. Any further distinct sites just run the full path. */
25
+ const MAXIMUM_TEMPLATES = 64;
26
+ const SQUARE_MICROMETERS_TO_SQUARE_METERS = 1e-12;
27
+ const REDUCTION_TOLERANCE = 1e-10;
28
+ /** Disables the lean executor process-wide (internal; tests compare both paths). */
29
+ let leanDisabled = false;
30
+ /** Internal counters of lean work (tests assert the lean path actually runs). Not exported from the package. */
31
+ export const nativeEnvironmentLeanStatistics = { plannedSites: 0, executedSites: 0, sensorSites: 0, psfFallbacks: 0 };
32
+ export function setNativeEnvironmentLeanExecutionEnabled(enabled) { leanDisabled = !enabled; }
33
+ function isPlainRecord(value) {
34
+ const prototype = Object.getPrototypeOf(value);
35
+ return prototype === Object.prototype || prototype === null;
36
+ }
37
+ /**
38
+ * Strict structural equality of engine-owned structured-clone output: Object.is leaves (0 and -0 differ), plain
39
+ * records with the same own keys in the same order, dense arrays without extra properties. Anything else is equal
40
+ * only by reference. `memo` remembers subtrees already proven equal (both sides are engine-owned and unmutated).
41
+ */
42
+ function sameData(a, b, memo) {
43
+ if (Object.is(a, b))
44
+ return true;
45
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null)
46
+ return false;
47
+ if (memo.get(a) === b)
48
+ return true;
49
+ if (Array.isArray(a)) {
50
+ if (!Array.isArray(b) || Object.getPrototypeOf(a) !== Array.prototype || Object.getPrototypeOf(b) !== Array.prototype)
51
+ return false;
52
+ const length = a.length;
53
+ if (length !== b.length)
54
+ return false;
55
+ for (let i = 0; i < length; i++)
56
+ if (!(i in a) || !(i in b) || !sameData(a[i], b[i], memo))
57
+ return false;
58
+ if (Object.keys(a).length !== length || Object.keys(b).length !== length)
59
+ return false;
60
+ }
61
+ else {
62
+ if (Array.isArray(b) || !isPlainRecord(a) || !isPlainRecord(b) || Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
63
+ return false;
64
+ if (!sameKeysExcept(a, b, undefined, memo))
65
+ return false;
66
+ }
67
+ memo.set(a, b);
68
+ return true;
69
+ }
70
+ /** Same own keys in the same order and equal values, except `skip` (compared by the caller). */
71
+ function sameKeysExcept(a, b, skip, memo) {
72
+ const ak = Object.keys(a), bk = Object.keys(b);
73
+ if (ak.length !== bk.length || Object.getOwnPropertySymbols(a).length !== 0 || Object.getOwnPropertySymbols(b).length !== 0)
74
+ return false;
75
+ for (let i = 0; i < ak.length; i++)
76
+ if (ak[i] !== bk[i])
77
+ return false;
78
+ for (let i = 0; i < ak.length; i++) {
79
+ const key = ak[i];
80
+ if (key !== skip && !sameData(a[key], b[key], memo))
81
+ return false;
82
+ }
83
+ return true;
84
+ }
85
+ function plainChild(value, key) {
86
+ const child = typeof value === "object" && value !== null ? value[key] : undefined;
87
+ return typeof child === "object" && child !== null && !Array.isArray(child) && isPlainRecord(child) ? child : undefined;
88
+ }
89
+ /** Environment equality except temporalIntegrationId and sensor.spatialSampling.site (index-bound, checked per site). */
90
+ function environmentMatches(e, t, memo) {
91
+ const er = e, tr = t;
92
+ if (typeof er !== "object" || er === null || !isPlainRecord(er))
93
+ return false;
94
+ const es = plainChild(er, "sensor"), ts = plainChild(tr, "sensor"), ess = plainChild(es, "spatialSampling"), tss = plainChild(ts, "spatialSampling");
95
+ if (!es || !ts || !ess || !tss)
96
+ return false;
97
+ return environmentShallow(er, tr, memo);
98
+ }
99
+ /** Top level and sensor compared key by key so only the two index-bound fields are skipped. */
100
+ function environmentShallow(er, tr, memo) {
101
+ const ek = Object.keys(er), tk = Object.keys(tr);
102
+ if (ek.length !== tk.length || Object.getOwnPropertySymbols(er).length !== 0)
103
+ return false;
104
+ for (let i = 0; i < ek.length; i++)
105
+ if (ek[i] !== tk[i])
106
+ return false;
107
+ for (const key of ek) {
108
+ if (key === "temporalIntegrationId")
109
+ continue;
110
+ if (key === "sensor") {
111
+ const es = er.sensor, ts = tr.sensor, sk = Object.keys(es), tsk = Object.keys(ts);
112
+ if (sk.length !== tsk.length || Object.getOwnPropertySymbols(es).length !== 0)
113
+ return false;
114
+ for (let i = 0; i < sk.length; i++)
115
+ if (sk[i] !== tsk[i])
116
+ return false;
117
+ for (const sensorKey of sk) {
118
+ if (sensorKey === "spatialSampling") {
119
+ if (!sameKeysExcept(es.spatialSampling, ts.spatialSampling, "site", memo))
120
+ return false;
121
+ }
122
+ else if (!sameData(es[sensorKey], ts[sensorKey], memo))
123
+ return false;
124
+ }
125
+ }
126
+ else if (!sameData(er[key], tr[key], memo))
127
+ return false;
128
+ }
129
+ return true;
130
+ }
131
+ export function isLeanEnvironmentPlan(plan) {
132
+ return typeof plan === "object" && plan !== null && plan.lean === true;
133
+ }
134
+ function siteOf(environment) {
135
+ const site = plainChild(plainChild(plainChild(environment, "sensor"), "spatialSampling"), "site");
136
+ return site;
137
+ }
138
+ /** Plans the site-dependent parts with the full planner's arithmetic. Returns undefined on any doubt, and the caller plans in full. */
139
+ function geometry(t, k, frame, environment, index) {
140
+ try {
141
+ const x = index % frame.nativeWidth, y = Math.floor(index / frame.nativeWidth), site = siteOf(environment);
142
+ // Object.is: a -0 coordinate would flow into the full path's outputs, so it takes the full path.
143
+ if (!site || !Object.is(site.x, x) || !Object.is(site.y, y) || !isPublicOpaqueId(environment.temporalIntegrationId))
144
+ return undefined;
145
+ const g = k.geometry;
146
+ // resolveSensorSamplingAperture: per-site aperture centre and bounds.
147
+ const siteCenterFromTopLeftX = g.firstX + x * g.pitchX, siteCenterFromTopLeftY = g.firstY + y * g.pitchY;
148
+ const apertureCenterFromTopLeftX = siteCenterFromTopLeftX + g.offsetX, apertureCenterFromTopLeftY = siteCenterFromTopLeftY + g.offsetY;
149
+ const imagingWidthMicrometers = g.imagingWidthMm * 1000, imagingHeightMicrometers = g.imagingHeightMm * 1000;
150
+ if (apertureCenterFromTopLeftX - g.widthUm / 2 < 0 || apertureCenterFromTopLeftY - g.heightUm / 2 < 0 ||
151
+ apertureCenterFromTopLeftX + g.widthUm / 2 > imagingWidthMicrometers || apertureCenterFromTopLeftY + g.heightUm / 2 > imagingHeightMicrometers)
152
+ return undefined;
153
+ const centerX = -g.imagingWidthMm / 2 + apertureCenterFromTopLeftX / 1000, centerY = -g.imagingHeightMm / 2 + apertureCenterFromTopLeftY / 1000;
154
+ // calculateSensorSpatialSamplingQuadrature: midpoint grid nodes minus the anti-aliasing (AA) offset.
155
+ const widthMm = g.widthUm / 1000, heightMm = g.heightUm / 1000;
156
+ const leftMm = centerX - widthMm / 2, topMm = centerY - heightMm / 2;
157
+ const sources = [];
158
+ for (const node of k.spatial) {
159
+ const source = { x: (leftMm + node.xPhase * widthMm) - node.aaX, y: (topMm + node.yPhase * heightMm) - node.aaY };
160
+ if (!Number.isFinite(source.x) || !Number.isFinite(source.y))
161
+ return undefined;
162
+ sources.push(source);
163
+ }
164
+ const window = k.sampler({ x: x + .5, y: y + .5 });
165
+ const start = window.startOffsetSecondsFromOpeningReference, end = window.endOffsetSecondsFromOpeningReference;
166
+ const duration = window.localExposureDurationSeconds;
167
+ const e = environment, optics = e.optics, motion = e.motion;
168
+ const focalLengthMm = optics.focalLengthMm, nominalFNumber = optics.nominalFNumber;
169
+ const omega = motion.angularVelocityRadPerSec;
170
+ // The pupil, f-number and focus were validated by the template's full planning (they are site-independent); the ray
171
+ // arithmetic and its rotation and forward-hemisphere checks run per site through calculateSensorApertureRays' own code.
172
+ const pupil = e.pupil;
173
+ if (pupil !== undefined && sensorApertureRayValues({ sourcePointNativeSensorMm: { x: 0, y: 0 }, focalLengthMm, nominalFNumber,
174
+ angularVelocityRadPerSec: omega, timeSecondsFromOpeningReference: start }, pupil, k.parsedFocus).rays.length !== k.pupilCount)
175
+ return undefined;
176
+ // Field throughput at a planned point, as the full planner computes it.
177
+ const field = e.fieldThroughput;
178
+ const fieldAt = (point) => {
179
+ if (field.kind === "unity")
180
+ return { value: { kind: "unity" }, factor: 1, valid: true };
181
+ const result = calculateIlluminationVignetting({ imagePointMm: { x: point.x, y: -point.y },
182
+ profile: field.profile }).value;
183
+ const imagePoint = { x: point.x, y: -point.y };
184
+ const scale = Math.max(1, Math.abs(imagePoint.x), Math.abs(imagePoint.y), Math.abs(result.imagePointMm.x), Math.abs(result.imagePointMm.y));
185
+ const tolerance = Number.EPSILON * 64 * scale, factor = result.linearThroughputFactor;
186
+ const valid = !(Math.abs(result.imagePointMm.x - imagePoint.x) > tolerance || Math.abs(result.imagePointMm.y - imagePoint.y) > tolerance) &&
187
+ Number.isFinite(factor) && factor > 0 && factor <= 1;
188
+ return { value: { kind: "illumination-vignetting-result", result }, factor, valid };
189
+ };
190
+ // Tap points per group (spectral-major, spatial-minor). Without a PSF a group has one tap at its destination
191
+ // (one field throughput per spatial node, shared by its spectral nodes). With a sampled PSF the kernel is resolved
192
+ // at the destination and the taps sit at sensorPsfSourcePoint offsets, as in the full planner.
193
+ const S = k.spectralCount, P = k.spatialCount;
194
+ const tapPoints = [], tapFields = [];
195
+ const kernels = [];
196
+ // Without a PSF, the single tap of group gi is the destination sources[gi % P] (no per-group arrays are built).
197
+ const destinationFields = k.psf === undefined ? sources.map(fieldAt) : undefined;
198
+ if (k.psf !== undefined)
199
+ for (let s = 0; s < S; s++)
200
+ for (let p = 0; p < P; p++) {
201
+ const destination = sources[p], gi = s * P + p;
202
+ const kernel = resolveLensSampledPsfKernel({ ...k.psf, wavelengthNm: k.wavelengths[s], fieldPointMm: { x: destination.x, y: -destination.y } });
203
+ const n = kernel.widthSamples * kernel.heightSamples, weights = kernel.normalizedIntensity;
204
+ if (n !== k.tapCounts[gi] || weights.length !== n)
205
+ return undefined;
206
+ const points = [];
207
+ for (let i = 0; i < n; i++) {
208
+ const point = sensorPsfSourcePoint(destination, kernel, i % kernel.widthSamples, Math.floor(i / kernel.widthSamples));
209
+ // A non-finite kernel weight or tap point would fail the full planner's result checks: plan this site in full.
210
+ if (!Number.isFinite(weights[i]) || !Number.isFinite(point.x) || !Number.isFinite(point.y))
211
+ return undefined;
212
+ points.push(point);
213
+ }
214
+ tapPoints.push(points);
215
+ tapFields.push(points.map(fieldAt));
216
+ kernels.push(weights);
217
+ }
218
+ const measure = duration / k.temporalCount;
219
+ let previous = -Infinity;
220
+ const instants = [];
221
+ const pd = k.projectionDistanceMm, base = k.requestBase, id = environment.temporalIntegrationId;
222
+ for (let ti = 0; ti < k.temporalCount; ti++) {
223
+ const time = start + (ti + .5) * measure;
224
+ if (!(time > start && time > previous && time < end))
225
+ return undefined;
226
+ previous = time;
227
+ if (!Number.isFinite(time) || time < 0)
228
+ return undefined;
229
+ const displacement = { pitch: omega.pitch * time, yaw: omega.yaw * time, roll: omega.roll * time };
230
+ const taps = [];
231
+ for (let gi = 0; gi < S * P; gi++) {
232
+ const s = Math.floor(gi / P), points = destinationFields === undefined ? tapPoints[gi] : undefined;
233
+ const tapCount = points === undefined ? 1 : points.length;
234
+ for (let pi = 0; pi < tapCount; pi++) {
235
+ const point = points === undefined ? sources[gi % P] : points[pi], sampleId = `${id}-t${ti}-n${gi}-p${pi}`;
236
+ const apertureRays = pupil === undefined ? undefined : sensorApertureRayValues({ sourcePointNativeSensorMm: point, focalLengthMm,
237
+ nominalFNumber, angularVelocityRadPerSec: omega, timeSecondsFromOpeningReference: time }, pupil, k.parsedFocus).rays;
238
+ let request, imagePointMm, distortionAreaFactor;
239
+ if (k.lensMapping !== undefined) {
240
+ // The full planner's own mapped query, with the same input; only its result envelope is not kept.
241
+ const query = calculateMappedSensorEnvironmentRadianceQuery({ ...motion, sourcePointNativeSensorMm: point, focalLengthMm, focus: k.focus,
242
+ timeSecondsFromOpeningReference: time, request: { schemaVersion: "0.1.0", sampleId, providerProfileId: base.providerProfileId, sceneId: base.sceneId,
243
+ illuminationProfileId: base.illuminationProfileId, materialResponseProfileId: base.materialResponseProfileId, wavelengthNanometers: k.wavelengths[s],
244
+ wavelengthBasis: base.wavelengthBasis } }, k.lensMapping).value;
245
+ request = freezeOwnedData(query.request);
246
+ imagePointMm = query.sourcePointImagePlaneMm;
247
+ distortionAreaFactor = query.lensFieldMapping?.distortionAreaFactor;
248
+ if (distortionAreaFactor === undefined)
249
+ return undefined;
250
+ }
251
+ else {
252
+ // calculateSensorEnvironmentRadianceQuery with calculateInverseCameraRotationImageMapping.
253
+ imagePointMm = { x: point.x, y: -point.y };
254
+ if (!Number.isFinite(imagePointMm.x) || !Number.isFinite(imagePointMm.y))
255
+ return undefined;
256
+ const reference = applyPhysicalCameraRotation({ x: imagePointMm.x / pd, y: imagePointMm.y / pd, z: 1 }, displacement, "camera-to-reference");
257
+ if (!Number.isFinite(reference.z) || reference.z <= 0)
258
+ return undefined;
259
+ const rx = pd * (reference.x / reference.z), ry = pd * (reference.y / reference.z);
260
+ const length = Math.hypot(rx, ry, pd);
261
+ const ray = { x: rx / length, y: ry / length, z: pd / length };
262
+ // Build the parseSceneRadianceEvaluationRequest output directly. Every other field is a template constant already
263
+ // parsed for the template site. The sample ID is a public opaque ID (trimming cannot change it) and the time is
264
+ // checked above. So only parseUnitDirection's unit-direction check depends on this site.
265
+ const direction = { x: -ray.x, y: -ray.y, z: -ray.z };
266
+ if (!Number.isFinite(direction.x) || !Number.isFinite(direction.y) || !Number.isFinite(direction.z))
267
+ return undefined;
268
+ const norm = Math.hypot(direction.x, direction.y, direction.z);
269
+ if (!Number.isFinite(norm) || Math.abs(norm - 1) > 1e-9)
270
+ return undefined;
271
+ request = Object.freeze({ schemaVersion: "0.1.0", sampleId, providerProfileId: base.providerProfileId,
272
+ sceneId: base.sceneId, illuminationProfileId: base.illuminationProfileId, materialResponseProfileId: base.materialResponseProfileId,
273
+ target: Object.freeze({ kind: "environment-direction", outgoingDirectionUnitVector: Object.freeze(direction) }),
274
+ timeSecondsFromExposureStart: time, wavelengthNanometers: k.wavelengths[s],
275
+ wavelengthBasis: base.wavelengthBasis });
276
+ }
277
+ const f = destinationFields === undefined ? tapFields[gi][pi] : destinationFields[gi % P];
278
+ // Built without object spread (cheaper per tap); optional fields are added only when present.
279
+ const leanTap = { request, sourcePointImagePlaneMm: imagePointMm, fieldThroughput: f.value, fieldFactor: f.factor, fieldValid: f.valid };
280
+ if (apertureRays !== undefined)
281
+ leanTap.apertureRays = apertureRays;
282
+ if (distortionAreaFactor !== undefined)
283
+ leanTap.distortionAreaFactor = distortionAreaFactor;
284
+ taps.push(leanTap);
285
+ }
286
+ }
287
+ instants.push({ time, taps });
288
+ }
289
+ return { lean: true, template: t, index, owned: environment, count: k.count, site: { x, y }, start, end, duration, instants,
290
+ ...(k.psf === undefined ? {} : { kernels }) };
291
+ }
292
+ catch {
293
+ return undefined;
294
+ }
295
+ }
296
+ /** Lean photo-signal arithmetic over values[ti][s*P+p]. Returns undefined when any data-dependent check fails. */
297
+ function photo(k, c, values, environment, site, start, end, duration, times) {
298
+ const S = k.spectralCount, P = k.spatialCount, T = k.temporalCount;
299
+ const photonRates = new Float64Array(T), electronRates = new Float64Array(T);
300
+ const flux = new Float64Array(S), contribution = new Float64Array(S), averageContribution = new Float64Array(S);
301
+ for (let ti = 0; ti < T; ti++) {
302
+ const v = values[ti];
303
+ // reduceSensorSpatioSpectralIrradiance
304
+ let integratedAverage = 0, integratedFlux = 0;
305
+ for (let s = 0; s < S; s++) {
306
+ let average = 0, geometric = 0;
307
+ for (let p = 0; p < P; p++) {
308
+ const value = v[s * P + p];
309
+ average += value * c.weight[p];
310
+ geometric += value * c.areaSquareMeters[p];
311
+ if (!Number.isFinite(average) || !Number.isFinite(geometric))
312
+ return undefined;
313
+ }
314
+ const averageTerm = average * c.measure[s], fluxTerm = geometric * c.measure[s];
315
+ integratedAverage += averageTerm;
316
+ integratedFlux += fluxTerm;
317
+ if (!Number.isFinite(integratedAverage) || !Number.isFinite(integratedFlux))
318
+ return undefined;
319
+ flux[s] = geometric;
320
+ contribution[s] = fluxTerm;
321
+ averageContribution[s] = averageTerm;
322
+ }
323
+ // assessSensorResponseOperatingRange: selected metric and per-bin values inside the calibrated range.
324
+ const metric = c.rangeKind === "power" ? integratedFlux : integratedAverage;
325
+ if (!Number.isFinite(metric) || metric < 0 || metric < c.rangeMinimum || metric > c.rangeMaximum)
326
+ return undefined;
327
+ if (c.perBin)
328
+ for (let s = 0; s < S; s++) {
329
+ const value = c.rangeKind === "power" ? contribution[s] : averageContribution[s];
330
+ if (!Number.isFinite(value) || value < 0 || value < c.rangeMinimum || value > c.rangeMaximum)
331
+ return undefined;
332
+ }
333
+ // calculateSensorEqeElectronRate: reduction node checks, compensated power, then per-node rates.
334
+ let powerSum = 0, powerCorrection = 0;
335
+ for (let s = 0; s < S; s++) {
336
+ const expected = flux[s] * c.measure[s];
337
+ if (!Number.isFinite(flux[s]) || flux[s] < 0 || !Number.isFinite(contribution[s]) || contribution[s] < 0 ||
338
+ !Number.isFinite(expected) || !approximatelyEqual(contribution[s], expected))
339
+ return undefined;
340
+ const adjusted = contribution[s] - powerCorrection, next = powerSum + adjusted;
341
+ powerCorrection = (next - powerSum) - adjusted;
342
+ powerSum = next;
343
+ }
344
+ if (!(Number.isFinite(integratedFlux) && integratedFlux >= 0) || !approximatelyEqual(powerSum, integratedFlux))
345
+ return undefined;
346
+ let photonSum = 0, photonCorrection = 0, electronSum = 0, electronCorrection = 0;
347
+ for (let s = 0; s < S; s++) {
348
+ const radiantPower = flux[s] * c.measure[s];
349
+ const photonRate = radiantPower / c.photonEnergy[s];
350
+ const electronRate = photonRate * c.eqe[s];
351
+ if (!Number.isFinite(radiantPower) || !Number.isFinite(photonRate) || !Number.isFinite(electronRate))
352
+ return undefined;
353
+ const adjustedPhotons = photonRate - photonCorrection, nextPhotons = photonSum + adjustedPhotons;
354
+ photonCorrection = (nextPhotons - photonSum) - adjustedPhotons;
355
+ photonSum = nextPhotons;
356
+ const adjustedElectrons = electronRate - electronCorrection, nextElectrons = electronSum + adjustedElectrons;
357
+ electronCorrection = (nextElectrons - electronSum) - adjustedElectrons;
358
+ electronSum = nextElectrons;
359
+ }
360
+ if (!Number.isFinite(photonSum) || !Number.isFinite(electronSum))
361
+ return undefined;
362
+ photonRates[ti] = photonSum;
363
+ electronRates[ti] = electronSum;
364
+ }
365
+ // sumTemporalEqeRateExpectations with the binding's seconds-valued measure.
366
+ const measure = duration / T;
367
+ let photons = 0, electrons = 0, photonCorrection = 0, electronCorrection = 0;
368
+ for (let ti = 0; ti < T; ti++) {
369
+ const p = photonRates[ti] * measure, e = electronRates[ti] * measure;
370
+ const ap = p - photonCorrection, np = photons + ap;
371
+ photonCorrection = (np - photons) - ap;
372
+ photons = np;
373
+ const ae = e - electronCorrection, ne = electrons + ae;
374
+ electronCorrection = (ne - electrons) - ae;
375
+ electrons = ne;
376
+ }
377
+ // parseSensorEqeTemporalPhotoSignal: finite non-negative rates, EQE domain and finite counts.
378
+ for (let ti = 0; ti < T; ti++) {
379
+ const pr = photonRates[ti], er = electronRates[ti];
380
+ if (!Number.isFinite(pr) || pr < 0 || !Number.isFinite(er) || er < 0 || er > pr)
381
+ return undefined;
382
+ }
383
+ if (!Number.isFinite(photons) || photons < 0 || !Number.isFinite(electrons) || electrons < 0)
384
+ return undefined;
385
+ const temporalSamples = [];
386
+ for (let ti = 0; ti < T; ti++)
387
+ temporalSamples.push(Object.freeze({ timeSecondsFromOpeningReference: times[ti],
388
+ incidentPhotonRatePerSecond: photonRates[ti], expectedGeneratedElectronRatePerSecond: electronRates[ti] }));
389
+ return Object.freeze({ ...c.photo, temporalIntegrationId: environment.temporalIntegrationId, site: Object.freeze({ x: site.x, y: site.y }),
390
+ startOffsetSecondsFromOpeningReference: start, endOffsetSecondsFromOpeningReference: end, localExposureDurationSeconds: duration,
391
+ expectedIncidentPhotonCount: photons, expectedGeneratedElectronCount: electrons, temporalSamples: Object.freeze(temporalSamples) });
392
+ }
393
+ /** The temporal photo-signal input the full executor builds from these irradiance values (a PSF quadrature's nodes are equal plain data). */
394
+ function fullPhotoInput(k, values, environment, times) {
395
+ return { temporalIntegrationId: environment.temporalIntegrationId, exposure: { ...environment.sensor, samples: values.map((v, ti) => ({
396
+ temporalSampleIndex: ti, timeSecondsFromOpeningReference: times[ti],
397
+ irradianceSamples: k.nodes.map((node, gi) => ({ node: structuredClone(node), spectralIrradianceWattsPerSquareMeterPerNanometer: v[gi] }))
398
+ })) } };
399
+ }
400
+ /** Derives a template's plan constants from its full plan; throws when anything is outside the lean scope. */
401
+ function planConstants(environment, plan) {
402
+ const e = environment, sensor = e.sensor, spatial = sensor.spatialSampling;
403
+ const apertureProfile = spatial.samplingApertureProfile;
404
+ const aperture = apertureProfile.geometricSensitiveAperture, lattice = apertureProfile.siteCenterLattice;
405
+ const first = lattice.firstSiteCenterFromImagingAreaTopLeftMicrometers;
406
+ const offset = aperture.centerOffsetFromSiteCenterMicrometers;
407
+ const imaging = spatial.imagingArea;
408
+ const spatialNodes = plan.spatialQuadrature.nodes, spectralNodes = plan.spectralQuadrature.nodes;
409
+ const countX = spatial.spatialSampleCountX, countY = spatial.spatialSampleCountY;
410
+ const S = spectralNodes.length, P = spatialNodes.length, T = plan.instants.length, groups = plan.instants[0].groups;
411
+ const tapCounts = groups.map(group => group.taps.length), taps = tapCounts.reduce((sum, n) => sum + n, 0);
412
+ const pupilCount = plan.count / (taps * T);
413
+ const psf = e.psf, sampled = psf.kind === "sampled-local";
414
+ if (!Number.isSafeInteger(pupilCount) || pupilCount < 1 || groups.length !== S * P || (!sampled && psf.kind !== "not-applied") ||
415
+ (sampled && pupilCount !== 1) || (!sampled && tapCounts.some(n => n !== 1)) ||
416
+ plan.instants.some(i => i.groups.length !== S * P || i.groups.some((g, gi) => g.taps.length !== tapCounts[gi]))) {
417
+ throw new Error("outside lean scope");
418
+ }
419
+ const configuration = sampled ? psf.configuration.psf : undefined;
420
+ return {
421
+ spectralCount: S, spatialCount: P, temporalCount: T, pupilCount, count: plan.count, tapCounts,
422
+ tapOffsets: tapCounts.reduce((offsets, n) => { offsets.push(offsets[offsets.length - 1] + n); return offsets; }, [0]),
423
+ ...(configuration === undefined ? {} : { psf: { profile: configuration.profile, focalLengthMm: configuration.focalLengthMm, focus: configuration.focus,
424
+ apertureFNumber: configuration.apertureFNumber, signedDefocusImagePlaneMicrometers: configuration.signedDefocusImagePlaneMicrometers } }),
425
+ ...("lensFieldMapping" in e ? { lensMapping: prepareEnvironmentLensFieldMapping(e.lensFieldMapping) } : {}),
426
+ wavelengths: Float64Array.from(spectralNodes, n => n.wavelengthNanometers),
427
+ nodes: groups.map(group => freezeOwnedData(structuredClone(group.node))),
428
+ spatial: spatialNodes.map(n => ({ xPhase: (n.apertureSampleXIndex + 0.5) / countX, yPhase: (n.apertureSampleYIndex + 0.5) / countY,
429
+ aaX: n.antiAliasingOffsetMicrometers.x / 1000, aaY: n.antiAliasingOffsetMicrometers.y / 1000 })),
430
+ geometry: { firstX: first.x, firstY: first.y, pitchX: lattice.pitchXMicrometers, pitchY: lattice.pitchYMicrometers,
431
+ offsetX: offset.x, offsetY: offset.y, widthUm: aperture.widthMicrometers, heightUm: aperture.heightMicrometers,
432
+ imagingWidthMm: imaging.widthMm, imagingHeightMm: imaging.heightMm },
433
+ sampler: prepareCaptureExposureWindowSampler(sensor.localExposure.exposureWindowInput),
434
+ projectionDistanceMm: resolveProjectionDistanceMm(e.optics.focalLengthMm, plan.focus.kind === "finite" ? plan.focus.distanceM : undefined).projectionDistanceMm,
435
+ focus: plan.focus,
436
+ parsedFocus: parseFocusPlane(plan.focus),
437
+ requestBase: { providerProfileId: plan.sceneBindings.providerProfile.profileId, sceneId: plan.sceneBindings.providerProfile.sceneId,
438
+ illuminationProfileId: plan.sceneBindings.illuminationProfile.profileId, materialResponseProfileId: plan.sceneBindings.materialResponseProfile.profileId,
439
+ wavelengthBasis: plan.spectralQuadrature.wavelengthBasis },
440
+ sceneBindings: plan.sceneBindings
441
+ };
442
+ }
443
+ /** The lean planner must reproduce the template site's full plan bit for bit, including each resolved PSF kernel. */
444
+ function planReproduced(lean, plan, k) {
445
+ if (!lean || lean.count !== plan.count || lean.instants.length !== plan.instants.length || (lean.kernels !== undefined) !== (k.psf !== undefined))
446
+ return false;
447
+ const check = new WeakMap();
448
+ for (let ti = 0; ti < plan.instants.length; ti++) {
449
+ const full = plan.instants[ti], mine = lean.instants[ti];
450
+ if (!Object.is(full.time, mine.time) || full.temporalSampleIndex !== ti || full.groups.length !== k.tapCounts.length ||
451
+ mine.taps.length !== k.tapOffsets[k.tapCounts.length])
452
+ return false;
453
+ for (let gi = 0; gi < full.groups.length; gi++) {
454
+ const fullTaps = full.groups[gi].taps, first = k.tapOffsets[gi];
455
+ if (fullTaps.length !== k.tapCounts[gi] || !sameData(full.groups[gi].node, k.nodes[gi], check))
456
+ return false;
457
+ for (let pi = 0; pi < fullTaps.length; pi++) {
458
+ const fullTap = fullTaps[pi], tap = mine.taps[first + pi];
459
+ if (!Object.isFrozen(fullTap.request) || !Object.isFrozen(tap.request) || !sameData(fullTap.request, tap.request, check) ||
460
+ !sameData(fullTap.sourcePointImagePlaneMm, tap.sourcePointImagePlaneMm, check) ||
461
+ !sameData(fullTap.fieldThroughput, tap.fieldThroughput, check) || !sameData(fullTap.apertureRays, tap.apertureRays, check) ||
462
+ !Object.is(fullTap.distortionAreaFactor, tap.distortionAreaFactor))
463
+ return false;
464
+ }
465
+ }
466
+ }
467
+ if (k.psf !== undefined) {
468
+ // Each kernel must equal the public resolver's kernel for the template site's destination and wavelength.
469
+ const S = k.spectralCount, P = k.spatialCount;
470
+ for (let gi = 0; gi < S * P; gi++) {
471
+ const destination = plan.spatialQuadrature.nodes[gi % P].preAntiAliasingSourcePointMm;
472
+ const kernel = resolveLensSampledPsf({ ...k.psf, wavelengthNm: k.wavelengths[Math.floor(gi / P)],
473
+ fieldPointMm: { x: destination.x, y: -destination.y } }).value.kernel;
474
+ if (!sameData(kernel.normalizedIntensity, lean.kernels[gi], check))
475
+ return false;
476
+ }
477
+ }
478
+ return true;
479
+ }
480
+ /** Sum of a PSF group's taps in kernel order, the same expression calculateSensorPsfIrradianceQuadrature reduces. */
481
+ function psfSum(kernel, values) {
482
+ let sum = 0;
483
+ for (let i = 0; i < values.length; i++)
484
+ sum = sum + kernel[i] * values[i];
485
+ return sum;
486
+ }
487
+ /**
488
+ * True when every data-dependent check calculateSensorPsfIrradianceQuadrature makes on one instant passes: finite,
489
+ * non-negative tap irradiances, finite weighted sums, and the finite partial sums of its spatio-spectral reduction
490
+ * (in the reduction's node order). When false, the full quadrature runs and decides.
491
+ */
492
+ function psfChecksPass(k, c, taps, v) {
493
+ for (const values of taps)
494
+ for (let i = 0; i < values.length; i++)
495
+ if (!Number.isFinite(values[i]) || values[i] < 0)
496
+ return false;
497
+ const S = k.spectralCount, P = k.spatialCount;
498
+ let integratedAverage = 0, integratedFlux = 0;
499
+ for (let s = 0; s < S; s++) {
500
+ let average = 0, geometric = 0;
501
+ for (let p = 0; p < P; p++) {
502
+ const value = v[s * P + p];
503
+ if (!Number.isFinite(value) || value < 0)
504
+ return false;
505
+ average += value * c.weight[p];
506
+ geometric += value * c.areaSquareMeters[p];
507
+ if (!Number.isFinite(average) || !Number.isFinite(geometric))
508
+ return false;
509
+ }
510
+ integratedAverage += average * c.measure[s];
511
+ integratedFlux += geometric * c.measure[s];
512
+ if (!Number.isFinite(integratedAverage) || !Number.isFinite(integratedFlux))
513
+ return false;
514
+ }
515
+ return true;
516
+ }
517
+ /** The full executor's PSF quadrature for one instant of a site's full plan, with the given tap irradiances. Throws its own errors. */
518
+ function fullPsfInstant(plan, ti, taps) {
519
+ nativeEnvironmentLeanStatistics.psfFallbacks++;
520
+ const instant = plan.instants[ti], owned = plan.owned;
521
+ if (owned.psf.kind !== "sampled-local")
522
+ throw new InvalidConfigurationError("Lean PSF fallback requires a sampled-PSF plan.");
523
+ const psf = calculateSensorPsfIrradianceQuadrature({ ...owned.psf.configuration, spatialQuadrature: plan.spatialQuadrature,
524
+ spectralQuadrature: plan.spectralQuadrature, timeSecondsFromOpeningReference: instant.time,
525
+ inputMeaning: "pre-psf-pre-sensor-stack-pre-aa-spectral-irradiance", samples: instant.groups.map((group, gi) => ({ node: group.node,
526
+ sourceSamples: group.taps.map((tap, pi) => ({ kernelSampleX: tap.kernelSampleX, kernelSampleY: tap.kernelSampleY, sourcePointNativeSensorMm: tap.point,
527
+ timeSecondsFromOpeningReference: instant.time, spectralIrradianceWattsPerSquareMeterPerNanometer: taps[gi][pi] })) })) });
528
+ return Float64Array.from(psf.value.irradianceSamples, sample => sample.spectralIrradianceWattsPerSquareMeterPerNanometer);
529
+ }
530
+ /** Derives execution constants from the template site's full execution ("full" retention) and checks them. Returns undefined on a mismatch. */
531
+ function executionConstants(k, environment, plan, result, self) {
532
+ const S = k.spectralCount, P = k.spatialCount, T = k.temporalCount;
533
+ const value = result.value, stages = value.photo.value.exposure.value.samples[0].stages;
534
+ const spatial = stages.spatialQuadrature.value.nodes, spectral = stages.spectralQuadrature.value.nodes;
535
+ const rate = stages.electronRate.value.perWavelength, range = stages.operatingRange.value;
536
+ if (spatial.length !== P || spectral.length !== S || rate.length !== S || value.instants.length !== T)
537
+ return undefined;
538
+ for (let s = 0; s < S; s++)
539
+ if (rate[s].spectralSampleIndex !== s || spectral[s].spectralSampleIndex !== s)
540
+ return undefined;
541
+ const c = {
542
+ weight: Float64Array.from(spatial, n => n.combinedNormalizedSpatialWeight),
543
+ areaSquareMeters: Float64Array.from(spatial, n => n.combinedAreaMeasureSquareMicrometers * SQUARE_MICROMETERS_TO_SQUARE_METERS),
544
+ measure: Float64Array.from(spectral, n => n.wavelengthMeasureNanometers),
545
+ photonEnergy: Float64Array.from(rate, n => n.photonEnergyJoules), eqe: Float64Array.from(rate, n => n.effectiveExternalQuantumEfficiency),
546
+ acceptance: new Float64Array(S).fill(NaN),
547
+ rangeKind: range.inputRange.kind === "wavelength-integrated-geometric-aperture-radiant-power" ? "power" : "irradiance",
548
+ rangeMinimum: range.inputRange.minimumInclusive, rangeMaximum: range.inputRange.maximumInclusive,
549
+ perBin: range.spectralInputModel.kind === "per-spectral-bin", photo: value.photo.value.photoSignal
550
+ };
551
+ // Acceptance before field throughput per wavelength, and every evaluation's irradiance, must reproduce exactly.
552
+ // With a PSF, each group's kernel-weighted sum must equal the full quadrature's node irradiance.
553
+ const values = [];
554
+ const check = new WeakMap();
555
+ for (let ti = 0; ti < T; ti++) {
556
+ const evaluations = value.instants[ti].evaluations, v = new Float64Array(S * P), psf = value.instants[ti].psf;
557
+ if ((psf !== null) !== (k.psf !== undefined))
558
+ return undefined;
559
+ let next = 0;
560
+ for (let gi = 0; gi < S * P; gi++) {
561
+ const s = Math.floor(gi / P), taps = plan.instants[ti].groups[gi].taps, tapValues = new Float64Array(taps.length);
562
+ for (let pi = 0; pi < taps.length; pi++) {
563
+ const request = taps[pi].request;
564
+ let integrated = 0;
565
+ for (let r = 0; r < k.pupilCount; r++) {
566
+ const evaluation = evaluations[next++];
567
+ if (!evaluation)
568
+ return undefined;
569
+ const o = evaluation.optics.value;
570
+ let a = o.transmissionPath === "spectral-transmission" ? o.paraxialGeometricAcceptanceSolidAngleSteradians * o.spectralTransmissionFactor
571
+ : Math.PI / (4 * o.effectiveWorkingTStop * o.effectiveWorkingTStop);
572
+ a *= o.frontOfLensFilterTransmissionFactor;
573
+ if (Number.isNaN(c.acceptance[s]))
574
+ c.acceptance[s] = a;
575
+ else if (!Object.is(c.acceptance[s], a))
576
+ return undefined;
577
+ const acceptance = c.acceptance[s] * o.fieldThroughputFactor;
578
+ const irradiance = evaluation.result.spectralRadianceWattsPerSquareMeterSteradianNanometer * acceptance;
579
+ if (!Object.is(acceptance, o.effectiveAcceptanceAfterTransmissionAndFieldSteradians) ||
580
+ !Object.is(irradiance, o.sensorPlaneSpectralIrradianceWattsPerSquareMeterNanometer) ||
581
+ evaluation.result.sampleId !== request.sampleId + (evaluation.apertureRay ? "-a" + evaluation.apertureRay.pupilSampleIndex : ""))
582
+ return undefined;
583
+ integrated += irradiance * (evaluation.apertureRay?.weight ?? 1);
584
+ }
585
+ const factor = taps[pi].distortionAreaFactor;
586
+ if (factor !== undefined)
587
+ integrated *= factor;
588
+ tapValues[pi] = integrated;
589
+ }
590
+ if (psf === null)
591
+ v[gi] = tapValues[0];
592
+ else {
593
+ const sample = psf.value.irradianceSamples[gi];
594
+ v[gi] = psfSum(self.kernels[gi], tapValues);
595
+ if (!sample || !Object.is(v[gi], sample.spectralIrradianceWattsPerSquareMeterPerNanometer) || !sameData(sample.node, k.nodes[gi], check))
596
+ return undefined;
597
+ }
598
+ }
599
+ if (next !== evaluations.length)
600
+ return undefined;
601
+ values.push(v);
602
+ }
603
+ if (c.acceptance.some(Number.isNaN))
604
+ return undefined;
605
+ const full = value.photo.value.photoSignal;
606
+ const mine = photo(k, c, values, environment, full.site, full.startOffsetSecondsFromOpeningReference, full.endOffsetSecondsFromOpeningReference, full.localExposureDurationSeconds, plan.instants.map(i => i.time));
607
+ return mine && sameData(mine, full, new WeakMap()) ? c : undefined;
608
+ }
609
+ export function createNativeEnvironmentLeanExecutor(frame) {
610
+ const templates = [];
611
+ const candidates = new Map();
612
+ const memo = new WeakMap();
613
+ const enabled = !leanDisabled && frame.identityBinding && frame.repeatWidth > 0 && frame.repeatHeight > 0;
614
+ const phaseOf = (index) => {
615
+ const x = index % frame.nativeWidth, y = Math.floor(index / frame.nativeWidth);
616
+ return (y % frame.repeatHeight) * frame.repeatWidth + (x % frame.repeatWidth);
617
+ };
618
+ return {
619
+ plan(environment, index) {
620
+ if (!enabled)
621
+ return undefined;
622
+ const phase = phaseOf(index);
623
+ let t;
624
+ try {
625
+ for (const template of templates)
626
+ if (template.phase === phase && environmentMatches(environment, template.environment, memo)) {
627
+ t = template;
628
+ break;
629
+ }
630
+ }
631
+ catch {
632
+ return undefined;
633
+ }
634
+ if (!t)
635
+ return templates.length < MAXIMUM_TEMPLATES ? "candidate" : undefined;
636
+ if (t.disabled || !t.consts || t.executionVerified === false)
637
+ return undefined;
638
+ const leanPlan = geometry(t, t.consts, frame, environment, index);
639
+ if (leanPlan)
640
+ nativeEnvironmentLeanStatistics.plannedSites++;
641
+ return leanPlan;
642
+ },
643
+ admitCandidate(environment, index, plan) {
644
+ const template = { environment, phase: phaseOf(index), disabled: true };
645
+ templates.push(template);
646
+ candidates.set(index, template);
647
+ try {
648
+ const k = planConstants(environment, plan), self = geometry(template, k, frame, environment, index);
649
+ if (!planReproduced(self, plan, k))
650
+ return;
651
+ template.consts = k;
652
+ template.selfPlan = self;
653
+ template.disabled = false;
654
+ }
655
+ catch {
656
+ // An ineligible template leaves its sites on the full path.
657
+ }
658
+ },
659
+ isCandidate(index) { return candidates.has(index); },
660
+ verifyCandidate(index, plan, result) {
661
+ const t = candidates.get(index);
662
+ if (!t)
663
+ return;
664
+ candidates.delete(index);
665
+ t.executionVerified = false;
666
+ try {
667
+ if (t.disabled || !t.consts || !t.selfPlan)
668
+ return;
669
+ const c = executionConstants(t.consts, t.environment, plan, result, t.selfPlan);
670
+ t.selfPlan = undefined;
671
+ if (!c)
672
+ return;
673
+ t.execution = c;
674
+ t.executionVerified = true;
675
+ }
676
+ catch {
677
+ // Unverified: sites of this template run the full path.
678
+ }
679
+ },
680
+ execute(plan, evaluate, aperture, fullPlan) {
681
+ const t = plan.template, c = t.execution, k = t.consts;
682
+ if (t.executionVerified !== true || !c || !k)
683
+ return undefined;
684
+ const environment = plan.owned, optics = environment.optics;
685
+ const S = k.spectralCount, P = k.spatialCount, kernels = plan.kernels;
686
+ /** One tap: its callbacks in order, each result validated, the pupil sum, then the distortion area factor once. */
687
+ const tapIrradiance = (tap, s) => {
688
+ let integrated = 0;
689
+ const support = tap.apertureRays ?? [undefined];
690
+ for (const ray of support) {
691
+ const query = ray === undefined ? undefined : apertureRadianceQuery(tap.request, ray);
692
+ const request = query === undefined ? tap.request : query.request, apertureRay = query?.apertureRay;
693
+ const result = parseSceneRadianceEvaluationResult(apertureRay === undefined ? evaluate(request) : aperture(request, apertureRay));
694
+ if (result.sampleId !== request.sampleId || result.providerProfileId !== request.providerProfileId || result.sceneId !== request.sceneId ||
695
+ result.wavelengthNanometers !== request.wavelengthNanometers || result.wavelengthBasis !== request.wavelengthBasis) {
696
+ validateSceneRadianceEvaluationBindings({ ...k.sceneBindings, request, result });
697
+ }
698
+ let irradiance = result.spectralRadianceWattsPerSquareMeterSteradianNanometer * (c.acceptance[s] * tap.fieldFactor);
699
+ if (!tap.fieldValid || !Number.isFinite(irradiance) || irradiance < 0) {
700
+ irradiance = calculateSceneRadianceToSensorIrradiance({ ...optics,
701
+ sceneRadianceRequest: request, sceneRadianceResult: result, imagePointMm: tap.sourcePointImagePlaneMm,
702
+ fieldThroughput: tap.fieldThroughput }).value.sensorPlaneSpectralIrradianceWattsPerSquareMeterNanometer;
703
+ }
704
+ integrated += irradiance * (ray?.weight ?? 1);
705
+ }
706
+ // Distortion squeezes or stretches the ideal image; irradiance scales by 1/det once, as in the full executor.
707
+ if (tap.distortionAreaFactor !== undefined)
708
+ integrated *= tap.distortionAreaFactor;
709
+ return integrated;
710
+ };
711
+ const values = [], times = [];
712
+ let full;
713
+ for (let ti = 0; ti < plan.instants.length; ti++) {
714
+ const instant = plan.instants[ti];
715
+ let v = new Float64Array(S * P);
716
+ if (kernels === undefined) {
717
+ // One tap per group, so the flat list is indexed by group.
718
+ for (let gi = 0; gi < S * P; gi++)
719
+ v[gi] = tapIrradiance(instant.taps[gi], Math.floor(gi / P));
720
+ }
721
+ else {
722
+ const tapValues = [];
723
+ for (let gi = 0; gi < S * P; gi++) {
724
+ const first = k.tapOffsets[gi], s = Math.floor(gi / P), groupValues = new Float64Array(k.tapOffsets[gi + 1] - first);
725
+ for (let pi = 0; pi < groupValues.length; pi++)
726
+ groupValues[pi] = tapIrradiance(instant.taps[first + pi], s);
727
+ tapValues.push(groupValues);
728
+ v[gi] = psfSum(kernels[gi], groupValues);
729
+ }
730
+ // The full executor runs its PSF quadrature (and its checks) here, after this instant's callbacks. When a check
731
+ // fails, run that quadrature on the site's full plan (built without callbacks): it throws its own error or decides.
732
+ if (!psfChecksPass(k, c, tapValues, v))
733
+ v = fullPsfInstant(full ??= fullPlan(), ti, tapValues);
734
+ }
735
+ values.push(v);
736
+ times.push(instant.time);
737
+ }
738
+ nativeEnvironmentLeanStatistics.executedSites++;
739
+ return photo(k, c, values, environment, plan.site, plan.start, plan.end, plan.duration, times) ??
740
+ createSensorEqeTemporalPhotoSignal(fullPhotoInput(k, values, environment, times)).value.photoSignal;
741
+ }
742
+ };
743
+ }
744
+ function approximatelyEqual(actual, expected) {
745
+ const scale = Math.max(1, Math.abs(actual), Math.abs(expected));
746
+ return Math.abs(actual - expected) <= REDUCTION_TOLERANCE * scale;
747
+ }
748
+ /** Photo-signal fields that vary per site; every other field is template-level. */
749
+ const PHOTO_SITE_FIELDS = new Set(["temporalIntegrationId", "site", "startOffsetSecondsFromOpeningReference",
750
+ "endOffsetSecondsFromOpeningReference", "localExposureDurationSeconds", "expectedIncidentPhotonCount", "expectedGeneratedElectronCount", "temporalSamples"]);
751
+ const SITE_ONLY = new Set(["site"]);
752
+ const SITE_APPLICABILITY = new Set(["siteApplicability"]);
753
+ const COMPLETENESS = new Set(["completenessProfile"]);
754
+ const CAPACITY = new Set(["capacityProfile"]);
755
+ const COMPLETENESS_SITE_FIELDS = new Set(["site", "startOffsetSecondsFromOpeningReference", "endOffsetSecondsFromOpeningReference"]);
756
+ /** Same own keys in the same order; values strictly equal except `skip` keys (compared by the caller). */
757
+ function sameRecordExcept(a, b, skip, memo) {
758
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null || Array.isArray(a) || Array.isArray(b) ||
759
+ !isPlainRecord(a) || !isPlainRecord(b))
760
+ return false;
761
+ const ar = a, br = b, ak = Object.keys(ar), bk = Object.keys(br);
762
+ if (ak.length !== bk.length || Object.getOwnPropertySymbols(ar).length !== 0 || Object.getOwnPropertySymbols(br).length !== 0)
763
+ return false;
764
+ for (let i = 0; i < ak.length; i++)
765
+ if (ak[i] !== bk[i])
766
+ return false;
767
+ for (const key of ak)
768
+ if (!skip.has(key) && !sameData(ar[key], br[key], memo))
769
+ return false;
770
+ return true;
771
+ }
772
+ /** A plain {x, y} record equal (Object.is) to the given coordinates. */
773
+ function siteSlot(value, x, y) {
774
+ if (typeof value !== "object" || value === null || Array.isArray(value) || !isPlainRecord(value))
775
+ return false;
776
+ const keys = Object.keys(value), r = value;
777
+ return keys.length === 2 && keys[0] === "x" && keys[1] === "y" && Object.is(r.x, x) && Object.is(r.y, y) && Object.getOwnPropertySymbols(value).length === 0;
778
+ }
779
+ /** A record whose optional `site` key (the only one skipped) holds each side's own coordinates. */
780
+ function sameWithSiteSlot(a, b, ax, ay, bx, by, memo) {
781
+ if (!sameRecordExcept(a, b, SITE_ONLY, memo))
782
+ return false;
783
+ const ar = a, br = b;
784
+ return !("site" in ar) || (siteSlot(ar.site, ax, ay) && siteSlot(br.site, bx, by));
785
+ }
786
+ /** Sensor-site equality except the index-bound site slots and the per-site photo numbers. */
787
+ function sensorMatches(site, photo, x, y, t, memo) {
788
+ const a = site, b = t.site;
789
+ if (typeof a !== "object" || a === null || !isPlainRecord(a))
790
+ return false;
791
+ const ak = Object.keys(a), bk = Object.keys(b);
792
+ if (ak.length !== bk.length || Object.getOwnPropertySymbols(a).length !== 0)
793
+ return false;
794
+ for (let i = 0; i < ak.length; i++)
795
+ if (ak[i] !== bk[i])
796
+ return false;
797
+ for (const key of ak) {
798
+ if (key === "environment")
799
+ continue;
800
+ if (key === "darkCurrentProfile") {
801
+ const ad = a.darkCurrentProfile, bd = b.darkCurrentProfile;
802
+ if (!sameRecordExcept(ad, bd, SITE_APPLICABILITY, memo) ||
803
+ !sameWithSiteSlot(ad.siteApplicability, bd.siteApplicability, x, y, t.x, t.y, memo))
804
+ return false;
805
+ }
806
+ else if (key === "charge") {
807
+ const ac = a.charge, bc = b.charge;
808
+ if (!sameRecordExcept(ac, bc, COMPLETENESS, memo) || "additionalChargeComponents" in ac)
809
+ return false;
810
+ const ap = ac.completenessProfile, bp = bc.completenessProfile;
811
+ if (!sameRecordExcept(ap, bp, COMPLETENESS_SITE_FIELDS, memo) || !siteSlot(ap.site, x, y) || !siteSlot(bp.site, t.x, t.y) ||
812
+ ap.startOffsetSecondsFromOpeningReference !== photo.startOffsetSecondsFromOpeningReference ||
813
+ ap.endOffsetSecondsFromOpeningReference !== photo.endOffsetSecondsFromOpeningReference)
814
+ return false;
815
+ }
816
+ else if (key === "readout") {
817
+ const ar = a.readout, br = b.readout;
818
+ if (!sameRecordExcept(ar, br, CAPACITY, memo))
819
+ return false;
820
+ const ac = ar.capacityProfile, bc = br.capacityProfile;
821
+ if (!sameRecordExcept(ac, bc, SITE_APPLICABILITY, memo) ||
822
+ !sameWithSiteSlot(ac.siteApplicability, bc.siteApplicability, x, y, t.x, t.y, memo))
823
+ return false;
824
+ }
825
+ else if (!sameData(a[key], b[key], memo))
826
+ return false;
827
+ }
828
+ return sameRecordExcept(photo, t.photo, PHOTO_SITE_FIELDS, memo) && siteSlot(photo.site, x, y) &&
829
+ photo.temporalSamples.length === t.photo.temporalSamples.length;
830
+ }
831
+ /** The sensor stage of calculateNativeRawSite, in the same operation order. Returns undefined when one of its checks would throw. */
832
+ function leanSensorSite(t, h, index, seed) {
833
+ const ratio = h.total / t.capacity, headroom = t.capacity - h.total;
834
+ if (!Number.isFinite(ratio) || !Number.isFinite(headroom))
835
+ return undefined;
836
+ const pattern = t.pattern === undefined ? null : evaluateParsedFixedPatternSite(t.pattern, { x: h.x, y: h.y });
837
+ const photoE = h.photo.expectedGeneratedElectronCount;
838
+ const photoMean = pattern === null ? photoE : photoE * pattern.photoResponseGainFactor;
839
+ const darkMean = pattern === null ? h.darkE : h.darkE * pattern.darkCurrentFactor;
840
+ if (!Number.isFinite(photoMean) || photoMean < 0 || !Number.isFinite(darkMean) || darkMean < 0)
841
+ return undefined;
842
+ const random = createDeterministicUniformStream(deriveNativeSiteStreamSeedUint32(seed, index, NATIVE_SITE_CHARGE_STREAM_ID));
843
+ const photoRealized = samplePoisson(photoMean, random), darkRealized = samplePoisson(darkMean, random);
844
+ const realized = photoRealized + darkRealized + 0;
845
+ if (!Number.isFinite(realized) || realized < 0)
846
+ return undefined;
847
+ const readRandom = createDeterministicUniformStream(deriveNativeSiteStreamSeedUint32(seed, index, NATIVE_SITE_READ_NOISE_STREAM_ID));
848
+ const regime = t.readout.regime, capacity = t.capacity;
849
+ const afterPhysical = Math.min(realized, capacity), physicalSaturation = afterPhysical < realized;
850
+ const sampled = regime.readNoiseComponents.map(component => component.rmsElectrons.value === 0 ? 0 :
851
+ sampleDeterministicStandardNormal(readRandom) * component.rmsElectrons.value);
852
+ let totalReadNoise = 0;
853
+ for (const value of sampled)
854
+ totalReadNoise = totalReadNoise + value;
855
+ const afterReadNoise = afterPhysical + totalReadNoise + (pattern === null ? 0 : pattern.readoutOffsetElectrons);
856
+ const threshold = regime.preAdcSaturationElectronEquivalent.value;
857
+ const afterPreAdc = Math.min(afterReadNoise, threshold), preAdcSaturation = afterReadNoise > threshold;
858
+ const quantized = adcTransfer(regime, t.readout.adcMaximumCode, afterPreAdc).quantized;
859
+ const digitalSaturationCode = regime.adc.digitalSaturationCode;
860
+ return { rawCode: Math.max(0, Math.min(quantized, digitalSaturationCode)), blackLevelCode: regime.adc.blackLevelCode, digitalSaturationCode,
861
+ flags: Number(physicalSaturation) | Number(preAdcSaturation) << 1 | Number(quantized >= digitalSaturationCode) << 2,
862
+ whiteCode: t.whiteCode, photoRealized, darkRealized };
863
+ }
864
+ /** The Kahan (compensated) total that composeSensorAccumulatedCharge computes, for photo and dark charge only. */
865
+ function chargeTotal(photoE, darkE) {
866
+ let sum = 0, correction = 0;
867
+ for (const value of [photoE, darkE]) {
868
+ const adjusted = value - correction, next = sum + adjusted;
869
+ correction = (next - sum) - adjusted;
870
+ sum = next;
871
+ }
872
+ return sum;
873
+ }
874
+ export function createNativeEnvironmentSensorLean(frame, producerFrame, nativeWindow) {
875
+ const enabled = !leanDisabled && nativeWindow !== undefined && frame.identityBinding && frame.repeatWidth > 0 && frame.repeatHeight > 0;
876
+ const templates = [], handles = new WeakMap(), memo = new WeakMap();
877
+ let pending = new Map();
878
+ const coordinates = (index) => {
879
+ const x = index % frame.nativeWidth, y = Math.floor(index / frame.nativeWidth);
880
+ return { x, y, phase: (y % frame.repeatHeight) * frame.repeatWidth + (x % frame.repeatWidth) };
881
+ };
882
+ const find = (site, photo, x, y, phase) => {
883
+ for (const t of templates)
884
+ if (t.phase === phase && sensorMatches(site, photo, x, y, t, memo))
885
+ return t;
886
+ return undefined;
887
+ };
888
+ return {
889
+ beginTile() { pending = new Map(); },
890
+ claim(site, photo, index) {
891
+ if (!enabled)
892
+ return undefined;
893
+ try {
894
+ const { x, y, phase } = coordinates(index), t = find(site, photo, x, y, phase);
895
+ if (!t || !t.verified)
896
+ return undefined;
897
+ // Parse-phase predicates of the full path: EQE domain, dark and total charge, and the committed local window.
898
+ const photoE = photo.expectedGeneratedElectronCount, duration = photo.localExposureDurationSeconds;
899
+ if (!(photoE <= photo.expectedIncidentPhotonCount))
900
+ return undefined;
901
+ const darkE = t.darkRate * duration;
902
+ if (!Number.isFinite(darkE) || darkE < 0)
903
+ return undefined;
904
+ const total = chargeTotal(photoE, darkE);
905
+ if (!Number.isFinite(total) || total < 0)
906
+ return undefined;
907
+ const window = nativeWindow({ x: x + .5, y: y + .5 });
908
+ if (photo.startOffsetSecondsFromOpeningReference !== window.startOffsetSecondsFromOpeningReference ||
909
+ photo.endOffsetSecondsFromOpeningReference !== window.endOffsetSecondsFromOpeningReference ||
910
+ duration !== window.localExposureDurationSeconds)
911
+ return undefined;
912
+ const marker = Object.freeze({});
913
+ handles.set(marker, { template: t, site, photo, x, y, darkE, total });
914
+ return marker;
915
+ }
916
+ catch {
917
+ return undefined;
918
+ }
919
+ },
920
+ remember(index, site, photo) { if (enabled)
921
+ pending.set(index, { site, photo }); },
922
+ hook: {
923
+ claim(site) {
924
+ return typeof site === "object" && site !== null && handles.has(site) ? site : undefined;
925
+ },
926
+ compute(handle, index, seed, timing) {
927
+ const h = handles.get(handle), out = leanSensorSite(h.template, h, index, seed);
928
+ if (out)
929
+ nativeEnvironmentLeanStatistics.sensorSites++;
930
+ if (out)
931
+ return { rawCode: out.rawCode, blackLevelCode: out.blackLevelCode, digitalSaturationCode: out.digitalSaturationCode, flags: out.flags, whiteCode: out.whiteCode };
932
+ // A compute-phase check failed: the full path computes (and throws) exactly as it would have.
933
+ const parsed = parseNativeRawProducerSite(composeNativeEnvironmentSensorSite(h.site, h.photo), index, producerFrame, timing);
934
+ const r = calculateNativeRawSite(parsed, seed, index).readout.value;
935
+ return { rawCode: r.rawCode, blackLevelCode: r.blackLevelCode, digitalSaturationCode: r.digitalSaturationCode,
936
+ flags: Number(r.physicalScalarSaturationApplied) | Number(r.preAdcSaturationApplied) << 1 | Number(r.digitalSaturationApplied) << 2,
937
+ whiteCode: calculateSiteEffectiveSaturationCode(r, parsed.readoutProfile, parsed.regimeId) };
938
+ },
939
+ observe(index, parsed, result, whiteCode, seed) {
940
+ const entry = pending.get(index);
941
+ pending.delete(index);
942
+ if (!entry || templates.length >= MAXIMUM_TEMPLATES)
943
+ return;
944
+ try {
945
+ const { x, y, phase } = coordinates(index), { site, photo } = entry;
946
+ if (find(site, photo, x, y, phase) !== undefined)
947
+ return;
948
+ const readout = resolveSensorReadoutRegime({ profile: parsed.readoutProfile, regimeId: parsed.regimeId });
949
+ const t = { site, photo, phase, x, y, verified: false, darkRate: parsed.charge.darkCharge.darkCurrentElectronsPerSecond,
950
+ capacity: result.capacity.value.physicalChargeCapacityElectrons, readout, pattern: parsed.fixedPatternNoise, whiteCode };
951
+ templates.push(t);
952
+ // Self-check: the template matches itself and the lean arithmetic reproduces its full computation bit for bit.
953
+ if (!sensorMatches(site, photo, x, y, t, new WeakMap()))
954
+ return;
955
+ const darkE = t.darkRate * photo.localExposureDurationSeconds, total = chargeTotal(photo.expectedGeneratedElectronCount, darkE);
956
+ const r = result.readout.value, realization = result.realization.value;
957
+ const out = leanSensorSite(t, { photo, darkE, total, x, y }, index, seed);
958
+ if (!out || !Object.is(darkE, parsed.charge.darkCharge.expectedDarkElectronCount) ||
959
+ !Object.is(total, result.accumulatedCharge.value.totalExpectedStoredElectronCount) ||
960
+ !Object.is(out.photoRealized, realization.photoRealizedElectronCount) || !Object.is(out.darkRealized, realization.darkRealizedElectronCount) ||
961
+ realization.additionalComponents.length !== 0 || out.rawCode !== r.rawCode || out.blackLevelCode !== r.blackLevelCode ||
962
+ out.digitalSaturationCode !== r.digitalSaturationCode || out.flags !== (Number(r.physicalScalarSaturationApplied) |
963
+ Number(r.preAdcSaturationApplied) << 1 | Number(r.digitalSaturationApplied) << 2))
964
+ return;
965
+ t.verified = true;
966
+ }
967
+ catch {
968
+ // An unverified template leaves its sites on the full path.
969
+ }
970
+ }
971
+ }
972
+ };
973
+ }
974
+ //# sourceMappingURL=native-environment-lean.js.map