@photivra/engine 2.20.0 → 2.22.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 (275) hide show
  1. package/CHANGELOG.md +295 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +7 -6
  4. package/SECURITY.md +1 -1
  5. package/THIRD_PARTY.md +18 -0
  6. package/dist/capture/c2pa-embed.d.ts +116 -0
  7. package/dist/capture/c2pa-embed.js +493 -0
  8. package/dist/capture/c2pa-embed.js.map +1 -0
  9. package/dist/capture/dng-import.d.ts +73 -8
  10. package/dist/capture/dng-import.js +315 -80
  11. package/dist/capture/dng-import.js.map +1 -1
  12. package/dist/capture/dng-lens-correction-opcodes.d.ts +2 -2
  13. package/dist/capture/dng-lens-correction-opcodes.js +2 -2
  14. package/dist/capture/dng-lens-correction-opcodes.js.map +1 -1
  15. package/dist/capture/dng-opcodes.d.ts +96 -0
  16. package/dist/capture/dng-opcodes.js +391 -0
  17. package/dist/capture/dng-opcodes.js.map +1 -0
  18. package/dist/capture/dng-profile-maps.d.ts +99 -0
  19. package/dist/capture/dng-profile-maps.js +381 -0
  20. package/dist/capture/dng-profile-maps.js.map +1 -0
  21. package/dist/capture/dng-stage-image.d.ts +23 -0
  22. package/dist/capture/dng-stage-image.js +65 -0
  23. package/dist/capture/dng-stage-image.js.map +1 -0
  24. package/dist/capture/exposure-build-up-stage.d.ts +16 -0
  25. package/dist/capture/exposure-build-up-stage.js +4 -0
  26. package/dist/capture/exposure-build-up-stage.js.map +1 -0
  27. package/dist/capture/jpeg-xl-tiles.d.ts +22 -0
  28. package/dist/capture/jpeg-xl-tiles.js +151 -0
  29. package/dist/capture/jpeg-xl-tiles.js.map +1 -0
  30. package/dist/capture/lossy-jpeg.d.ts +17 -0
  31. package/dist/capture/lossy-jpeg.js +369 -0
  32. package/dist/capture/lossy-jpeg.js.map +1 -0
  33. package/dist/capture/native-environment-lean.d.ts +2 -1
  34. package/dist/capture/native-environment-lean.js +41 -73
  35. package/dist/capture/native-environment-lean.js.map +1 -1
  36. package/dist/capture/native-environment-tabulated.js +4 -3
  37. package/dist/capture/native-environment-tabulated.js.map +1 -1
  38. package/dist/capture/native-raw-development.d.ts +2 -1
  39. package/dist/capture/native-raw-development.js.map +1 -1
  40. package/dist/capture/native-raw.d.ts +3 -2
  41. package/dist/capture/native-raw.js +5 -4
  42. package/dist/capture/native-raw.js.map +1 -1
  43. package/dist/capture/sensor-raw-producer.d.ts +4 -1
  44. package/dist/capture/sensor-raw-producer.js +12 -3
  45. package/dist/capture/sensor-raw-producer.js.map +1 -1
  46. package/dist/color/neighbor-highlight-reconstruction.d.ts +66 -0
  47. package/dist/color/neighbor-highlight-reconstruction.js +234 -0
  48. package/dist/color/neighbor-highlight-reconstruction.js.map +1 -0
  49. package/dist/color/sensor-color-development.d.ts +5 -0
  50. package/dist/color/sensor-color-development.js +7 -1
  51. package/dist/color/sensor-color-development.js.map +1 -1
  52. package/dist/color/spectral-spikiness.d.ts +11 -0
  53. package/dist/color/spectral-spikiness.js +23 -0
  54. package/dist/color/spectral-spikiness.js.map +1 -0
  55. package/dist/core/execution-error.d.ts +21 -0
  56. package/dist/core/execution-error.js +12 -0
  57. package/dist/core/execution-error.js.map +1 -0
  58. package/dist/core/version.d.ts +1 -1
  59. package/dist/core/version.js +1 -1
  60. package/dist/core/version.js.map +1 -1
  61. package/dist/equipment/generic-lens-catalogue.d.ts +3 -2
  62. package/dist/equipment/generic-lens-catalogue.js +18 -5
  63. package/dist/equipment/generic-lens-catalogue.js.map +1 -1
  64. package/dist/equipment/generic-tier-assets.d.ts +32 -0
  65. package/dist/equipment/generic-tier-assets.js +16 -11
  66. package/dist/equipment/generic-tier-assets.js.map +1 -1
  67. package/dist/equipment/sensor-profile-body.d.ts +78 -0
  68. package/dist/equipment/sensor-profile-body.js +77 -0
  69. package/dist/equipment/sensor-profile-body.js.map +1 -0
  70. package/dist/equipment/sensor-profiles.d.ts +8 -0
  71. package/dist/equipment/sensor-profiles.js +82 -0
  72. package/dist/equipment/sensor-profiles.js.map +1 -0
  73. package/dist/facade/catalogue-lens-signal.d.ts +28 -3
  74. package/dist/facade/catalogue-lens-signal.js +83 -78
  75. package/dist/facade/catalogue-lens-signal.js.map +1 -1
  76. package/dist/facade/chart-radiance-batch.js +2 -1
  77. package/dist/facade/chart-radiance-batch.js.map +1 -1
  78. package/dist/facade/defocus-image-space-provider.d.ts +7 -0
  79. package/dist/facade/defocus-image-space-provider.js +64 -76
  80. package/dist/facade/defocus-image-space-provider.js.map +1 -1
  81. package/dist/facade/diffraction-provider.d.ts +1 -1
  82. package/dist/facade/diffraction-provider.js +4 -4
  83. package/dist/facade/diffraction-provider.js.map +1 -1
  84. package/dist/facade/display-view-gpu-session.js +39 -5
  85. package/dist/facade/display-view-gpu-session.js.map +1 -1
  86. package/dist/facade/display-view-gpu.d.ts +19 -6
  87. package/dist/facade/display-view-gpu.js.map +1 -1
  88. package/dist/facade/display-view-lens-signal.js +25 -23
  89. package/dist/facade/display-view-lens-signal.js.map +1 -1
  90. package/dist/facade/display-view-normal.d.ts +15 -0
  91. package/dist/facade/display-view-normal.js +44 -0
  92. package/dist/facade/display-view-normal.js.map +1 -0
  93. package/dist/facade/display-view-rendering.d.ts +97 -0
  94. package/dist/facade/display-view-rendering.js +598 -0
  95. package/dist/facade/display-view-rendering.js.map +1 -0
  96. package/dist/facade/display-view.d.ts +37 -65
  97. package/dist/facade/display-view.js +152 -499
  98. package/dist/facade/display-view.js.map +1 -1
  99. package/dist/facade/expected-signal-setup.d.ts +3 -1
  100. package/dist/facade/expected-signal-setup.js +3 -3
  101. package/dist/facade/expected-signal-setup.js.map +1 -1
  102. package/dist/facade/expected-signal.d.ts +47 -14
  103. package/dist/facade/expected-signal.js +117 -112
  104. package/dist/facade/expected-signal.js.map +1 -1
  105. package/dist/facade/exposure-build-up.d.ts +70 -0
  106. package/dist/facade/exposure-build-up.js +164 -0
  107. package/dist/facade/exposure-build-up.js.map +1 -0
  108. package/dist/facade/fast-methods.d.ts +1 -1
  109. package/dist/facade/fast-methods.js +46 -9
  110. package/dist/facade/fast-methods.js.map +1 -1
  111. package/dist/facade/generic-lens-capture.d.ts +3 -3
  112. package/dist/facade/generic-lens-capture.js +3 -3
  113. package/dist/facade/generic-lens-capture.js.map +1 -1
  114. package/dist/facade/image-plane-enable.d.ts +7 -0
  115. package/dist/facade/image-plane-enable.js +17 -0
  116. package/dist/facade/image-plane-enable.js.map +1 -0
  117. package/dist/facade/image-plane-lattice-data.d.ts +6 -0
  118. package/dist/facade/image-plane-lattice-data.js +10 -0
  119. package/dist/facade/image-plane-lattice-data.js.map +1 -0
  120. package/dist/facade/image-plane-support.d.ts +33 -0
  121. package/dist/facade/image-plane-support.js +11 -0
  122. package/dist/facade/image-plane-support.js.map +1 -0
  123. package/dist/facade/image-plane.d.ts +36 -0
  124. package/dist/facade/image-plane.js +384 -0
  125. package/dist/facade/image-plane.js.map +1 -0
  126. package/dist/facade/mixed-illumination.d.ts +108 -0
  127. package/dist/facade/mixed-illumination.js +174 -0
  128. package/dist/facade/mixed-illumination.js.map +1 -0
  129. package/dist/facade/on-demand-kits.d.ts +14 -0
  130. package/dist/facade/on-demand-kits.js +36 -0
  131. package/dist/facade/on-demand-kits.js.map +1 -0
  132. package/dist/facade/opt-in-kit.d.ts +9 -0
  133. package/dist/facade/opt-in-kit.js +11 -0
  134. package/dist/facade/opt-in-kit.js.map +1 -0
  135. package/dist/facade/quality-kit.d.ts +21 -0
  136. package/dist/facade/quality-kit.js +23 -0
  137. package/dist/facade/quality-kit.js.map +1 -0
  138. package/dist/facade/quality-paths.d.ts +22 -0
  139. package/dist/facade/quality-paths.js +44 -0
  140. package/dist/facade/quality-paths.js.map +1 -0
  141. package/dist/facade/representative-light-sources.d.ts +72 -0
  142. package/dist/facade/representative-light-sources.js +124 -0
  143. package/dist/facade/representative-light-sources.js.map +1 -0
  144. package/dist/facade/scene-radiance.d.ts +145 -4
  145. package/dist/facade/scene-radiance.js +50 -13
  146. package/dist/facade/scene-radiance.js.map +1 -1
  147. package/dist/facade/simulate-capture.d.ts +68 -20
  148. package/dist/facade/simulate-capture.js +399 -146
  149. package/dist/facade/simulate-capture.js.map +1 -1
  150. package/dist/facade/simulate-display-view.d.ts +10 -12
  151. package/dist/facade/simulate-display-view.js +70 -53
  152. package/dist/facade/simulate-display-view.js.map +1 -1
  153. package/dist/gpu/chart-composite-gpu.d.ts +13 -1
  154. package/dist/gpu/chart-composite-gpu.js +48 -9
  155. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  156. package/dist/gpu/chart-radiance-gpu.js +4 -30
  157. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  158. package/dist/gpu/display-view-composite-material-module.d.ts +10 -4
  159. package/dist/gpu/display-view-composite-material-module.js +39 -13
  160. package/dist/gpu/display-view-composite-material-module.js.map +1 -1
  161. package/dist/gpu/display-view-gpu-renderer.d.ts +43 -0
  162. package/dist/gpu/display-view-gpu-renderer.js +134 -0
  163. package/dist/gpu/display-view-gpu-renderer.js.map +1 -0
  164. package/dist/gpu/display-view-image-material-module.d.ts +87 -0
  165. package/dist/gpu/display-view-image-material-module.js +361 -0
  166. package/dist/gpu/display-view-image-material-module.js.map +1 -0
  167. package/dist/gpu/display-view-image-quality.d.ts +87 -0
  168. package/dist/gpu/display-view-image-quality.js +625 -0
  169. package/dist/gpu/display-view-image-quality.js.map +1 -0
  170. package/dist/gpu/display-view-quality-gpu.d.ts +80 -65
  171. package/dist/gpu/display-view-quality-gpu.js +187 -445
  172. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  173. package/dist/gpu/display-view-speed-gpu.d.ts +67 -19
  174. package/dist/gpu/display-view-speed-gpu.js +181 -105
  175. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  176. package/dist/gpu/image-kernel-accelerator.js +3 -0
  177. package/dist/gpu/image-kernel-accelerator.js.map +1 -1
  178. package/dist/gpu/image-kernel-execution.d.ts +2 -13
  179. package/dist/gpu/image-kernel-execution.js +2 -10
  180. package/dist/gpu/image-kernel-execution.js.map +1 -1
  181. package/dist/gpu/wgsl-display-view-coupled-stub.d.ts +8 -0
  182. package/dist/gpu/wgsl-display-view-coupled-stub.js +21 -0
  183. package/dist/gpu/wgsl-display-view-coupled-stub.js.map +1 -0
  184. package/dist/gpu/wgsl-display-view-coupled.d.ts +88 -0
  185. package/dist/gpu/wgsl-display-view-coupled.js +353 -0
  186. package/dist/gpu/wgsl-display-view-coupled.js.map +1 -0
  187. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +33 -24
  188. package/dist/gpu/wgsl-display-view-quality-kernel.js +166 -146
  189. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  190. package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +19 -44
  191. package/dist/gpu/wgsl-display-view-speed-kernel.js +116 -18
  192. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  193. package/dist/gpu/wgsl-exact-sum.d.ts +20 -0
  194. package/dist/gpu/wgsl-exact-sum.js +42 -0
  195. package/dist/gpu/wgsl-exact-sum.js.map +1 -0
  196. package/dist/index.d.ts +22 -6
  197. package/dist/index.js +16 -2
  198. package/dist/index.js.map +1 -1
  199. package/dist/motion/subject-motion.d.ts +66 -0
  200. package/dist/motion/subject-motion.js +52 -0
  201. package/dist/motion/subject-motion.js.map +1 -0
  202. package/dist/optics/generic-lens-lateral-color.d.ts +83 -0
  203. package/dist/optics/generic-lens-lateral-color.js +77 -0
  204. package/dist/optics/generic-lens-lateral-color.js.map +1 -0
  205. package/dist/optics/generic-lens-psf.js +54 -46
  206. package/dist/optics/generic-lens-psf.js.map +1 -1
  207. package/dist/optics/lens-psf-profile.d.ts +7 -0
  208. package/dist/optics/lens-psf-profile.js +2 -1
  209. package/dist/optics/lens-psf-profile.js.map +1 -1
  210. package/dist/output/camera-channel-response.d.ts +50 -0
  211. package/dist/output/camera-channel-response.js +69 -0
  212. package/dist/output/camera-channel-response.js.map +1 -0
  213. package/dist/output/developed-lens-corrections.d.ts +19 -5
  214. package/dist/output/developed-lens-corrections.js +28 -9
  215. package/dist/output/developed-lens-corrections.js.map +1 -1
  216. package/dist/output/generic-lens-corrections.d.ts +41 -5
  217. package/dist/output/generic-lens-corrections.js +52 -8
  218. package/dist/output/generic-lens-corrections.js.map +1 -1
  219. package/dist/output/native-capture-sdr.js +5 -2
  220. package/dist/output/native-capture-sdr.js.map +1 -1
  221. package/dist/output/print-plan.d.ts +41 -5
  222. package/dist/output/print-plan.js +59 -14
  223. package/dist/output/print-plan.js.map +1 -1
  224. package/dist/output/sdr-rendering.d.ts +18 -1
  225. package/dist/output/sdr-rendering.js +39 -2
  226. package/dist/output/sdr-rendering.js.map +1 -1
  227. package/dist/sensor/binomial-sample.d.ts +3 -0
  228. package/dist/sensor/binomial-sample.js +86 -0
  229. package/dist/sensor/binomial-sample.js.map +1 -0
  230. package/dist/sensor/native-sensor-report.d.ts +10 -0
  231. package/dist/sensor/native-sensor-report.js +16 -0
  232. package/dist/sensor/native-sensor-report.js.map +1 -0
  233. package/dist/sensor/sensor-characteristics.d.ts +91 -13
  234. package/dist/sensor/sensor-characteristics.js +30 -15
  235. package/dist/sensor/sensor-characteristics.js.map +1 -1
  236. package/docs/AGENT_GUIDE.md +1 -0
  237. package/docs/API_REFERENCE.md +214 -4
  238. package/docs/QUICK_START.md +162 -8
  239. package/docs/USAGE.md +195 -22
  240. package/docs/api/capture-c2pa-embed.md +177 -0
  241. package/docs/api/capture-dng-import.md +86 -10
  242. package/docs/api/capture-dng-opcodes.md +93 -0
  243. package/docs/api/capture-dng-profile-maps.md +141 -0
  244. package/docs/api/capture-dng-stage-image.md +43 -0
  245. package/docs/api/capture-jpeg-xl-tiles.md +33 -0
  246. package/docs/api/capture-lossy-jpeg.md +41 -0
  247. package/docs/api/capture-native-raw-development.md +2 -1
  248. package/docs/api/core-execution-error.md +43 -0
  249. package/docs/api/core-version.md +1 -1
  250. package/docs/api/equipment-generic-lens-catalogue.md +10 -5
  251. package/docs/api/equipment-sensor-profile-body.md +64 -0
  252. package/docs/api/equipment-sensor-profiles.md +86 -0
  253. package/docs/api/exports.json +460 -5
  254. package/docs/api/facade-display-view-gpu.md +5 -2
  255. package/docs/api/facade-display-view.md +11 -15
  256. package/docs/api/facade-exposure-build-up.md +105 -0
  257. package/docs/api/facade-fast-methods.md +47 -10
  258. package/docs/api/facade-image-plane-enable.md +16 -0
  259. package/docs/api/facade-mixed-illumination.md +67 -0
  260. package/docs/api/facade-quality-paths.md +24 -0
  261. package/docs/api/facade-representative-light-sources.md +131 -0
  262. package/docs/api/facade-scene-radiance.md +54 -3
  263. package/docs/api/facade-simulate-capture.md +48 -11
  264. package/docs/api/facade-simulate-display-view.md +10 -12
  265. package/docs/api/gpu-image-kernel-execution.md +0 -36
  266. package/docs/api/motion-subject-motion.md +23 -0
  267. package/docs/api/optics-generic-lens-lateral-color.md +79 -0
  268. package/docs/api/output-camera-channel-response.md +55 -0
  269. package/docs/api/output-developed-lens-corrections.md +10 -1
  270. package/docs/api/output-generic-lens-corrections.md +40 -4
  271. package/docs/api/output-print-plan.md +35 -1
  272. package/docs/api/output-sdr-rendering.md +6 -1
  273. package/docs/api/sensor-sensor-characteristics.md +54 -2
  274. package/llms.txt +3 -0
  275. package/package.json +6 -5
@@ -1,6 +1,6 @@
1
1
  # Public API reference
2
2
 
3
- Generated from the exact root exports for **@photivra/engine 2.20.0 / root contract 2.20.0** by `node scripts/generate-api-reference.mjs`. No module deep import is supported.
3
+ Generated from the exact root exports for **@photivra/engine 2.22.0 / root contract 2.22.0** by `node scripts/generate-api-reference.mjs`. No module deep import is supported.
4
4
 
5
5
  Use [the developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md) for executable paths and scientific boundaries. Types are contracts, not runtime validation: parse untrusted data, preserve units/reference frames, read assessment blockers, and retain evidence/limitations. Optional properties do not imply a universal default. Model/schema IDs remain independent of the distribution.
6
6
 
@@ -101,6 +101,28 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
101
101
  | [`SensorEquivalenceFieldOfView`](api/camera-sensor-equivalence.md#sensorequivalencefieldofview) | Type |
102
102
  | [`SensorEquivalenceQuantity`](api/camera-sensor-equivalence.md#sensorequivalencequantity) | Type |
103
103
 
104
+ ## capture/c2pa-embed.ts
105
+
106
+ [Detailed contracts](api/capture-c2pa-embed.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/c2pa-embed.ts)
107
+
108
+ | Export | Kind |
109
+ | --- | --- |
110
+ | [`bindC2paManifestStore`](api/capture-c2pa-embed.md#bindc2pamanifeststore) | Runtime |
111
+ | [`BindC2paManifestStoreInput`](api/capture-c2pa-embed.md#bindc2pamanifeststoreinput) | Type |
112
+ | [`C2PA_ALGORITHMIC_MEDIA_SOURCE_TYPE`](api/capture-c2pa-embed.md#c2pa_algorithmic_media_source_type) | Runtime |
113
+ | [`C2PA_MANIFEST_STORE_MAXIMUM_BYTES`](api/capture-c2pa-embed.md#c2pa_manifest_store_maximum_bytes) | Runtime |
114
+ | [`C2paBoundFile`](api/capture-c2pa-embed.md#c2paboundfile) | Type |
115
+ | [`C2paByteRange`](api/capture-c2pa-embed.md#c2pabyterange) | Type |
116
+ | [`C2paDataHash`](api/capture-c2pa-embed.md#c2padatahash) | Type |
117
+ | [`C2paFoundManifestStore`](api/capture-c2pa-embed.md#c2pafoundmanifeststore) | Type |
118
+ | [`C2paHardBinding`](api/capture-c2pa-embed.md#c2pahardbinding) | Type |
119
+ | [`calculateC2paDataHash`](api/capture-c2pa-embed.md#calculatec2padatahash) | Runtime |
120
+ | [`CalculateC2paDataHashInput`](api/capture-c2pa-embed.md#calculatec2padatahashinput) | Type |
121
+ | [`parseC2paManifestStore`](api/capture-c2pa-embed.md#parsec2pamanifeststore) | Runtime |
122
+ | [`ParseC2paManifestStoreInput`](api/capture-c2pa-embed.md#parsec2pamanifeststoreinput) | Type |
123
+ | [`setC2paManifestStore`](api/capture-c2pa-embed.md#setc2pamanifeststore) | Runtime |
124
+ | [`SetC2paManifestStoreInput`](api/capture-c2pa-embed.md#setc2pamanifeststoreinput) | Type |
125
+
104
126
  ## capture/capture-export-metadata.ts
105
127
 
106
128
  [Detailed contracts](api/capture-capture-export-metadata.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/capture-export-metadata.ts)
@@ -124,13 +146,57 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
124
146
  | --- | --- |
125
147
  | [`DNG_IMPORT_LIMITS`](api/capture-dng-import.md#dng_import_limits) | Runtime |
126
148
  | [`DNG_IMPORT_SCHEMA_VERSION`](api/capture-dng-import.md#dng_import_schema_version) | Runtime |
149
+ | [`DngImportAsyncInput`](api/capture-dng-import.md#dngimportasyncinput) | Type |
127
150
  | [`DngImportInput`](api/capture-dng-import.md#dngimportinput) | Type |
151
+ | [`importDngRawImage`](api/capture-dng-import.md#importdngrawimage) | Runtime |
128
152
  | [`ImportedDngBlackLevel`](api/capture-dng-import.md#importeddngblacklevel) | Type |
129
153
  | [`ImportedDngCfa`](api/capture-dng-import.md#importeddngcfa) | Type |
130
154
  | [`ImportedDngRaw`](api/capture-dng-import.md#importeddngraw) | Type |
131
155
  | [`ImportedDngRect`](api/capture-dng-import.md#importeddngrect) | Type |
156
+ | [`ImportedDngSemanticMask`](api/capture-dng-import.md#importeddngsemanticmask) | Type |
132
157
  | [`parseDngRawImage`](api/capture-dng-import.md#parsedngrawimage) | Runtime |
133
158
 
159
+ ## capture/dng-opcodes.ts
160
+
161
+ [Detailed contracts](api/capture-dng-opcodes.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/dng-opcodes.ts)
162
+
163
+ | Export | Kind |
164
+ | --- | --- |
165
+ | [`applyDngOpcodes`](api/capture-dng-opcodes.md#applydngopcodes) | Runtime |
166
+ | [`ApplyDngOpcodesOptions`](api/capture-dng-opcodes.md#applydngopcodesoptions) | Type |
167
+ | [`DngOpcode`](api/capture-dng-opcodes.md#dngopcode) | Type |
168
+ | [`DngOpcodeArea`](api/capture-dng-opcodes.md#dngopcodearea) | Type |
169
+ | [`DngOpcodeParameters`](api/capture-dng-opcodes.md#dngopcodeparameters) | Type |
170
+ | [`DngStageImage`](api/capture-dng-opcodes.md#dngstageimage) | Type |
171
+ | [`parseDngOpcodeList`](api/capture-dng-opcodes.md#parsedngopcodelist) | Runtime |
172
+
173
+ ## capture/dng-profile-maps.ts
174
+
175
+ [Detailed contracts](api/capture-dng-profile-maps.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/dng-profile-maps.ts)
176
+
177
+ | Export | Kind |
178
+ | --- | --- |
179
+ | [`applyDngProfileGainTableMap`](api/capture-dng-profile-maps.md#applydngprofilegaintablemap) | Runtime |
180
+ | [`ApplyDngProfileGainTableMapInput`](api/capture-dng-profile-maps.md#applydngprofilegaintablemapinput) | Type |
181
+ | [`applyDngRgbTables`](api/capture-dng-profile-maps.md#applydngrgbtables) | Runtime |
182
+ | [`ApplyDngRgbTablesInput`](api/capture-dng-profile-maps.md#applydngrgbtablesinput) | Type |
183
+ | [`DngProfileGainTableMap`](api/capture-dng-profile-maps.md#dngprofilegaintablemap) | Type |
184
+ | [`DngRgbImage`](api/capture-dng-profile-maps.md#dngrgbimage) | Type |
185
+ | [`DngRgbTable`](api/capture-dng-profile-maps.md#dngrgbtable) | Type |
186
+ | [`DngRgbTables`](api/capture-dng-profile-maps.md#dngrgbtables) | Type |
187
+ | [`parseDngProfileGainTableMap`](api/capture-dng-profile-maps.md#parsedngprofilegaintablemap) | Runtime |
188
+ | [`parseDngRgbTables`](api/capture-dng-profile-maps.md#parsedngrgbtables) | Runtime |
189
+
190
+ ## capture/dng-stage-image.ts
191
+
192
+ [Detailed contracts](api/capture-dng-stage-image.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/dng-stage-image.ts)
193
+
194
+ | Export | Kind |
195
+ | --- | --- |
196
+ | [`developDngStageImage`](api/capture-dng-stage-image.md#developdngstageimage) | Runtime |
197
+ | [`DevelopDngStageImageOptions`](api/capture-dng-stage-image.md#developdngstageimageoptions) | Type |
198
+ | [`DngStageImageResult`](api/capture-dng-stage-image.md#dngstageimageresult) | Type |
199
+
134
200
  ## capture/environment-raw-producer.ts
135
201
 
136
202
  [Detailed contracts](api/capture-environment-raw-producer.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/environment-raw-producer.ts)
@@ -180,6 +246,16 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
180
246
  | [`setManualFocusState`](api/capture-focus-control.md#setmanualfocusstate) | Runtime |
181
247
  | [`SetManualFocusStateInput`](api/capture-focus-control.md#setmanualfocusstateinput) | Type |
182
248
 
249
+ ## capture/jpeg-xl-tiles.ts
250
+
251
+ [Detailed contracts](api/capture-jpeg-xl-tiles.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/jpeg-xl-tiles.ts)
252
+
253
+ | Export | Kind |
254
+ | --- | --- |
255
+ | [`createJxlOxideDngDecoder`](api/capture-jpeg-xl-tiles.md#createjxloxidedngdecoder) | Runtime |
256
+ | [`DngJpegXlDecoder`](api/capture-jpeg-xl-tiles.md#dngjpegxldecoder) | Type |
257
+ | [`JxlOxideModule`](api/capture-jpeg-xl-tiles.md#jxloxidemodule) | Type |
258
+
183
259
  ## capture/linear-encoding.ts
184
260
 
185
261
  [Detailed contracts](api/capture-linear-encoding.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/linear-encoding.ts)
@@ -204,6 +280,16 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
204
280
  | [`LosslessJpegLimits`](api/capture-lossless-jpeg.md#losslessjpeglimits) | Type |
205
281
  | [`parseLosslessJpeg`](api/capture-lossless-jpeg.md#parselosslessjpeg) | Runtime |
206
282
 
283
+ ## capture/lossy-jpeg.ts
284
+
285
+ [Detailed contracts](api/capture-lossy-jpeg.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/lossy-jpeg.ts)
286
+
287
+ | Export | Kind |
288
+ | --- | --- |
289
+ | [`LossyJpegImage`](api/capture-lossy-jpeg.md#lossyjpegimage) | Type |
290
+ | [`LossyJpegLimits`](api/capture-lossy-jpeg.md#lossyjpeglimits) | Type |
291
+ | [`parseLossyJpeg`](api/capture-lossy-jpeg.md#parselossyjpeg) | Runtime |
292
+
207
293
  ## capture/native-environment-optical-stage.ts
208
294
 
209
295
  [Detailed contracts](api/capture-native-environment-optical-stage.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/capture/native-environment-optical-stage.ts)
@@ -727,6 +813,16 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
727
813
  | --- | --- |
728
814
  | [`InvalidConfigurationError`](api/core-configuration-error.md#invalidconfigurationerror) | Runtime |
729
815
 
816
+ ## core/execution-error.ts
817
+
818
+ [Detailed contracts](api/core-execution-error.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/core/execution-error.ts)
819
+
820
+ | Export | Kind |
821
+ | --- | --- |
822
+ | [`ImageKernelExecutionError`](api/core-execution-error.md#imagekernelexecutionerror) | Runtime |
823
+ | [`ImageKernelFailureReason`](api/core-execution-error.md#imagekernelfailurereason) | Type |
824
+ | [`ImageKernelFallbackReason`](api/core-execution-error.md#imagekernelfallbackreason) | Type |
825
+
730
826
  ## core/image-formation.ts
731
827
 
732
828
  [Detailed contracts](api/core-image-formation.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/core/image-formation.ts)
@@ -976,6 +1072,26 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
976
1072
  | [`GenericReleaseDriveMode`](api/equipment-release-capabilities.md#genericreleasedrivemode) | Type |
977
1073
  | [`parseGenericReleaseCapabilityProfile`](api/equipment-release-capabilities.md#parsegenericreleasecapabilityprofile) | Runtime |
978
1074
 
1075
+ ## equipment/sensor-profile-body.ts
1076
+
1077
+ [Detailed contracts](api/equipment-sensor-profile-body.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/equipment/sensor-profile-body.ts)
1078
+
1079
+ | Export | Kind |
1080
+ | --- | --- |
1081
+ | [`SENSOR_PROFILE_ISO_ANCHOR`](api/equipment-sensor-profile-body.md#sensor_profile_iso_anchor) | Runtime |
1082
+ | [`SensorProfile`](api/equipment-sensor-profile-body.md#sensorprofile) | Type |
1083
+ | [`SensorProfileValueKind`](api/equipment-sensor-profile-body.md#sensorprofilevaluekind) | Type |
1084
+
1085
+ ## equipment/sensor-profiles.ts
1086
+
1087
+ [Detailed contracts](api/equipment-sensor-profiles.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/equipment/sensor-profiles.ts)
1088
+
1089
+ | Export | Kind |
1090
+ | --- | --- |
1091
+ | [`resolveSensorProfile`](api/equipment-sensor-profiles.md#resolvesensorprofile) | Runtime |
1092
+ | [`SENSOR_PROFILE_IDS`](api/equipment-sensor-profiles.md#sensor_profile_ids) | Runtime |
1093
+ | [`SENSOR_PROFILES`](api/equipment-sensor-profiles.md#sensor_profiles) | Runtime |
1094
+
979
1095
  ## exposure/auto-iso-slowest-shutter.ts
980
1096
 
981
1097
  [Detailed contracts](api/exposure-auto-iso-slowest-shutter.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/exposure/auto-iso-slowest-shutter.ts)
@@ -1314,6 +1430,19 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1314
1430
  | [`DisplayViewCorrectionStateSet`](api/facade-display-view.md#displayviewcorrectionstateset) | Type |
1315
1431
  | [`serializeDisplayViewCorrectionStates`](api/facade-display-view.md#serializedisplayviewcorrectionstates) | Runtime |
1316
1432
 
1433
+ ## facade/exposure-build-up.ts
1434
+
1435
+ [Detailed contracts](api/facade-exposure-build-up.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/exposure-build-up.ts)
1436
+
1437
+ | Export | Kind |
1438
+ | --- | --- |
1439
+ | [`EXPOSURE_BUILD_UP_MAXIMUM_FRACTIONS`](api/facade-exposure-build-up.md#exposure_build_up_maximum_fractions) | Runtime |
1440
+ | [`EXPOSURE_BUILD_UP_STREAM_BASE`](api/facade-exposure-build-up.md#exposure_build_up_stream_base) | Runtime |
1441
+ | [`simulateExposureBuildUp`](api/facade-exposure-build-up.md#simulateexposurebuildup) | Runtime |
1442
+ | [`SimulateExposureBuildUpFrame`](api/facade-exposure-build-up.md#simulateexposurebuildupframe) | Type |
1443
+ | [`SimulateExposureBuildUpOptions`](api/facade-exposure-build-up.md#simulateexposurebuildupoptions) | Type |
1444
+ | [`SimulateExposureBuildUpResult`](api/facade-exposure-build-up.md#simulateexposurebuildupresult) | Type |
1445
+
1317
1446
  ## facade/fast-methods.ts
1318
1447
 
1319
1448
  [Detailed contracts](api/facade-fast-methods.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/fast-methods.ts)
@@ -1323,6 +1452,52 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1323
1452
  | [`SIMULATE_CAPTURE_FAST_METHODS`](api/facade-fast-methods.md#simulate_capture_fast_methods) | Runtime |
1324
1453
  | [`SimulateCaptureFastMethod`](api/facade-fast-methods.md#simulatecapturefastmethod) | Type |
1325
1454
 
1455
+ ## facade/image-plane-enable.ts
1456
+
1457
+ [Detailed contracts](api/facade-image-plane-enable.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/image-plane-enable.ts)
1458
+
1459
+ | Export | Kind |
1460
+ | --- | --- |
1461
+ | [`prepareImagePlaneScenes`](api/facade-image-plane-enable.md#prepareimageplanescenes) | Runtime |
1462
+
1463
+ ## facade/mixed-illumination.ts
1464
+
1465
+ [Detailed contracts](api/facade-mixed-illumination.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/mixed-illumination.ts)
1466
+
1467
+ | Export | Kind |
1468
+ | --- | --- |
1469
+ | [`MixedIllumination`](api/facade-mixed-illumination.md#mixedillumination) | Type |
1470
+ | [`MixedIlluminationBlend`](api/facade-mixed-illumination.md#mixedilluminationblend) | Type |
1471
+ | [`MixedIlluminationPoint`](api/facade-mixed-illumination.md#mixedilluminationpoint) | Type |
1472
+ | [`MixedIlluminationPointSource`](api/facade-mixed-illumination.md#mixedilluminationpointsource) | Type |
1473
+ | [`MixedIlluminationSource`](api/facade-mixed-illumination.md#mixedilluminationsource) | Type |
1474
+
1475
+ ## facade/quality-paths.ts
1476
+
1477
+ [Detailed contracts](api/facade-quality-paths.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/quality-paths.ts)
1478
+
1479
+ | Export | Kind |
1480
+ | --- | --- |
1481
+ | [`prepareQualityPaths`](api/facade-quality-paths.md#preparequalitypaths) | Runtime |
1482
+
1483
+ ## facade/representative-light-sources.ts
1484
+
1485
+ [Detailed contracts](api/facade-representative-light-sources.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/representative-light-sources.ts)
1486
+
1487
+ | Export | Kind |
1488
+ | --- | --- |
1489
+ | [`createRepresentativeLightSourceIlluminant`](api/facade-representative-light-sources.md#createrepresentativelightsourceilluminant) | Runtime |
1490
+ | [`createRepresentativeLightSourceSpectrum`](api/facade-representative-light-sources.md#createrepresentativelightsourcespectrum) | Runtime |
1491
+ | [`getRepresentativeLightSourceSet`](api/facade-representative-light-sources.md#getrepresentativelightsourceset) | Runtime |
1492
+ | [`REPRESENTATIVE_LIGHT_SOURCE_IDS`](api/facade-representative-light-sources.md#representative_light_source_ids) | Runtime |
1493
+ | [`REPRESENTATIVE_LIGHT_SOURCE_SET_ID`](api/facade-representative-light-sources.md#representative_light_source_set_id) | Runtime |
1494
+ | [`REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION`](api/facade-representative-light-sources.md#representative_light_source_set_version) | Runtime |
1495
+ | [`REPRESENTATIVE_LIGHT_SOURCE_WAVELENGTH_RANGE_NANOMETERS`](api/facade-representative-light-sources.md#representative_light_source_wavelength_range_nanometers) | Runtime |
1496
+ | [`RepresentativeLightSource`](api/facade-representative-light-sources.md#representativelightsource) | Type |
1497
+ | [`RepresentativeLightSourceBand`](api/facade-representative-light-sources.md#representativelightsourceband) | Type |
1498
+ | [`RepresentativeLightSourceId`](api/facade-representative-light-sources.md#representativelightsourceid) | Type |
1499
+ | [`RepresentativeLightSourceSet`](api/facade-representative-light-sources.md#representativelightsourceset) | Type |
1500
+
1326
1501
  ## facade/scene-radiance.ts
1327
1502
 
1328
1503
  [Detailed contracts](api/facade-scene-radiance.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/scene-radiance.ts)
@@ -1337,6 +1512,8 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1337
1512
  | [`CHART_SIZE_DEFAULT_SURROUND_REFLECTANCE`](api/facade-scene-radiance.md#chart_size_default_surround_reflectance) | Runtime |
1338
1513
  | [`ChartSizeOption`](api/facade-scene-radiance.md#chartsizeoption) | Type |
1339
1514
  | [`createPlanarSceneRadianceProvider`](api/facade-scene-radiance.md#createplanarsceneradianceprovider) | Runtime |
1515
+ | [`ImagePlaneImage`](api/facade-scene-radiance.md#imageplaneimage) | Type |
1516
+ | [`ImagePlaneScene`](api/facade-scene-radiance.md#imageplanescene) | Type |
1340
1517
  | [`PHOTOPIC_MAXIMUM_LUMINOUS_EFFICACY_LM_PER_W`](api/facade-scene-radiance.md#photopic_maximum_luminous_efficacy_lm_per_w) | Runtime |
1341
1518
  | [`PlanarSceneRadianceProvider`](api/facade-scene-radiance.md#planarsceneradianceprovider) | Type |
1342
1519
  | [`resolveCaptureIlluminant`](api/facade-scene-radiance.md#resolvecaptureilluminant) | Runtime |
@@ -1451,9 +1628,6 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1451
1628
  | [`ImageKernelBackend`](api/gpu-image-kernel-execution.md#imagekernelbackend) | Type |
1452
1629
  | [`ImageKernelCodeErrorBound`](api/gpu-image-kernel-execution.md#imagekernelcodeerrorbound) | Type |
1453
1630
  | [`ImageKernelExecution`](api/gpu-image-kernel-execution.md#imagekernelexecution) | Type |
1454
- | [`ImageKernelExecutionError`](api/gpu-image-kernel-execution.md#imagekernelexecutionerror) | Runtime |
1455
- | [`ImageKernelFailureReason`](api/gpu-image-kernel-execution.md#imagekernelfailurereason) | Type |
1456
- | [`ImageKernelFallbackReason`](api/gpu-image-kernel-execution.md#imagekernelfallbackreason) | Type |
1457
1631
  | [`ImageKernelRelativeErrorBound`](api/gpu-image-kernel-execution.md#imagekernelrelativeerrorbound) | Type |
1458
1632
  | [`ImageKernelSeededRealizationBound`](api/gpu-image-kernel-execution.md#imagekernelseededrealizationbound) | Type |
1459
1633
  | [`WEBGPU_F32_TRANSFER_ABSOLUTE_BOUND`](api/gpu-image-kernel-execution.md#webgpu_f32_transfer_absolute_bound) | Runtime |
@@ -1563,6 +1737,14 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1563
1737
  | [`CalculateProjectedMotionBlurInput`](api/motion-projected-motion.md#calculateprojectedmotionblurinput) | Type |
1564
1738
  | [`ProjectedMotionBlur`](api/motion-projected-motion.md#projectedmotionblur) | Type |
1565
1739
 
1740
+ ## motion/subject-motion.ts
1741
+
1742
+ [Detailed contracts](api/motion-subject-motion.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/motion/subject-motion.ts)
1743
+
1744
+ | Export | Kind |
1745
+ | --- | --- |
1746
+ | [`SimulateCaptureSubjectMotion`](api/motion-subject-motion.md#simulatecapturesubjectmotion) | Type |
1747
+
1566
1748
  ## motion/temporal-exposure-sum.ts
1567
1749
 
1568
1750
  [Detailed contracts](api/motion-temporal-exposure-sum.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/motion/temporal-exposure-sum.ts)
@@ -1801,6 +1983,17 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1801
1983
  | [`resolveFrontOfLensFilterTransmission`](api/optics-front-of-lens-filter.md#resolvefrontoflensfiltertransmission) | Runtime |
1802
1984
  | [`ResolveFrontOfLensFilterTransmissionInput`](api/optics-front-of-lens-filter.md#resolvefrontoflensfiltertransmissioninput) | Type |
1803
1985
 
1986
+ ## optics/generic-lens-lateral-color.ts
1987
+
1988
+ [Detailed contracts](api/optics-generic-lens-lateral-color.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/optics/generic-lens-lateral-color.ts)
1989
+
1990
+ | Export | Kind |
1991
+ | --- | --- |
1992
+ | [`calculateLateralColorFringe`](api/optics-generic-lens-lateral-color.md#calculatelateralcolorfringe) | Runtime |
1993
+ | [`CalculateLateralColorFringeInput`](api/optics-generic-lens-lateral-color.md#calculatelateralcolorfringeinput) | Type |
1994
+ | [`LateralColorDisplacement`](api/optics-generic-lens-lateral-color.md#lateralcolordisplacement) | Type |
1995
+ | [`LateralColorFringe`](api/optics-generic-lens-lateral-color.md#lateralcolorfringe) | Type |
1996
+
1804
1997
  ## optics/generic-nd-filter-presets.ts
1805
1998
 
1806
1999
  [Detailed contracts](api/optics-generic-nd-filter-presets.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/optics/generic-nd-filter-presets.ts)
@@ -2097,6 +2290,16 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
2097
2290
  | [`ZernikeCoefficient`](api/optics-zernike-wavefront.md#zernikecoefficient) | Type |
2098
2291
  | [`ZernikeOrder`](api/optics-zernike-wavefront.md#zernikeorder) | Type |
2099
2292
 
2293
+ ## output/camera-channel-response.ts
2294
+
2295
+ [Detailed contracts](api/output-camera-channel-response.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/output/camera-channel-response.ts)
2296
+
2297
+ | Export | Kind |
2298
+ | --- | --- |
2299
+ | [`calculateCameraChannelResponse`](api/output-camera-channel-response.md#calculatecamerachannelresponse) | Runtime |
2300
+ | [`CalculateCameraChannelResponseInput`](api/output-camera-channel-response.md#calculatecamerachannelresponseinput) | Type |
2301
+ | [`CameraChannelResponse`](api/output-camera-channel-response.md#camerachannelresponse) | Type |
2302
+
2100
2303
  ## output/capture-corrected-sdr.ts
2101
2304
 
2102
2305
  [Detailed contracts](api/output-capture-corrected-sdr.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/output/capture-corrected-sdr.ts)
@@ -2183,6 +2386,7 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
2183
2386
 
2184
2387
  | Export | Kind |
2185
2388
  | --- | --- |
2389
+ | [`ChannelDispersion`](api/output-developed-lens-corrections.md#channeldispersion) | Type |
2186
2390
  | [`GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM`](api/output-developed-lens-corrections.md#generic_lens_correction_channel_wavelengths_nm) | Runtime |
2187
2391
 
2188
2392
  ## output/generic-lens-corrections.ts
@@ -2191,6 +2395,8 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
2191
2395
 
2192
2396
  | Export | Kind |
2193
2397
  | --- | --- |
2398
+ | [`calculateChannelEffectiveDispersion`](api/output-generic-lens-corrections.md#calculatechanneleffectivedispersion) | Runtime |
2399
+ | [`CalculateChannelEffectiveDispersionInput`](api/output-generic-lens-corrections.md#calculatechanneleffectivedispersioninput) | Type |
2194
2400
  | [`createGenericLensCorrectionProfile`](api/output-generic-lens-corrections.md#creategenericlenscorrectionprofile) | Runtime |
2195
2401
  | [`CreateGenericLensCorrectionProfileInput`](api/output-generic-lens-corrections.md#creategenericlenscorrectionprofileinput) | Type |
2196
2402
 
@@ -2336,7 +2542,9 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
2336
2542
  | [`calculatePrintPlan`](api/output-print-plan.md#calculateprintplan) | Runtime |
2337
2543
  | [`calculatePrintSizeLimit`](api/output-print-plan.md#calculateprintsizelimit) | Runtime |
2338
2544
  | [`parsePrintPlanInput`](api/output-print-plan.md#parseprintplaninput) | Runtime |
2545
+ | [`PrintContainLayout`](api/output-print-plan.md#printcontainlayout) | Type |
2339
2546
  | [`PrintedImageSize`](api/output-print-plan.md#printedimagesize) | Type |
2547
+ | [`PrintFit`](api/output-print-plan.md#printfit) | Type |
2340
2548
  | [`PrintLength`](api/output-print-plan.md#printlength) | Type |
2341
2549
  | [`PrintNativeSource`](api/output-print-plan.md#printnativesource) | Type |
2342
2550
  | [`PrintPlan`](api/output-print-plan.md#printplan) | Type |
@@ -3194,6 +3402,8 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
3194
3402
 
3195
3403
  | Export | Kind |
3196
3404
  | --- | --- |
3405
+ | [`SimulateCaptureMidGreyFigure`](api/sensor-sensor-characteristics.md#simulatecapturemidgreyfigure) | Type |
3406
+ | [`SimulateCaptureNativeSensorReport`](api/sensor-sensor-characteristics.md#simulatecapturenativesensorreport) | Type |
3197
3407
  | [`SimulateCaptureNoiseComponents`](api/sensor-sensor-characteristics.md#simulatecapturenoisecomponents) | Type |
3198
3408
  | [`SimulateCaptureSensorCharacteristics`](api/sensor-sensor-characteristics.md#simulatecapturesensorcharacteristics) | Type |
3199
3409
  | [`SimulateCaptureSensorReport`](api/sensor-sensor-characteristics.md#simulatecapturesensorreport) | Type |
@@ -48,7 +48,7 @@ the example above is [simulate-capture.mjs](examples/simulate-capture.mjs).
48
48
  | `raw` | The packed native RAW: codes, black levels, saturation flags and per-phase white levels |
49
49
  | `plan` | The native RAW plan the engine executed |
50
50
  | `request` | The complete underlying request: `environmentRaw` (the native environment RAW input), `siteInput(index)` (rebuilds the physical input of any sensor site), `development` (the RAW development input) and `whiteBalanceState` |
51
- | `sensor` | 2.20 (#555, #535): the sensor characteristics used (pitch, peak QE, full well, read noise of each conversion gain and the dual-gain switch ISO, readout time, ADC bit depth, fixed-pattern noise), the calculated dynamic range (`dynamicRangeStops`, and per ISO setting) and, on exact requests, the mid-gray noise figure (`midGrey`); see [Sensor characteristics](#sensor-characteristics-555) |
51
+ | `sensor` | 2.20 (#555, #535): the sensor characteristics used (pitch, peak QE, full well, read noise of each conversion gain and the dual-gain switch ISO, readout time, ADC bit depth, fixed-pattern noise), the calculated dynamic range (`dynamicRangeStops`, and per ISO setting) and, on exact requests, the mid-gray noise figure (`midGrey`); 2.22 (#595): the same for one native photosite with the EMVA 1288 and 8 MP-normalized dynamic range (`native`); see [Sensor characteristics](#sensor-characteristics-555) |
52
52
  | `exposure` | Mode, resolved settings, EV100, `isoControl` (`"manual"` or `"automatic"`) and, with `iso: "auto"`, `autoIso` (how the ISO was chosen and what limited it), metered scene luminance, the deviation from the standard exposure in stops (`standardExposureDeviationStops`), the illuminance at which the settings give the standard exposure (`standardExposureIlluminanceLux`), from 2.14 the deviation from the standard exposure of an 18 % grey card under the scene's illuminance (`greyCardDeviationStops`, incident metering) and the exposure-mode resolver's full output |
53
53
  | `scene` | Chart parameters, illuminant, distance, framed size and the scene's SHA-256 digest (it covers caller illuminant and reflectance spectra; see `sourceSha256`) |
54
54
  | `diagnostics` | Radiance query count, highlight and rendering counters, per-stage timings (`timingsMs`) and, from 2.1, the opt-ins that ran (`options`); see [Cost of each option](#cost-of-each-option) |
@@ -88,6 +88,7 @@ modelling choices (such as "no lens PSF") as `kind: "model"`.
88
88
  | `chartSize` | fill the frame | 2.3: `{ widthM, heightM?, surroundReflectance? }` places the chart at its physical size (see [Fixed-size chart](#fixed-size-chart-23)). |
89
89
  | `illuminant` | Planckian 6500 K | Also `"cie-a"`, `{ kind: "planckian", temperatureKelvin }`, `{ kind: "daylight", correlatedColorTemperatureKelvin, basis }` or `{ kind: "spectrum", spectrum }`. |
90
90
  | `illuminanceLux` | 21 481 (π·80 000/11.7) | See [Exposure](#exposure). |
91
+ | `illumination` | off | 2.22 (#550): mixed lighting, two to eight sources (`{ illuminant, illuminanceLux }`) blended across the chart by a linear gradient, a radial falloff or regions, and point sources (`points`) with inverse-square falloff, instead of `illuminant` and `illuminanceLux`. The frame center's light sets the grey card and its strongest source the `"scene-illuminant"` white balance (see [Mixed lighting](https://github.com/Photivra/photivra/blob/main/docs/MIXED_ILLUMINATION.md)). |
91
92
  | `output.width`, `output.height` | 64 × 64 | Output pixels, 1–4094 each. The sensor has one extra site on each side for demosaicing (see `output.borderHandling`). |
92
93
  | `output.maximumPixels` | off | Opt-in large images (2.2): the most native sensor sites the capture may allocate, up to `NATIVE_RAW_LIMITS.ceilingPixels` (2^27). Sides may then reach 16 384 sites including the margin (see [Large images](#large-images)). |
93
94
  | `output.region` | whole frame | 2.3: `{ x, y, width, height }` renders that rectangle of the frame, byte-identical to the whole render (see [Region rendering](#region-rendering-23)). |
@@ -109,7 +110,7 @@ modelling choices (such as "no lens PSF") as `kind: "model"`.
109
110
  | `output.whiteBalance` | `"scene-illuminant"` | Also `"auto"`, `"none"`, `{ kelvin, tint? }` and `{ channelGains }`. |
110
111
  | `output.jpegQuantizationStep` | 2 | JPEG only: constant step 1–255, not a manufacturer quality scale. |
111
112
  | `sensor.pixelPitchMicrometers` | 6 | 0.5–1000 (2.5; 0.5–100 before). The sensor is `width × pitch` wide (see [Geometry](#geometry)); the ISO readout scales with the pixel area (see [ISO and pixel size](#iso-and-pixel-size)). Above 100 µm the capture is a downsized view of a whole frame (see [Whole-frame views](#whole-frame-views-25)). |
112
- | `sensor.spectralStepNanometers` | 20 | Spectral quadrature over 380–780 nm. |
113
+ | `sensor.spectralStepNanometers` | 20; 5 on exact requests under a spiky light (2.22.0, #590) | Spectral quadrature over 380–780 nm. A light is spiky when R(20) = 20²·κ/24 > 0.01, κ = Σ\|Δ²S\| / ΣS on a 1 nm grid (the midpoint rule's error term, DLMF §3.5(i)): the fluorescent and LED representative sources. Exact requests (DNG, JPEG, PNG, `fast: false`) then take 5 nm; fast ones keep 20 nm, add the assumption `sensor.spectralSpikiness` and report `diagnostics.fast.applied["sensor.spectralStepNanometers"]: true` (exact ones `false`). An explicit step wins and adds no key. |
113
114
  | `sensor.temporalSampleCount` | 1, or 8 when the camera rotates | Midpoints across each site's exposure window. |
114
115
  | `sensor.noiseSeed` | 1 | Output is deterministic for a given seed. |
115
116
  | `sensor.antiAliasing` | off | 2.1: an optical low-pass (anti-aliasing) filter: `{ kind: "four-spot", separationSites? }`, `{ kind: "two-spot", axis, separationSites? }` or `{ kind: "point-splitting", components }` (see [Anti-aliasing filter](#anti-aliasing-filter)). Each record also takes `fast`. |
@@ -118,6 +119,7 @@ modelling choices (such as "no lens PSF") as `kind: "model"`.
118
119
  | `motion.angularVelocityRadPerSec` | still | `{ pitch?, yaw?, roll? }` in rad/s (see [Motion](#motion)). |
119
120
  | `motion.shutter` | `"global"` | Or `"rolling"`. |
120
121
  | `motion.rollingShutterSkewSeconds` | the body's readout skew | Rolling only. |
122
+ | `motion.subject` | still subject | 2.22.0: `{ velocityMPerSec?: { x?, y? }, angularVelocityRadPerSec?, region?, fast? }`, a moving subject (see [Subject motion](#subject-motion)). |
121
123
  | `signal`, `onProgress` | none | An `AbortSignal` cancels the running task; `onProgress` reports `raw`, `white-balance`, `development`, `diffraction-correction` and `sharpening` (#571: output rows, with those options) and `jpeg` tiles. The last event of each stage has `completedTileCount === totalTileCount`. The capture yields to the host about every 8 ms with a `MessageChannel` message (else `setImmediate`, else `setTimeout`), so other queued tasks run in between: an abort sent from another task, such as a Web Worker `message` event, takes effect at the next yield. |
122
124
 
123
125
  Unknown fields are rejected, so a typo never silently falls back to a default.
@@ -442,7 +444,10 @@ independent of pixel size, so the same exposure gives the same image brightness
442
444
  - So the facade multiplies the system conversion gain (e⁻ per code) and the pre-ADC saturation
443
445
  signal of every ISO regime by the area ratio pitch²/36 µm². Codes, black level, ADC and digital gain
444
446
  are unchanged. At 6 µm the ratio is exactly 1 and nothing is changed (byte-identical to 2.1.0).
445
- - Read noise (in e⁻) and the synthetic dark current (1 e⁻/s) stay per pixel.
447
+ - Above 6 µm a pixel stands for N = pitch²/36 µm² of the tier's 6 µm photosites, so (from 2.22.0, #599) its
448
+ read noise is the photosite's summed in quadrature, ×√N, as for a [sensor profile](#sensor-profiles-554)
449
+ (EMVA 1288 Release 4.0, §6.4: binning multiplies the pixel area). Below 6 µm the read noise (in e⁻) stays
450
+ per pixel, and the synthetic dark current (1 e⁻/s) stays per pixel at every pitch.
446
451
 
447
452
  What you see: brightness stays the same, and per-pixel noise rises as pixels shrink, because a
448
453
  smaller pixel collects fewer electrons for the same exposure (shot-noise SNR = √N_e). At f/8, 1/125 s,
@@ -487,7 +492,7 @@ r.sensor.dynamicRangeStops; r.sensor.midGrey?.snrDecibels;
487
492
  | --- | --- | --- | --- |
488
493
  | `peakQuantumEfficiency` | 0.05–0.9 | 0.5 | Multiplies every channel's EQE curve by value / 0.5: the curves keep their shape and the colour matrix, and the collected charge scales in proportion. 0.9 keeps the blue channel's peak below 1. |
489
494
  | `fullWell` | 100–1e10 e⁻ at the pitch | the body's base-ISO saturation at 6 µm, × pitch²/36 µm² | The charge at the RAW white level at base ISO (the saturation capacity of EMVA 1288 Release 4.0). `link: "pixel-area"` (default) scales `electrons`, the full well at `referencePixelPitchMicrometers` (default 6), by (pitch / reference)²; `link: "none"` uses it at any pitch. |
490
- | `readNoise` | 0–100 e⁻; switch ISO 100–1e7 | the body's (tiers: 2/1.1, 3/1.4 and 6/2.5 e⁻, switch at ISO 800) | Read noise of the low and the high conversion gain, and `highGainFromIso`, the ISO from which the high gain is used. A switch above the body's top ISO keeps the low gain throughout. |
495
+ | `readNoise` | 0–100 e⁻; switch ISO 100–1e7 | the body's (tiers: 2/1.1, 3/1.4 and 6/2.5 e⁻ per 6 µm photosite, ×√N above 6 µm; switch at ISO 800) | Read noise of one physical photosite (2.22.0, tiers and profiles alike; a rendered site that sums N photosites takes it ×√N) for the low and the high conversion gain, and `highGainFromIso`, the ISO from which the high gain is used. A switch above the body's top ISO keeps the low gain throughout. |
491
496
  | `readoutSeconds` | 1e-6–1 s | the body's (8, 15, 30 ms) | The rolling shutter's top-to-bottom skew (`motion.shutter: "rolling"`; `motion.rollingShutterSkewSeconds` still overrides it). |
492
497
  | `adcBitDepth` | 12, 14, 16 | the body's (consumer 12, others 14) | The black level scales by 2^Δbits (1 024 at 14 bits → 4 096 at 16), the saturation code is 2^bits − 1 and the conversion gain follows, so the same charge reaches the same fraction of the code range. A 16-bit RAW writes a 16-bit DNG with white level 65 535. |
493
498
  | `fixedPatternNoise` | `true`/`false` | `false` | The body's synthetic fixed-pattern profile (PRNU, DSNU, hot pixels, row and column offsets), the same pattern in every capture. Not available in `simulateDisplayView`, which refuses it. |
@@ -514,6 +519,32 @@ gain) in electrons. With no read noise the range is limited by the ADC alone: lo
514
519
  The Professional tier gives 14.7 stops at ISO 100, 12.7 at ISO 800 (high gain) and 9.7 at ISO 6400;
515
520
  the Consumer tier 11.7, 10.0 and 7.0.
516
521
 
522
+ **Native-pixel dynamic range (#595)** (`sensor.native`, from 2.22.0): the figures above are those of
523
+ the rendered site, which at a pitch other than the body's own stands for N = (pitch / native pitch)²
524
+ photosites (`native.photositesPerSite`). `sensor.native` gives the same figures for one native
525
+ photosite: a generic tier's declared 6 µm reference, or a sensor profile's own pitch, with the request's
526
+ sensor characteristics applied as at that pitch. It has the photosite's `fullWellElectrons`,
527
+ `readNoiseElectrons`, engineering `dynamicRangeStops` and `dynamicRangeByIso`, and, on exact requests,
528
+ its `midGrey` figure (the site's charge × 1/N). For N independent photosites summed with their read noise,
529
+ S_sat,N = N·S_sat,0 and σ_N = √N·σ_0, so the rendered range is the native range + ½·log₂N, limited by the
530
+ ADC, and the rendered mid-gray SNR is √N times the native one.
531
+
532
+ - `native.emva1288`: EMVA 1288 Release 4.0 Linear (§2.7, Eq. 26–28, free from emva.org): the absolute
533
+ sensitivity threshold μ_e.min = √(σ_d² + σ_q² + 1/4) + 1/2 (σ_d the read noise, dark current excluded),
534
+ `dynamicRangeStops` = log₂(μ_e.sat / μ_e.min) and `dynamicRangeDecibels`, and the saturation capacity
535
+ per µm² (Table 2). This is the figure to show as "dynamic range (EMVA 1288)". It is slightly lower than
536
+ the engineering figure: 14.36 against 14.67 stops for the Professional tier at ISO 100.
537
+ - `native.normalized8Megapixel`: **a convention, not part of EMVA 1288**, for comparing bodies of
538
+ different resolutions: the frame's native photosites (`framePhotosites`, the output frame's area over
539
+ the native photosite's) resampled to 8 million pixels, each summing framePhotosites / 8 000 000
540
+ photosites with their read noise (the binning rule above): DR + ½·log₂(framePhotosites / 8 000 000),
541
+ for the engineering and the EMVA figure. No ADC limit is applied to the sum. A 6000 × 4000 frame of
542
+ 6 µm photosites adds 0.79 stops.
543
+
544
+ All are model figures from the engine's noise model, not measurements. `sensor.readNoise` is per **physical
545
+ photosite** on a tier and a profile alike (2.22.0): `native.readNoiseElectrons` is the value given, and a rendered site
546
+ that sums N photosites takes it ×√N.
547
+
517
548
  **Noise figure** (#535, `sensor.midGrey`): computed only when the request resolves to exact (`fast:
518
549
  false`, the default for DNG, JPEG and PNG exports; about 0.3 ms); a fast request (the sRGB default)
519
550
  omits it. The expected signal-to-noise ratio of an 18 % Lambertian
@@ -530,6 +561,29 @@ SNR is 88.5 (38.9 dB); at ISO 6400 with 1/64 of the light, S ≈ 123 e⁻ and th
530
561
  the photon shot noise grows as √S, so less light means more noise whatever the ISO. The display view
531
562
  reports the same `sensor` record as its capture.
532
563
 
564
+ ### Sensor profiles (#554)
565
+
566
+ `sensor.profile` takes one of eight representative sensor profile records whose values come from
567
+ published specifications (`SENSOR_PROFILES`, or `resolveSensorProfile(id)`; unnamed, by format,
568
+ resolution, architecture and era), checked strictly, so a modified copy also works. It
569
+ replaces the body's ISO range, readout regimes (full well, read noise of each conversion gain, the
570
+ dual-gain switch and the high gain's storage, ADC bit depth), readout time and fixed-pattern noise,
571
+ and sets the default pitch and peak QE; the characteristics above still override it one at a time.
572
+
573
+ ```ts
574
+ import { resolveSensorProfile, simulateCapture } from "@photivra/engine";
575
+ const phone = await simulateCapture({ scene: { preset: "uniform" }, sensor: { profile: resolveSensorProfile("phone-50mp-stacked") } });
576
+ phone.sensor.fullWellElectrons; // 8 600 e⁻ at 1.197 µm
577
+ ```
578
+
579
+ Each profile's base ISO is re-rated from its full well, QE and pixel area, so the same ISO reaches
580
+ the RAW white at the same exposure on every profile (the assumption `sensor.profile` records the
581
+ values and the rounding). The phone profile takes the catalogue's three phone lenses
582
+ (`lens: { catalogue: "pv-24-1.8-phone" }`), and they need it. With a profile, a catalogue lens is framed on
583
+ the profile's real sensor (the largest centred region of the output's aspect; assumption `sensor.profileView`), so it
584
+ shows its real field of view. Values, sources, the framing and the ISO rating:
585
+ [SENSOR_PROFILES.md](https://github.com/Photivra/photivra/blob/main/docs/SENSOR_PROFILES.md).
586
+
533
587
  ## Exposure
534
588
 
535
589
  The facade meters the scene like a reflected-light meter:
@@ -1689,6 +1743,48 @@ const pan = await simulateCapture({
1689
1743
  console.log(pan.assumptions.find((a) => a.id === "sensor.shutter")?.value, pan.exposure.settings.shutterSeconds);
1690
1744
  ```
1691
1745
 
1746
+ ## Subject motion
1747
+
1748
+ `motion.subject` (2.22.0, #551) moves the subject on the scene plane during the exposure: the whole scene, or one
1749
+ rectangle of it (`region: { centerXM, centerYM, widthM, heightM }` in metres at rest) over a still background.
1750
+
1751
+ - `velocityMPerSec: { x, y }` is a translation in m/s on the plane (+x right, +y up as seen from the camera).
1752
+ `angularVelocityRadPerSec` adds a rotation about an axis parallel to the optical axis, counter-clockwise as seen from
1753
+ the camera: the optical axis for the whole scene, the region's center for a region.
1754
+ - The model is rigid motion of a planar layer. At time t from the first opening (camera rotation's time reference), a
1755
+ subject point at rest q is at R(ωt)(q − c) + c + v·t. A plane point shows the subject where one is there, else the
1756
+ region's rest rectangle shows a neutral 18 % background (what the subject revealed), else the still scene. The background
1757
+ is lit by the plane's irradiance at that point: the illuminant, or with `illumination` (#550) the blend and point sources there.
1758
+ - Every scene query reads the subject at its own time. The blur is therefore the same temporal midpoint quadrature as
1759
+ camera rotation (`sensor.temporalSampleCount`, default 8 with a moving subject), and an edge streaks over
1760
+ v·T·m on the sensor (m = v′/D, the thin-lens image distance over the subject distance). With few samples a long streak
1761
+ shows separate copies; raise the count. A test checks the length within sampling error.
1762
+ - A rolling shutter skews a moving subject: each row's exposure window opens later, so it sees the subject later. A test
1763
+ checks the skew against the site windows' start offsets.
1764
+ - Panning: a camera yaw of −v/D rad/s (the engine's rotation convention) follows a subject moving at v m/s in +x. The
1765
+ subject stays sharp and the background streaks.
1766
+ - It combines with `lens.diffraction`, `lens.defocus` (global shutter; their site lattices are formed at each midpoint), the
1767
+ lens projection, distortion and vignetting, and camera rotation. `lens.pupilSampling` is refused.
1768
+ - Display view: sideways motion under a global shutter only. It refuses a rotating subject and a rolling shutter with a
1769
+ reason; `simulateCapture` renders both.
1770
+ - Fast method (2.20.0 convention): with the default count and a still camera, `fast` takes one midpoint per site of the
1771
+ streak plus one when that is fewer than 8 (taps less than one site apart). Exact keeps 8, and an explicit
1772
+ `sensor.temporalSampleCount` always wins. Fast is the default for sRGB samples and the display view, exact for DNG,
1773
+ JPEG and PNG.
1774
+ - Off by default: a request without `motion.subject` is byte-identical to 2.20.0.
1775
+
1776
+ ```ts
1777
+ import { simulateCapture } from "@photivra/engine";
1778
+
1779
+ // A subject 4 mm wide moving right at 0.2 m/s, with the camera panning to follow it.
1780
+ const pan = await simulateCapture({
1781
+ scene: { preset: "bar-groups" }, subjectDistanceM: 2, lens: { focalLengthMm: 50 },
1782
+ motion: { angularVelocityRadPerSec: { yaw: -0.1 }, subject: { velocityMPerSec: { x: 0.2 }, region: { centerXM: 0.002, centerYM: 0, widthM: 0.004, heightM: 0.004 } } },
1783
+ output: { width: 32, height: 16 }
1784
+ });
1785
+ console.log(pan.assumptions.find((a) => a.id === "motion.subject")?.value);
1786
+ ```
1787
+
1692
1788
  ## Performance
1693
1789
 
1694
1790
  Almost all of the cost is engine time per sensor site; the facade itself adds little. Since 2.0, the
@@ -2029,6 +2125,64 @@ developed image in 64-bit floats (24 bytes per pixel, 549 MiB at 24 MP), held as
2029
2125
  sampled every 50 ms). The extra pass therefore costs about 5 s on one worker after the parts, against about 10 s to render
2030
2126
  the whole frame again on one worker.
2031
2127
 
2128
+ ### Exposure build-up (#534)
2129
+
2130
+ `simulateExposureBuildUp(options, { fractions })` renders fractions of one exposure as one accumulating process, the way a
2131
+ camera's live readout of a long exposure shows the light building up. Each fraction is read out and developed as its own
2132
+ photo, and the fraction at 1 is `simulateCapture(options)`, byte for byte (owner decision, 2026-11-06).
2133
+
2134
+ - **Signal.** Each fraction fⱼ below 1 is a capture of the same request in manual mode at the whole exposure's resolved
2135
+ f-number and ISO and the shutter fⱼ·t. So its expected signal at every site is integrated from the spectrum over the window
2136
+ [0, fⱼ·t] by the capture itself. That includes camera rotation, `motion.subject` (#551), mixed lighting (#550, which does not
2137
+ change over time) and, with a rolling shutter, each row's own window. No per-channel signal is precomputed (owner rule).
2138
+ - **Charge.** Photon and dark-charge arrivals are Poisson processes with any rate over time. Given a count n over [0, t], the
2139
+ count over [0, s] is Binomial(n, Λ(s)/Λ(t)), with Λ the expected count (R. G. Gallager, *Discrete Stochastic Processes*,
2140
+ chapter 2, sections 2.4 and 2.5, MIT OpenCourseWare 6.262, free). The whole exposure keeps its ordinary draws. Going down
2141
+ the fractions, each site's photo and dark counts are split: N(fⱼ) ~ Binomial(N(fⱼ₊₁), λ(fⱼ)/λ(fⱼ₊₁)), with λ the site's
2142
+ expected mean in each render (after PRNU and DSNU). As a result:
2143
+ - each fraction's counts are Poisson with that fraction's own mean, which is the mean and variance of a capture at fⱼ·t;
2144
+ - the counts never decrease from one fraction to the next;
2145
+ - two fractions' counts covary by the earlier one's mean.
2146
+
2147
+ The binomial draws are exact: inversion, and Hörmann's BTRS rejection (`src/sensor/binomial-sample.ts`).
2148
+ - **Quadrature.** The windows are nested, so the true means never decrease. The temporal midpoint quadrature can still give an
2149
+ earlier fraction a larger estimate than a later one at a site under motion. There the count is kept (probability 1), and the
2150
+ `exposure.buildUp` assumption counts those sites (`nonMonotoneSites`). Raise `sensor.temporalSampleCount` to remove them.
2151
+ - **Sensor.** Fixed-pattern noise (PRNU, DSNU, hot pixels, offsets) belongs to the sensor and is the same in every fraction.
2152
+ Each fraction's charge is clipped at the full well (`sensor.fullWell`), then read out once: its own read noise (the regime's
2153
+ components; dual gain as the ISO selects), pre-ADC and ADC saturation, and quantization at the ADC bit depth (#555; a #554
2154
+ sensor profile's readout feeds the same stage).
2155
+ - **Cost and settings.** One capture per fraction, plus about 64 bytes per native site for the chain. The request's `fast`
2156
+ and the format default apply to every fraction, and the build-up adds no fast method: with `fast: false` (the calculator's
2157
+ setting) every fraction is an exact capture. `"auto"` white balance is measured on each fraction, as its own photo.
2158
+ - **Limits.** On screen only: formats `"srgb-8"` and `"srgb-16"` (a fraction's JPEG, PNG or DNG is refused). 1 to 64
2159
+ fractions, strictly increasing, above 0 and at most 1. Each fraction's shutter fⱼ·t must be one the body can set. A
2160
+ fraction's realization depends on the whole list, because each step of the chain has its own seeded streams
2161
+ (`EXPOSURE_BUILD_UP_STREAM_BASE`). The same request and list always give the same frames.
2162
+ - **Result.** One frame per fraction: `{ fraction, elapsedSeconds, result }`. Below 1, `result` is the fraction capture's
2163
+ result (`image`, `raw`, `plan` and `request` at fⱼ·t), with the build-up's counts and the assumption `exposure.buildUp`.
2164
+ Its `exposure` and `sensor` are the whole exposure's reports: the camera's settings and noise figure, not the elapsed part's.
2165
+
2166
+ ```ts
2167
+ import { simulateExposureBuildUp } from "@photivra/engine";
2168
+
2169
+ const build = await simulateExposureBuildUp({ scene: { preset: "slanted-edge" }, exposure: { mode: "manual", shutterSeconds: 1 / 15, iso: 400 },
2170
+ motion: { angularVelocityRadPerSec: { yaw: 0.2 } }, output: { width: 64, height: 48 } }, { fractions: [0.2, 0.4, 0.6, 0.8, 1] });
2171
+ for (const frame of build.frames) console.log(frame.fraction, frame.elapsedSeconds, frame.result.image.samples.length);
2172
+ ```
2173
+
2174
+ The tests are in `test/exposure-build-up.test.ts`:
2175
+
2176
+ - The last fraction equals `simulateCapture` byte for byte: tabulated and lean paths, fixed pattern, dual gain, auto white
2177
+ balance and Auto ISO, camera rotation, rolling shutter, a moving subject and mixed lighting.
2178
+ - Each fraction's mean and variance match a single capture at f·t. Under motion this is checked column by column, and the
2179
+ fraction is shown to differ from the whole exposure scaled by f.
2180
+ - Without read noise the codes never decrease, and Cov(c₁, c₂) = Var(c₁).
2181
+ - Dark frames' read noise is independent between readouts.
2182
+ - A fraction past the full well clips.
2183
+
2184
+ `test/binomial-sample.test.ts` checks the binomial draws with chi-square tests of the probability mass function.
2185
+
2032
2186
  ### A Print JPEG written in strips
2033
2187
 
2034
2188
  At 1:1 (output size equal to the crop), a Print JPEG's rows can be coded on separate workers.
@@ -2164,10 +2318,10 @@ the exact speed-ups, in [DISPLAY_VIEW.md](https://github.com/Photivra/photivra/b
2164
2318
  | 12 MP phone | Quality | 49.7 s (20×) | 106 s (3.8×) | 272 s (2.2×) |
2165
2319
  | 100 MP medium format | Quality | 18.2 s (3.7×) | 49.7 s (1.8×) | 126 s (1.0×) |
2166
2320
 
2167
- Quality costs more on small pixels. The diffraction kernel spans several real sites, and at 1.4 µm even ISO 100 is
2168
- noisy enough for the AHD correction to run on every sampled pixel; its correction states are kept for later views of
2169
- the same sensor, exposure and development in the same JavaScript realm (2.6.0: a second 384-wide phone view of the same
2170
- request took 73 s instead of 103 s). In 2.6.0 the results were byte-identical to those of the display view as first
2321
+ Quality costs more on small pixels. The diffraction kernel spans several real sites, and (2.6.0 to 2.21.0) at 1.4 µm even
2322
+ ISO 100 was noisy enough for the AHD low-signal correction to run on every sampled pixel (2.6.0: a second 384-wide phone view
2323
+ of the same request took 73 s instead of 103 s, reusing its states). 2.22.0 removed that correction, so these timings
2324
+ include work the view no longer does. In 2.6.0 the results were byte-identical to those of the display view as first
2171
2325
  merged, which took 222 s, 450 s and 837 s on the phone; later releases changed some views' values (for example the
2172
2326
  exact area mean, 2.8.0; AHD's choice, 2.13.0).
2173
2327