@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 @@
1
+ {"version":3,"file":"diffraction-psf-profile.js","sourceRoot":"","sources":["../../src/optics/diffraction-psf-profile.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Builds a `LensSampledPsfProfile` for an ideal, aberration-free, in-focus lens with a uniformly lit\n * circular pupil: the Airy pattern of scalar Fraunhofer diffraction, one unit-sum kernel per declared\n * wavelength on ONE shared sample grid (2.1.0).\n *\n * **Model.** The pupil diameter is D = f/N (entrance pupil = exit pupil, unity pupil magnification) and\n * the pupil-to-image distance z is the thin-lens image distance for the focus (f at infinity), so the\n * image-side (working) f-number is N_w = z/D. The incoherent optical transfer function (OTF) of a\n * uniform circular pupil is the normalized autocorrelation of the pupil,\n * H(ρ) = (2/π)·(acos ρ − ρ·√(1 − ρ²)), ρ = |f|/f_c ≤ 1, f_c = 1/(λ·N_w),\n * and the intensity PSF is its inverse Fourier transform (the Airy pattern, first zero at 1.21967·λ·N_w)\n * (MIT OpenCourseWare 2.71 Optics, Spring 2009, lectures 21–22, free: the intensity PSF as the transform of\n * the pupil autocorrelation and the circular-pupil MTF; also see: Goodman, Introduction to Fourier Optics,\n * 4th ed., 2017, §6.3).\n *\n * **Cell integration (exact, no Bessel functions).** Kernel sample (i, j) is the PSF energy inside the\n * square cell of side p centred on (i·p, j·p). The cell integral is the PSF convolved with the cell's\n * indicator, evaluated at the cell centre, so in the frequency domain\n * K(i, j) = p² ∫∫ H(|f|/f_c)·sinc(p·f_x)·sinc(p·f_y)·cos(2π·p·i·f_x)·cos(2π·p·j·f_y) d²f,\n * with sinc(x) = sin(πx)/(πx) (the sine terms vanish because H is even). It is evaluated in polar\n * coordinates: a trapezoid rule in angle (exponentially convergent for this smooth periodic integrand) and\n * Gauss–Legendre in t with ρ = 1 − t², which removes the (1 − ρ)^{3/2} edge behaviour of H. The node counts\n * follow from the integrand's bandwidth with a fixed margin; the tests check convergence by doubling them and\n * check the values against an independent real-space integration of `calculateIdealPolygonDiffractionPsf` in\n * its many-blade (circular) limit. The sum of all cells is exactly 1 (Parseval), so the energy captured by\n * the finite kernel is Σ K over its window and the truncated energy is 1 − Σ K.\n *\n * **Truncation and normalization.** The kernel is the (2R+1)² window of cells. The Airy tails fall only as\n * r⁻³, so a finite window always misses some energy: it is reported per wavelength, and the window is then\n * renormalized to unit sum because the sampled-profile contract requires unit-energy kernels. The missing\n * tail energy is thereby put back inside the window (an approximation that slightly raises low-frequency\n * contrast compared with the untruncated pattern).\n *\n * **Approximations (labelled):** scalar (no polarization), aberration-free, uniform pupil amplitude, exactly in\n * focus (no defocus), thin lens with unity pupil magnification, the on-axis PSF used across the declared field\n * (isoplanatic), PSF energy binned into the sample cells, finite window renormalized. Not a measured lens.\n * @see docs/PSF_FOUNDATION.md, \"Diffraction-limited sampled profile (2.1)\".\n */\n\nimport { approximationResult, type CalculationResult } from \"../core/calculation-result.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireAllowlistedRecord } from \"../core/record-validation.js\";\nimport type { EvidenceProvenance } from \"../core/evidence-provenance.js\";\nimport type { FocusPlane } from \"./focus-state.js\";\nimport { calculateThinLensImageDistance } from \"./thin-lens.js\";\nimport { parseLensSampledPsfProfile, type LensSampledPsfProfile } from \"./lens-psf-profile.js\";\n\nexport const DIFFRACTION_LIMITED_PSF_PROFILE_MODEL = Object.freeze({\n modelId: \"photivra-diffraction-limited-circular-pupil-psf\" as const, modelVersion: \"1.0.0\" as const });\n/** Input limits: at most 64 wavelengths, kernel radius 0–32 samples (the irradiance-convolution limit). */\nexport const DIFFRACTION_LIMITED_PSF_PROFILE_LIMITS = Object.freeze({ maximumWavelengths: 64, maximumKernelRadiusSamples: 32 });\n/** Radius of the first dark ring of the Airy pattern in units of λ·N_w: j₁,₁/π, j₁,₁ = 3.8317059702 (first zero of J₁). */\nconst AIRY_FIRST_ZERO_PER_LAMBDA_N = 3.8317059702075125 / Math.PI;\n\nexport interface CreateDiffractionLimitedPsfProfileInput {\n /** Only `circular` in 2.1.0 (polygon pupils: `calculateIdealPolygonDiffractionPsf` gives point densities). */\n aperture: \"circular\";\n focalLengthMm: number;\n apertureFNumber: number;\n focus: FocusPlane;\n /** Strictly increasing wavelengths, nm, in the medium of propagation (no air/vacuum conversion is applied). 1–64. */\n wavelengthsNm: readonly number[];\n /** Square sample pitch of every kernel, µm. */\n samplePitchMicrometers: number;\n /** Kernel half-width in samples; each kernel is (2R + 1)². 0–32. */\n kernelRadiusSamples: number;\n /** Half-extent of the image field over which the on-axis PSF is declared (profile field axes ±x, ±y), mm. */\n fieldHalfExtentMm: { x: number; y: number };\n profileId: string;\n}\n\nexport interface DiffractionLimitedPsfWavelength {\n wavelengthNm: number;\n /** f_c = 1/(λ·N_w), cycles per µm. */\n cutoffFrequencyCyclesPerMicrometer: number;\n /** 1.21967·λ·N_w, µm. */\n firstZeroRadiusMicrometers: number;\n /** Σ of the cell energies inside the window before renormalization (of a total of 1). */\n capturedEnergyFraction: number;\n /** 1 − capturedEnergyFraction: the Airy tail energy outside the window, put back by renormalization. */\n truncatedEnergyFraction: number;\n /** Fraction of the renormalized kernel in the centre sample. */\n centreSampleFraction: number;\n}\n\nexport interface DiffractionLimitedPsfProfile {\n profile: LensSampledPsfProfile;\n model: typeof DIFFRACTION_LIMITED_PSF_PROFILE_MODEL;\n pupilDiameterMm: number;\n pupilToImageDistanceMm: number;\n workingFNumber: number;\n kernelRadiusSamples: number;\n samplePitchMicrometers: number;\n wavelengths: readonly DiffractionLimitedPsfWavelength[];\n /** Largest truncated energy over the wavelengths. */\n maximumTruncatedEnergyFraction: number;\n quadrature: { method: \"polar-frequency-domain-trapezoid-gauss-legendre\"; maximumRadialNodes: number; maximumAngularNodes: number };\n}\n\nconst EVIDENCE: readonly EvidenceProvenance[] = Object.freeze([Object.freeze({ sourceOrigin: \"photivra\" as const,\n sourceReference: \"photivra:diffraction-limited-psf-profile\", reuseStatus: \"photivra-owned\" as const })]);\nconst LIMITATIONS = Object.freeze([\n \"Scalar Fraunhofer diffraction of an ideal, uniformly lit circular pupil (Airy pattern); no aberration, apodization, polarization or stray light.\",\n \"Exactly in focus: no defocus or depth of field. Thin lens with unity pupil magnification; the pupil-to-image distance is the thin-lens image distance.\",\n \"The on-axis PSF is declared unchanged across the field (isoplanatic); no field-dependent aberration or pupil clipping.\",\n \"PSF energy is binned into square sample cells; the finite window misses the Airy tail energy listed per wavelength and is renormalized to unit sum.\",\n \"Wavelengths are used as given, in the declared basis, without air/vacuum conversion.\"\n]);\n\nfunction positive(value: unknown, name: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) throw new InvalidConfigurationError(name + \" must be a positive finite number.\");\n return value;\n}\n\n/** Gauss–Legendre nodes and weights on [0, 1] (Newton iteration on Pₙ; DLMF §3.5(v)). Cached per n. */\nconst GAUSS_LEGENDRE = new Map<number, { nodes: Float64Array; weights: Float64Array }>();\nfunction gaussLegendre(n: number): { nodes: Float64Array; weights: Float64Array } {\n const cached = GAUSS_LEGENDRE.get(n);\n if (cached) return cached;\n const nodes = new Float64Array(n), weights = new Float64Array(n);\n for (let k = 0; k < Math.ceil(n / 2); k++) {\n let x = Math.cos(Math.PI * (k + 0.75) / (n + 0.5));\n for (let iteration = 0; iteration < 100; iteration++) {\n let p0 = 1, p1 = x;\n for (let m = 2; m <= n; m++) { const p2 = ((2 * m - 1) * x * p1 - (m - 1) * p0) / m; p0 = p1; p1 = p2; }\n const step = p1 / (n * (x * p1 - p0) / (x * x - 1));\n x -= step;\n if (Math.abs(step) < 1e-16) break;\n }\n let p0 = 1, p1 = x;\n for (let m = 2; m <= n; m++) { const p2 = ((2 * m - 1) * x * p1 - (m - 1) * p0) / m; p0 = p1; p1 = p2; }\n const derivative = n * (x * p1 - p0) / (x * x - 1);\n const w = 1 / ((1 - x * x) * derivative * derivative);\n // Map [-1, 1] to [0, 1]: t = (1 ± x)/2, weight w (2/(1-x²)P'² halved).\n nodes[k] = (1 - x) / 2; weights[k] = w;\n nodes[n - 1 - k] = (1 + x) / 2; weights[n - 1 - k] = w;\n }\n const result = { nodes, weights };\n if (GAUSS_LEGENDRE.size < 64) GAUSS_LEGENDRE.set(n, result);\n return result;\n}\nfunction sinc(x: number): number {\n if (x === 0) return 1;\n const a = Math.PI * x;\n return Math.sin(a) / a;\n}\n\n/**\n * Cell energies K(i, j), 0 ≤ i, j ≤ R, of the Airy pattern for β = p·f_c (cell side in units of the cut-off\n * period). `scale` multiplies the node counts (1 in production; the tests use 2 to check convergence).\n */\nexport function calculateAiryCellEnergies(beta: number, radius: number, scale = 1): { cells: Float64Array; radialNodes: number; angularNodes: number } {\n // Bandwidth of the angular and radial integrands: c = π·β·(2R + 1)·√2 (the sinc factors and the highest cosine).\n const c = Math.PI * beta * (2 * radius + 1) * Math.SQRT2, margin = 10 * Math.cbrt(c) + 24;\n const quarter = Math.ceil(scale * (c + margin) / 4), radialNodes = Math.ceil(scale * (c + margin));\n const { nodes, weights } = gaussLegendre(radialNodes), size = radius + 1, cells = new Float64Array(size * size);\n const ca = new Float64Array(size), cb = new Float64Array(size), angularStep = (Math.PI / 2) / quarter;\n for (let r = 0; r < radialNodes; r++) {\n const t = nodes[r]!, rho = 1 - t * t;\n // H(1 − t²) without cancellation: acos(1 − t²) = 2·asin(t/√2), ρ·√(1 − ρ²) = ρ·t·√(2 − t²).\n const otf = (2 / Math.PI) * (2 * Math.asin(t / Math.SQRT2) - rho * t * Math.sqrt(2 - t * t));\n // ∫₀¹ g(ρ) dρ = ∫₀¹ g(1 − t²)·2t dt; the 4 is the four symmetric quadrants of the angular trapezoid.\n const radialWeight = weights[r]! * 2 * t * rho * otf * 4 * angularStep;\n for (let k = 0; k <= quarter; k++) {\n const theta = k * angularStep, x = beta * rho * Math.cos(theta), y = beta * rho * Math.sin(theta);\n const w = radialWeight * (k === 0 || k === quarter ? 0.5 : 1) * sinc(x) * sinc(y);\n // cos(2π·i·x) and cos(2π·j·y) by the Chebyshev recurrence.\n const cx = Math.cos(2 * Math.PI * x), cy = Math.cos(2 * Math.PI * y);\n ca[0] = 1; cb[0] = 1;\n if (size > 1) { ca[1] = cx; cb[1] = cy; }\n for (let i = 2; i < size; i++) { ca[i] = 2 * cx * ca[i - 1]! - ca[i - 2]!; cb[i] = 2 * cy * cb[i - 1]! - cb[i - 2]!; }\n for (let j = 0; j < size; j++) {\n const wj = w * cb[j]!;\n for (let i = 0; i < size; i++) { const o = j * size + i; cells[o] = cells[o]! + wj * ca[i]!; }\n }\n }\n }\n const area = beta * beta;\n for (let i = 0; i < cells.length; i++) cells[i] = cells[i]! * area;\n return { cells, radialNodes, angularNodes: 4 * quarter };\n}\n\n/**\n * Creates a sampled lens PSF profile for an ideal diffraction-limited lens with a circular pupil: one\n * unit-sum Airy kernel per wavelength on one shared (2R+1)² grid, with the truncated energy reported per\n * wavelength. The profile declares the given focal length, f-number and focus exactly, and the field axes\n * ±`fieldHalfExtentMm` with the same kernel at every field node.\n * @param input - See `CreateDiffractionLimitedPsfProfileInput`.\n * @returns The profile and its diffraction record. An approximation; not a measured lens.\n * @see docs/PSF_FOUNDATION.md, \"Diffraction-limited sampled profile (2.1)\".\n */\nexport function createDiffractionLimitedPsfProfile(input: CreateDiffractionLimitedPsfProfileInput): CalculationResult<DiffractionLimitedPsfProfile> {\n const r = requireAllowlistedRecord(input, [\"aperture\", \"focalLengthMm\", \"apertureFNumber\", \"focus\", \"wavelengthsNm\", \"samplePitchMicrometers\",\n \"kernelRadiusSamples\", \"fieldHalfExtentMm\", \"profileId\"], \"Invalid diffraction-limited PSF profile input.\");\n if (r.aperture !== \"circular\") throw new InvalidConfigurationError(\"aperture must be \\\"circular\\\".\");\n const focalLengthMm = positive(r.focalLengthMm, \"focalLengthMm\"), fNumber = positive(r.apertureFNumber, \"apertureFNumber\");\n const pitch = positive(r.samplePitchMicrometers, \"samplePitchMicrometers\");\n const L = DIFFRACTION_LIMITED_PSF_PROFILE_LIMITS;\n const radius = r.kernelRadiusSamples;\n if (typeof radius !== \"number\" || !Number.isSafeInteger(radius) || radius < 0 || radius > L.maximumKernelRadiusSamples) {\n throw new InvalidConfigurationError(\"kernelRadiusSamples must be an integer from 0 to \" + L.maximumKernelRadiusSamples + \".\");\n }\n const focus = requireAllowlistedRecord(r.focus, [\"kind\", \"distanceM\"], \"Invalid focus.\");\n let focusDiopters: number, distanceMm: number;\n if (focus.kind === \"infinity\") {\n if (focus.distanceM !== undefined) throw new InvalidConfigurationError(\"An infinity focus has no distanceM.\");\n focusDiopters = 0; distanceMm = focalLengthMm;\n } else if (focus.kind === \"finite\") {\n const distanceM = positive(focus.distanceM, \"focus.distanceM\");\n focusDiopters = 1 / distanceM;\n distanceMm = calculateThinLensImageDistance({ focalLengthMm, objectDistanceM: distanceM }).value.imageDistanceMm;\n } else throw new InvalidConfigurationError(\"focus.kind must be finite or infinity.\");\n const field = requireAllowlistedRecord(r.fieldHalfExtentMm, [\"x\", \"y\"], \"Invalid fieldHalfExtentMm.\");\n const fieldX = positive(field.x, \"fieldHalfExtentMm.x\"), fieldY = positive(field.y, \"fieldHalfExtentMm.y\");\n const list = r.wavelengthsNm;\n if (!Array.isArray(list) || list.length < 1 || list.length > L.maximumWavelengths) throw new InvalidConfigurationError(\"wavelengthsNm must list 1 to 64 wavelengths.\");\n const wavelengths = (list as unknown[]).map((value, index) => positive(value, \"wavelengthsNm[\" + index + \"]\"));\n for (let i = 1; i < wavelengths.length; i++) if (!(wavelengths[i]! > wavelengths[i - 1]!)) throw new InvalidConfigurationError(\"wavelengthsNm must be strictly increasing.\");\n if (typeof r.profileId !== \"string\" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(r.profileId)) throw new InvalidConfigurationError(\"profileId must be a public opaque ID.\");\n\n const pupilDiameterMm = focalLengthMm / fNumber, workingFNumber = distanceMm / pupilDiameterMm, size = 2 * radius + 1;\n let maximumRadialNodes = 0, maximumAngularNodes = 0, maximumTruncated = 0;\n const records: DiffractionLimitedPsfWavelength[] = [], kernels: number[][] = [];\n for (const nm of wavelengths) {\n const lambdaN = nm / 1000 * workingFNumber, cutoff = 1 / lambdaN;\n const airy = calculateAiryCellEnergies(pitch * cutoff, radius);\n maximumRadialNodes = Math.max(maximumRadialNodes, airy.radialNodes); maximumAngularNodes = Math.max(maximumAngularNodes, airy.angularNodes);\n const values: number[] = new Array(size * size);\n let captured = 0;\n for (let ky = 0; ky < size; ky++) for (let kx = 0; kx < size; kx++) {\n const value = airy.cells[Math.abs(ky - radius) * (radius + 1) + Math.abs(kx - radius)]!;\n // Every cell energy of a non-negative PSF is positive; a negative value would be a quadrature failure.\n if (!(value > -1e-13)) throw new InvalidConfigurationError(\"Diffraction cell integration failed to converge.\");\n values[ky * size + kx] = Math.max(0, value);\n captured += values[ky * size + kx]!;\n }\n if (!(captured > 0 && captured <= 1 + 1e-9)) throw new InvalidConfigurationError(\"Diffraction cell integration failed to converge.\");\n const truncated = Math.max(0, 1 - captured);\n maximumTruncated = Math.max(maximumTruncated, truncated);\n const kernel = values.map((v) => v / captured);\n kernels.push(kernel);\n records.push({ wavelengthNm: nm, cutoffFrequencyCyclesPerMicrometer: cutoff, firstZeroRadiusMicrometers: AIRY_FIRST_ZERO_PER_LAMBDA_N * lambdaN,\n capturedEnergyFraction: captured, truncatedEnergyFraction: truncated, centreSampleFraction: kernel[radius * size + radius]! });\n }\n const uncertainty = { kind: \"not-quantified\" as const, limitation: \"Ideal diffraction-limited model; no measured lens or quadrature error bound.\" };\n const nodes = [-fieldX, fieldX].flatMap((fx) => [-fieldY, fieldY].flatMap((fy) => wavelengths.map((nm, index) => ({\n nodeId: \"airy-\" + (fx < 0 ? \"xm\" : \"xp\") + \"-\" + (fy < 0 ? \"ym\" : \"yp\") + \"-\" + index,\n coordinate: { focalLengthMm, focusDiopters, apertureFNumber: fNumber, fieldXmm: fx, fieldYmm: fy, wavelengthNm: nm, signedDefocusImagePlaneMicrometers: 0 },\n kernel: { widthSamples: size, heightSamples: size, samplePitchMicrometersX: pitch, samplePitchMicrometersY: pitch, centerSampleX: radius, centerSampleY: radius,\n normalizedIntensity: kernels[index]! },\n bestFocusImagePlaneOffsetMicrometers: 0, relativePupilThroughputFactor: 1, evidence: EVIDENCE, uncertainty }))));\n const profile = parseLensSampledPsfProfile({ schemaVersion: \"0.1.0\", profileId: r.profileId, profileVersion: DIFFRACTION_LIMITED_PSF_PROFILE_MODEL.modelVersion,\n scientificStatus: \"approximation\", opticalDomain: \"lens-primary-optical-path-only\", coordinateSystem: \"image-plane-metric\", fieldAxes: \"+X right, +Y up\",\n kernelEnergyNormalization: \"unit-energy-shape\", interpolation: \"bounded-regular-grid-multilinear\", throughputOwnership: \"separate-relative-pupil-throughput-factor\",\n responseIncludes: { diffraction: true, aberration: false, defocus: false, pupilClippingShape: false },\n sensorOpticalStackIncluded: false, sensorSamplingIncluded: false, reconstructionIncluded: false, strayLightIncluded: false,\n axes: { focalLengthMm: [focalLengthMm], focusDiopters: [focusDiopters], apertureFNumber: [fNumber], fieldXmm: [-fieldX, fieldX], fieldYmm: [-fieldY, fieldY],\n wavelengthNm: wavelengths, signedDefocusImagePlaneMicrometers: [0] },\n nodes, evidence: EVIDENCE, limitations: [...LIMITATIONS] });\n return approximationResult({ profile, model: DIFFRACTION_LIMITED_PSF_PROFILE_MODEL, pupilDiameterMm, pupilToImageDistanceMm: distanceMm, workingFNumber,\n kernelRadiusSamples: radius, samplePitchMicrometers: pitch, wavelengths: records, maximumTruncatedEnergyFraction: maximumTruncated,\n quadrature: { method: \"polar-frequency-domain-trapezoid-gauss-legendre\" as const, maximumRadialNodes, maximumAngularNodes } },\n DIFFRACTION_LIMITED_PSF_PROFILE_MODEL.modelId, DIFFRACTION_LIMITED_PSF_PROFILE_MODEL.modelVersion, [...LIMITATIONS]);\n}\n"]}
@@ -1,10 +1,11 @@
1
1
  /**
2
- * Module boundary and integration notes.
3
- * Calculates the first-zero Airy-disk diameter for an ideal circular aperture. This uses the
4
- * established diffraction relation d = 2.44 * lambda * N. It is an independent implementation of the
5
- * mathematical relation and does not model lens aberrations or non-circular pupil geometry.
6
- * @see docs/PHYSICS_FOUNDATION.md for equations, coordinate/unit conventions, blockers and support
7
- * limits.
2
+ * Diameter of the Airy disk (the central diffraction spot) out to its first dark ring, for an ideal
3
+ * circular aperture. It uses the standard relation d = 2.44 * lambda * N.
4
+ *
5
+ * This is an independent implementation of that relation. It does not model lens aberrations or
6
+ * non-circular pupils.
7
+ * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers
8
+ * and support limits.
8
9
  */
9
10
  import { type CalculationResult } from "../core/calculation-result.js";
10
11
  export interface CalculateAiryDiskInput {
@@ -15,20 +16,20 @@ export interface CalculateAiryDiskInput {
15
16
  }
16
17
  export interface AiryDisk {
17
18
  /**
18
- * Diameter from the center of the diffraction pattern to the first dark-ring
19
- * diameter, in micrometres: 2.44 * wavelength * f-number.
19
+ * Diameter of the first dark ring of the diffraction pattern, in
20
+ * micrometres: 2.44 * wavelength * f-number.
20
21
  */
21
22
  firstZeroDiameterMicrometers: number;
22
23
  }
23
24
  /**
24
- * Calculates the first-zero Airy-disk diameter for an ideal circular aperture.
25
+ * Calculates the Airy-disk diameter to the first dark ring for an ideal
26
+ * circular aperture.
25
27
  *
26
- * This uses the established diffraction relation d = 2.44 * lambda * N.
27
- * It is an independent implementation of the mathematical relation and does
28
- * not model lens aberrations or non-circular pupil geometry.
28
+ * It uses the standard diffraction relation d = 2.44 * lambda * N. This is an
29
+ * independent implementation of that relation. It does not model lens
30
+ * aberrations or non-circular pupils.
29
31
  *
30
32
  * @param input F-number and wavelength.
31
33
  * @returns Diffraction diameter at the image plane.
32
34
  */
33
35
  export declare function calculateAiryDisk(input: CalculateAiryDiskInput): CalculationResult<AiryDisk>;
34
- //# sourceMappingURL=diffraction.d.ts.map
@@ -1,25 +1,29 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
- * Module boundary and integration notes.
4
- * Calculates the first-zero Airy-disk diameter for an ideal circular aperture. This uses the
5
- * established diffraction relation d = 2.44 * lambda * N. It is an independent implementation of the
6
- * mathematical relation and does not model lens aberrations or non-circular pupil geometry.
7
- * @see docs/PHYSICS_FOUNDATION.md for equations, coordinate/unit conventions, blockers and support
8
- * limits.
3
+ * Diameter of the Airy disk (the central diffraction spot) out to its first dark ring, for an ideal
4
+ * circular aperture. It uses the standard relation d = 2.44 * lambda * N.
5
+ *
6
+ * This is an independent implementation of that relation. It does not model lens aberrations or
7
+ * non-circular pupils.
8
+ * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers
9
+ * and support limits.
9
10
  */
10
11
  import { calculatedResult } from "../core/calculation-result.js";
11
12
  import { requirePositiveFinite } from "../core/validation.js";
13
+ import { requireInputKeys } from "../core/record-validation.js";
12
14
  /**
13
- * Calculates the first-zero Airy-disk diameter for an ideal circular aperture.
15
+ * Calculates the Airy-disk diameter to the first dark ring for an ideal
16
+ * circular aperture.
14
17
  *
15
- * This uses the established diffraction relation d = 2.44 * lambda * N.
16
- * It is an independent implementation of the mathematical relation and does
17
- * not model lens aberrations or non-circular pupil geometry.
18
+ * It uses the standard diffraction relation d = 2.44 * lambda * N. This is an
19
+ * independent implementation of that relation. It does not model lens
20
+ * aberrations or non-circular pupils.
18
21
  *
19
22
  * @param input F-number and wavelength.
20
23
  * @returns Diffraction diameter at the image plane.
21
24
  */
22
25
  export function calculateAiryDisk(input) {
26
+ requireInputKeys(input, "calculateAiryDisk", ["aperture", "wavelengthNm"]);
23
27
  requirePositiveFinite("aperture", input.aperture);
24
28
  requirePositiveFinite("wavelengthNm", input.wavelengthNm);
25
29
  return calculatedResult({
@@ -1 +1 @@
1
- {"version":3,"file":"diffraction.js","sourceRoot":"","sources":["../../src/optics/diffraction.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;GAOG;AAEH,OAAO,EACL,gBAAgB,EAEjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAiB9D;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAA6B;IAE7B,qBAAqB,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClD,qBAAqB,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAE1D,OAAO,gBAAgB,CACrB;QACE,4BAA4B,EAC1B,IAAI,GAAG,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ;KACtD,EACD,mCAAmC,EACnC,OAAO,EACP,CAAC,yBAAyB,EAAE,0BAA0B,CAAC,CACxD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"diffraction.js","sourceRoot":"","sources":["../../src/optics/diffraction.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;;;GAQG;AAEH,OAAO,EACL,gBAAgB,EAEjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAiBhE;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAA6B;IAE7B,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,EAAE,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;IAC3E,qBAAqB,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClD,qBAAqB,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IAE1D,OAAO,gBAAgB,CACrB;QACE,4BAA4B,EAC1B,IAAI,GAAG,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ;KACtD,EACD,mCAAmC,EACnC,OAAO,EACP,CAAC,yBAAyB,EAAE,0BAA0B,CAAC,CACxD,CAAC;AACJ,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Diameter of the Airy disk (the central diffraction spot) out to its first dark ring, for an ideal\n * circular aperture. It uses the standard relation d = 2.44 * lambda * N.\n *\n * This is an independent implementation of that relation. It does not model lens aberrations or\n * non-circular pupils.\n * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers\n * and support limits.\n */\n\nimport {\n calculatedResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { requirePositiveFinite } from \"../core/validation.js\";\nimport { requireInputKeys } from \"../core/record-validation.js\";\n\nexport interface CalculateAiryDiskInput {\n /** F-number. */\n aperture: number;\n /** Wavelength in nanometres. Defaults are intentionally left to callers. */\n wavelengthNm: number;\n}\n\nexport interface AiryDisk {\n /**\n * Diameter of the first dark ring of the diffraction pattern, in\n * micrometres: 2.44 * wavelength * f-number.\n */\n firstZeroDiameterMicrometers: number;\n}\n\n/**\n * Calculates the Airy-disk diameter to the first dark ring for an ideal\n * circular aperture.\n *\n * It uses the standard diffraction relation d = 2.44 * lambda * N. This is an\n * independent implementation of that relation. It does not model lens\n * aberrations or non-circular pupils.\n *\n * @param input F-number and wavelength.\n * @returns Diffraction diameter at the image plane.\n */\nexport function calculateAiryDisk(\n input: CalculateAiryDiskInput\n): CalculationResult<AiryDisk> {\n requireInputKeys(input, \"calculateAiryDisk\", [\"aperture\", \"wavelengthNm\"]);\n requirePositiveFinite(\"aperture\", input.aperture);\n requirePositiveFinite(\"wavelengthNm\", input.wavelengthNm);\n\n return calculatedResult(\n {\n firstZeroDiameterMicrometers:\n 2.44 * (input.wavelengthNm / 1000) * input.aperture\n },\n \"ideal-circular-aperture-airy-disk\",\n \"1.0.0\",\n [\"Ideal circular aperture\", \"Monochromatic wavelength\"]\n );\n}\n"]}
@@ -1,15 +1,19 @@
1
1
  /**
2
- * Module boundary and integration notes.
3
- * Applies a caller-declared focus-breathing projection scale to the ideal Gaussian thin-lens
4
- * projection for one focus state. Photivra does not infer the scale from focal length, focus distance,
5
- * lens identity, or marketing data. A value of 1 exactly preserves the current thin-lens projection.
6
- * This is a generic approximation of focus-dependent projection/magnification, not a calibrated
7
- * real-lens model. The physical focal length remains authoritative and unchanged.
8
- * Calculates one-axis field of view for the generic declared-scale focus- breathing projection and
9
- * reports the corresponding ideal thin-lens FOV. A breathingProjectionScale of 1 reproduces the
10
- * current focus-aware thin-lens field-of-view result exactly.
11
- * @see docs/PHYSICS_FOUNDATION.md for equations, coordinate/unit conventions, blockers and support
12
- * limits.
2
+ * Focus breathing: the change in framing (magnification) as a lens focuses.
3
+ *
4
+ * The declared-scale model applies a caller-supplied projection scale to the ideal Gaussian thin-lens
5
+ * projection for one focus state. Photivra does not guess the scale from focal length, focus
6
+ * distance, lens identity or marketing data. A scale of 1 keeps the thin-lens projection exactly.
7
+ * This is a generic approximation of how projection and magnification change with focus. It is not a
8
+ * calibrated real-lens model. The physical focal length is never changed and stays authoritative.
9
+ *
10
+ * The field-of-view function gives the one-axis field of view (FOV) under this model, and the ideal
11
+ * thin-lens FOV for comparison. A breathingProjectionScale of 1 reproduces the focus-aware thin-lens
12
+ * FOV exactly.
13
+ *
14
+ * The geometric model derives breathing from ideal focusing geometry instead of a declared scale.
15
+ * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers
16
+ * and support limits.
13
17
  */
14
18
  import { type CalculationResult } from "../core/calculation-result.js";
15
19
  export interface CalculateFocusBreathingProjectionInput {
@@ -21,9 +25,9 @@ export interface CalculateFocusBreathingProjectionInput {
21
25
  * Caller-declared projection scale for this focus state, relative to the
22
26
  * ideal thin-lens image distance.
23
27
  *
24
- * 1 means no additional breathing relative to the current thin-lens model.
25
- * Values above 1 narrow framing / increase magnification; values below 1
26
- * widen framing / reduce magnification.
28
+ * 1 means no breathing beyond the thin-lens model. Values above 1 narrow the
29
+ * framing (more magnification). Values below 1 widen it (less
30
+ * magnification).
27
31
  */
28
32
  breathingProjectionScale: number;
29
33
  }
@@ -36,8 +40,8 @@ export interface FocusBreathingProjection {
36
40
  /**
37
41
  * Effective projection distance used by the generic breathing model.
38
42
  *
39
- * This is a projection/magnification parameter, not a replacement physical
40
- * focal length.
43
+ * This is a projection (magnification) parameter. It does not replace the
44
+ * physical focal length.
41
45
  */
42
46
  effectiveProjectionDistanceMm: number;
43
47
  /** Caller-declared scale relative to ideal thin-lens projection. */
@@ -66,21 +70,78 @@ export interface FocusBreathingFieldOfView {
66
70
  * Applies a caller-declared focus-breathing projection scale to the ideal
67
71
  * Gaussian thin-lens projection for one focus state.
68
72
  *
69
- * Photivra does not infer the scale from focal length, focus distance, lens
70
- * identity, or marketing data. A value of 1 exactly preserves the current
71
- * thin-lens projection.
73
+ * Photivra does not guess the scale from focal length, focus distance, lens
74
+ * identity or marketing data. A scale of 1 keeps the thin-lens projection
75
+ * exactly.
72
76
  *
73
- * This is a generic approximation of focus-dependent projection/magnification,
74
- * not a calibrated real-lens model. The physical focal length remains
75
- * authoritative and unchanged.
77
+ * This is a generic approximation of how projection and magnification change
78
+ * with focus. It is not a calibrated real-lens model. The physical focal
79
+ * length is never changed and stays authoritative.
76
80
  */
77
81
  export declare function calculateFocusBreathingProjection(input: CalculateFocusBreathingProjectionInput): CalculationResult<FocusBreathingProjection>;
78
82
  /**
79
- * Calculates one-axis field of view for the generic declared-scale focus-
80
- * breathing projection and reports the corresponding ideal thin-lens FOV.
83
+ * Calculates the one-axis field of view under the declared-scale
84
+ * focus-breathing model, and reports the ideal thin-lens field of view for
85
+ * comparison.
81
86
  *
82
- * A breathingProjectionScale of 1 reproduces the current focus-aware
83
- * thin-lens field-of-view result exactly.
87
+ * A breathingProjectionScale of 1 reproduces the focus-aware thin-lens field
88
+ * of view exactly.
84
89
  */
85
90
  export declare function calculateFocusBreathingFieldOfView(input: CalculateFocusBreathingFieldOfViewInput): CalculationResult<FocusBreathingFieldOfView>;
86
- //# sourceMappingURL=focus-breathing.d.ts.map
91
+ /** Ideal focusing geometry for {@link calculateGeometricFocusBreathing}. */
92
+ export type GeometricFocusingMethod = "unit-focus" | "fixed-image-distance-internal-focus";
93
+ export interface CalculateGeometricFocusBreathingInput {
94
+ /** Focal length at infinity focus, mm. */
95
+ focalLengthMm: number;
96
+ /**
97
+ * Photographic focus distance measured from the subject plane to the sensor (image) plane, in
98
+ * metres, as marked on lens distance scales.
99
+ */
100
+ subjectToSensorDistanceM: number;
101
+ /** Sensor/capture dimension along the axis of interest, mm. */
102
+ sensorDimensionMm: number;
103
+ focusingMethod: GeometricFocusingMethod;
104
+ /**
105
+ * Signed distance between the front and rear principal planes (the "hiatus"), in mm. Default 0
106
+ * (thin lens). The subject-to-sensor distance is u + hiatus + v.
107
+ */
108
+ principalPlaneSeparationMm?: number;
109
+ }
110
+ export interface GeometricFocusBreathing {
111
+ focusingMethod: GeometricFocusingMethod;
112
+ infinityFocalLengthMm: number;
113
+ /** Focal length of the focused system (changes only for internal focus), mm. */
114
+ effectiveFocalLengthMm: number;
115
+ /** Subject distance from the front principal plane, mm. */
116
+ objectDistanceMm: number;
117
+ /** Rear principal plane to sensor distance (projection distance), mm. */
118
+ imageDistanceMm: number;
119
+ /** Lateral magnification v / u. */
120
+ magnification: number;
121
+ /** v / f_infinity: framing scale relative to infinity focus. */
122
+ projectionScaleRelativeToInfinity: number;
123
+ /**
124
+ * v divided by the ideal thin-lens image distance, at objectDistanceMm, of a lens with the same
125
+ * infinity focal length. Exactly 1 for unit focus. You can pass it as breathingProjectionScale to
126
+ * calculateFocusBreathingProjection() with focusDistanceM = objectDistanceMm / 1000.
127
+ */
128
+ equivalentBreathingProjectionScale: number;
129
+ fieldOfViewDegrees: number;
130
+ infinityFieldOfViewDegrees: number;
131
+ deltaDegrees: number;
132
+ }
133
+ /**
134
+ * Focus breathing derived from ideal focusing geometry, instead of a declared scale.
135
+ *
136
+ * - unit-focus: the whole lens moves. u + v = L - hiatus and 1/u + 1/v = 1/f, so
137
+ * v = (T - sqrt(T^2 - 4 f T)) / 2, where T = L - hiatus >= 4 f. The field narrows as v grows.
138
+ * - fixed-image-distance-internal-focus: an idealised internal-focus lens keeps the rear principal
139
+ * plane at v = f_infinity and shortens its focal length to f' = u v / (u + v). The angular field
140
+ * at the rear nodal point then stays the same, and the magnification is f_infinity / u.
141
+ * Both use paraxial Gaussian optics with the nodal points at the principal planes (unit pupil
142
+ * magnification; Greivenkamp, OPTI-502 course notes, University of Arizona, sec. 3 and 5, free. Also
143
+ * see: Kingslake & Johnson, Lens Design Fundamentals, 2nd ed., ch. 3; Ray, Applied Photographic
144
+ * Optics, 3rd ed., ch. 9 and 14). Real internal-focus lenses also move their pupils and
145
+ * principal planes, so modelling their breathing needs a calibrated profile.
146
+ */
147
+ export declare function calculateGeometricFocusBreathing(input: CalculateGeometricFocusBreathingInput): CalculationResult<GeometricFocusBreathing>;
@@ -1,33 +1,40 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
- * Module boundary and integration notes.
4
- * Applies a caller-declared focus-breathing projection scale to the ideal Gaussian thin-lens
5
- * projection for one focus state. Photivra does not infer the scale from focal length, focus distance,
6
- * lens identity, or marketing data. A value of 1 exactly preserves the current thin-lens projection.
7
- * This is a generic approximation of focus-dependent projection/magnification, not a calibrated
8
- * real-lens model. The physical focal length remains authoritative and unchanged.
9
- * Calculates one-axis field of view for the generic declared-scale focus- breathing projection and
10
- * reports the corresponding ideal thin-lens FOV. A breathingProjectionScale of 1 reproduces the
11
- * current focus-aware thin-lens field-of-view result exactly.
12
- * @see docs/PHYSICS_FOUNDATION.md for equations, coordinate/unit conventions, blockers and support
13
- * limits.
3
+ * Focus breathing: the change in framing (magnification) as a lens focuses.
4
+ *
5
+ * The declared-scale model applies a caller-supplied projection scale to the ideal Gaussian thin-lens
6
+ * projection for one focus state. Photivra does not guess the scale from focal length, focus
7
+ * distance, lens identity or marketing data. A scale of 1 keeps the thin-lens projection exactly.
8
+ * This is a generic approximation of how projection and magnification change with focus. It is not a
9
+ * calibrated real-lens model. The physical focal length is never changed and stays authoritative.
10
+ *
11
+ * The field-of-view function gives the one-axis field of view (FOV) under this model, and the ideal
12
+ * thin-lens FOV for comparison. A breathingProjectionScale of 1 reproduces the focus-aware thin-lens
13
+ * FOV exactly.
14
+ *
15
+ * The geometric model derives breathing from ideal focusing geometry instead of a declared scale.
16
+ * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers
17
+ * and support limits.
14
18
  */
15
19
  import { approximationResult } from "../core/calculation-result.js";
16
- import { requirePositiveFinite } from "../core/validation.js";
20
+ import { InvalidScientificInputError, requirePositiveFinite } from "../core/validation.js";
17
21
  import { calculateThinLensImageDistance } from "./thin-lens.js";
22
+ import { requireInputKeys } from "../core/record-validation.js";
23
+ import { InvalidConfigurationError } from "../core/configuration-error.js";
18
24
  /**
19
25
  * Applies a caller-declared focus-breathing projection scale to the ideal
20
26
  * Gaussian thin-lens projection for one focus state.
21
27
  *
22
- * Photivra does not infer the scale from focal length, focus distance, lens
23
- * identity, or marketing data. A value of 1 exactly preserves the current
24
- * thin-lens projection.
28
+ * Photivra does not guess the scale from focal length, focus distance, lens
29
+ * identity or marketing data. A scale of 1 keeps the thin-lens projection
30
+ * exactly.
25
31
  *
26
- * This is a generic approximation of focus-dependent projection/magnification,
27
- * not a calibrated real-lens model. The physical focal length remains
28
- * authoritative and unchanged.
32
+ * This is a generic approximation of how projection and magnification change
33
+ * with focus. It is not a calibrated real-lens model. The physical focal
34
+ * length is never changed and stays authoritative.
29
35
  */
30
36
  export function calculateFocusBreathingProjection(input) {
37
+ requireInputKeys(input, "calculateFocusBreathingProjection", ["focalLengthMm", "focusDistanceM", "breathingProjectionScale"]);
31
38
  requirePositiveFinite("focalLengthMm", input.focalLengthMm);
32
39
  requirePositiveFinite("focusDistanceM", input.focusDistanceM);
33
40
  requirePositiveFinite("breathingProjectionScale", input.breathingProjectionScale);
@@ -55,15 +62,21 @@ export function calculateFocusBreathingProjection(input) {
55
62
  ]);
56
63
  }
57
64
  /**
58
- * Calculates one-axis field of view for the generic declared-scale focus-
59
- * breathing projection and reports the corresponding ideal thin-lens FOV.
65
+ * Calculates the one-axis field of view under the declared-scale
66
+ * focus-breathing model, and reports the ideal thin-lens field of view for
67
+ * comparison.
60
68
  *
61
- * A breathingProjectionScale of 1 reproduces the current focus-aware
62
- * thin-lens field-of-view result exactly.
69
+ * A breathingProjectionScale of 1 reproduces the focus-aware thin-lens field
70
+ * of view exactly.
63
71
  */
64
72
  export function calculateFocusBreathingFieldOfView(input) {
73
+ requireInputKeys(input, "calculateFocusBreathingFieldOfView", ["sensorDimensionMm", "focalLengthMm", "focusDistanceM", "breathingProjectionScale"]);
65
74
  requirePositiveFinite("sensorDimensionMm", input.sensorDimensionMm);
66
- const projection = calculateFocusBreathingProjection(input);
75
+ const projection = calculateFocusBreathingProjection({
76
+ focalLengthMm: input.focalLengthMm,
77
+ focusDistanceM: input.focusDistanceM,
78
+ breathingProjectionScale: input.breathingProjectionScale
79
+ });
67
80
  const idealRadians = 2 *
68
81
  Math.atan(input.sensorDimensionMm /
69
82
  (2 * projection.value.idealProjectionDistanceMm));
@@ -87,4 +100,82 @@ export function calculateFocusBreathingFieldOfView(input) {
87
100
  "Rectilinear field of view is calculated from the declared sensor/capture dimension and effective projection distance"
88
101
  ]);
89
102
  }
103
+ /**
104
+ * Focus breathing derived from ideal focusing geometry, instead of a declared scale.
105
+ *
106
+ * - unit-focus: the whole lens moves. u + v = L - hiatus and 1/u + 1/v = 1/f, so
107
+ * v = (T - sqrt(T^2 - 4 f T)) / 2, where T = L - hiatus >= 4 f. The field narrows as v grows.
108
+ * - fixed-image-distance-internal-focus: an idealised internal-focus lens keeps the rear principal
109
+ * plane at v = f_infinity and shortens its focal length to f' = u v / (u + v). The angular field
110
+ * at the rear nodal point then stays the same, and the magnification is f_infinity / u.
111
+ * Both use paraxial Gaussian optics with the nodal points at the principal planes (unit pupil
112
+ * magnification; Greivenkamp, OPTI-502 course notes, University of Arizona, sec. 3 and 5, free. Also
113
+ * see: Kingslake & Johnson, Lens Design Fundamentals, 2nd ed., ch. 3; Ray, Applied Photographic
114
+ * Optics, 3rd ed., ch. 9 and 14). Real internal-focus lenses also move their pupils and
115
+ * principal planes, so modelling their breathing needs a calibrated profile.
116
+ */
117
+ export function calculateGeometricFocusBreathing(input) {
118
+ requireInputKeys(input, "calculateGeometricFocusBreathing", ["focalLengthMm", "subjectToSensorDistanceM", "sensorDimensionMm", "focusingMethod", "principalPlaneSeparationMm"]);
119
+ requirePositiveFinite("focalLengthMm", input.focalLengthMm);
120
+ requirePositiveFinite("subjectToSensorDistanceM", input.subjectToSensorDistanceM);
121
+ requirePositiveFinite("sensorDimensionMm", input.sensorDimensionMm);
122
+ const hiatus = input.principalPlaneSeparationMm ?? 0;
123
+ if (typeof hiatus !== "number" || !Number.isFinite(hiatus)) {
124
+ throw new InvalidScientificInputError("principalPlaneSeparationMm must be finite.");
125
+ }
126
+ const f = input.focalLengthMm;
127
+ const conjugateSum = input.subjectToSensorDistanceM * 1000 - hiatus;
128
+ let imageDistanceMm;
129
+ let objectDistanceMm;
130
+ let effectiveFocalLengthMm;
131
+ if (input.focusingMethod === "unit-focus") {
132
+ if (!(conjugateSum >= 4 * f)) {
133
+ throw new InvalidScientificInputError("Unit focus requires subject-to-sensor distance minus hiatus of at least 4 x focal length (1:1 limit).");
134
+ }
135
+ // Stable smaller root of v^2 - T v + f T = 0: v = 2 f T / (T + sqrt(T^2 - 4 f T)).
136
+ imageDistanceMm =
137
+ (2 * f * conjugateSum) /
138
+ (conjugateSum + Math.sqrt(conjugateSum * conjugateSum - 4 * f * conjugateSum));
139
+ objectDistanceMm = conjugateSum - imageDistanceMm;
140
+ effectiveFocalLengthMm = f;
141
+ }
142
+ else if (input.focusingMethod === "fixed-image-distance-internal-focus") {
143
+ imageDistanceMm = f;
144
+ objectDistanceMm = conjugateSum - f;
145
+ if (!(objectDistanceMm > f)) {
146
+ throw new InvalidScientificInputError("Internal focus requires the subject to lie more than one focal length in front of the lens.");
147
+ }
148
+ effectiveFocalLengthMm = (objectDistanceMm * f) / (objectDistanceMm + f);
149
+ }
150
+ else {
151
+ throw new InvalidConfigurationError("focusingMethod must be unit-focus or fixed-image-distance-internal-focus.");
152
+ }
153
+ const thinLens = calculateThinLensImageDistance({
154
+ focalLengthMm: f,
155
+ objectDistanceM: objectDistanceMm / 1000
156
+ }).value.imageDistanceMm;
157
+ const fov = (projection) => (2 * Math.atan(input.sensorDimensionMm / (2 * projection)) * 180) / Math.PI;
158
+ const fieldOfViewDegrees = fov(imageDistanceMm);
159
+ const infinityFieldOfViewDegrees = fov(f);
160
+ return approximationResult({
161
+ focusingMethod: input.focusingMethod,
162
+ infinityFocalLengthMm: f,
163
+ effectiveFocalLengthMm,
164
+ objectDistanceMm,
165
+ imageDistanceMm,
166
+ magnification: imageDistanceMm / objectDistanceMm,
167
+ projectionScaleRelativeToInfinity: imageDistanceMm / f,
168
+ equivalentBreathingProjectionScale: input.focusingMethod === "unit-focus" ? 1 : imageDistanceMm / thinLens,
169
+ fieldOfViewDegrees,
170
+ infinityFieldOfViewDegrees,
171
+ deltaDegrees: fieldOfViewDegrees - infinityFieldOfViewDegrees
172
+ }, "geometric-focus-breathing", "1.0.0", [
173
+ "Paraxial Gaussian optics with nodal points at the principal planes (unit pupil magnification)",
174
+ input.focusingMethod === "unit-focus"
175
+ ? "Unit focus: the whole lens moves; focal length is constant"
176
+ : "Idealised internal focus: image distance fixed at the infinity focal length; focal length shortens",
177
+ "Subject-to-sensor distance = object distance + principal-plane separation + image distance",
178
+ "Rectilinear field of view from the rear-principal-plane projection distance; distortion, pupil shifts and named-lens behaviour are not modeled"
179
+ ]);
180
+ }
90
181
  //# sourceMappingURL=focus-breathing.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"focus-breathing.js","sourceRoot":"","sources":["../../src/optics/focus-breathing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"focus-breathing.js","sourceRoot":"","sources":["../../src/optics/focus-breathing.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Focus breathing: the change in framing (magnification) as a lens focuses.\n *\n * The declared-scale model applies a caller-supplied projection scale to the ideal Gaussian thin-lens\n * projection for one focus state. Photivra does not guess the scale from focal length, focus\n * distance, lens identity or marketing data. A scale of 1 keeps the thin-lens projection exactly.\n * This is a generic approximation of how projection and magnification change with focus. It is not a\n * calibrated real-lens model. The physical focal length is never changed and stays authoritative.\n *\n * The field-of-view function gives the one-axis field of view (FOV) under this model, and the ideal\n * thin-lens FOV for comparison. A breathingProjectionScale of 1 reproduces the focus-aware thin-lens\n * FOV exactly.\n *\n * The geometric model derives breathing from ideal focusing geometry instead of a declared scale.\n * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers\n * and support limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport {\n InvalidScientificInputError,\n requirePositiveFinite\n} from \"../core/validation.js\";\nimport { calculateThinLensImageDistance } from \"./thin-lens.js\";\nimport { requireInputKeys } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\n\nexport interface CalculateFocusBreathingProjectionInput {\n /** Physical lens focal length in millimetres. This value is never rewritten. */\n focalLengthMm: number;\n /** Selected focus distance in metres. */\n focusDistanceM: number;\n /**\n * Caller-declared projection scale for this focus state, relative to the\n * ideal thin-lens image distance.\n *\n * 1 means no breathing beyond the thin-lens model. Values above 1 narrow the\n * framing (more magnification). Values below 1 widen it (less\n * magnification).\n */\n breathingProjectionScale: number;\n}\n\nexport interface FocusBreathingProjection {\n /** Authoritative physical focal length supplied by the caller. */\n physicalFocalLengthMm: number;\n focusDistanceM: number;\n /** Ideal Gaussian thin-lens image distance before breathing adjustment. */\n idealProjectionDistanceMm: number;\n /**\n * Effective projection distance used by the generic breathing model.\n *\n * This is a projection (magnification) parameter. It does not replace the\n * physical focal length.\n */\n effectiveProjectionDistanceMm: number;\n /** Caller-declared scale relative to ideal thin-lens projection. */\n breathingProjectionScale: number;\n /** Ideal Gaussian thin-lens magnification at the selected focus distance. */\n idealMagnification: number;\n /** Generic breathing-adjusted magnification. */\n effectiveMagnification: number;\n}\n\nexport interface CalculateFocusBreathingFieldOfViewInput\n extends CalculateFocusBreathingProjectionInput {\n /** Sensor/capture dimension corresponding to the requested FOV, in millimetres. */\n sensorDimensionMm: number;\n}\n\nexport interface FocusBreathingFieldOfView {\n physicalFocalLengthMm: number;\n focusDistanceM: number;\n sensorDimensionMm: number;\n breathingProjectionScale: number;\n idealProjectionDistanceMm: number;\n effectiveProjectionDistanceMm: number;\n idealDegrees: number;\n effectiveDegrees: number;\n deltaDegrees: number;\n}\n\n/**\n * Applies a caller-declared focus-breathing projection scale to the ideal\n * Gaussian thin-lens projection for one focus state.\n *\n * Photivra does not guess the scale from focal length, focus distance, lens\n * identity or marketing data. A scale of 1 keeps the thin-lens projection\n * exactly.\n *\n * This is a generic approximation of how projection and magnification change\n * with focus. It is not a calibrated real-lens model. The physical focal\n * length is never changed and stays authoritative.\n */\nexport function calculateFocusBreathingProjection(\n input: CalculateFocusBreathingProjectionInput\n): CalculationResult<FocusBreathingProjection> {\n requireInputKeys(input, \"calculateFocusBreathingProjection\", [\"focalLengthMm\", \"focusDistanceM\", \"breathingProjectionScale\"]);\n requirePositiveFinite(\"focalLengthMm\", input.focalLengthMm);\n requirePositiveFinite(\"focusDistanceM\", input.focusDistanceM);\n requirePositiveFinite(\n \"breathingProjectionScale\",\n input.breathingProjectionScale\n );\n\n const thinLens = calculateThinLensImageDistance({\n focalLengthMm: input.focalLengthMm,\n objectDistanceM: input.focusDistanceM\n });\n const idealProjectionDistanceMm = thinLens.value.imageDistanceMm;\n const effectiveProjectionDistanceMm =\n idealProjectionDistanceMm * input.breathingProjectionScale;\n const objectDistanceMm = input.focusDistanceM * 1000;\n\n return approximationResult(\n {\n physicalFocalLengthMm: input.focalLengthMm,\n focusDistanceM: input.focusDistanceM,\n idealProjectionDistanceMm,\n effectiveProjectionDistanceMm,\n breathingProjectionScale: input.breathingProjectionScale,\n idealMagnification: thinLens.value.magnification,\n effectiveMagnification:\n effectiveProjectionDistanceMm / objectDistanceMm\n },\n \"declared-scale-focus-breathing-projection\",\n \"1.0.0\",\n [\n \"Base projection is the ideal Gaussian thin-lens image distance for the selected focus distance\",\n \"The focus-breathing projection scale is supplied explicitly by the caller and is not inferred\",\n \"One declared scale applies uniformly to the current focus state\",\n \"Physical focal length remains unchanged and authoritative\",\n \"The model represents focus-dependent framing/magnification only; distortion, pupil magnification, aberrations, and named-lens calibration are not modeled\"\n ]\n );\n}\n\n/**\n * Calculates the one-axis field of view under the declared-scale\n * focus-breathing model, and reports the ideal thin-lens field of view for\n * comparison.\n *\n * A breathingProjectionScale of 1 reproduces the focus-aware thin-lens field\n * of view exactly.\n */\nexport function calculateFocusBreathingFieldOfView(\n input: CalculateFocusBreathingFieldOfViewInput\n): CalculationResult<FocusBreathingFieldOfView> {\n requireInputKeys(input, \"calculateFocusBreathingFieldOfView\", [\"sensorDimensionMm\", \"focalLengthMm\", \"focusDistanceM\", \"breathingProjectionScale\"]);\n requirePositiveFinite(\"sensorDimensionMm\", input.sensorDimensionMm);\n\n const projection = calculateFocusBreathingProjection({\n focalLengthMm: input.focalLengthMm,\n focusDistanceM: input.focusDistanceM,\n breathingProjectionScale: input.breathingProjectionScale\n });\n const idealRadians =\n 2 *\n Math.atan(\n input.sensorDimensionMm /\n (2 * projection.value.idealProjectionDistanceMm)\n );\n const effectiveRadians =\n 2 *\n Math.atan(\n input.sensorDimensionMm /\n (2 * projection.value.effectiveProjectionDistanceMm)\n );\n const idealDegrees = (idealRadians * 180) / Math.PI;\n const effectiveDegrees = (effectiveRadians * 180) / Math.PI;\n\n return approximationResult(\n {\n physicalFocalLengthMm: input.focalLengthMm,\n focusDistanceM: input.focusDistanceM,\n sensorDimensionMm: input.sensorDimensionMm,\n breathingProjectionScale: input.breathingProjectionScale,\n idealProjectionDistanceMm:\n projection.value.idealProjectionDistanceMm,\n effectiveProjectionDistanceMm:\n projection.value.effectiveProjectionDistanceMm,\n idealDegrees,\n effectiveDegrees,\n deltaDegrees: effectiveDegrees - idealDegrees\n },\n \"declared-scale-focus-breathing-field-of-view\",\n \"1.0.0\",\n [\n ...(projection.provenance.assumptions ?? []),\n \"Rectilinear field of view is calculated from the declared sensor/capture dimension and effective projection distance\"\n ]\n );\n}\n\n/** Ideal focusing geometry for {@link calculateGeometricFocusBreathing}. */\nexport type GeometricFocusingMethod =\n | \"unit-focus\"\n | \"fixed-image-distance-internal-focus\";\n\nexport interface CalculateGeometricFocusBreathingInput {\n /** Focal length at infinity focus, mm. */\n focalLengthMm: number;\n /**\n * Photographic focus distance measured from the subject plane to the sensor (image) plane, in\n * metres, as marked on lens distance scales.\n */\n subjectToSensorDistanceM: number;\n /** Sensor/capture dimension along the axis of interest, mm. */\n sensorDimensionMm: number;\n focusingMethod: GeometricFocusingMethod;\n /**\n * Signed distance between the front and rear principal planes (the \"hiatus\"), in mm. Default 0\n * (thin lens). The subject-to-sensor distance is u + hiatus + v.\n */\n principalPlaneSeparationMm?: number;\n}\n\nexport interface GeometricFocusBreathing {\n focusingMethod: GeometricFocusingMethod;\n infinityFocalLengthMm: number;\n /** Focal length of the focused system (changes only for internal focus), mm. */\n effectiveFocalLengthMm: number;\n /** Subject distance from the front principal plane, mm. */\n objectDistanceMm: number;\n /** Rear principal plane to sensor distance (projection distance), mm. */\n imageDistanceMm: number;\n /** Lateral magnification v / u. */\n magnification: number;\n /** v / f_infinity: framing scale relative to infinity focus. */\n projectionScaleRelativeToInfinity: number;\n /**\n * v divided by the ideal thin-lens image distance, at objectDistanceMm, of a lens with the same\n * infinity focal length. Exactly 1 for unit focus. You can pass it as breathingProjectionScale to\n * calculateFocusBreathingProjection() with focusDistanceM = objectDistanceMm / 1000.\n */\n equivalentBreathingProjectionScale: number;\n fieldOfViewDegrees: number;\n infinityFieldOfViewDegrees: number;\n deltaDegrees: number;\n}\n\n/**\n * Focus breathing derived from ideal focusing geometry, instead of a declared scale.\n *\n * - unit-focus: the whole lens moves. u + v = L - hiatus and 1/u + 1/v = 1/f, so\n * v = (T - sqrt(T^2 - 4 f T)) / 2, where T = L - hiatus >= 4 f. The field narrows as v grows.\n * - fixed-image-distance-internal-focus: an idealised internal-focus lens keeps the rear principal\n * plane at v = f_infinity and shortens its focal length to f' = u v / (u + v). The angular field\n * at the rear nodal point then stays the same, and the magnification is f_infinity / u.\n * Both use paraxial Gaussian optics with the nodal points at the principal planes (unit pupil\n * magnification; Greivenkamp, OPTI-502 course notes, University of Arizona, sec. 3 and 5, free. Also\n * see: Kingslake & Johnson, Lens Design Fundamentals, 2nd ed., ch. 3; Ray, Applied Photographic\n * Optics, 3rd ed., ch. 9 and 14). Real internal-focus lenses also move their pupils and\n * principal planes, so modelling their breathing needs a calibrated profile.\n */\nexport function calculateGeometricFocusBreathing(\n input: CalculateGeometricFocusBreathingInput\n): CalculationResult<GeometricFocusBreathing> {\n requireInputKeys(input, \"calculateGeometricFocusBreathing\", [\"focalLengthMm\", \"subjectToSensorDistanceM\", \"sensorDimensionMm\", \"focusingMethod\", \"principalPlaneSeparationMm\"]);\n requirePositiveFinite(\"focalLengthMm\", input.focalLengthMm);\n requirePositiveFinite(\"subjectToSensorDistanceM\", input.subjectToSensorDistanceM);\n requirePositiveFinite(\"sensorDimensionMm\", input.sensorDimensionMm);\n const hiatus = input.principalPlaneSeparationMm ?? 0;\n if (typeof hiatus !== \"number\" || !Number.isFinite(hiatus)) {\n throw new InvalidScientificInputError(\"principalPlaneSeparationMm must be finite.\");\n }\n const f = input.focalLengthMm;\n const conjugateSum = input.subjectToSensorDistanceM * 1000 - hiatus;\n\n let imageDistanceMm: number;\n let objectDistanceMm: number;\n let effectiveFocalLengthMm: number;\n if (input.focusingMethod === \"unit-focus\") {\n if (!(conjugateSum >= 4 * f)) {\n throw new InvalidScientificInputError(\n \"Unit focus requires subject-to-sensor distance minus hiatus of at least 4 x focal length (1:1 limit).\"\n );\n }\n // Stable smaller root of v^2 - T v + f T = 0: v = 2 f T / (T + sqrt(T^2 - 4 f T)).\n imageDistanceMm =\n (2 * f * conjugateSum) /\n (conjugateSum + Math.sqrt(conjugateSum * conjugateSum - 4 * f * conjugateSum));\n objectDistanceMm = conjugateSum - imageDistanceMm;\n effectiveFocalLengthMm = f;\n } else if (input.focusingMethod === \"fixed-image-distance-internal-focus\") {\n imageDistanceMm = f;\n objectDistanceMm = conjugateSum - f;\n if (!(objectDistanceMm > f)) {\n throw new InvalidScientificInputError(\n \"Internal focus requires the subject to lie more than one focal length in front of the lens.\"\n );\n }\n effectiveFocalLengthMm = (objectDistanceMm * f) / (objectDistanceMm + f);\n } else {\n throw new InvalidConfigurationError(\n \"focusingMethod must be unit-focus or fixed-image-distance-internal-focus.\"\n );\n }\n\n const thinLens = calculateThinLensImageDistance({\n focalLengthMm: f,\n objectDistanceM: objectDistanceMm / 1000\n }).value.imageDistanceMm;\n const fov = (projection: number): number =>\n (2 * Math.atan(input.sensorDimensionMm / (2 * projection)) * 180) / Math.PI;\n const fieldOfViewDegrees = fov(imageDistanceMm);\n const infinityFieldOfViewDegrees = fov(f);\n\n return approximationResult(\n {\n focusingMethod: input.focusingMethod,\n infinityFocalLengthMm: f,\n effectiveFocalLengthMm,\n objectDistanceMm,\n imageDistanceMm,\n magnification: imageDistanceMm / objectDistanceMm,\n projectionScaleRelativeToInfinity: imageDistanceMm / f,\n equivalentBreathingProjectionScale:\n input.focusingMethod === \"unit-focus\" ? 1 : imageDistanceMm / thinLens,\n fieldOfViewDegrees,\n infinityFieldOfViewDegrees,\n deltaDegrees: fieldOfViewDegrees - infinityFieldOfViewDegrees\n },\n \"geometric-focus-breathing\",\n \"1.0.0\",\n [\n \"Paraxial Gaussian optics with nodal points at the principal planes (unit pupil magnification)\",\n input.focusingMethod === \"unit-focus\"\n ? \"Unit focus: the whole lens moves; focal length is constant\"\n : \"Idealised internal focus: image distance fixed at the infinity focal length; focal length shortens\",\n \"Subject-to-sensor distance = object distance + principal-plane separation + image distance\",\n \"Rectilinear field of view from the rear-principal-plane projection distance; distortion, pupil shifts and named-lens behaviour are not modeled\"\n ]\n );\n}\n"]}
@@ -1,22 +1,23 @@
1
1
  /**
2
- * Module boundary and integration notes.
3
- * Parses an explicit focus-plane state from an untrusted JSON boundary. Missing/unknown focus is
4
- * rejected rather than being interpreted as infinity.
5
- * Calculates the ideal image-plane distance for an explicit focus state. Finite focus delegates to the
6
- * existing Gaussian thin-lens calculation, so its numerical result and provenance are unchanged.
7
- * Infinity focus resolves exactly to the nominal focal length with zero limiting magnification.
8
- * @see docs/PHYSICS_FOUNDATION.md for equations, coordinate/unit conventions, blockers and support
9
- * limits.
2
+ * Explicit focus state: a finite focus distance, or infinity.
3
+ *
4
+ * The parser reads the state from untrusted JSON. Missing or unknown focus is rejected; it is never
5
+ * read as infinity.
6
+ *
7
+ * The image-distance function uses the existing Gaussian thin-lens calculation for finite focus, so
8
+ * its numbers and provenance are unchanged. Infinity focus gives exactly the nominal focal length,
9
+ * with a limiting magnification of zero.
10
+ * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers
11
+ * and support limits.
10
12
  */
11
13
  import { type CalculationResult } from "../core/calculation-result.js";
12
14
  import { type ThinLensImageDistance } from "./thin-lens.js";
13
15
  /**
14
16
  * Explicit ideal focus-plane state.
15
17
  *
16
- * Finite distance is the longitudinal object-plane distance from the ideal
17
- * lens principal plane along the camera optical axis. Infinity is a semantic
18
- * state and is never represented with JavaScript Infinity or a fabricated
19
- * large distance.
18
+ * A finite distance is measured along the camera's optical axis, from the
19
+ * ideal lens principal plane to the object plane. Infinity is a named state.
20
+ * It is never stored as JavaScript Infinity or as a made-up large distance.
20
21
  */
21
22
  export type FocusPlane = {
22
23
  kind: "finite";
@@ -31,17 +32,16 @@ export interface CalculateFocusPlaneImageDistanceInput {
31
32
  focus: FocusPlane;
32
33
  }
33
34
  /**
34
- * Parses an explicit focus-plane state from an untrusted JSON boundary.
35
+ * Parses an explicit focus-plane state from untrusted JSON.
35
36
  *
36
- * Missing/unknown focus is rejected rather than being interpreted as infinity.
37
+ * Missing or unknown focus is rejected. It is never read as infinity.
37
38
  */
38
39
  export declare function parseFocusPlane(value: unknown): FocusPlane;
39
40
  /**
40
41
  * Calculates the ideal image-plane distance for an explicit focus state.
41
42
  *
42
- * Finite focus delegates to the existing Gaussian thin-lens calculation, so
43
- * its numerical result and provenance are unchanged. Infinity focus resolves
44
- * exactly to the nominal focal length with zero limiting magnification.
43
+ * Finite focus uses the existing Gaussian thin-lens calculation, so its
44
+ * numbers and provenance are unchanged. Infinity focus gives exactly the
45
+ * nominal focal length, with a limiting magnification of zero.
45
46
  */
46
47
  export declare function calculateFocusPlaneImageDistance(input: CalculateFocusPlaneImageDistanceInput): CalculationResult<ThinLensImageDistance>;
47
- //# sourceMappingURL=focus-state.d.ts.map