@photivra/engine 0.5.1 → 1.0.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 (753) hide show
  1. package/AGENTS.md +674 -0
  2. package/CHANGELOG.md +218 -0
  3. package/CITATION.cff +1 -1
  4. package/CONTRIBUTING.md +76 -0
  5. package/DCO +33 -0
  6. package/NODE_SUPPORT.md +37 -0
  7. package/NOTICE +2 -0
  8. package/README.md +157 -56
  9. package/SECURITY.md +55 -0
  10. package/THIRD_PARTY.md +63 -0
  11. package/dist/camera/equivalent-focal-length.d.ts +9 -0
  12. package/dist/camera/equivalent-focal-length.d.ts.map +1 -1
  13. package/dist/camera/equivalent-focal-length.js +9 -0
  14. package/dist/camera/equivalent-focal-length.js.map +1 -1
  15. package/dist/camera/field-of-view.d.ts +13 -0
  16. package/dist/camera/field-of-view.d.ts.map +1 -1
  17. package/dist/camera/field-of-view.js +13 -0
  18. package/dist/camera/field-of-view.js.map +1 -1
  19. package/dist/camera/projected-object-size.d.ts +8 -0
  20. package/dist/camera/projected-object-size.d.ts.map +1 -1
  21. package/dist/camera/projected-object-size.js +8 -0
  22. package/dist/camera/projected-object-size.js.map +1 -1
  23. package/dist/capture/capture-export-metadata.d.ts +60 -0
  24. package/dist/capture/capture-export-metadata.d.ts.map +1 -0
  25. package/dist/capture/capture-export-metadata.js +62 -0
  26. package/dist/capture/capture-export-metadata.js.map +1 -0
  27. package/dist/capture/environment-raw-producer.d.ts +55 -0
  28. package/dist/capture/environment-raw-producer.d.ts.map +1 -0
  29. package/dist/capture/environment-raw-producer.js +88 -0
  30. package/dist/capture/environment-raw-producer.js.map +1 -0
  31. package/dist/capture/export-jpeg.d.ts +12 -0
  32. package/dist/capture/export-jpeg.d.ts.map +1 -0
  33. package/dist/capture/export-jpeg.js +126 -0
  34. package/dist/capture/export-jpeg.js.map +1 -0
  35. package/dist/capture/export-tiff.d.ts +45 -0
  36. package/dist/capture/export-tiff.d.ts.map +1 -0
  37. package/dist/capture/export-tiff.js +129 -0
  38. package/dist/capture/export-tiff.js.map +1 -0
  39. package/dist/capture/focus-control.d.ts +210 -0
  40. package/dist/capture/focus-control.d.ts.map +1 -0
  41. package/dist/capture/focus-control.js +664 -0
  42. package/dist/capture/focus-control.js.map +1 -0
  43. package/dist/capture/linear-encoding.d.ts +59 -0
  44. package/dist/capture/linear-encoding.d.ts.map +1 -0
  45. package/dist/capture/linear-encoding.js +98 -0
  46. package/dist/capture/linear-encoding.js.map +1 -0
  47. package/dist/capture/photographic-export.d.ts +135 -0
  48. package/dist/capture/photographic-export.d.ts.map +1 -0
  49. package/dist/capture/photographic-export.js +273 -0
  50. package/dist/capture/photographic-export.js.map +1 -0
  51. package/dist/capture/raw-frame-limits.d.ts +12 -0
  52. package/dist/capture/raw-frame-limits.d.ts.map +1 -0
  53. package/dist/capture/raw-frame-limits.js +13 -0
  54. package/dist/capture/raw-frame-limits.js.map +1 -0
  55. package/dist/capture/raw-frame-reconstruction.d.ts +48 -0
  56. package/dist/capture/raw-frame-reconstruction.d.ts.map +1 -0
  57. package/dist/capture/raw-frame-reconstruction.js +146 -0
  58. package/dist/capture/raw-frame-reconstruction.js.map +1 -0
  59. package/dist/capture/release-sequence.d.ts +120 -0
  60. package/dist/capture/release-sequence.d.ts.map +1 -0
  61. package/dist/capture/release-sequence.js +446 -0
  62. package/dist/capture/release-sequence.js.map +1 -0
  63. package/dist/capture/sensor-raw-frame.d.ts +34 -0
  64. package/dist/capture/sensor-raw-frame.d.ts.map +1 -0
  65. package/dist/capture/sensor-raw-frame.js +106 -0
  66. package/dist/capture/sensor-raw-frame.js.map +1 -0
  67. package/dist/capture/sensor-raw-producer.d.ts +51 -0
  68. package/dist/capture/sensor-raw-producer.d.ts.map +1 -0
  69. package/dist/capture/sensor-raw-producer.js +235 -0
  70. package/dist/capture/sensor-raw-producer.js.map +1 -0
  71. package/dist/capture/simulated-capture.d.ts +125 -0
  72. package/dist/capture/simulated-capture.d.ts.map +1 -0
  73. package/dist/capture/simulated-capture.js +248 -0
  74. package/dist/capture/simulated-capture.js.map +1 -0
  75. package/dist/color/capture-color.d.ts +73 -0
  76. package/dist/color/capture-color.d.ts.map +1 -0
  77. package/dist/color/capture-color.js +145 -0
  78. package/dist/color/capture-color.js.map +1 -0
  79. package/dist/color/sensor-color-development.d.ts +23 -0
  80. package/dist/color/sensor-color-development.d.ts.map +1 -0
  81. package/dist/color/sensor-color-development.js +56 -0
  82. package/dist/color/sensor-color-development.js.map +1 -0
  83. package/dist/color/white-balance.d.ts +175 -0
  84. package/dist/color/white-balance.d.ts.map +1 -0
  85. package/dist/color/white-balance.js +606 -0
  86. package/dist/color/white-balance.js.map +1 -0
  87. package/dist/composition/image-formation-plan.d.ts +481 -0
  88. package/dist/composition/image-formation-plan.d.ts.map +1 -0
  89. package/dist/composition/image-formation-plan.js +2499 -0
  90. package/dist/composition/image-formation-plan.js.map +1 -0
  91. package/dist/composition/plan-consumer.d.ts +53 -0
  92. package/dist/composition/plan-consumer.d.ts.map +1 -0
  93. package/dist/composition/plan-consumer.js +119 -0
  94. package/dist/composition/plan-consumer.js.map +1 -0
  95. package/dist/core/calculation-result.d.ts.map +1 -1
  96. package/dist/core/calculation-result.js +6 -0
  97. package/dist/core/calculation-result.js.map +1 -1
  98. package/dist/core/canonical-json.d.ts +18 -0
  99. package/dist/core/canonical-json.d.ts.map +1 -0
  100. package/dist/core/canonical-json.js +44 -0
  101. package/dist/core/canonical-json.js.map +1 -0
  102. package/dist/core/configuration-error.d.ts +6 -0
  103. package/dist/core/configuration-error.d.ts.map +1 -1
  104. package/dist/core/configuration-error.js +6 -0
  105. package/dist/core/configuration-error.js.map +1 -1
  106. package/dist/core/evidence-provenance.d.ts +6 -0
  107. package/dist/core/evidence-provenance.d.ts.map +1 -1
  108. package/dist/core/evidence-provenance.js +7 -0
  109. package/dist/core/evidence-provenance.js.map +1 -1
  110. package/dist/core/image-formation.d.ts +9 -3
  111. package/dist/core/image-formation.d.ts.map +1 -1
  112. package/dist/core/image-formation.js +29 -5
  113. package/dist/core/image-formation.js.map +1 -1
  114. package/dist/core/owned-data.d.ts +25 -0
  115. package/dist/core/owned-data.d.ts.map +1 -0
  116. package/dist/core/owned-data.js +34 -0
  117. package/dist/core/owned-data.js.map +1 -0
  118. package/dist/core/record-validation.d.ts +17 -0
  119. package/dist/core/record-validation.d.ts.map +1 -0
  120. package/dist/core/record-validation.js +44 -0
  121. package/dist/core/record-validation.js.map +1 -0
  122. package/dist/core/scientific-assurance.d.ts +101 -0
  123. package/dist/core/scientific-assurance.d.ts.map +1 -0
  124. package/dist/core/scientific-assurance.js +301 -0
  125. package/dist/core/scientific-assurance.js.map +1 -0
  126. package/dist/core/spectral-composition.d.ts +106 -0
  127. package/dist/core/spectral-composition.d.ts.map +1 -0
  128. package/dist/core/spectral-composition.js +334 -0
  129. package/dist/core/spectral-composition.js.map +1 -0
  130. package/dist/core/spectral.d.ts +34 -0
  131. package/dist/core/spectral.d.ts.map +1 -0
  132. package/dist/core/spectral.js +57 -0
  133. package/dist/core/spectral.js.map +1 -0
  134. package/dist/core/validation.d.ts +6 -0
  135. package/dist/core/validation.d.ts.map +1 -1
  136. package/dist/core/validation.js +6 -0
  137. package/dist/core/validation.js.map +1 -1
  138. package/dist/core/version.d.ts +14 -0
  139. package/dist/core/version.d.ts.map +1 -0
  140. package/dist/core/version.js +15 -0
  141. package/dist/core/version.js.map +1 -0
  142. package/dist/equipment/exposure-capabilities.d.ts +125 -0
  143. package/dist/equipment/exposure-capabilities.d.ts.map +1 -0
  144. package/dist/equipment/exposure-capabilities.js +391 -0
  145. package/dist/equipment/exposure-capabilities.js.map +1 -0
  146. package/dist/equipment/generic-tier-assets.d.ts +82 -0
  147. package/dist/equipment/generic-tier-assets.d.ts.map +1 -0
  148. package/dist/equipment/generic-tier-assets.js +119 -0
  149. package/dist/equipment/generic-tier-assets.js.map +1 -0
  150. package/dist/equipment/generic-tier-presets.d.ts +57 -0
  151. package/dist/equipment/generic-tier-presets.d.ts.map +1 -0
  152. package/dist/equipment/generic-tier-presets.js +122 -0
  153. package/dist/equipment/generic-tier-presets.js.map +1 -0
  154. package/dist/equipment/iso-capabilities.d.ts +143 -0
  155. package/dist/equipment/iso-capabilities.d.ts.map +1 -0
  156. package/dist/equipment/iso-capabilities.js +578 -0
  157. package/dist/equipment/iso-capabilities.js.map +1 -0
  158. package/dist/equipment/metering-capabilities.d.ts +58 -0
  159. package/dist/equipment/metering-capabilities.d.ts.map +1 -0
  160. package/dist/equipment/metering-capabilities.js +151 -0
  161. package/dist/equipment/metering-capabilities.js.map +1 -0
  162. package/dist/equipment/release-capabilities.d.ts +33 -0
  163. package/dist/equipment/release-capabilities.d.ts.map +1 -0
  164. package/dist/equipment/release-capabilities.js +176 -0
  165. package/dist/equipment/release-capabilities.js.map +1 -0
  166. package/dist/exposure/exposure-duration-control.d.ts +72 -0
  167. package/dist/exposure/exposure-duration-control.d.ts.map +1 -0
  168. package/dist/exposure/exposure-duration-control.js +161 -0
  169. package/dist/exposure/exposure-duration-control.js.map +1 -0
  170. package/dist/exposure/exposure-mode-resolver.d.ts +637 -0
  171. package/dist/exposure/exposure-mode-resolver.d.ts.map +1 -0
  172. package/dist/exposure/exposure-mode-resolver.js +1905 -0
  173. package/dist/exposure/exposure-mode-resolver.js.map +1 -0
  174. package/dist/exposure/exposure.d.ts +8 -0
  175. package/dist/exposure/exposure.d.ts.map +1 -1
  176. package/dist/exposure/exposure.js +8 -0
  177. package/dist/exposure/exposure.js.map +1 -1
  178. package/dist/exposure/flash.d.ts +179 -0
  179. package/dist/exposure/flash.d.ts.map +1 -0
  180. package/dist/exposure/flash.js +644 -0
  181. package/dist/exposure/flash.js.map +1 -0
  182. package/dist/exposure/metering-scene-radiance.d.ts +72 -0
  183. package/dist/exposure/metering-scene-radiance.d.ts.map +1 -0
  184. package/dist/exposure/metering-scene-radiance.js +222 -0
  185. package/dist/exposure/metering-scene-radiance.js.map +1 -0
  186. package/dist/exposure/metering-target.d.ts +67 -0
  187. package/dist/exposure/metering-target.d.ts.map +1 -0
  188. package/dist/exposure/metering-target.js +265 -0
  189. package/dist/exposure/metering-target.js.map +1 -0
  190. package/dist/exposure/metering-temporal.d.ts +76 -0
  191. package/dist/exposure/metering-temporal.d.ts.map +1 -0
  192. package/dist/exposure/metering-temporal.js +210 -0
  193. package/dist/exposure/metering-temporal.js.map +1 -0
  194. package/dist/exposure/metering.d.ts +124 -0
  195. package/dist/exposure/metering.d.ts.map +1 -0
  196. package/dist/exposure/metering.js +422 -0
  197. package/dist/exposure/metering.js.map +1 -0
  198. package/dist/exposure/program-line.d.ts +29 -0
  199. package/dist/exposure/program-line.d.ts.map +1 -0
  200. package/dist/exposure/program-line.js +126 -0
  201. package/dist/exposure/program-line.js.map +1 -0
  202. package/dist/index.d.ts +101 -7
  203. package/dist/index.d.ts.map +1 -1
  204. package/dist/index.js +99 -7
  205. package/dist/index.js.map +1 -1
  206. package/dist/motion/camera-rotation.d.ts +76 -0
  207. package/dist/motion/camera-rotation.d.ts.map +1 -1
  208. package/dist/motion/camera-rotation.js +111 -0
  209. package/dist/motion/camera-rotation.js.map +1 -1
  210. package/dist/motion/capture-rotation-inverse-mapping.d.ts +113 -0
  211. package/dist/motion/capture-rotation-inverse-mapping.d.ts.map +1 -0
  212. package/dist/motion/capture-rotation-inverse-mapping.js +184 -0
  213. package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -0
  214. package/dist/motion/capture-rotation-temporal-quadrature.d.ts +104 -0
  215. package/dist/motion/capture-rotation-temporal-quadrature.d.ts.map +1 -0
  216. package/dist/motion/capture-rotation-temporal-quadrature.js +131 -0
  217. package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -0
  218. package/dist/motion/capture-rotation-trajectory.d.ts +113 -0
  219. package/dist/motion/capture-rotation-trajectory.d.ts.map +1 -0
  220. package/dist/motion/capture-rotation-trajectory.js +168 -0
  221. package/dist/motion/capture-rotation-trajectory.js.map +1 -0
  222. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +119 -0
  223. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts.map +1 -0
  224. package/dist/motion/capture-translation-parallax-temporal-quadrature.js +263 -0
  225. package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -0
  226. package/dist/motion/extended-object-projection.d.ts +175 -0
  227. package/dist/motion/extended-object-projection.d.ts.map +1 -0
  228. package/dist/motion/extended-object-projection.js +402 -0
  229. package/dist/motion/extended-object-projection.js.map +1 -0
  230. package/dist/motion/projected-motion.d.ts +11 -0
  231. package/dist/motion/projected-motion.d.ts.map +1 -1
  232. package/dist/motion/projected-motion.js +11 -0
  233. package/dist/motion/projected-motion.js.map +1 -1
  234. package/dist/optics/aperture.d.ts +9 -0
  235. package/dist/optics/aperture.d.ts.map +1 -1
  236. package/dist/optics/aperture.js +9 -0
  237. package/dist/optics/aperture.js.map +1 -1
  238. package/dist/optics/circle-of-confusion.d.ts +8 -0
  239. package/dist/optics/circle-of-confusion.d.ts.map +1 -1
  240. package/dist/optics/circle-of-confusion.js +8 -0
  241. package/dist/optics/circle-of-confusion.js.map +1 -1
  242. package/dist/optics/complex-pupil-psf.d.ts +128 -0
  243. package/dist/optics/complex-pupil-psf.d.ts.map +1 -0
  244. package/dist/optics/complex-pupil-psf.js +462 -0
  245. package/dist/optics/complex-pupil-psf.js.map +1 -0
  246. package/dist/optics/depth-of-field.d.ts +18 -0
  247. package/dist/optics/depth-of-field.d.ts.map +1 -1
  248. package/dist/optics/depth-of-field.js +29 -4
  249. package/dist/optics/depth-of-field.js.map +1 -1
  250. package/dist/optics/diffraction.d.ts +8 -0
  251. package/dist/optics/diffraction.d.ts.map +1 -1
  252. package/dist/optics/diffraction.js +8 -0
  253. package/dist/optics/diffraction.js.map +1 -1
  254. package/dist/optics/focus-breathing.d.ts +13 -0
  255. package/dist/optics/focus-breathing.d.ts.map +1 -1
  256. package/dist/optics/focus-breathing.js +13 -0
  257. package/dist/optics/focus-breathing.js.map +1 -1
  258. package/dist/optics/focus-state.d.ts +47 -0
  259. package/dist/optics/focus-state.d.ts.map +1 -0
  260. package/dist/optics/focus-state.js +78 -0
  261. package/dist/optics/focus-state.js.map +1 -0
  262. package/dist/optics/front-of-lens-filter.d.ts +114 -0
  263. package/dist/optics/front-of-lens-filter.d.ts.map +1 -0
  264. package/dist/optics/front-of-lens-filter.js +468 -0
  265. package/dist/optics/front-of-lens-filter.js.map +1 -0
  266. package/dist/optics/illumination-vignetting.d.ts +9 -0
  267. package/dist/optics/illumination-vignetting.d.ts.map +1 -1
  268. package/dist/optics/illumination-vignetting.js +9 -0
  269. package/dist/optics/illumination-vignetting.js.map +1 -1
  270. package/dist/optics/lateral-chromatic-aberration.d.ts +11 -0
  271. package/dist/optics/lateral-chromatic-aberration.d.ts.map +1 -1
  272. package/dist/optics/lateral-chromatic-aberration.js +23 -4
  273. package/dist/optics/lateral-chromatic-aberration.js.map +1 -1
  274. package/dist/optics/lens-psf-profile.d.ts +217 -0
  275. package/dist/optics/lens-psf-profile.d.ts.map +1 -0
  276. package/dist/optics/lens-psf-profile.js +823 -0
  277. package/dist/optics/lens-psf-profile.js.map +1 -0
  278. package/dist/optics/polygon-diffraction.d.ts +67 -0
  279. package/dist/optics/polygon-diffraction.d.ts.map +1 -0
  280. package/dist/optics/polygon-diffraction.js +145 -0
  281. package/dist/optics/polygon-diffraction.js.map +1 -0
  282. package/dist/optics/profile-contract.d.ts +42 -0
  283. package/dist/optics/profile-contract.d.ts.map +1 -0
  284. package/dist/optics/profile-contract.js +92 -0
  285. package/dist/optics/profile-contract.js.map +1 -0
  286. package/dist/optics/psf-foundation.d.ts +16 -3
  287. package/dist/optics/psf-foundation.d.ts.map +1 -1
  288. package/dist/optics/psf-foundation.js +28 -15
  289. package/dist/optics/psf-foundation.js.map +1 -1
  290. package/dist/optics/radial-distortion.d.ts +22 -2
  291. package/dist/optics/radial-distortion.d.ts.map +1 -1
  292. package/dist/optics/radial-distortion.js +101 -23
  293. package/dist/optics/radial-distortion.js.map +1 -1
  294. package/dist/optics/scene-to-sensor-irradiance.d.ts +213 -0
  295. package/dist/optics/scene-to-sensor-irradiance.d.ts.map +1 -0
  296. package/dist/optics/scene-to-sensor-irradiance.js +662 -0
  297. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -0
  298. package/dist/optics/scene-to-sensor-quadrature.d.ts +63 -0
  299. package/dist/optics/scene-to-sensor-quadrature.d.ts.map +1 -0
  300. package/dist/optics/scene-to-sensor-quadrature.js +82 -0
  301. package/dist/optics/scene-to-sensor-quadrature.js.map +1 -0
  302. package/dist/optics/sensor-environment-query.d.ts +60 -0
  303. package/dist/optics/sensor-environment-query.d.ts.map +1 -0
  304. package/dist/optics/sensor-environment-query.js +50 -0
  305. package/dist/optics/sensor-environment-query.js.map +1 -0
  306. package/dist/optics/sensor-psf-quadrature.d.ts +70 -0
  307. package/dist/optics/sensor-psf-quadrature.d.ts.map +1 -0
  308. package/dist/optics/sensor-psf-quadrature.js +101 -0
  309. package/dist/optics/sensor-psf-quadrature.js.map +1 -0
  310. package/dist/optics/sensor-psf-support.d.ts +20 -0
  311. package/dist/optics/sensor-psf-support.d.ts.map +1 -0
  312. package/dist/optics/sensor-psf-support.js +13 -0
  313. package/dist/optics/sensor-psf-support.js.map +1 -0
  314. package/dist/optics/stray-light.d.ts +91 -0
  315. package/dist/optics/stray-light.d.ts.map +1 -0
  316. package/dist/optics/stray-light.js +110 -0
  317. package/dist/optics/stray-light.js.map +1 -0
  318. package/dist/optics/thin-lens.d.ts +8 -0
  319. package/dist/optics/thin-lens.d.ts.map +1 -1
  320. package/dist/optics/thin-lens.js +8 -0
  321. package/dist/optics/thin-lens.js.map +1 -1
  322. package/dist/output/capture-corrected-sdr.d.ts +49 -0
  323. package/dist/output/capture-corrected-sdr.d.ts.map +1 -0
  324. package/dist/output/capture-corrected-sdr.js +149 -0
  325. package/dist/output/capture-corrected-sdr.js.map +1 -0
  326. package/dist/output/capture-geometry.d.ts.map +1 -1
  327. package/dist/output/capture-geometry.js +32 -11
  328. package/dist/output/capture-geometry.js.map +1 -1
  329. package/dist/output/capture-sdr.d.ts +49 -0
  330. package/dist/output/capture-sdr.d.ts.map +1 -0
  331. package/dist/output/capture-sdr.js +90 -0
  332. package/dist/output/capture-sdr.js.map +1 -0
  333. package/dist/output/crop.d.ts +6 -0
  334. package/dist/output/crop.d.ts.map +1 -1
  335. package/dist/output/crop.js +6 -0
  336. package/dist/output/crop.js.map +1 -1
  337. package/dist/output/geometric-transforms.d.ts +137 -0
  338. package/dist/output/geometric-transforms.d.ts.map +1 -0
  339. package/dist/output/geometric-transforms.js +225 -0
  340. package/dist/output/geometric-transforms.js.map +1 -0
  341. package/dist/output/lens-corrections.d.ts +121 -0
  342. package/dist/output/lens-corrections.d.ts.map +1 -0
  343. package/dist/output/lens-corrections.js +210 -0
  344. package/dist/output/lens-corrections.js.map +1 -0
  345. package/dist/output/sdr-rendering.d.ts +81 -0
  346. package/dist/output/sdr-rendering.d.ts.map +1 -0
  347. package/dist/output/sdr-rendering.js +106 -0
  348. package/dist/output/sdr-rendering.js.map +1 -0
  349. package/dist/output/subject-framing-crop.d.ts +8 -0
  350. package/dist/output/subject-framing-crop.d.ts.map +1 -1
  351. package/dist/output/subject-framing-crop.js +8 -0
  352. package/dist/output/subject-framing-crop.js.map +1 -1
  353. package/dist/schema/camera.d.ts +6 -0
  354. package/dist/schema/camera.d.ts.map +1 -1
  355. package/dist/schema/illumination-spectral.d.ts +51 -0
  356. package/dist/schema/illumination-spectral.d.ts.map +1 -0
  357. package/dist/schema/illumination-spectral.js +132 -0
  358. package/dist/schema/illumination-spectral.js.map +1 -0
  359. package/dist/schema/illumination-temporal.d.ts +156 -0
  360. package/dist/schema/illumination-temporal.d.ts.map +1 -0
  361. package/dist/schema/illumination-temporal.js +554 -0
  362. package/dist/schema/illumination-temporal.js.map +1 -0
  363. package/dist/schema/illumination.d.ts +138 -0
  364. package/dist/schema/illumination.d.ts.map +1 -0
  365. package/dist/schema/illumination.js +483 -0
  366. package/dist/schema/illumination.js.map +1 -0
  367. package/dist/schema/scene-radiance-temporal.d.ts +107 -0
  368. package/dist/schema/scene-radiance-temporal.d.ts.map +1 -0
  369. package/dist/schema/scene-radiance-temporal.js +259 -0
  370. package/dist/schema/scene-radiance-temporal.js.map +1 -0
  371. package/dist/schema/scene-radiance.d.ts +185 -0
  372. package/dist/schema/scene-radiance.d.ts.map +1 -0
  373. package/dist/schema/scene-radiance.js +535 -0
  374. package/dist/schema/scene-radiance.js.map +1 -0
  375. package/dist/schema/scene.d.ts +7 -0
  376. package/dist/schema/scene.d.ts.map +1 -1
  377. package/dist/schema/validation.d.ts.map +1 -1
  378. package/dist/schema/validation.js +7 -0
  379. package/dist/schema/validation.js.map +1 -1
  380. package/dist/sensor/accumulated-charge.d.ts +199 -0
  381. package/dist/sensor/accumulated-charge.d.ts.map +1 -0
  382. package/dist/sensor/accumulated-charge.js +450 -0
  383. package/dist/sensor/accumulated-charge.js.map +1 -0
  384. package/dist/sensor/architecture.d.ts +48 -13
  385. package/dist/sensor/architecture.d.ts.map +1 -1
  386. package/dist/sensor/architecture.js +58 -16
  387. package/dist/sensor/architecture.js.map +1 -1
  388. package/dist/sensor/camera-saturation-capacity.d.ts +138 -0
  389. package/dist/sensor/camera-saturation-capacity.d.ts.map +1 -0
  390. package/dist/sensor/camera-saturation-capacity.js +356 -0
  391. package/dist/sensor/camera-saturation-capacity.js.map +1 -0
  392. package/dist/sensor/capture-color-sampling-binding.d.ts +212 -0
  393. package/dist/sensor/capture-color-sampling-binding.d.ts.map +1 -0
  394. package/dist/sensor/capture-color-sampling-binding.js +437 -0
  395. package/dist/sensor/capture-color-sampling-binding.js.map +1 -0
  396. package/dist/sensor/capture-mode-timing.d.ts +63 -0
  397. package/dist/sensor/capture-mode-timing.d.ts.map +1 -0
  398. package/dist/sensor/capture-mode-timing.js +270 -0
  399. package/dist/sensor/capture-mode-timing.js.map +1 -0
  400. package/dist/sensor/capture-mode.d.ts +157 -0
  401. package/dist/sensor/capture-mode.d.ts.map +1 -0
  402. package/dist/sensor/capture-mode.js +447 -0
  403. package/dist/sensor/capture-mode.js.map +1 -0
  404. package/dist/sensor/color-sampling.d.ts +133 -0
  405. package/dist/sensor/color-sampling.d.ts.map +1 -0
  406. package/dist/sensor/color-sampling.js +245 -0
  407. package/dist/sensor/color-sampling.js.map +1 -0
  408. package/dist/sensor/constant-rate-temporal-integration.d.ts +126 -0
  409. package/dist/sensor/constant-rate-temporal-integration.d.ts.map +1 -0
  410. package/dist/sensor/constant-rate-temporal-integration.js +382 -0
  411. package/dist/sensor/constant-rate-temporal-integration.js.map +1 -0
  412. package/dist/sensor/dark-current.d.ts +169 -0
  413. package/dist/sensor/dark-current.d.ts.map +1 -0
  414. package/dist/sensor/dark-current.js +427 -0
  415. package/dist/sensor/dark-current.js.map +1 -0
  416. package/dist/sensor/environment-photo-signal.d.ts +123 -0
  417. package/dist/sensor/environment-photo-signal.d.ts.map +1 -0
  418. package/dist/sensor/environment-photo-signal.js +186 -0
  419. package/dist/sensor/environment-photo-signal.js.map +1 -0
  420. package/dist/sensor/eqe-electron-rate.d.ts +107 -0
  421. package/dist/sensor/eqe-electron-rate.d.ts.map +1 -0
  422. package/dist/sensor/eqe-electron-rate.js +561 -0
  423. package/dist/sensor/eqe-electron-rate.js.map +1 -0
  424. package/dist/sensor/eqe-local-exposure.d.ts +65 -0
  425. package/dist/sensor/eqe-local-exposure.d.ts.map +1 -0
  426. package/dist/sensor/eqe-local-exposure.js +84 -0
  427. package/dist/sensor/eqe-local-exposure.js.map +1 -0
  428. package/dist/sensor/eqe-temporal-exposure.d.ts +55 -0
  429. package/dist/sensor/eqe-temporal-exposure.d.ts.map +1 -0
  430. package/dist/sensor/eqe-temporal-exposure.js +62 -0
  431. package/dist/sensor/eqe-temporal-exposure.js.map +1 -0
  432. package/dist/sensor/exposure-window.d.ts +117 -0
  433. package/dist/sensor/exposure-window.d.ts.map +1 -0
  434. package/dist/sensor/exposure-window.js +305 -0
  435. package/dist/sensor/exposure-window.js.map +1 -0
  436. package/dist/sensor/iso-signal-chain.d.ts +148 -0
  437. package/dist/sensor/iso-signal-chain.d.ts.map +1 -0
  438. package/dist/sensor/iso-signal-chain.js +411 -0
  439. package/dist/sensor/iso-signal-chain.js.map +1 -0
  440. package/dist/sensor/local-exposure-binding.d.ts +87 -0
  441. package/dist/sensor/local-exposure-binding.d.ts.map +1 -0
  442. package/dist/sensor/local-exposure-binding.js +214 -0
  443. package/dist/sensor/local-exposure-binding.js.map +1 -0
  444. package/dist/sensor/optical-stack.d.ts +132 -0
  445. package/dist/sensor/optical-stack.d.ts.map +1 -0
  446. package/dist/sensor/optical-stack.js +303 -0
  447. package/dist/sensor/optical-stack.js.map +1 -0
  448. package/dist/sensor/photon-energy.d.ts +97 -0
  449. package/dist/sensor/photon-energy.d.ts.map +1 -0
  450. package/dist/sensor/photon-energy.js +390 -0
  451. package/dist/sensor/photon-energy.js.map +1 -0
  452. package/dist/sensor/physical-charge-capacity.d.ts +130 -0
  453. package/dist/sensor/physical-charge-capacity.d.ts.map +1 -0
  454. package/dist/sensor/physical-charge-capacity.js +345 -0
  455. package/dist/sensor/physical-charge-capacity.js.map +1 -0
  456. package/dist/sensor/pixel-pitch.d.ts +6 -0
  457. package/dist/sensor/pixel-pitch.d.ts.map +1 -1
  458. package/dist/sensor/pixel-pitch.js +6 -0
  459. package/dist/sensor/pixel-pitch.js.map +1 -1
  460. package/dist/sensor/radiometry-readiness.d.ts +10 -0
  461. package/dist/sensor/radiometry-readiness.d.ts.map +1 -1
  462. package/dist/sensor/radiometry-readiness.js +10 -0
  463. package/dist/sensor/radiometry-readiness.js.map +1 -1
  464. package/dist/sensor/raw-readout.d.ts +314 -0
  465. package/dist/sensor/raw-readout.d.ts.map +1 -0
  466. package/dist/sensor/raw-readout.js +914 -0
  467. package/dist/sensor/raw-readout.js.map +1 -0
  468. package/dist/sensor/raw-reconstruction.d.ts +170 -0
  469. package/dist/sensor/raw-reconstruction.d.ts.map +1 -0
  470. package/dist/sensor/raw-reconstruction.js +424 -0
  471. package/dist/sensor/raw-reconstruction.js.map +1 -0
  472. package/dist/sensor/readout-exposure-linkage.d.ts +123 -0
  473. package/dist/sensor/readout-exposure-linkage.d.ts.map +1 -0
  474. package/dist/sensor/readout-exposure-linkage.js +222 -0
  475. package/dist/sensor/readout-exposure-linkage.js.map +1 -0
  476. package/dist/sensor/readout-timing.d.ts +137 -0
  477. package/dist/sensor/readout-timing.d.ts.map +1 -0
  478. package/dist/sensor/readout-timing.js +243 -0
  479. package/dist/sensor/readout-timing.js.map +1 -0
  480. package/dist/sensor/response-application-compatibility.d.ts +136 -0
  481. package/dist/sensor/response-application-compatibility.d.ts.map +1 -0
  482. package/dist/sensor/response-application-compatibility.js +408 -0
  483. package/dist/sensor/response-application-compatibility.js.map +1 -0
  484. package/dist/sensor/response-operating-range.d.ts +173 -0
  485. package/dist/sensor/response-operating-range.d.ts.map +1 -0
  486. package/dist/sensor/response-operating-range.js +672 -0
  487. package/dist/sensor/response-operating-range.js.map +1 -0
  488. package/dist/sensor/responsivity-photocurrent.d.ts +158 -0
  489. package/dist/sensor/responsivity-photocurrent.d.ts.map +1 -0
  490. package/dist/sensor/responsivity-photocurrent.js +644 -0
  491. package/dist/sensor/responsivity-photocurrent.js.map +1 -0
  492. package/dist/sensor/sampling-aperture.d.ts +154 -0
  493. package/dist/sensor/sampling-aperture.d.ts.map +1 -0
  494. package/dist/sensor/sampling-aperture.js +388 -0
  495. package/dist/sensor/sampling-aperture.js.map +1 -0
  496. package/dist/sensor/scene-eqe-temporal-exposure.d.ts +45 -0
  497. package/dist/sensor/scene-eqe-temporal-exposure.d.ts.map +1 -0
  498. package/dist/sensor/scene-eqe-temporal-exposure.js +64 -0
  499. package/dist/sensor/scene-eqe-temporal-exposure.js.map +1 -0
  500. package/dist/sensor/sensor-geometry.d.ts +12 -0
  501. package/dist/sensor/sensor-geometry.d.ts.map +1 -1
  502. package/dist/sensor/sensor-geometry.js +12 -0
  503. package/dist/sensor/sensor-geometry.js.map +1 -1
  504. package/dist/sensor/signal-noise.d.ts +10 -0
  505. package/dist/sensor/signal-noise.d.ts.map +1 -1
  506. package/dist/sensor/signal-noise.js +10 -0
  507. package/dist/sensor/signal-noise.js.map +1 -1
  508. package/dist/sensor/spatial-sample-reduction.d.ts +171 -0
  509. package/dist/sensor/spatial-sample-reduction.d.ts.map +1 -0
  510. package/dist/sensor/spatial-sample-reduction.js +345 -0
  511. package/dist/sensor/spatial-sample-reduction.js.map +1 -0
  512. package/dist/sensor/spatial-sampling-quadrature.d.ts +179 -0
  513. package/dist/sensor/spatial-sampling-quadrature.d.ts.map +1 -0
  514. package/dist/sensor/spatial-sampling-quadrature.js +224 -0
  515. package/dist/sensor/spatial-sampling-quadrature.js.map +1 -0
  516. package/dist/sensor/spatio-spectral-reduction.d.ts +187 -0
  517. package/dist/sensor/spatio-spectral-reduction.d.ts.map +1 -0
  518. package/dist/sensor/spatio-spectral-reduction.js +373 -0
  519. package/dist/sensor/spatio-spectral-reduction.js.map +1 -0
  520. package/dist/sensor/spectral-coverage.d.ts +24 -0
  521. package/dist/sensor/spectral-coverage.d.ts.map +1 -0
  522. package/dist/sensor/spectral-coverage.js +86 -0
  523. package/dist/sensor/spectral-coverage.js.map +1 -0
  524. package/dist/sensor/spectral-quadrature.d.ts +169 -0
  525. package/dist/sensor/spectral-quadrature.d.ts.map +1 -0
  526. package/dist/sensor/spectral-quadrature.js +542 -0
  527. package/dist/sensor/spectral-quadrature.js.map +1 -0
  528. package/dist/sensor/spectral-response.d.ts +192 -0
  529. package/dist/sensor/spectral-response.d.ts.map +1 -0
  530. package/dist/sensor/spectral-response.js +664 -0
  531. package/dist/sensor/spectral-response.js.map +1 -0
  532. package/dist/sensor/temporal-eqe-sum.d.ts +15 -0
  533. package/dist/sensor/temporal-eqe-sum.d.ts.map +1 -0
  534. package/dist/sensor/temporal-eqe-sum.js +30 -0
  535. package/dist/sensor/temporal-eqe-sum.js.map +1 -0
  536. package/dist/sensor/temporal-photo-signal.d.ts +38 -0
  537. package/dist/sensor/temporal-photo-signal.d.ts.map +1 -0
  538. package/dist/sensor/temporal-photo-signal.js +110 -0
  539. package/dist/sensor/temporal-photo-signal.js.map +1 -0
  540. package/dist/sensor/temporal-sample-binding.d.ts +6 -0
  541. package/dist/sensor/temporal-sample-binding.d.ts.map +1 -0
  542. package/dist/sensor/temporal-sample-binding.js +32 -0
  543. package/dist/sensor/temporal-sample-binding.js.map +1 -0
  544. package/dist/simulation/poc-simulation.d.ts.map +1 -1
  545. package/dist/simulation/poc-simulation.js +34 -11
  546. package/dist/simulation/poc-simulation.js.map +1 -1
  547. package/dist/stabilization/camera-shake.d.ts +11 -0
  548. package/dist/stabilization/camera-shake.d.ts.map +1 -1
  549. package/dist/stabilization/camera-shake.js +11 -0
  550. package/dist/stabilization/camera-shake.js.map +1 -1
  551. package/dist/stabilization/system.d.ts +218 -0
  552. package/dist/stabilization/system.d.ts.map +1 -0
  553. package/dist/stabilization/system.js +695 -0
  554. package/dist/stabilization/system.js.map +1 -0
  555. package/docs/API_REFERENCE.md +2017 -0
  556. package/docs/API_STYLE.md +132 -0
  557. package/docs/ARCHITECTURE.md +150 -23
  558. package/docs/AUTOMATION_COORDINATION.md +190 -0
  559. package/docs/CAPTURE_COLOR.md +25 -0
  560. package/docs/CAPTURE_CORRECTED_SDR.md +25 -0
  561. package/docs/CAPTURE_EXPORT_METADATA.md +27 -0
  562. package/docs/CAPTURE_SDR.md +20 -0
  563. package/docs/DEVELOPERS.md +60 -0
  564. package/docs/DIGITAL_OPTICS_FOUNDATION.md +69 -0
  565. package/docs/ENVIRONMENT_RAW_CAPTURE.md +187 -0
  566. package/docs/EXPORT_ACCEPTANCE.md +133 -0
  567. package/docs/GENERIC_TIER_PRESETS.md +269 -0
  568. package/docs/GEOMETRIC_PREPARATION_REUSE.md +141 -0
  569. package/docs/IMAGE_FORMATION.md +105 -9
  570. package/docs/LINEAR_CAPTURE_ENCODING.md +25 -0
  571. package/docs/MOTION_AND_SIGNAL.md +145 -1
  572. package/docs/NUMERICAL_CORRECTNESS.md +191 -0
  573. package/docs/PERFORMANCE_BASELINE.md +56 -0
  574. package/docs/PHOTOGRAPHIC_EXPORT.md +206 -0
  575. package/docs/PHYSICS_FOUNDATION.md +152 -5
  576. package/docs/POC_API.md +2 -0
  577. package/docs/POC_PROJECTION_REUSE.md +124 -0
  578. package/docs/PROCESSED_OUTPUT.md +157 -0
  579. package/docs/PRODUCTION_COMPOSITION.md +373 -0
  580. package/docs/PRODUCTION_ENVIRONMENT_CAPTURE.md +131 -0
  581. package/docs/PROVENANCE.md +4 -0
  582. package/docs/PSF_FOUNDATION.md +110 -88
  583. package/docs/RAW_FRAME_ENVELOPE.md +56 -0
  584. package/docs/RAW_FRAME_RECONSTRUCTION.md +30 -0
  585. package/docs/RELEASE_1_0.md +65 -0
  586. package/docs/RELEASE_AUDIT.md +38 -0
  587. package/docs/SCENE_RADIANCE_AND_ILLUMINATION.md +298 -0
  588. package/docs/SCENE_SENSOR_QUADRATURE.md +98 -0
  589. package/docs/SCENE_SENSOR_TEMPORAL_EXPOSURE.md +86 -0
  590. package/docs/SCIENTIFIC_ASSURANCE.md +280 -0
  591. package/docs/SCIENTIFIC_CONFORMANCE.md +83 -0
  592. package/docs/SDR_RENDERING.md +33 -0
  593. package/docs/SENSOR_ENVIRONMENT_QUERY.md +86 -0
  594. package/docs/SENSOR_EQE_LOCAL_EXPOSURE.md +104 -0
  595. package/docs/SENSOR_EQE_TEMPORAL_EXPOSURE.md +74 -0
  596. package/docs/SENSOR_PSF_QUADRATURE.md +90 -0
  597. package/docs/SENSOR_RAW_FRAME.md +20 -0
  598. package/docs/SENSOR_RAW_PRODUCER.md +77 -0
  599. package/docs/SIGNAL_CONFORMANCE.md +23 -0
  600. package/docs/SIMULATED_CAPTURE.md +65 -0
  601. package/docs/STABILIZATION.md +160 -17
  602. package/docs/TEMPORAL_PHOTO_RAW.md +83 -0
  603. package/docs/TIER_ACCEPTANCE.md +129 -0
  604. package/docs/TIER_PRESET_ACCEPTANCE.md +59 -0
  605. package/docs/USAGE.md +5604 -331
  606. package/docs/V1_COMPOSITION_MAP.md +123 -0
  607. package/docs/V1_HELPER_REUSE_REVIEW.md +60 -0
  608. package/docs/V1_PERFORMANCE_DISPOSITION.md +88 -0
  609. package/docs/api/camera-equivalent-focal-length.md +53 -0
  610. package/docs/api/camera-field-of-view.md +119 -0
  611. package/docs/api/camera-projected-object-size.md +54 -0
  612. package/docs/api/capture-capture-export-metadata.md +107 -0
  613. package/docs/api/capture-environment-raw-producer.md +56 -0
  614. package/docs/api/capture-focus-control.md +419 -0
  615. package/docs/api/capture-linear-encoding.md +99 -0
  616. package/docs/api/capture-photographic-export.md +172 -0
  617. package/docs/api/capture-raw-frame-reconstruction.md +87 -0
  618. package/docs/api/capture-release-sequence.md +252 -0
  619. package/docs/api/capture-sensor-raw-frame.md +66 -0
  620. package/docs/api/capture-sensor-raw-producer.md +98 -0
  621. package/docs/api/capture-simulated-capture.md +179 -0
  622. package/docs/api/color-capture-color.md +122 -0
  623. package/docs/api/color-white-balance.md +386 -0
  624. package/docs/api/composition-image-formation-plan.md +825 -0
  625. package/docs/api/composition-plan-consumer.md +98 -0
  626. package/docs/api/core-calculation-result.md +220 -0
  627. package/docs/api/core-configuration-error.md +19 -0
  628. package/docs/api/core-image-formation.md +204 -0
  629. package/docs/api/core-scientific-assurance.md +214 -0
  630. package/docs/api/core-spectral-composition.md +268 -0
  631. package/docs/api/core-spectral.md +78 -0
  632. package/docs/api/core-validation.md +34 -0
  633. package/docs/api/core-version.md +14 -0
  634. package/docs/api/equipment-exposure-capabilities.md +270 -0
  635. package/docs/api/equipment-generic-tier-assets.md +82 -0
  636. package/docs/api/equipment-generic-tier-presets.md +103 -0
  637. package/docs/api/equipment-iso-capabilities.md +295 -0
  638. package/docs/api/equipment-metering-capabilities.md +126 -0
  639. package/docs/api/equipment-release-capabilities.md +91 -0
  640. package/docs/api/exports.json +5656 -0
  641. package/docs/api/exposure-exposure-duration-control.md +115 -0
  642. package/docs/api/exposure-exposure-mode-resolver.md +966 -0
  643. package/docs/api/exposure-exposure.md +150 -0
  644. package/docs/api/exposure-flash.md +327 -0
  645. package/docs/api/exposure-metering-scene-radiance.md +154 -0
  646. package/docs/api/exposure-metering-target.md +134 -0
  647. package/docs/api/exposure-metering-temporal.md +77 -0
  648. package/docs/api/exposure-metering.md +172 -0
  649. package/docs/api/exposure-program-line.md +64 -0
  650. package/docs/api/motion-camera-rotation.md +215 -0
  651. package/docs/api/motion-capture-rotation-inverse-mapping.md +128 -0
  652. package/docs/api/motion-capture-rotation-temporal-quadrature.md +127 -0
  653. package/docs/api/motion-capture-rotation-trajectory.md +132 -0
  654. package/docs/api/motion-capture-translation-parallax-temporal-quadrature.md +171 -0
  655. package/docs/api/motion-extended-object-projection.md +312 -0
  656. package/docs/api/motion-projected-motion.md +60 -0
  657. package/docs/api/optics-aperture.md +69 -0
  658. package/docs/api/optics-circle-of-confusion.md +46 -0
  659. package/docs/api/optics-complex-pupil-psf.md +193 -0
  660. package/docs/api/optics-depth-of-field.md +92 -0
  661. package/docs/api/optics-diffraction.md +46 -0
  662. package/docs/api/optics-focus-breathing.md +119 -0
  663. package/docs/api/optics-focus-state.md +64 -0
  664. package/docs/api/optics-front-of-lens-filter.md +263 -0
  665. package/docs/api/optics-illumination-vignetting.md +95 -0
  666. package/docs/api/optics-lateral-chromatic-aberration.md +225 -0
  667. package/docs/api/optics-lens-psf-profile.md +380 -0
  668. package/docs/api/optics-polygon-diffraction.md +68 -0
  669. package/docs/api/optics-profile-contract.md +47 -0
  670. package/docs/api/optics-psf-foundation.md +181 -0
  671. package/docs/api/optics-radial-distortion.md +194 -0
  672. package/docs/api/optics-scene-to-sensor-irradiance.md +371 -0
  673. package/docs/api/optics-scene-to-sensor-quadrature.md +78 -0
  674. package/docs/api/optics-sensor-environment-query.md +58 -0
  675. package/docs/api/optics-sensor-psf-quadrature.md +81 -0
  676. package/docs/api/optics-stray-light.md +109 -0
  677. package/docs/api/optics-thin-lens.md +53 -0
  678. package/docs/api/output-capture-corrected-sdr.md +71 -0
  679. package/docs/api/output-capture-geometry.md +500 -0
  680. package/docs/api/output-capture-sdr.md +69 -0
  681. package/docs/api/output-crop.md +47 -0
  682. package/docs/api/output-geometric-transforms.md +199 -0
  683. package/docs/api/output-lens-corrections.md +162 -0
  684. package/docs/api/output-sdr-rendering.md +122 -0
  685. package/docs/api/output-subject-framing-crop.md +59 -0
  686. package/docs/api/schema-camera.md +84 -0
  687. package/docs/api/schema-illumination-spectral.md +77 -0
  688. package/docs/api/schema-illumination-temporal.md +289 -0
  689. package/docs/api/schema-illumination.md +246 -0
  690. package/docs/api/schema-scene-radiance-temporal.md +215 -0
  691. package/docs/api/schema-scene-radiance.md +415 -0
  692. package/docs/api/schema-scene.md +105 -0
  693. package/docs/api/schema-validation.md +25 -0
  694. package/docs/api/sensor-accumulated-charge.md +273 -0
  695. package/docs/api/sensor-architecture.md +155 -0
  696. package/docs/api/sensor-camera-saturation-capacity.md +215 -0
  697. package/docs/api/sensor-capture-color-sampling-binding.md +323 -0
  698. package/docs/api/sensor-capture-mode-timing.md +123 -0
  699. package/docs/api/sensor-capture-mode.md +321 -0
  700. package/docs/api/sensor-color-sampling.md +228 -0
  701. package/docs/api/sensor-constant-rate-temporal-integration.md +152 -0
  702. package/docs/api/sensor-dark-current.md +227 -0
  703. package/docs/api/sensor-environment-photo-signal.md +77 -0
  704. package/docs/api/sensor-eqe-electron-rate.md +166 -0
  705. package/docs/api/sensor-eqe-local-exposure.md +68 -0
  706. package/docs/api/sensor-eqe-temporal-exposure.md +73 -0
  707. package/docs/api/sensor-exposure-window.md +183 -0
  708. package/docs/api/sensor-iso-signal-chain.md +264 -0
  709. package/docs/api/sensor-local-exposure-binding.md +126 -0
  710. package/docs/api/sensor-optical-stack.md +211 -0
  711. package/docs/api/sensor-photon-energy.md +149 -0
  712. package/docs/api/sensor-physical-charge-capacity.md +196 -0
  713. package/docs/api/sensor-pixel-pitch.md +41 -0
  714. package/docs/api/sensor-radiometry-readiness.md +240 -0
  715. package/docs/api/sensor-raw-readout.md +499 -0
  716. package/docs/api/sensor-raw-reconstruction.md +260 -0
  717. package/docs/api/sensor-readout-exposure-linkage.md +172 -0
  718. package/docs/api/sensor-readout-timing.md +209 -0
  719. package/docs/api/sensor-response-application-compatibility.md +256 -0
  720. package/docs/api/sensor-response-operating-range.md +293 -0
  721. package/docs/api/sensor-responsivity-photocurrent.md +245 -0
  722. package/docs/api/sensor-sampling-aperture.md +221 -0
  723. package/docs/api/sensor-scene-eqe-temporal-exposure.md +56 -0
  724. package/docs/api/sensor-sensor-geometry.md +143 -0
  725. package/docs/api/sensor-signal-noise.md +75 -0
  726. package/docs/api/sensor-spatial-sample-reduction.md +186 -0
  727. package/docs/api/sensor-spatial-sampling-quadrature.md +188 -0
  728. package/docs/api/sensor-spatio-spectral-reduction.md +217 -0
  729. package/docs/api/sensor-spectral-coverage.md +33 -0
  730. package/docs/api/sensor-spectral-quadrature.md +183 -0
  731. package/docs/api/sensor-spectral-response.md +291 -0
  732. package/docs/api/sensor-temporal-photo-signal.md +62 -0
  733. package/docs/api/simulation-poc-simulation.md +364 -0
  734. package/docs/api/stabilization-camera-shake.md +71 -0
  735. package/docs/api/stabilization-system.md +442 -0
  736. package/docs/benchmarks/2026-10-01-main-baseline.json +694 -0
  737. package/docs/benchmarks/2026-10-02-geometric-preparation-reuse.json +2190 -0
  738. package/docs/benchmarks/2026-10-02-poc-projection-reuse.json +2423 -0
  739. package/docs/benchmarks/2026-10-02-v1-environment-gc-profile.json +210 -0
  740. package/docs/benchmarks/2026-10-02-v1-environment-ordinary.json +187 -0
  741. package/docs/benchmarks/2026-10-02-v1-geometry-gc-profile.json +756 -0
  742. package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-1.json +711 -0
  743. package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-2.json +711 -0
  744. package/docs/benchmarks/2026-10-02-v1-poc-gc-profile.json +885 -0
  745. package/docs/benchmarks/2026-10-02-v1-poc-ordinary-1.json +868 -0
  746. package/docs/benchmarks/2026-10-02-v1-poc-ordinary-2.json +868 -0
  747. package/docs/examples/production-capture.mjs +34 -0
  748. package/docs/examples/production-request.json +4613 -0
  749. package/docs/examples/quick-start.mjs +12 -0
  750. package/docs/validation/documentation-fragments.json +212 -0
  751. package/docs/validation/release-audit-inventory.json +1306 -0
  752. package/docs/validation/tier-acceptance-report-v1.json +2538 -0
  753. package/package.json +18 -4
@@ -0,0 +1,1905 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Module boundary and integration notes.
4
+ * Resolves Manual exposure with either manual ISO or Auto ISO. Aperture and shutter are always
5
+ * caller-owned and are never changed. The relative meter target is normalized by an explicit reference
6
+ * exposure anchor; no ISO-100 or other hidden absolute calibration is assumed.
7
+ * Resolves Aperture Priority with manual ISO. Aperture and ISO remain caller-owned. Shutter is the
8
+ * only automatic axis. The target/reference relationship is the same relative exposure model used by
9
+ * Manual + Auto ISO; no new mode-specific exposure equation is introduced.
10
+ * @see docs/USAGE.md for equations, coordinate/unit conventions, blockers and support limits.
11
+ */
12
+ import { InvalidScientificInputError } from "../core/validation.js";
13
+ import { EXPOSURE_METER_TARGET_SCHEMA_VERSION } from "./metering-target.js";
14
+ import { parseExposureProgramLineProfile } from "./program-line.js";
15
+ export const EXPOSURE_MODE_RESOLVER_VERSION = "0.5.0";
16
+ function requireRecord(value, path) {
17
+ if (typeof value !== "object" ||
18
+ value === null ||
19
+ Array.isArray(value)) {
20
+ throw new InvalidScientificInputError(path + " must be an object.");
21
+ }
22
+ return value;
23
+ }
24
+ function requirePositiveFinite(value, path) {
25
+ if (typeof value !== "number" ||
26
+ !Number.isFinite(value) ||
27
+ value <= 0) {
28
+ throw new InvalidScientificInputError(path +
29
+ " must be finite and greater than zero.");
30
+ }
31
+ return value;
32
+ }
33
+ function settingEquals(left, right) {
34
+ const scale = Math.max(Math.abs(left), Math.abs(right), 1);
35
+ return (Math.abs(left - right) <=
36
+ Number.EPSILON * 32 * scale);
37
+ }
38
+ function validateSettingAgainstGrid(value, minimum, maximum, grid, path) {
39
+ if (value < minimum ||
40
+ value > maximum) {
41
+ throw new InvalidScientificInputError(path +
42
+ " lies outside the resolved equipment capability range.");
43
+ }
44
+ if (grid.kind ===
45
+ "discrete-values" &&
46
+ !grid.values.some((candidate) => settingEquals(candidate, value))) {
47
+ throw new InvalidScientificInputError(path +
48
+ " is not present in the resolved discrete equipment setting grid.");
49
+ }
50
+ }
51
+ function validateTarget(value) {
52
+ const record = requireRecord(value, "target");
53
+ if (record.schemaVersion !==
54
+ EXPOSURE_METER_TARGET_SCHEMA_VERSION) {
55
+ throw new InvalidScientificInputError('target.schemaVersion must be "' +
56
+ EXPOSURE_METER_TARGET_SCHEMA_VERSION +
57
+ '".');
58
+ }
59
+ if (record.scientificStatus !==
60
+ "approximation" ||
61
+ record.inputDomain !==
62
+ "relative-pre-exposure-linear-signal" ||
63
+ record.intendedConsumer !==
64
+ "exposure-mode-resolver" ||
65
+ record.automaticExposureResolved !==
66
+ false ||
67
+ record.sourceMeterSnapshotPreserved !==
68
+ true) {
69
+ throw new InvalidScientificInputError("target does not satisfy the exposure-mode resolver boundary.");
70
+ }
71
+ const targetId = record.targetId;
72
+ if (typeof targetId !== "string" ||
73
+ targetId.trim().length === 0) {
74
+ throw new InvalidScientificInputError("target.targetId must be a non-empty string.");
75
+ }
76
+ requireRecord(record.sourceMeterSnapshot, "target.sourceMeterSnapshot");
77
+ if (record.status === "resolved") {
78
+ requirePositiveFinite(record
79
+ .requiredExposureScaleToTarget, "target.requiredExposureScaleToTarget");
80
+ if (typeof record
81
+ .exposureOffsetStopsToTarget !==
82
+ "number" ||
83
+ !Number.isFinite(record
84
+ .exposureOffsetStopsToTarget)) {
85
+ throw new InvalidScientificInputError("target.exposureOffsetStopsToTarget must be finite.");
86
+ }
87
+ }
88
+ else if (record.status !== "no-signal") {
89
+ throw new InvalidScientificInputError("target.status is invalid.");
90
+ }
91
+ return value;
92
+ }
93
+ function requireNonEmptyString(value, path) {
94
+ if (typeof value !== "string" ||
95
+ value.trim().length === 0) {
96
+ throw new InvalidScientificInputError(path + " must be a non-empty string.");
97
+ }
98
+ return value.trim();
99
+ }
100
+ function validateResolvedGrid(grid, minimum, maximum, path) {
101
+ if (grid.kind ===
102
+ "continuous-within-range") {
103
+ return;
104
+ }
105
+ if (grid.kind !== "discrete-values" ||
106
+ !Array.isArray(grid.values) ||
107
+ grid.values.length === 0) {
108
+ throw new InvalidScientificInputError(path +
109
+ " must be a continuous grid or a non-empty discrete-values grid.");
110
+ }
111
+ let previous = Number.NEGATIVE_INFINITY;
112
+ for (let index = 0; index < grid.values.length; index += 1) {
113
+ const value = requirePositiveFinite(grid.values[index], path +
114
+ ".values[" +
115
+ index +
116
+ "]");
117
+ if (value <= previous) {
118
+ throw new InvalidScientificInputError(path +
119
+ ".values must be strictly increasing with no duplicates.");
120
+ }
121
+ if (value < minimum ||
122
+ value > maximum) {
123
+ throw new InvalidScientificInputError(path +
124
+ ".values must stay inside the resolved capability range.");
125
+ }
126
+ previous = value;
127
+ }
128
+ }
129
+ function validateCapabilities(value) {
130
+ if (value.schemaVersion !== "0.1.0" ||
131
+ value.scientificStatus !==
132
+ "approximation") {
133
+ throw new InvalidScientificInputError("capabilities do not satisfy the generic equipment exposure-capability boundary.");
134
+ }
135
+ requirePositiveFinite(value.selectedFocalLengthMm, "capabilities.selectedFocalLengthMm");
136
+ requirePositiveFinite(value.aperture
137
+ .widestAvailableFNumber, "capabilities.aperture.widestAvailableFNumber");
138
+ requirePositiveFinite(value.aperture
139
+ .narrowestAvailableFNumber, "capabilities.aperture.narrowestAvailableFNumber");
140
+ requirePositiveFinite(value.shutter.minimumSeconds, "capabilities.shutter.minimumSeconds");
141
+ requirePositiveFinite(value.shutter.maximumSeconds, "capabilities.shutter.maximumSeconds");
142
+ requirePositiveFinite(value.iso.minimum, "capabilities.iso.minimum");
143
+ requirePositiveFinite(value.iso.maximum, "capabilities.iso.maximum");
144
+ if (value.aperture
145
+ .widestAvailableFNumber >
146
+ value.aperture
147
+ .narrowestAvailableFNumber) {
148
+ throw new InvalidScientificInputError("capabilities aperture range is invalid.");
149
+ }
150
+ if (value.shutter.minimumSeconds >
151
+ value.shutter.maximumSeconds) {
152
+ throw new InvalidScientificInputError("capabilities shutter range is invalid.");
153
+ }
154
+ if (value.iso.minimum >
155
+ value.iso.maximum) {
156
+ throw new InvalidScientificInputError("capabilities ISO range is invalid.");
157
+ }
158
+ const hasAutoMinimum = value.iso.autoIsoMinimum !==
159
+ undefined;
160
+ const hasAutoMaximum = value.iso.autoIsoMaximum !==
161
+ undefined;
162
+ if (hasAutoMinimum !==
163
+ hasAutoMaximum) {
164
+ throw new InvalidScientificInputError("capabilities Auto ISO bounds must provide both minimum and maximum or neither.");
165
+ }
166
+ if (hasAutoMinimum &&
167
+ hasAutoMaximum) {
168
+ const autoMinimum = requirePositiveFinite(value.iso.autoIsoMinimum, "capabilities.iso.autoIsoMinimum");
169
+ const autoMaximum = requirePositiveFinite(value.iso.autoIsoMaximum, "capabilities.iso.autoIsoMaximum");
170
+ if (value.iso
171
+ .autoIsoAvailability !==
172
+ "supported" ||
173
+ autoMinimum >
174
+ autoMaximum ||
175
+ autoMinimum <
176
+ value.iso.minimum ||
177
+ autoMaximum >
178
+ value.iso.maximum) {
179
+ throw new InvalidScientificInputError("capabilities Auto ISO bounds must be ordered, inside the manual ISO range, and used only when Auto ISO is supported.");
180
+ }
181
+ }
182
+ requireNonEmptyString(value.bodyProfile.profileId, "capabilities.bodyProfile.profileId");
183
+ requireNonEmptyString(value.bodyProfile.profileVersion, "capabilities.bodyProfile.profileVersion");
184
+ requireNonEmptyString(value.lensProfile.profileId, "capabilities.lensProfile.profileId");
185
+ requireNonEmptyString(value.lensProfile.profileVersion, "capabilities.lensProfile.profileVersion");
186
+ if (value.iso
187
+ .autoIsoAvailability !==
188
+ "supported" &&
189
+ value.iso
190
+ .autoIsoAvailability !==
191
+ "unsupported" &&
192
+ value.iso
193
+ .autoIsoAvailability !==
194
+ "unknown") {
195
+ throw new InvalidScientificInputError("capabilities.iso.autoIsoAvailability is invalid.");
196
+ }
197
+ validateResolvedGrid(value.aperture.settingGrid, value.aperture
198
+ .widestAvailableFNumber, value.aperture
199
+ .narrowestAvailableFNumber, "capabilities.aperture.settingGrid");
200
+ validateResolvedGrid(value.shutter.settingGrid, value.shutter.minimumSeconds, value.shutter.maximumSeconds, "capabilities.shutter.settingGrid");
201
+ validateResolvedGrid(value.iso.settingGrid, value.iso.minimum, value.iso.maximum, "capabilities.iso.settingGrid");
202
+ }
203
+ function validateReferenceExposure(reference, capabilities) {
204
+ const aperture = requirePositiveFinite(reference.aperture, "referenceExposure.aperture");
205
+ const shutterSeconds = requirePositiveFinite(reference.shutterSeconds, "referenceExposure.shutterSeconds");
206
+ const iso = requirePositiveFinite(reference.iso, "referenceExposure.iso");
207
+ validateSettingAgainstGrid(aperture, capabilities.aperture
208
+ .widestAvailableFNumber, capabilities.aperture
209
+ .narrowestAvailableFNumber, capabilities.aperture
210
+ .settingGrid, "referenceExposure.aperture");
211
+ validateSettingAgainstGrid(shutterSeconds, capabilities.shutter
212
+ .minimumSeconds, capabilities.shutter
213
+ .maximumSeconds, capabilities.shutter
214
+ .settingGrid, "referenceExposure.shutterSeconds");
215
+ validateSettingAgainstGrid(iso, capabilities.iso.minimum, capabilities.iso.maximum, capabilities.iso.settingGrid, "referenceExposure.iso");
216
+ return {
217
+ aperture,
218
+ shutterSeconds,
219
+ iso
220
+ };
221
+ }
222
+ function opticalExposureFactor(aperture, shutterSeconds, reference) {
223
+ const current = shutterSeconds /
224
+ (aperture * aperture);
225
+ const referenceOptical = reference.shutterSeconds /
226
+ (reference.aperture *
227
+ reference.aperture);
228
+ const factor = current /
229
+ referenceOptical;
230
+ if (!Number.isFinite(factor) ||
231
+ factor <= 0) {
232
+ throw new InvalidScientificInputError("Optical exposure factor must remain finite and greater than zero.");
233
+ }
234
+ return factor;
235
+ }
236
+ function targetResidual(target, achievedScale, limitingConstraint) {
237
+ if (target.status ===
238
+ "no-signal") {
239
+ return {
240
+ status: "target-unresolved",
241
+ state: "target-unresolved",
242
+ reason: "no-signal-target"
243
+ };
244
+ }
245
+ const targetScale = target
246
+ .requiredExposureScaleToTarget;
247
+ const targetStops = target
248
+ .exposureOffsetStopsToTarget;
249
+ const achievedStops = Math.log2(achievedScale);
250
+ const residualStops = Math.log2(targetScale /
251
+ achievedScale);
252
+ if (!Number.isFinite(achievedStops) ||
253
+ !Number.isFinite(residualStops)) {
254
+ throw new InvalidScientificInputError("Exposure target residual must remain finite.");
255
+ }
256
+ const toleranceStops = 1e-12;
257
+ const state = Math.abs(residualStops) <=
258
+ toleranceStops
259
+ ? "matched"
260
+ : residualStops > 0
261
+ ? "under-target"
262
+ : "over-target";
263
+ return {
264
+ status: "resolved",
265
+ state,
266
+ targetExposureStops: targetStops,
267
+ achievedExposureStops: achievedStops,
268
+ residualStops,
269
+ limitingConstraint
270
+ };
271
+ }
272
+ function nearestDiscreteIso(idealIso, values) {
273
+ const first = values[0];
274
+ const last = values[values.length - 1];
275
+ if (idealIso < first) {
276
+ return {
277
+ iso: first,
278
+ quantized: true,
279
+ clamped: "minimum",
280
+ limitingConstraint: "iso-minimum"
281
+ };
282
+ }
283
+ if (idealIso > last) {
284
+ return {
285
+ iso: last,
286
+ quantized: true,
287
+ clamped: "maximum",
288
+ limitingConstraint: "iso-maximum"
289
+ };
290
+ }
291
+ let selected = first;
292
+ let selectedDistance = Math.abs(Math.log2(idealIso / first));
293
+ for (let index = 1; index < values.length; index += 1) {
294
+ const candidate = values[index];
295
+ const distance = Math.abs(Math.log2(idealIso /
296
+ candidate));
297
+ if (distance <
298
+ selectedDistance -
299
+ 1e-15 ||
300
+ (Math.abs(distance -
301
+ selectedDistance) <= 1e-15 &&
302
+ candidate < selected)) {
303
+ selected = candidate;
304
+ selectedDistance =
305
+ distance;
306
+ }
307
+ }
308
+ const quantized = !settingEquals(selected, idealIso);
309
+ return {
310
+ iso: selected,
311
+ quantized,
312
+ clamped: false,
313
+ limitingConstraint: quantized
314
+ ? "iso-grid-quantization"
315
+ : "none"
316
+ };
317
+ }
318
+ function autoIsoBounds(capabilities) {
319
+ return {
320
+ minimum: capabilities.iso
321
+ .autoIsoMinimum ??
322
+ capabilities.iso.minimum,
323
+ maximum: capabilities.iso
324
+ .autoIsoMaximum ??
325
+ capabilities.iso.maximum
326
+ };
327
+ }
328
+ function resolveAutomaticIso(idealIso, capabilities) {
329
+ const grid = capabilities.iso.settingGrid;
330
+ const bounds = autoIsoBounds(capabilities);
331
+ if (grid.kind ===
332
+ "discrete-values") {
333
+ const autoValues = grid.values.filter((value) => value >= bounds.minimum &&
334
+ value <= bounds.maximum);
335
+ if (autoValues.length === 0) {
336
+ throw new InvalidScientificInputError("Auto ISO bounds contain no selectable values from the resolved ISO grid.");
337
+ }
338
+ const discrete = nearestDiscreteIso(idealIso, autoValues);
339
+ return {
340
+ ...discrete,
341
+ kind: "discrete"
342
+ };
343
+ }
344
+ if (idealIso <
345
+ bounds.minimum) {
346
+ return {
347
+ iso: bounds.minimum,
348
+ kind: "continuous",
349
+ quantized: false,
350
+ clamped: "minimum",
351
+ limitingConstraint: "iso-minimum"
352
+ };
353
+ }
354
+ if (idealIso >
355
+ bounds.maximum) {
356
+ return {
357
+ iso: bounds.maximum,
358
+ kind: "continuous",
359
+ quantized: false,
360
+ clamped: "maximum",
361
+ limitingConstraint: "iso-maximum"
362
+ };
363
+ }
364
+ return {
365
+ iso: idealIso,
366
+ kind: "continuous",
367
+ quantized: false,
368
+ clamped: false,
369
+ limitingConstraint: "none"
370
+ };
371
+ }
372
+ function nearestDiscreteShutter(idealShutterSeconds, values) {
373
+ const first = values[0];
374
+ const last = values[values.length - 1];
375
+ if (idealShutterSeconds < first) {
376
+ return {
377
+ shutterSeconds: first,
378
+ quantized: true,
379
+ clamped: "minimum",
380
+ limitingConstraint: "shutter-minimum"
381
+ };
382
+ }
383
+ if (idealShutterSeconds > last) {
384
+ return {
385
+ shutterSeconds: last,
386
+ quantized: true,
387
+ clamped: "maximum",
388
+ limitingConstraint: "shutter-maximum"
389
+ };
390
+ }
391
+ let selected = first;
392
+ let selectedDistance = Math.abs(Math.log2(idealShutterSeconds /
393
+ first));
394
+ for (let index = 1; index < values.length; index += 1) {
395
+ const candidate = values[index];
396
+ const distance = Math.abs(Math.log2(idealShutterSeconds /
397
+ candidate));
398
+ if (distance <
399
+ selectedDistance -
400
+ 1e-15 ||
401
+ (Math.abs(distance -
402
+ selectedDistance) <= 1e-15 &&
403
+ candidate < selected)) {
404
+ selected = candidate;
405
+ selectedDistance =
406
+ distance;
407
+ }
408
+ }
409
+ const quantized = !settingEquals(selected, idealShutterSeconds);
410
+ return {
411
+ shutterSeconds: selected,
412
+ quantized,
413
+ clamped: false,
414
+ limitingConstraint: quantized
415
+ ? "shutter-grid-quantization"
416
+ : "none"
417
+ };
418
+ }
419
+ function resolveAutomaticShutter(idealShutterSeconds, capabilities) {
420
+ const grid = capabilities.shutter.settingGrid;
421
+ if (grid.kind ===
422
+ "discrete-values") {
423
+ const discrete = nearestDiscreteShutter(idealShutterSeconds, grid.values);
424
+ return {
425
+ ...discrete,
426
+ kind: "discrete"
427
+ };
428
+ }
429
+ if (idealShutterSeconds <
430
+ capabilities.shutter
431
+ .minimumSeconds) {
432
+ return {
433
+ shutterSeconds: capabilities.shutter
434
+ .minimumSeconds,
435
+ kind: "continuous",
436
+ quantized: false,
437
+ clamped: "minimum",
438
+ limitingConstraint: "shutter-minimum"
439
+ };
440
+ }
441
+ if (idealShutterSeconds >
442
+ capabilities.shutter
443
+ .maximumSeconds) {
444
+ return {
445
+ shutterSeconds: capabilities.shutter
446
+ .maximumSeconds,
447
+ kind: "continuous",
448
+ quantized: false,
449
+ clamped: "maximum",
450
+ limitingConstraint: "shutter-maximum"
451
+ };
452
+ }
453
+ return {
454
+ shutterSeconds: idealShutterSeconds,
455
+ kind: "continuous",
456
+ quantized: false,
457
+ clamped: false,
458
+ limitingConstraint: "none"
459
+ };
460
+ }
461
+ function minimumSelectableIso(capabilities) {
462
+ const grid = capabilities.iso.settingGrid;
463
+ const bounds = autoIsoBounds(capabilities);
464
+ if (grid.kind ===
465
+ "continuous-within-range") {
466
+ return bounds.minimum;
467
+ }
468
+ const first = grid.values.find((value) => value >= bounds.minimum &&
469
+ value <= bounds.maximum);
470
+ if (first === undefined) {
471
+ throw new InvalidScientificInputError("Auto ISO bounds contain no selectable values from the resolved ISO grid.");
472
+ }
473
+ return first;
474
+ }
475
+ function selectShutterNotLongerThanTarget(targetSeconds, capabilities) {
476
+ const minimum = capabilities.shutter.minimumSeconds;
477
+ const maximum = capabilities.shutter.maximumSeconds;
478
+ const grid = capabilities.shutter.settingGrid;
479
+ if (grid.kind === "continuous-within-range") {
480
+ if (targetSeconds < minimum) {
481
+ return {
482
+ shutterSeconds: minimum,
483
+ kind: "continuous",
484
+ quantized: false,
485
+ clamped: "minimum",
486
+ limitingConstraint: "shutter-minimum"
487
+ };
488
+ }
489
+ if (targetSeconds > maximum) {
490
+ return {
491
+ shutterSeconds: maximum,
492
+ kind: "continuous",
493
+ quantized: false,
494
+ clamped: "maximum",
495
+ limitingConstraint: "shutter-maximum"
496
+ };
497
+ }
498
+ return {
499
+ shutterSeconds: targetSeconds,
500
+ kind: "continuous",
501
+ quantized: false,
502
+ clamped: false,
503
+ limitingConstraint: "none"
504
+ };
505
+ }
506
+ const values = grid.values;
507
+ const first = values[0];
508
+ const last = values[values.length - 1];
509
+ if (targetSeconds < first) {
510
+ return {
511
+ shutterSeconds: first,
512
+ kind: "discrete",
513
+ quantized: true,
514
+ clamped: "minimum",
515
+ limitingConstraint: "shutter-minimum"
516
+ };
517
+ }
518
+ if (targetSeconds >= last) {
519
+ return {
520
+ shutterSeconds: targetSeconds > last
521
+ ? last
522
+ : targetSeconds,
523
+ kind: "discrete",
524
+ quantized: !settingEquals(targetSeconds, last),
525
+ clamped: targetSeconds > last
526
+ ? "maximum"
527
+ : false,
528
+ limitingConstraint: targetSeconds > last
529
+ ? "shutter-maximum"
530
+ : "none"
531
+ };
532
+ }
533
+ let selected = first;
534
+ for (const candidate of values) {
535
+ if (candidate > targetSeconds) {
536
+ break;
537
+ }
538
+ selected = candidate;
539
+ }
540
+ const quantized = !settingEquals(selected, targetSeconds);
541
+ return {
542
+ shutterSeconds: selected,
543
+ kind: "discrete",
544
+ quantized,
545
+ clamped: false,
546
+ limitingConstraint: quantized
547
+ ? "shutter-grid-quantization"
548
+ : "none"
549
+ };
550
+ }
551
+ function nearestDiscreteAperture(idealFNumber, values) {
552
+ const first = values[0];
553
+ const last = values[values.length - 1];
554
+ if (idealFNumber < first) {
555
+ return {
556
+ aperture: first,
557
+ quantized: true,
558
+ clamped: "widest",
559
+ limitingConstraint: "aperture-widest"
560
+ };
561
+ }
562
+ if (idealFNumber > last) {
563
+ return {
564
+ aperture: last,
565
+ quantized: true,
566
+ clamped: "narrowest",
567
+ limitingConstraint: "aperture-narrowest"
568
+ };
569
+ }
570
+ let selected = first;
571
+ let selectedDistance = Math.abs(Math.log2(idealFNumber /
572
+ first));
573
+ for (let index = 1; index < values.length; index += 1) {
574
+ const candidate = values[index];
575
+ const distance = Math.abs(Math.log2(idealFNumber /
576
+ candidate));
577
+ if (distance <
578
+ selectedDistance -
579
+ 1e-15 ||
580
+ (Math.abs(distance -
581
+ selectedDistance) <= 1e-15 &&
582
+ candidate > selected)) {
583
+ selected = candidate;
584
+ selectedDistance =
585
+ distance;
586
+ }
587
+ }
588
+ const quantized = !settingEquals(selected, idealFNumber);
589
+ return {
590
+ aperture: selected,
591
+ quantized,
592
+ clamped: false,
593
+ limitingConstraint: quantized
594
+ ? "aperture-grid-quantization"
595
+ : "none"
596
+ };
597
+ }
598
+ function resolveAutomaticAperture(idealFNumber, capabilities) {
599
+ const minimum = capabilities.aperture
600
+ .widestAvailableFNumber;
601
+ const maximum = capabilities.aperture
602
+ .narrowestAvailableFNumber;
603
+ const grid = capabilities.aperture.settingGrid;
604
+ if (grid.kind === "discrete-values") {
605
+ return {
606
+ ...nearestDiscreteAperture(idealFNumber, grid.values),
607
+ kind: "discrete"
608
+ };
609
+ }
610
+ if (idealFNumber < minimum) {
611
+ return {
612
+ aperture: minimum,
613
+ kind: "continuous",
614
+ quantized: false,
615
+ clamped: "widest",
616
+ limitingConstraint: "aperture-widest"
617
+ };
618
+ }
619
+ if (idealFNumber > maximum) {
620
+ return {
621
+ aperture: maximum,
622
+ kind: "continuous",
623
+ quantized: false,
624
+ clamped: "narrowest",
625
+ limitingConstraint: "aperture-narrowest"
626
+ };
627
+ }
628
+ return {
629
+ aperture: idealFNumber,
630
+ kind: "continuous",
631
+ quantized: false,
632
+ clamped: false,
633
+ limitingConstraint: "none"
634
+ };
635
+ }
636
+ function selectApertureNotWiderThanTarget(idealFNumber, capabilities) {
637
+ const minimum = capabilities.aperture
638
+ .widestAvailableFNumber;
639
+ const maximum = capabilities.aperture
640
+ .narrowestAvailableFNumber;
641
+ const grid = capabilities.aperture.settingGrid;
642
+ if (grid.kind === "continuous-within-range") {
643
+ if (idealFNumber < minimum) {
644
+ return {
645
+ aperture: minimum,
646
+ kind: "continuous",
647
+ quantized: false,
648
+ clamped: "widest",
649
+ limitingConstraint: "aperture-widest"
650
+ };
651
+ }
652
+ if (idealFNumber > maximum) {
653
+ return {
654
+ aperture: maximum,
655
+ kind: "continuous",
656
+ quantized: false,
657
+ clamped: "narrowest",
658
+ limitingConstraint: "aperture-narrowest"
659
+ };
660
+ }
661
+ return {
662
+ aperture: idealFNumber,
663
+ kind: "continuous",
664
+ quantized: false,
665
+ clamped: false,
666
+ limitingConstraint: "none"
667
+ };
668
+ }
669
+ const values = grid.values;
670
+ const first = values[0];
671
+ const last = values[values.length - 1];
672
+ if (idealFNumber <= first) {
673
+ return {
674
+ aperture: first,
675
+ kind: "discrete",
676
+ quantized: !settingEquals(idealFNumber, first),
677
+ clamped: idealFNumber < first
678
+ ? "widest"
679
+ : false,
680
+ limitingConstraint: idealFNumber < first
681
+ ? "aperture-widest"
682
+ : "none"
683
+ };
684
+ }
685
+ if (idealFNumber > last) {
686
+ return {
687
+ aperture: last,
688
+ kind: "discrete",
689
+ quantized: true,
690
+ clamped: "narrowest",
691
+ limitingConstraint: "aperture-narrowest"
692
+ };
693
+ }
694
+ const selected = values.find((candidate) => candidate >= idealFNumber) ?? last;
695
+ const quantized = !settingEquals(selected, idealFNumber);
696
+ return {
697
+ aperture: selected,
698
+ kind: "discrete",
699
+ quantized,
700
+ clamped: false,
701
+ limitingConstraint: quantized
702
+ ? "aperture-grid-quantization"
703
+ : "none"
704
+ };
705
+ }
706
+ function idealApertureForTarget(targetScale, shutterSeconds, iso, reference) {
707
+ const numerator = reference.aperture *
708
+ reference.aperture *
709
+ (shutterSeconds /
710
+ reference.shutterSeconds) *
711
+ (iso /
712
+ reference.iso);
713
+ const squared = numerator / targetScale;
714
+ const aperture = Math.sqrt(squared);
715
+ if (!Number.isFinite(aperture) ||
716
+ aperture <= 0) {
717
+ throw new InvalidScientificInputError("Ideal automatic aperture must remain finite and greater than zero.");
718
+ }
719
+ return aperture;
720
+ }
721
+ function validateProgramLineForResolution(value, referenceExposure, capabilities) {
722
+ const profile = parseExposureProgramLineProfile(value);
723
+ const toleranceStops = 1e-9;
724
+ for (const node of profile.nodes) {
725
+ if (node.aperture <
726
+ capabilities.aperture
727
+ .widestAvailableFNumber ||
728
+ node.aperture >
729
+ capabilities.aperture
730
+ .narrowestAvailableFNumber) {
731
+ throw new InvalidScientificInputError("Program-line aperture lies outside the resolved equipment capability range.");
732
+ }
733
+ if (node.shutterSeconds <
734
+ capabilities.shutter
735
+ .minimumSeconds ||
736
+ node.shutterSeconds >
737
+ capabilities.shutter
738
+ .maximumSeconds) {
739
+ throw new InvalidScientificInputError("Program-line shutter duration lies outside the resolved equipment capability range.");
740
+ }
741
+ const computedStops = Math.log2(opticalExposureFactor(node.aperture, node.shutterSeconds, referenceExposure));
742
+ if (!Number.isFinite(computedStops) ||
743
+ Math.abs(computedStops -
744
+ node
745
+ .opticalExposureStopsFromReference) > toleranceStops) {
746
+ throw new InvalidScientificInputError("Program-line node opticalExposureStopsFromReference is inconsistent with its aperture/shutter pair and the selected reference exposure.");
747
+ }
748
+ }
749
+ return profile;
750
+ }
751
+ function selectProgramLineSettings(requestedOpticalStops, profile, capabilities) {
752
+ if (!Number.isFinite(requestedOpticalStops)) {
753
+ throw new InvalidScientificInputError("Requested program-line optical exposure stops must be finite.");
754
+ }
755
+ const first = profile.nodes[0];
756
+ const last = profile.nodes[profile.nodes.length - 1];
757
+ let position;
758
+ let selectedStops;
759
+ let interpolationPhase;
760
+ let idealAperture;
761
+ let idealShutterSeconds;
762
+ if (requestedOpticalStops <=
763
+ first
764
+ .opticalExposureStopsFromReference) {
765
+ position =
766
+ requestedOpticalStops <
767
+ first
768
+ .opticalExposureStopsFromReference
769
+ ? "below-line"
770
+ : "within-line";
771
+ selectedStops =
772
+ first
773
+ .opticalExposureStopsFromReference;
774
+ interpolationPhase = null;
775
+ idealAperture = first.aperture;
776
+ idealShutterSeconds =
777
+ first.shutterSeconds;
778
+ }
779
+ else if (requestedOpticalStops >=
780
+ last
781
+ .opticalExposureStopsFromReference) {
782
+ position =
783
+ requestedOpticalStops >
784
+ last
785
+ .opticalExposureStopsFromReference
786
+ ? "above-line"
787
+ : "within-line";
788
+ selectedStops =
789
+ last
790
+ .opticalExposureStopsFromReference;
791
+ interpolationPhase = null;
792
+ idealAperture = last.aperture;
793
+ idealShutterSeconds =
794
+ last.shutterSeconds;
795
+ }
796
+ else {
797
+ position = "within-line";
798
+ let left = first;
799
+ let right = profile.nodes[1];
800
+ for (let index = 1; index < profile.nodes.length; index += 1) {
801
+ const candidate = profile.nodes[index];
802
+ if (requestedOpticalStops <=
803
+ candidate
804
+ .opticalExposureStopsFromReference) {
805
+ left =
806
+ profile.nodes[index - 1];
807
+ right = candidate;
808
+ break;
809
+ }
810
+ }
811
+ const span = right
812
+ .opticalExposureStopsFromReference -
813
+ left
814
+ .opticalExposureStopsFromReference;
815
+ const phase = (requestedOpticalStops -
816
+ left
817
+ .opticalExposureStopsFromReference) /
818
+ span;
819
+ interpolationPhase = phase;
820
+ selectedStops =
821
+ requestedOpticalStops;
822
+ const logAperture = Math.log2(left.aperture) +
823
+ phase *
824
+ (Math.log2(right.aperture) -
825
+ Math.log2(left.aperture));
826
+ const logShutter = Math.log2(left.shutterSeconds) +
827
+ phase *
828
+ (Math.log2(right.shutterSeconds) -
829
+ Math.log2(left.shutterSeconds));
830
+ idealAperture =
831
+ Math.pow(2, logAperture);
832
+ idealShutterSeconds =
833
+ Math.pow(2, logShutter);
834
+ }
835
+ const aperture = resolveAutomaticAperture(idealAperture, capabilities);
836
+ const shutter = resolveAutomaticShutter(idealShutterSeconds, capabilities);
837
+ return {
838
+ profileId: profile.profileId,
839
+ profileVersion: profile.profileVersion,
840
+ requestedOpticalExposureStopsFromReference: requestedOpticalStops,
841
+ selectedOpticalExposureStopsFromReference: selectedStops,
842
+ position,
843
+ interpolationPhase,
844
+ idealAperture,
845
+ idealShutterSeconds,
846
+ resolvedAperture: aperture.aperture,
847
+ resolvedShutterSeconds: shutter.shutterSeconds,
848
+ apertureQuantized: aperture.quantized,
849
+ shutterQuantized: shutter.quantized,
850
+ apertureClamped: aperture.clamped,
851
+ shutterClamped: shutter.clamped
852
+ };
853
+ }
854
+ function programLineResidualConstraint(selection) {
855
+ if (selection.apertureClamped ===
856
+ "widest") {
857
+ return "aperture-widest";
858
+ }
859
+ if (selection.apertureClamped ===
860
+ "narrowest") {
861
+ return "aperture-narrowest";
862
+ }
863
+ if (selection.shutterClamped ===
864
+ "minimum") {
865
+ return "shutter-minimum";
866
+ }
867
+ if (selection.shutterClamped ===
868
+ "maximum") {
869
+ return "shutter-maximum";
870
+ }
871
+ if (selection.apertureQuantized) {
872
+ return "aperture-grid-quantization";
873
+ }
874
+ if (selection.shutterQuantized) {
875
+ return "shutter-grid-quantization";
876
+ }
877
+ return "none";
878
+ }
879
+ /**
880
+ * Resolves Manual exposure with either manual ISO or Auto ISO.
881
+ *
882
+ * Aperture and shutter are always caller-owned and are never changed.
883
+ * The relative meter target is normalized by an explicit reference exposure
884
+ * anchor; no ISO-100 or other hidden absolute calibration is assumed.
885
+ */
886
+ export function resolveManualExposureMode(input) {
887
+ const target = validateTarget(input.target);
888
+ validateCapabilities(input.capabilities);
889
+ const referenceExposure = validateReferenceExposure(input.referenceExposure, input.capabilities);
890
+ const manualAperture = requirePositiveFinite(input.manualAperture, "manualAperture");
891
+ const manualShutterSeconds = requirePositiveFinite(input.manualShutterSeconds, "manualShutterSeconds");
892
+ validateSettingAgainstGrid(manualAperture, input.capabilities.aperture
893
+ .widestAvailableFNumber, input.capabilities.aperture
894
+ .narrowestAvailableFNumber, input.capabilities.aperture
895
+ .settingGrid, "manualAperture");
896
+ validateSettingAgainstGrid(manualShutterSeconds, input.capabilities.shutter
897
+ .minimumSeconds, input.capabilities.shutter
898
+ .maximumSeconds, input.capabilities.shutter
899
+ .settingGrid, "manualShutterSeconds");
900
+ const base = {
901
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
902
+ mode: "manual",
903
+ axisOwnership: {
904
+ aperture: "manual",
905
+ shutter: "manual",
906
+ iso: input.isoControl.kind ===
907
+ "manual"
908
+ ? "manual"
909
+ : "automatic"
910
+ },
911
+ targetId: target.targetId,
912
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
913
+ capabilityProfiles: {
914
+ bodyProfileId: input.capabilities
915
+ .bodyProfile.profileId,
916
+ bodyProfileVersion: input.capabilities
917
+ .bodyProfile.profileVersion,
918
+ lensProfileId: input.capabilities
919
+ .lensProfile.profileId,
920
+ lensProfileVersion: input.capabilities
921
+ .lensProfile.profileVersion
922
+ },
923
+ selectedFocalLengthMm: input.capabilities
924
+ .selectedFocalLengthMm,
925
+ referenceExposure,
926
+ manualAperture,
927
+ manualShutterSeconds,
928
+ apertureMutatedByResolver: false,
929
+ shutterMutatedByResolver: false,
930
+ exposureCompensationAppliedByResolver: false,
931
+ meterRecomputedByResolver: false,
932
+ isoNoiseOrGainTopologyInferred: false,
933
+ flashPolicyApplied: false,
934
+ safetyShiftApplied: false
935
+ };
936
+ const opticalFactor = opticalExposureFactor(manualAperture, manualShutterSeconds, referenceExposure);
937
+ if (input.isoControl.kind !==
938
+ "manual" &&
939
+ input.isoControl.kind !==
940
+ "automatic") {
941
+ throw new InvalidScientificInputError("isoControl.kind is invalid.");
942
+ }
943
+ if (input.isoControl.kind ===
944
+ "automatic" &&
945
+ input.isoControl
946
+ .quantizationPolicy !==
947
+ "nearest-log2-lower-on-tie") {
948
+ throw new InvalidScientificInputError('isoControl.quantizationPolicy must be "nearest-log2-lower-on-tie".');
949
+ }
950
+ if (input.isoControl.kind ===
951
+ "manual") {
952
+ const manualIso = requirePositiveFinite(input.isoControl.iso, "isoControl.iso");
953
+ validateSettingAgainstGrid(manualIso, input.capabilities.iso.minimum, input.capabilities.iso.maximum, input.capabilities.iso.settingGrid, "isoControl.iso");
954
+ const achievedScale = opticalFactor *
955
+ (manualIso /
956
+ referenceExposure.iso);
957
+ return {
958
+ ...base,
959
+ status: "resolved",
960
+ isoControl: "manual",
961
+ resolvedSettings: {
962
+ aperture: manualAperture,
963
+ shutterSeconds: manualShutterSeconds,
964
+ iso: manualIso
965
+ },
966
+ idealIsoBeforeConstraints: null,
967
+ isoResolution: {
968
+ kind: "manual-preserved",
969
+ quantized: false,
970
+ clamped: false
971
+ },
972
+ targetResidual: targetResidual(target, achievedScale, "none")
973
+ };
974
+ }
975
+ const availability = input.capabilities.iso
976
+ .autoIsoAvailability;
977
+ if (availability !== "supported") {
978
+ return {
979
+ ...base,
980
+ status: "blocked",
981
+ isoControl: "automatic",
982
+ resolvedSettings: {
983
+ aperture: manualAperture,
984
+ shutterSeconds: manualShutterSeconds
985
+ },
986
+ idealIsoBeforeConstraints: null,
987
+ blocker: availability ===
988
+ "unknown"
989
+ ? "auto-iso-unknown"
990
+ : "auto-iso-unsupported",
991
+ targetResidual: {
992
+ status: "target-unresolved",
993
+ state: "target-unresolved",
994
+ reason: "auto-iso-unavailable"
995
+ }
996
+ };
997
+ }
998
+ if (target.status === "no-signal") {
999
+ return {
1000
+ ...base,
1001
+ status: "blocked",
1002
+ isoControl: "automatic",
1003
+ resolvedSettings: {
1004
+ aperture: manualAperture,
1005
+ shutterSeconds: manualShutterSeconds
1006
+ },
1007
+ idealIsoBeforeConstraints: null,
1008
+ blocker: "target-no-signal",
1009
+ targetResidual: {
1010
+ status: "target-unresolved",
1011
+ state: "target-unresolved",
1012
+ reason: "no-signal-target"
1013
+ }
1014
+ };
1015
+ }
1016
+ const idealIso = referenceExposure.iso *
1017
+ (target
1018
+ .requiredExposureScaleToTarget /
1019
+ opticalFactor);
1020
+ if (!Number.isFinite(idealIso) ||
1021
+ idealIso <= 0) {
1022
+ throw new InvalidScientificInputError("Ideal Auto ISO must remain finite and greater than zero.");
1023
+ }
1024
+ const automatic = resolveAutomaticIso(idealIso, input.capabilities);
1025
+ const achievedScale = opticalFactor *
1026
+ (automatic.iso /
1027
+ referenceExposure.iso);
1028
+ const residual = targetResidual(target, achievedScale, automatic
1029
+ .limitingConstraint);
1030
+ return {
1031
+ ...base,
1032
+ status: "resolved",
1033
+ isoControl: "automatic",
1034
+ resolvedSettings: {
1035
+ aperture: manualAperture,
1036
+ shutterSeconds: manualShutterSeconds,
1037
+ iso: automatic.iso
1038
+ },
1039
+ idealIsoBeforeConstraints: idealIso,
1040
+ isoResolution: {
1041
+ kind: automatic.kind,
1042
+ quantizationPolicy: input.isoControl
1043
+ .quantizationPolicy,
1044
+ quantized: automatic.quantized,
1045
+ clamped: automatic.clamped
1046
+ },
1047
+ targetResidual: residual
1048
+ };
1049
+ }
1050
+ /**
1051
+ * Resolves Aperture Priority with manual ISO.
1052
+ *
1053
+ * Aperture and ISO remain caller-owned. Shutter is the only automatic axis.
1054
+ * The target/reference relationship is the same relative exposure model used
1055
+ * by Manual + Auto ISO; no new mode-specific exposure equation is introduced.
1056
+ */
1057
+ export function resolveAperturePriorityExposureMode(input) {
1058
+ const target = validateTarget(input.target);
1059
+ validateCapabilities(input.capabilities);
1060
+ const referenceExposure = validateReferenceExposure(input.referenceExposure, input.capabilities);
1061
+ const manualAperture = requirePositiveFinite(input.manualAperture, "manualAperture");
1062
+ const manualIso = requirePositiveFinite(input.manualIso, "manualIso");
1063
+ validateSettingAgainstGrid(manualAperture, input.capabilities.aperture
1064
+ .widestAvailableFNumber, input.capabilities.aperture
1065
+ .narrowestAvailableFNumber, input.capabilities.aperture
1066
+ .settingGrid, "manualAperture");
1067
+ validateSettingAgainstGrid(manualIso, input.capabilities.iso.minimum, input.capabilities.iso.maximum, input.capabilities.iso.settingGrid, "manualIso");
1068
+ if (input.shutterQuantizationPolicy !==
1069
+ "nearest-log2-shorter-on-tie") {
1070
+ throw new InvalidScientificInputError('shutterQuantizationPolicy must be "nearest-log2-shorter-on-tie".');
1071
+ }
1072
+ const base = {
1073
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1074
+ mode: "aperture-priority",
1075
+ axisOwnership: {
1076
+ aperture: "manual",
1077
+ shutter: "automatic",
1078
+ iso: "manual"
1079
+ },
1080
+ targetId: target.targetId,
1081
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1082
+ capabilityProfiles: {
1083
+ bodyProfileId: input.capabilities
1084
+ .bodyProfile.profileId,
1085
+ bodyProfileVersion: input.capabilities
1086
+ .bodyProfile.profileVersion,
1087
+ lensProfileId: input.capabilities
1088
+ .lensProfile.profileId,
1089
+ lensProfileVersion: input.capabilities
1090
+ .lensProfile.profileVersion
1091
+ },
1092
+ selectedFocalLengthMm: input.capabilities
1093
+ .selectedFocalLengthMm,
1094
+ referenceExposure,
1095
+ manualAperture,
1096
+ manualIso,
1097
+ apertureMutatedByResolver: false,
1098
+ isoMutatedByResolver: false,
1099
+ shutterResolvedByResolver: true,
1100
+ exposureCompensationAppliedByResolver: false,
1101
+ meterRecomputedByResolver: false,
1102
+ isoNoiseOrGainTopologyInferred: false,
1103
+ flashPolicyApplied: false,
1104
+ safetyShiftApplied: false
1105
+ };
1106
+ if (target.status === "no-signal") {
1107
+ return {
1108
+ ...base,
1109
+ status: "blocked",
1110
+ resolvedSettings: {
1111
+ aperture: manualAperture,
1112
+ iso: manualIso
1113
+ },
1114
+ idealShutterSecondsBeforeConstraints: null,
1115
+ blocker: "target-no-signal",
1116
+ targetResidual: {
1117
+ status: "target-unresolved",
1118
+ state: "target-unresolved",
1119
+ reason: "no-signal-target"
1120
+ }
1121
+ };
1122
+ }
1123
+ const fixedAxisFactorAtReferenceShutter = opticalExposureFactor(manualAperture, referenceExposure
1124
+ .shutterSeconds, referenceExposure) *
1125
+ (manualIso /
1126
+ referenceExposure.iso);
1127
+ if (!Number.isFinite(fixedAxisFactorAtReferenceShutter) ||
1128
+ fixedAxisFactorAtReferenceShutter <= 0) {
1129
+ throw new InvalidScientificInputError("Aperture Priority fixed-axis exposure factor must remain finite and greater than zero.");
1130
+ }
1131
+ const idealShutterSeconds = referenceExposure
1132
+ .shutterSeconds *
1133
+ (target
1134
+ .requiredExposureScaleToTarget /
1135
+ fixedAxisFactorAtReferenceShutter);
1136
+ if (!Number.isFinite(idealShutterSeconds) ||
1137
+ idealShutterSeconds <= 0) {
1138
+ throw new InvalidScientificInputError("Ideal automatic shutter duration must remain finite and greater than zero.");
1139
+ }
1140
+ const automatic = resolveAutomaticShutter(idealShutterSeconds, input.capabilities);
1141
+ const achievedScale = opticalExposureFactor(manualAperture, automatic.shutterSeconds, referenceExposure) *
1142
+ (manualIso /
1143
+ referenceExposure.iso);
1144
+ const residual = targetResidual(target, achievedScale, automatic
1145
+ .limitingConstraint);
1146
+ return {
1147
+ ...base,
1148
+ status: "resolved",
1149
+ resolvedSettings: {
1150
+ aperture: manualAperture,
1151
+ shutterSeconds: automatic.shutterSeconds,
1152
+ iso: manualIso
1153
+ },
1154
+ idealShutterSecondsBeforeConstraints: idealShutterSeconds,
1155
+ shutterResolution: {
1156
+ kind: automatic.kind,
1157
+ quantizationPolicy: input
1158
+ .shutterQuantizationPolicy,
1159
+ quantized: automatic.quantized,
1160
+ clamped: automatic.clamped
1161
+ },
1162
+ targetResidual: residual
1163
+ };
1164
+ }
1165
+ function validateAutoIsoAvailability(capabilities) {
1166
+ return capabilities.iso.autoIsoAvailability;
1167
+ }
1168
+ function buildPriorityAutoIsoBlocked(mode, target, referenceExposure, reason, resolvedSettings) {
1169
+ return {
1170
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1171
+ mode,
1172
+ status: "blocked",
1173
+ targetId: target.targetId,
1174
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1175
+ referenceExposure,
1176
+ resolvedSettings,
1177
+ blocker: reason,
1178
+ targetResidual: {
1179
+ status: "target-unresolved",
1180
+ state: "target-unresolved",
1181
+ reason: reason === "target-no-signal"
1182
+ ? "no-signal-target"
1183
+ : "auto-iso-unavailable"
1184
+ }
1185
+ };
1186
+ }
1187
+ /**
1188
+ * Hold aperture fixed, follow the declared minimum-shutter policy and use bounded Auto ISO to absorb
1189
+ * remaining target residual.
1190
+ *
1191
+ * Exposure modes apply control policy to one shared relative exposure equation and an explicit
1192
+ * reference anchor. Compensation is already included in the immutable meter target. Manual axes remain
1193
+ * unchanged; automatic axes use declared setting grids and expose signed residual stops and limit
1194
+ * diagnostics. A zero-signal target cannot authorize an invented exposure.
1195
+ * @param input - ResolveAperturePriorityAutoIsoExposureModeInput. See the linked contract for coordinate, unit and profile binding semantics.
1196
+ * @returns AperturePriorityAutoIsoExposureModeResolution. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
1197
+ *
1198
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
1199
+ */
1200
+ export function resolveAperturePriorityAutoIsoExposureMode(input) {
1201
+ const target = validateTarget(input.target);
1202
+ validateCapabilities(input.capabilities);
1203
+ const referenceExposure = validateReferenceExposure(input.referenceExposure, input.capabilities);
1204
+ const manualAperture = requirePositiveFinite(input.manualAperture, "manualAperture");
1205
+ validateSettingAgainstGrid(manualAperture, input.capabilities.aperture
1206
+ .widestAvailableFNumber, input.capabilities.aperture
1207
+ .narrowestAvailableFNumber, input.capabilities.aperture
1208
+ .settingGrid, "manualAperture");
1209
+ const policy = input.policy;
1210
+ if (policy.kind !==
1211
+ "minimum-iso-until-slowest-preferred-shutter" ||
1212
+ policy.isoBaseline !==
1213
+ "minimum-selectable" ||
1214
+ policy.isoQuantizationPolicy !==
1215
+ "nearest-log2-lower-on-tie" ||
1216
+ policy.shutterSelectionPolicy !==
1217
+ "not-longer-than-target" ||
1218
+ (policy.afterMaximumIso !==
1219
+ "allow-slower-shutter" &&
1220
+ policy.afterMaximumIso !==
1221
+ "hold-preferred-shutter")) {
1222
+ throw new InvalidScientificInputError("Aperture Priority Auto ISO policy is invalid.");
1223
+ }
1224
+ const slowestPreferred = requirePositiveFinite(policy.slowestPreferredShutterSeconds, "policy.slowestPreferredShutterSeconds");
1225
+ if (slowestPreferred <
1226
+ input.capabilities.shutter
1227
+ .minimumSeconds ||
1228
+ slowestPreferred >
1229
+ input.capabilities.shutter
1230
+ .maximumSeconds) {
1231
+ throw new InvalidScientificInputError("policy.slowestPreferredShutterSeconds lies outside the resolved shutter capability range.");
1232
+ }
1233
+ const availability = validateAutoIsoAvailability(input.capabilities);
1234
+ const commonBlocked = (blocker) => {
1235
+ const raw = buildPriorityAutoIsoBlocked("aperture-priority", target, referenceExposure, blocker, { aperture: manualAperture });
1236
+ return {
1237
+ ...raw,
1238
+ axisOwnership: {
1239
+ aperture: "manual",
1240
+ shutter: "automatic",
1241
+ iso: "automatic"
1242
+ },
1243
+ manualAperture,
1244
+ policy,
1245
+ apertureMutatedByResolver: false,
1246
+ exposureCompensationAppliedByResolver: false,
1247
+ meterRecomputedByResolver: false,
1248
+ flashPolicyApplied: false,
1249
+ safetyShiftApplied: false
1250
+ };
1251
+ };
1252
+ if (availability !== "supported") {
1253
+ return commonBlocked(availability === "unknown"
1254
+ ? "auto-iso-unknown"
1255
+ : "auto-iso-unsupported");
1256
+ }
1257
+ if (target.status === "no-signal") {
1258
+ return commonBlocked("target-no-signal");
1259
+ }
1260
+ const baselineIso = minimumSelectableIso(input.capabilities);
1261
+ const factorAtReferenceShutter = opticalExposureFactor(manualAperture, referenceExposure
1262
+ .shutterSeconds, referenceExposure) *
1263
+ (baselineIso /
1264
+ referenceExposure.iso);
1265
+ const idealAtBaseline = referenceExposure
1266
+ .shutterSeconds *
1267
+ (target
1268
+ .requiredExposureScaleToTarget /
1269
+ factorAtReferenceShutter);
1270
+ if (!Number.isFinite(idealAtBaseline) ||
1271
+ idealAtBaseline <= 0) {
1272
+ throw new InvalidScientificInputError("Ideal Aperture Priority shutter duration at baseline ISO must remain finite and greater than zero.");
1273
+ }
1274
+ const desiredPreferred = Math.min(idealAtBaseline, slowestPreferred);
1275
+ let shutter = selectShutterNotLongerThanTarget(desiredPreferred, input.capabilities);
1276
+ const isoPass = resolveManualExposureMode({
1277
+ target,
1278
+ capabilities: input.capabilities,
1279
+ referenceExposure,
1280
+ manualAperture,
1281
+ manualShutterSeconds: shutter.shutterSeconds,
1282
+ isoControl: {
1283
+ kind: "automatic",
1284
+ quantizationPolicy: policy.isoQuantizationPolicy
1285
+ }
1286
+ });
1287
+ if (isoPass.status !== "resolved" ||
1288
+ isoPass.isoControl !== "automatic") {
1289
+ throw new InvalidScientificInputError("Aperture Priority Auto ISO could not resolve its ISO pass.");
1290
+ }
1291
+ let fallbackUsed = false;
1292
+ let shutterSelectionPolicy = "not-longer-than-target";
1293
+ if (isoPass.isoResolution.clamped ===
1294
+ "maximum" &&
1295
+ isoPass.targetResidual.state ===
1296
+ "under-target" &&
1297
+ policy.afterMaximumIso ===
1298
+ "allow-slower-shutter") {
1299
+ const maxIso = isoPass.resolvedSettings.iso;
1300
+ const fixedAtReference = opticalExposureFactor(manualAperture, referenceExposure
1301
+ .shutterSeconds, referenceExposure) *
1302
+ (maxIso /
1303
+ referenceExposure.iso);
1304
+ const fallbackIdeal = referenceExposure
1305
+ .shutterSeconds *
1306
+ (target
1307
+ .requiredExposureScaleToTarget /
1308
+ fixedAtReference);
1309
+ shutter =
1310
+ resolveAutomaticShutter(fallbackIdeal, input.capabilities);
1311
+ fallbackUsed = true;
1312
+ shutterSelectionPolicy =
1313
+ "nearest-log2-shorter-on-tie";
1314
+ const achievedScale = opticalExposureFactor(manualAperture, shutter.shutterSeconds, referenceExposure) *
1315
+ (maxIso /
1316
+ referenceExposure.iso);
1317
+ const residual = targetResidual(target, achievedScale, shutter.limitingConstraint);
1318
+ return {
1319
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1320
+ mode: "aperture-priority",
1321
+ status: "resolved",
1322
+ axisOwnership: {
1323
+ aperture: "manual",
1324
+ shutter: "automatic",
1325
+ iso: "automatic"
1326
+ },
1327
+ targetId: target.targetId,
1328
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1329
+ referenceExposure,
1330
+ manualAperture,
1331
+ policy,
1332
+ baselineIso,
1333
+ idealShutterAtBaselineIsoSeconds: idealAtBaseline,
1334
+ preferredShutterSeconds: desiredPreferred,
1335
+ afterMaximumIsoFallbackUsed: fallbackUsed,
1336
+ resolvedSettings: {
1337
+ aperture: manualAperture,
1338
+ shutterSeconds: shutter.shutterSeconds,
1339
+ iso: maxIso
1340
+ },
1341
+ shutterResolution: {
1342
+ kind: shutter.kind,
1343
+ quantized: shutter.quantized,
1344
+ clamped: shutter.clamped,
1345
+ selectionPolicy: shutterSelectionPolicy
1346
+ },
1347
+ idealIsoBeforeConstraints: isoPass
1348
+ .idealIsoBeforeConstraints,
1349
+ isoResolution: isoPass.isoResolution,
1350
+ targetResidual: residual,
1351
+ apertureMutatedByResolver: false,
1352
+ shutterResolvedByResolver: true,
1353
+ isoResolvedByResolver: true,
1354
+ exposureCompensationAppliedByResolver: false,
1355
+ meterRecomputedByResolver: false,
1356
+ flashPolicyApplied: false,
1357
+ safetyShiftApplied: false
1358
+ };
1359
+ }
1360
+ return {
1361
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1362
+ mode: "aperture-priority",
1363
+ status: "resolved",
1364
+ axisOwnership: {
1365
+ aperture: "manual",
1366
+ shutter: "automatic",
1367
+ iso: "automatic"
1368
+ },
1369
+ targetId: target.targetId,
1370
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1371
+ referenceExposure,
1372
+ manualAperture,
1373
+ policy,
1374
+ baselineIso,
1375
+ idealShutterAtBaselineIsoSeconds: idealAtBaseline,
1376
+ preferredShutterSeconds: desiredPreferred,
1377
+ afterMaximumIsoFallbackUsed: fallbackUsed,
1378
+ resolvedSettings: isoPass.resolvedSettings,
1379
+ shutterResolution: {
1380
+ kind: shutter.kind,
1381
+ quantized: shutter.quantized,
1382
+ clamped: shutter.clamped,
1383
+ selectionPolicy: shutterSelectionPolicy
1384
+ },
1385
+ idealIsoBeforeConstraints: isoPass
1386
+ .idealIsoBeforeConstraints,
1387
+ isoResolution: isoPass.isoResolution,
1388
+ targetResidual: isoPass.targetResidual,
1389
+ apertureMutatedByResolver: false,
1390
+ shutterResolvedByResolver: true,
1391
+ isoResolvedByResolver: true,
1392
+ exposureCompensationAppliedByResolver: false,
1393
+ meterRecomputedByResolver: false,
1394
+ flashPolicyApplied: false,
1395
+ safetyShiftApplied: false
1396
+ };
1397
+ }
1398
+ /**
1399
+ * Hold shutter fixed and resolve aperture plus optional Auto ISO against the exact capability
1400
+ * envelope.
1401
+ *
1402
+ * Exposure modes apply control policy to one shared relative exposure equation and an explicit
1403
+ * reference anchor. Compensation is already included in the immutable meter target. Manual axes remain
1404
+ * unchanged; automatic axes use declared setting grids and expose signed residual stops and limit
1405
+ * diagnostics. A zero-signal target cannot authorize an invented exposure.
1406
+ * @param input - ResolveShutterPriorityExposureModeInput. See the linked contract for coordinate, unit and profile binding semantics.
1407
+ * @returns ShutterPriorityExposureModeResolution. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
1408
+ *
1409
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
1410
+ */
1411
+ export function resolveShutterPriorityExposureMode(input) {
1412
+ const target = validateTarget(input.target);
1413
+ validateCapabilities(input.capabilities);
1414
+ const referenceExposure = validateReferenceExposure(input.referenceExposure, input.capabilities);
1415
+ const manualShutterSeconds = requirePositiveFinite(input.manualShutterSeconds, "manualShutterSeconds");
1416
+ validateSettingAgainstGrid(manualShutterSeconds, input.capabilities.shutter
1417
+ .minimumSeconds, input.capabilities.shutter
1418
+ .maximumSeconds, input.capabilities.shutter
1419
+ .settingGrid, "manualShutterSeconds");
1420
+ const base = {
1421
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1422
+ mode: "shutter-priority",
1423
+ targetId: target.targetId,
1424
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1425
+ referenceExposure,
1426
+ manualShutterSeconds,
1427
+ shutterMutatedByResolver: false,
1428
+ apertureResolvedByResolver: true,
1429
+ exposureCompensationAppliedByResolver: false,
1430
+ meterRecomputedByResolver: false,
1431
+ flashPolicyApplied: false,
1432
+ safetyShiftApplied: false
1433
+ };
1434
+ if (input.isoControl.kind === "manual") {
1435
+ const manualIso = requirePositiveFinite(input.isoControl.iso, "isoControl.iso");
1436
+ validateSettingAgainstGrid(manualIso, input.capabilities.iso.minimum, input.capabilities.iso.maximum, input.capabilities.iso.settingGrid, "isoControl.iso");
1437
+ if (input.isoControl
1438
+ .apertureQuantizationPolicy !==
1439
+ "nearest-log2-narrower-on-tie") {
1440
+ throw new InvalidScientificInputError('isoControl.apertureQuantizationPolicy must be "nearest-log2-narrower-on-tie".');
1441
+ }
1442
+ if (target.status === "no-signal") {
1443
+ return {
1444
+ ...base,
1445
+ status: "blocked",
1446
+ axisOwnership: {
1447
+ aperture: "automatic",
1448
+ shutter: "manual",
1449
+ iso: "manual"
1450
+ },
1451
+ isoControl: "manual",
1452
+ resolvedSettings: {
1453
+ shutterSeconds: manualShutterSeconds
1454
+ },
1455
+ blocker: "target-no-signal",
1456
+ targetResidual: {
1457
+ status: "target-unresolved",
1458
+ state: "target-unresolved",
1459
+ reason: "no-signal-target"
1460
+ }
1461
+ };
1462
+ }
1463
+ const idealAperture = idealApertureForTarget(target
1464
+ .requiredExposureScaleToTarget, manualShutterSeconds, manualIso, referenceExposure);
1465
+ const aperture = resolveAutomaticAperture(idealAperture, input.capabilities);
1466
+ const achievedScale = opticalExposureFactor(aperture.aperture, manualShutterSeconds, referenceExposure) *
1467
+ (manualIso /
1468
+ referenceExposure.iso);
1469
+ return {
1470
+ ...base,
1471
+ status: "resolved",
1472
+ axisOwnership: {
1473
+ aperture: "automatic",
1474
+ shutter: "manual",
1475
+ iso: "manual"
1476
+ },
1477
+ isoControl: "manual",
1478
+ manualIso,
1479
+ idealApertureBeforeConstraints: idealAperture,
1480
+ resolvedSettings: {
1481
+ aperture: aperture.aperture,
1482
+ shutterSeconds: manualShutterSeconds,
1483
+ iso: manualIso
1484
+ },
1485
+ apertureResolution: {
1486
+ kind: aperture.kind,
1487
+ quantizationPolicy: input.isoControl
1488
+ .apertureQuantizationPolicy,
1489
+ quantized: aperture.quantized,
1490
+ clamped: aperture.clamped
1491
+ },
1492
+ targetResidual: targetResidual(target, achievedScale, aperture
1493
+ .limitingConstraint)
1494
+ };
1495
+ }
1496
+ if (input.isoControl.kind !==
1497
+ "automatic") {
1498
+ throw new InvalidScientificInputError("isoControl.kind is invalid for Shutter Priority.");
1499
+ }
1500
+ const policy = input.isoControl.policy;
1501
+ if (policy.kind !==
1502
+ "minimum-iso-aperture-first" ||
1503
+ policy.isoBaseline !==
1504
+ "minimum-selectable" ||
1505
+ policy.isoQuantizationPolicy !==
1506
+ "nearest-log2-lower-on-tie" ||
1507
+ policy.apertureSelectionPolicy !==
1508
+ "not-wider-than-target") {
1509
+ throw new InvalidScientificInputError("Shutter Priority Auto ISO policy is invalid.");
1510
+ }
1511
+ const availability = validateAutoIsoAvailability(input.capabilities);
1512
+ if (availability !== "supported") {
1513
+ const raw = buildPriorityAutoIsoBlocked("shutter-priority", target, referenceExposure, availability === "unknown"
1514
+ ? "auto-iso-unknown"
1515
+ : "auto-iso-unsupported", {
1516
+ shutterSeconds: manualShutterSeconds
1517
+ });
1518
+ return {
1519
+ ...base,
1520
+ ...raw,
1521
+ axisOwnership: {
1522
+ aperture: "automatic",
1523
+ shutter: "manual",
1524
+ iso: "automatic"
1525
+ },
1526
+ isoControl: "automatic"
1527
+ };
1528
+ }
1529
+ if (target.status === "no-signal") {
1530
+ return {
1531
+ ...base,
1532
+ status: "blocked",
1533
+ axisOwnership: {
1534
+ aperture: "automatic",
1535
+ shutter: "manual",
1536
+ iso: "automatic"
1537
+ },
1538
+ isoControl: "automatic",
1539
+ resolvedSettings: {
1540
+ shutterSeconds: manualShutterSeconds
1541
+ },
1542
+ blocker: "target-no-signal",
1543
+ targetResidual: {
1544
+ status: "target-unresolved",
1545
+ state: "target-unresolved",
1546
+ reason: "no-signal-target"
1547
+ }
1548
+ };
1549
+ }
1550
+ const baselineIso = minimumSelectableIso(input.capabilities);
1551
+ const idealAtBaseline = idealApertureForTarget(target
1552
+ .requiredExposureScaleToTarget, manualShutterSeconds, baselineIso, referenceExposure);
1553
+ const aperture = selectApertureNotWiderThanTarget(idealAtBaseline, input.capabilities);
1554
+ const isoPass = resolveManualExposureMode({
1555
+ target,
1556
+ capabilities: input.capabilities,
1557
+ referenceExposure,
1558
+ manualAperture: aperture.aperture,
1559
+ manualShutterSeconds,
1560
+ isoControl: {
1561
+ kind: "automatic",
1562
+ quantizationPolicy: policy.isoQuantizationPolicy
1563
+ }
1564
+ });
1565
+ if (isoPass.status !== "resolved" ||
1566
+ isoPass.isoControl !== "automatic") {
1567
+ throw new InvalidScientificInputError("Shutter Priority Auto ISO could not resolve its ISO pass.");
1568
+ }
1569
+ return {
1570
+ ...base,
1571
+ status: "resolved",
1572
+ axisOwnership: {
1573
+ aperture: "automatic",
1574
+ shutter: "manual",
1575
+ iso: "automatic"
1576
+ },
1577
+ isoControl: "automatic",
1578
+ policy,
1579
+ baselineIso,
1580
+ idealApertureAtBaselineIso: idealAtBaseline,
1581
+ resolvedSettings: isoPass.resolvedSettings,
1582
+ apertureResolution: {
1583
+ kind: aperture.kind,
1584
+ quantized: aperture.quantized,
1585
+ clamped: aperture.clamped,
1586
+ selectionPolicy: policy.apertureSelectionPolicy
1587
+ },
1588
+ idealIsoBeforeConstraints: isoPass
1589
+ .idealIsoBeforeConstraints,
1590
+ isoResolution: isoPass.isoResolution,
1591
+ targetResidual: isoPass.targetResidual
1592
+ };
1593
+ }
1594
+ /**
1595
+ * Evaluate the declared generic program line in log2 exposure space, quantize aperture/shutter and
1596
+ * optionally use Auto ISO for residual exposure.
1597
+ *
1598
+ * Exposure modes apply control policy to one shared relative exposure equation and an explicit
1599
+ * reference anchor. Compensation is already included in the immutable meter target. Manual axes remain
1600
+ * unchanged; automatic axes use declared setting grids and expose signed residual stops and limit
1601
+ * diagnostics. A zero-signal target cannot authorize an invented exposure.
1602
+ * @param input - ResolveProgramAutoExposureModeInput. See the linked contract for coordinate, unit and profile binding semantics.
1603
+ * @returns ProgramAutoExposureModeResolution. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
1604
+ *
1605
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
1606
+ */
1607
+ export function resolveProgramAutoExposureMode(input) {
1608
+ const target = validateTarget(input.target);
1609
+ validateCapabilities(input.capabilities);
1610
+ const referenceExposure = validateReferenceExposure(input.referenceExposure, input.capabilities);
1611
+ const programLine = validateProgramLineForResolution(input.programLine, referenceExposure, input.capabilities);
1612
+ if (input.isoControl.kind !==
1613
+ "manual" &&
1614
+ input.isoControl.kind !==
1615
+ "automatic") {
1616
+ throw new InvalidScientificInputError("isoControl.kind is invalid for Program Auto.");
1617
+ }
1618
+ if (target.status === "no-signal") {
1619
+ return {
1620
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1621
+ mode: "program-auto",
1622
+ status: "blocked",
1623
+ axisOwnership: {
1624
+ aperture: "automatic",
1625
+ shutter: "automatic",
1626
+ iso: input.isoControl.kind ===
1627
+ "manual"
1628
+ ? "manual"
1629
+ : "automatic"
1630
+ },
1631
+ isoControl: input.isoControl.kind,
1632
+ targetId: target.targetId,
1633
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1634
+ referenceExposure,
1635
+ blocker: "target-no-signal",
1636
+ targetResidual: {
1637
+ status: "target-unresolved",
1638
+ state: "target-unresolved",
1639
+ reason: "no-signal-target"
1640
+ },
1641
+ exposureCompensationAppliedByResolver: false,
1642
+ meterRecomputedByResolver: false,
1643
+ flashPolicyApplied: false,
1644
+ safetyShiftApplied: false
1645
+ };
1646
+ }
1647
+ if (input.isoControl.kind ===
1648
+ "manual") {
1649
+ const manualIso = requirePositiveFinite(input.isoControl.iso, "isoControl.iso");
1650
+ validateSettingAgainstGrid(manualIso, input.capabilities.iso.minimum, input.capabilities.iso.maximum, input.capabilities.iso.settingGrid, "isoControl.iso");
1651
+ const requestedOpticalStops = target
1652
+ .exposureOffsetStopsToTarget -
1653
+ Math.log2(manualIso /
1654
+ referenceExposure.iso);
1655
+ const selection = selectProgramLineSettings(requestedOpticalStops, programLine, input.capabilities);
1656
+ const achievedScale = opticalExposureFactor(selection.resolvedAperture, selection
1657
+ .resolvedShutterSeconds, referenceExposure) *
1658
+ (manualIso /
1659
+ referenceExposure.iso);
1660
+ return {
1661
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1662
+ mode: "program-auto",
1663
+ status: "resolved",
1664
+ axisOwnership: {
1665
+ aperture: "automatic",
1666
+ shutter: "automatic",
1667
+ iso: "manual"
1668
+ },
1669
+ isoControl: "manual",
1670
+ targetId: target.targetId,
1671
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1672
+ referenceExposure,
1673
+ programLineSelection: selection,
1674
+ apertureResolvedByResolver: true,
1675
+ shutterResolvedByResolver: true,
1676
+ exposureCompensationAppliedByResolver: false,
1677
+ meterRecomputedByResolver: false,
1678
+ flashPolicyApplied: false,
1679
+ safetyShiftApplied: false,
1680
+ manualIso,
1681
+ resolvedSettings: {
1682
+ aperture: selection
1683
+ .resolvedAperture,
1684
+ shutterSeconds: selection
1685
+ .resolvedShutterSeconds,
1686
+ iso: manualIso
1687
+ },
1688
+ targetResidual: targetResidual(target, achievedScale, programLineResidualConstraint(selection))
1689
+ };
1690
+ }
1691
+ if (input.isoControl
1692
+ .isoBaseline !==
1693
+ "minimum-selectable" ||
1694
+ input.isoControl
1695
+ .isoQuantizationPolicy !==
1696
+ "nearest-log2-lower-on-tie") {
1697
+ throw new InvalidScientificInputError("Program Auto ISO policy is invalid.");
1698
+ }
1699
+ const availability = validateAutoIsoAvailability(input.capabilities);
1700
+ if (availability !== "supported") {
1701
+ return {
1702
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1703
+ mode: "program-auto",
1704
+ status: "blocked",
1705
+ axisOwnership: {
1706
+ aperture: "automatic",
1707
+ shutter: "automatic",
1708
+ iso: "automatic"
1709
+ },
1710
+ isoControl: "automatic",
1711
+ targetId: target.targetId,
1712
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1713
+ referenceExposure,
1714
+ blocker: availability === "unknown"
1715
+ ? "auto-iso-unknown"
1716
+ : "auto-iso-unsupported",
1717
+ targetResidual: {
1718
+ status: "target-unresolved",
1719
+ state: "target-unresolved",
1720
+ reason: "auto-iso-unavailable"
1721
+ },
1722
+ exposureCompensationAppliedByResolver: false,
1723
+ meterRecomputedByResolver: false,
1724
+ flashPolicyApplied: false,
1725
+ safetyShiftApplied: false
1726
+ };
1727
+ }
1728
+ const baselineIso = minimumSelectableIso(input.capabilities);
1729
+ const requestedOpticalStops = target
1730
+ .exposureOffsetStopsToTarget -
1731
+ Math.log2(baselineIso /
1732
+ referenceExposure.iso);
1733
+ const selection = selectProgramLineSettings(requestedOpticalStops, programLine, input.capabilities);
1734
+ const isoPass = resolveManualExposureMode({
1735
+ target,
1736
+ capabilities: input.capabilities,
1737
+ referenceExposure,
1738
+ manualAperture: selection.resolvedAperture,
1739
+ manualShutterSeconds: selection
1740
+ .resolvedShutterSeconds,
1741
+ isoControl: {
1742
+ kind: "automatic",
1743
+ quantizationPolicy: input.isoControl
1744
+ .isoQuantizationPolicy
1745
+ }
1746
+ });
1747
+ if (isoPass.status !== "resolved" ||
1748
+ isoPass.isoControl !== "automatic") {
1749
+ throw new InvalidScientificInputError("Program Auto could not resolve its Auto ISO pass.");
1750
+ }
1751
+ return {
1752
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1753
+ mode: "program-auto",
1754
+ status: "resolved",
1755
+ axisOwnership: {
1756
+ aperture: "automatic",
1757
+ shutter: "automatic",
1758
+ iso: "automatic"
1759
+ },
1760
+ isoControl: "automatic",
1761
+ targetId: target.targetId,
1762
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1763
+ referenceExposure,
1764
+ programLineSelection: selection,
1765
+ apertureResolvedByResolver: true,
1766
+ shutterResolvedByResolver: true,
1767
+ exposureCompensationAppliedByResolver: false,
1768
+ meterRecomputedByResolver: false,
1769
+ flashPolicyApplied: false,
1770
+ safetyShiftApplied: false,
1771
+ baselineIso,
1772
+ idealIsoBeforeConstraints: isoPass
1773
+ .idealIsoBeforeConstraints,
1774
+ isoResolution: isoPass.isoResolution,
1775
+ resolvedSettings: isoPass.resolvedSettings,
1776
+ targetResidual: isoPass.targetResidual
1777
+ };
1778
+ }
1779
+ /**
1780
+ * Resolve aperture, shutter and ISO under an explicit generic Full Auto exposure policy. Autofocus,
1781
+ * WB, flash, drive and scene recognition remain unresolved.
1782
+ *
1783
+ * Exposure modes apply control policy to one shared relative exposure equation and an explicit
1784
+ * reference anchor. Compensation is already included in the immutable meter target. Manual axes remain
1785
+ * unchanged; automatic axes use declared setting grids and expose signed residual stops and limit
1786
+ * diagnostics. A zero-signal target cannot authorize an invented exposure.
1787
+ * @param input - ResolveFullAutoExposureModeInput. See the linked contract for coordinate, unit and profile binding semantics.
1788
+ * @returns FullAutoExposureModeResolution. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
1789
+ *
1790
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
1791
+ */
1792
+ export function resolveFullAutoExposureMode(input) {
1793
+ const target = validateTarget(input.target);
1794
+ validateCapabilities(input.capabilities);
1795
+ const referenceExposure = validateReferenceExposure(input.referenceExposure, input.capabilities);
1796
+ if (input.policy.kind !==
1797
+ "generic-program-line-minimum-iso" ||
1798
+ input.policy.isoBaseline !==
1799
+ "minimum-selectable" ||
1800
+ input.policy
1801
+ .isoQuantizationPolicy !==
1802
+ "nearest-log2-lower-on-tie") {
1803
+ throw new InvalidScientificInputError("Full Auto exposure policy is invalid.");
1804
+ }
1805
+ const programLine = validateProgramLineForResolution(input.policy.programLine, referenceExposure, input.capabilities);
1806
+ const blocked = (blocker) => ({
1807
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1808
+ mode: "full-auto-exposure",
1809
+ status: "blocked",
1810
+ axisOwnership: {
1811
+ aperture: "automatic",
1812
+ shutter: "automatic",
1813
+ iso: "automatic"
1814
+ },
1815
+ policy: input.policy,
1816
+ targetId: target.targetId,
1817
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1818
+ referenceExposure,
1819
+ blocker,
1820
+ targetResidual: {
1821
+ status: "target-unresolved",
1822
+ state: "target-unresolved",
1823
+ reason: blocker ===
1824
+ "target-no-signal"
1825
+ ? "no-signal-target"
1826
+ : "auto-iso-unavailable"
1827
+ },
1828
+ exposureCompensationAppliedByResolver: false,
1829
+ meterRecomputedByResolver: false,
1830
+ flashPolicyApplied: false,
1831
+ safetyShiftApplied: false,
1832
+ autofocusResolved: false,
1833
+ whiteBalanceResolved: false,
1834
+ flashResolved: false,
1835
+ driveResolved: false,
1836
+ sceneRecognitionResolved: false,
1837
+ stabilizationPolicyResolved: false
1838
+ });
1839
+ if (target.status === "no-signal") {
1840
+ return blocked("target-no-signal");
1841
+ }
1842
+ const availability = validateAutoIsoAvailability(input.capabilities);
1843
+ if (availability !== "supported") {
1844
+ return blocked(availability === "unknown"
1845
+ ? "auto-iso-unknown"
1846
+ : "auto-iso-unsupported");
1847
+ }
1848
+ const baselineIso = minimumSelectableIso(input.capabilities);
1849
+ const requestedOpticalStops = target
1850
+ .exposureOffsetStopsToTarget -
1851
+ Math.log2(baselineIso /
1852
+ referenceExposure.iso);
1853
+ const selection = selectProgramLineSettings(requestedOpticalStops, programLine, input.capabilities);
1854
+ const isoPass = resolveManualExposureMode({
1855
+ target,
1856
+ capabilities: input.capabilities,
1857
+ referenceExposure,
1858
+ manualAperture: selection.resolvedAperture,
1859
+ manualShutterSeconds: selection
1860
+ .resolvedShutterSeconds,
1861
+ isoControl: {
1862
+ kind: "automatic",
1863
+ quantizationPolicy: input.policy
1864
+ .isoQuantizationPolicy
1865
+ }
1866
+ });
1867
+ if (isoPass.status !== "resolved" ||
1868
+ isoPass.isoControl !== "automatic") {
1869
+ throw new InvalidScientificInputError("Full Auto exposure could not resolve its Auto ISO pass.");
1870
+ }
1871
+ return {
1872
+ resolverVersion: EXPOSURE_MODE_RESOLVER_VERSION,
1873
+ mode: "full-auto-exposure",
1874
+ status: "resolved",
1875
+ axisOwnership: {
1876
+ aperture: "automatic",
1877
+ shutter: "automatic",
1878
+ iso: "automatic"
1879
+ },
1880
+ policy: input.policy,
1881
+ targetId: target.targetId,
1882
+ targetSourceMeterSnapshot: target.sourceMeterSnapshot,
1883
+ referenceExposure,
1884
+ programLineSelection: selection,
1885
+ apertureResolvedByResolver: true,
1886
+ shutterResolvedByResolver: true,
1887
+ exposureCompensationAppliedByResolver: false,
1888
+ meterRecomputedByResolver: false,
1889
+ flashPolicyApplied: false,
1890
+ safetyShiftApplied: false,
1891
+ baselineIso,
1892
+ idealIsoBeforeConstraints: isoPass
1893
+ .idealIsoBeforeConstraints,
1894
+ isoResolution: isoPass.isoResolution,
1895
+ resolvedSettings: isoPass.resolvedSettings,
1896
+ targetResidual: isoPass.targetResidual,
1897
+ autofocusResolved: false,
1898
+ whiteBalanceResolved: false,
1899
+ flashResolved: false,
1900
+ driveResolved: false,
1901
+ sceneRecognitionResolved: false,
1902
+ stabilizationPolicyResolved: false
1903
+ };
1904
+ }
1905
+ //# sourceMappingURL=exposure-mode-resolver.js.map