@photivra/engine 2.18.0 → 2.19.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 (261) hide show
  1. package/CHANGELOG.md +68 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +6 -6
  4. package/SECURITY.md +1 -1
  5. package/dist/capture/focus-control.js +2 -75
  6. package/dist/capture/focus-control.js.map +1 -1
  7. package/dist/capture/native-environment-lean.d.ts +1 -0
  8. package/dist/capture/native-environment-lean.js +1 -1
  9. package/dist/capture/native-environment-lean.js.map +1 -1
  10. package/dist/capture/native-environment-optical-stage.d.ts +1 -0
  11. package/dist/capture/native-environment-optical-stage.js +2 -5
  12. package/dist/capture/native-environment-optical-stage.js.map +1 -1
  13. package/dist/capture/native-environment-raw.js +1 -5
  14. package/dist/capture/native-environment-raw.js.map +1 -1
  15. package/dist/capture/release-sequence.js +2 -47
  16. package/dist/capture/release-sequence.js.map +1 -1
  17. package/dist/color/white-balance.d.ts +2 -0
  18. package/dist/color/white-balance.js +3 -56
  19. package/dist/color/white-balance.js.map +1 -1
  20. package/dist/composition/image-formation-plan.d.ts +1 -0
  21. package/dist/composition/image-formation-plan.js +3 -49
  22. package/dist/composition/image-formation-plan.js.map +1 -1
  23. package/dist/core/evidence-provenance.js +1 -16
  24. package/dist/core/evidence-provenance.js.map +1 -1
  25. package/dist/core/record-validation.d.ts +54 -0
  26. package/dist/core/record-validation.js +176 -0
  27. package/dist/core/record-validation.js.map +1 -1
  28. package/dist/core/scientific-assurance.js +1 -18
  29. package/dist/core/scientific-assurance.js.map +1 -1
  30. package/dist/core/shared-helpers.d.ts +33 -0
  31. package/dist/core/shared-helpers.js +34 -0
  32. package/dist/core/shared-helpers.js.map +1 -0
  33. package/dist/core/spectral-composition.js +1 -36
  34. package/dist/core/spectral-composition.js.map +1 -1
  35. package/dist/core/spectral.js +1 -19
  36. package/dist/core/spectral.js.map +1 -1
  37. package/dist/core/version.d.ts +1 -1
  38. package/dist/core/version.js +1 -1
  39. package/dist/core/version.js.map +1 -1
  40. package/dist/equipment/exposure-capabilities.d.ts +1 -0
  41. package/dist/equipment/exposure-capabilities.js +2 -36
  42. package/dist/equipment/exposure-capabilities.js.map +1 -1
  43. package/dist/equipment/iso-capabilities.js +2 -49
  44. package/dist/equipment/iso-capabilities.js.map +1 -1
  45. package/dist/equipment/metering-capabilities.js +1 -26
  46. package/dist/equipment/metering-capabilities.js.map +1 -1
  47. package/dist/equipment/release-capabilities.js +1 -53
  48. package/dist/equipment/release-capabilities.js.map +1 -1
  49. package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
  50. package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
  51. package/dist/exposure/exposure-duration-control.js +1 -16
  52. package/dist/exposure/exposure-duration-control.js.map +1 -1
  53. package/dist/exposure/exposure-mode-resolver.js +1 -17
  54. package/dist/exposure/exposure-mode-resolver.js.map +1 -1
  55. package/dist/exposure/filtered-exposure-time.d.ts +93 -0
  56. package/dist/exposure/filtered-exposure-time.js +129 -0
  57. package/dist/exposure/filtered-exposure-time.js.map +1 -0
  58. package/dist/exposure/flash-ttl.d.ts +1 -0
  59. package/dist/exposure/flash-ttl.js +1 -1
  60. package/dist/exposure/flash-ttl.js.map +1 -1
  61. package/dist/exposure/flash.js +1 -49
  62. package/dist/exposure/flash.js.map +1 -1
  63. package/dist/exposure/metering-scene-radiance.js +1 -25
  64. package/dist/exposure/metering-scene-radiance.js.map +1 -1
  65. package/dist/exposure/metering-target.js +1 -30
  66. package/dist/exposure/metering-target.js.map +1 -1
  67. package/dist/exposure/metering-temporal.js +1 -8
  68. package/dist/exposure/metering-temporal.js.map +1 -1
  69. package/dist/exposure/metering.js +1 -72
  70. package/dist/exposure/metering.js.map +1 -1
  71. package/dist/exposure/program-line.js +1 -45
  72. package/dist/exposure/program-line.js.map +1 -1
  73. package/dist/facade/develop-joined-parts.d.ts +29 -0
  74. package/dist/facade/develop-joined-parts.js +33 -0
  75. package/dist/facade/develop-joined-parts.js.map +1 -0
  76. package/dist/facade/generic-lens-capture.d.ts +4 -2
  77. package/dist/facade/generic-lens-capture.js +4 -2
  78. package/dist/facade/generic-lens-capture.js.map +1 -1
  79. package/dist/facade/simulate-capture.d.ts +37 -5
  80. package/dist/facade/simulate-capture.js +153 -96
  81. package/dist/facade/simulate-capture.js.map +1 -1
  82. package/dist/gpu/chart-composite-gpu.js +1 -3
  83. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  84. package/dist/gpu/chart-radiance-gpu.js +1 -5
  85. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  86. package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
  87. package/dist/gpu/display-view-quality-gpu.js +4 -8
  88. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  89. package/dist/gpu/display-view-speed-gpu.js +3 -25
  90. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  91. package/dist/gpu/sensor-stage-gpu.js +1 -5
  92. package/dist/gpu/sensor-stage-gpu.js.map +1 -1
  93. package/dist/gpu/webgpu-runtime.d.ts +2 -0
  94. package/dist/gpu/webgpu-runtime.js +3 -0
  95. package/dist/gpu/webgpu-runtime.js.map +1 -1
  96. package/dist/index.d.ts +4 -1
  97. package/dist/index.js +3 -0
  98. package/dist/index.js.map +1 -1
  99. package/dist/motion/camera-rotation.js +1 -6
  100. package/dist/motion/camera-rotation.js.map +1 -1
  101. package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
  102. package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
  103. package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
  104. package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
  105. package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
  106. package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
  107. package/dist/motion/capture-rotation-trajectory.js +2 -17
  108. package/dist/motion/capture-rotation-trajectory.js.map +1 -1
  109. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
  110. package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
  111. package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
  112. package/dist/motion/extended-object-projection.js +5 -40
  113. package/dist/motion/extended-object-projection.js.map +1 -1
  114. package/dist/optics/atmospheric-haze.js +1 -7
  115. package/dist/optics/atmospheric-haze.js.map +1 -1
  116. package/dist/optics/brown-conrady-distortion.js +1 -7
  117. package/dist/optics/brown-conrady-distortion.js.map +1 -1
  118. package/dist/optics/complex-pupil-psf.d.ts +1 -0
  119. package/dist/optics/complex-pupil-psf.js +2 -84
  120. package/dist/optics/complex-pupil-psf.js.map +1 -1
  121. package/dist/optics/focus-state.js +1 -11
  122. package/dist/optics/focus-state.js.map +1 -1
  123. package/dist/optics/front-of-lens-filter.d.ts +5 -0
  124. package/dist/optics/front-of-lens-filter.js +3 -65
  125. package/dist/optics/front-of-lens-filter.js.map +1 -1
  126. package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
  127. package/dist/optics/generic-nd-filter-presets.js +48 -0
  128. package/dist/optics/generic-nd-filter-presets.js.map +1 -0
  129. package/dist/optics/illumination-vignetting.js +1 -6
  130. package/dist/optics/illumination-vignetting.js.map +1 -1
  131. package/dist/optics/lens-psf-profile.d.ts +4 -1
  132. package/dist/optics/lens-psf-profile.js +12 -111
  133. package/dist/optics/lens-psf-profile.js.map +1 -1
  134. package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
  135. package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
  136. package/dist/optics/pupil-vignetting.js +1 -7
  137. package/dist/optics/pupil-vignetting.js.map +1 -1
  138. package/dist/optics/radial-distortion.js +1 -6
  139. package/dist/optics/radial-distortion.js.map +1 -1
  140. package/dist/optics/scene-to-sensor-irradiance.js +4 -96
  141. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
  142. package/dist/optics/stray-light.d.ts +1 -0
  143. package/dist/optics/stray-light.js +1 -1
  144. package/dist/optics/stray-light.js.map +1 -1
  145. package/dist/optics/zernike-wavefront.js +1 -7
  146. package/dist/optics/zernike-wavefront.js.map +1 -1
  147. package/dist/output/capture-geometry.js +1 -8
  148. package/dist/output/capture-geometry.js.map +1 -1
  149. package/dist/output/developed-lens-corrections.d.ts +62 -0
  150. package/dist/output/developed-lens-corrections.js +135 -0
  151. package/dist/output/developed-lens-corrections.js.map +1 -0
  152. package/dist/output/generic-lens-corrections.d.ts +2 -6
  153. package/dist/output/generic-lens-corrections.js +3 -6
  154. package/dist/output/generic-lens-corrections.js.map +1 -1
  155. package/dist/output/geometric-transforms.js +1 -4
  156. package/dist/output/geometric-transforms.js.map +1 -1
  157. package/dist/output/native-capture-sdr.d.ts +2 -2
  158. package/dist/output/native-capture-sdr.js +3 -2
  159. package/dist/output/native-capture-sdr.js.map +1 -1
  160. package/dist/processing/development-detail.d.ts +29 -0
  161. package/dist/processing/development-detail.js +128 -107
  162. package/dist/processing/development-detail.js.map +1 -1
  163. package/dist/schema/illumination-temporal.js +3 -72
  164. package/dist/schema/illumination-temporal.js.map +1 -1
  165. package/dist/schema/illumination.d.ts +1 -0
  166. package/dist/schema/illumination.js +2 -65
  167. package/dist/schema/illumination.js.map +1 -1
  168. package/dist/schema/scene-radiance-temporal.js +2 -14
  169. package/dist/schema/scene-radiance-temporal.js.map +1 -1
  170. package/dist/schema/scene-radiance.js +2 -60
  171. package/dist/schema/scene-radiance.js.map +1 -1
  172. package/dist/schema/validation.d.ts +2 -0
  173. package/dist/schema/validation.js +2 -17
  174. package/dist/schema/validation.js.map +1 -1
  175. package/dist/sensor/accumulated-charge.js +2 -59
  176. package/dist/sensor/accumulated-charge.js.map +1 -1
  177. package/dist/sensor/architecture.js +1 -16
  178. package/dist/sensor/architecture.js.map +1 -1
  179. package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
  180. package/dist/sensor/camera-saturation-capacity.js +3 -55
  181. package/dist/sensor/camera-saturation-capacity.js.map +1 -1
  182. package/dist/sensor/capture-color-sampling-binding.js +1 -26
  183. package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
  184. package/dist/sensor/capture-mode-timing.js +1 -39
  185. package/dist/sensor/capture-mode-timing.js.map +1 -1
  186. package/dist/sensor/capture-mode.js +1 -23
  187. package/dist/sensor/capture-mode.js.map +1 -1
  188. package/dist/sensor/color-sampling.js +1 -26
  189. package/dist/sensor/color-sampling.js.map +1 -1
  190. package/dist/sensor/constant-rate-temporal-integration.js +2 -46
  191. package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
  192. package/dist/sensor/dark-current.js +2 -45
  193. package/dist/sensor/dark-current.js.map +1 -1
  194. package/dist/sensor/eqe-electron-rate.js +2 -35
  195. package/dist/sensor/eqe-electron-rate.js.map +1 -1
  196. package/dist/sensor/exposure-window.d.ts +5 -0
  197. package/dist/sensor/exposure-window.js +7 -22
  198. package/dist/sensor/exposure-window.js.map +1 -1
  199. package/dist/sensor/iso-gain.js +1 -7
  200. package/dist/sensor/iso-gain.js.map +1 -1
  201. package/dist/sensor/iso-signal-chain.js +1 -43
  202. package/dist/sensor/iso-signal-chain.js.map +1 -1
  203. package/dist/sensor/optical-stack.js +1 -25
  204. package/dist/sensor/optical-stack.js.map +1 -1
  205. package/dist/sensor/photon-energy.js +1 -26
  206. package/dist/sensor/photon-energy.js.map +1 -1
  207. package/dist/sensor/physical-charge-capacity.js +3 -77
  208. package/dist/sensor/physical-charge-capacity.js.map +1 -1
  209. package/dist/sensor/radiometry-readiness.js +2 -23
  210. package/dist/sensor/radiometry-readiness.js.map +1 -1
  211. package/dist/sensor/raw-readout.d.ts +3 -0
  212. package/dist/sensor/raw-readout.js +4 -66
  213. package/dist/sensor/raw-readout.js.map +1 -1
  214. package/dist/sensor/raw-reconstruction.js +2 -64
  215. package/dist/sensor/raw-reconstruction.js.map +1 -1
  216. package/dist/sensor/readout-exposure-linkage.js +1 -9
  217. package/dist/sensor/readout-exposure-linkage.js.map +1 -1
  218. package/dist/sensor/readout-timing.js +3 -57
  219. package/dist/sensor/readout-timing.js.map +1 -1
  220. package/dist/sensor/response-application-compatibility.d.ts +2 -0
  221. package/dist/sensor/response-application-compatibility.js +3 -29
  222. package/dist/sensor/response-application-compatibility.js.map +1 -1
  223. package/dist/sensor/response-operating-range.d.ts +1 -0
  224. package/dist/sensor/response-operating-range.js +3 -79
  225. package/dist/sensor/response-operating-range.js.map +1 -1
  226. package/dist/sensor/responsivity-photocurrent.js +4 -108
  227. package/dist/sensor/responsivity-photocurrent.js.map +1 -1
  228. package/dist/sensor/sampling-aperture.js +1 -25
  229. package/dist/sensor/sampling-aperture.js.map +1 -1
  230. package/dist/sensor/spatial-sample-reduction.js +2 -19
  231. package/dist/sensor/spatial-sample-reduction.js.map +1 -1
  232. package/dist/sensor/spatial-sampling-quadrature.js +1 -3
  233. package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
  234. package/dist/sensor/spatio-spectral-reduction.js +1 -18
  235. package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
  236. package/dist/sensor/spectral-coverage.d.ts +10 -1
  237. package/dist/sensor/spectral-coverage.js +1 -1
  238. package/dist/sensor/spectral-coverage.js.map +1 -1
  239. package/dist/sensor/spectral-quadrature.js +2 -35
  240. package/dist/sensor/spectral-quadrature.js.map +1 -1
  241. package/dist/sensor/spectral-response.js +1 -47
  242. package/dist/sensor/spectral-response.js.map +1 -1
  243. package/dist/stabilization/camera-shake.js +1 -6
  244. package/dist/stabilization/camera-shake.js.map +1 -1
  245. package/dist/stabilization/system.js +2 -80
  246. package/dist/stabilization/system.js.map +1 -1
  247. package/docs/AGENT_GUIDE.md +1 -0
  248. package/docs/API_REFERENCE.md +41 -2
  249. package/docs/QUICK_START.md +90 -8
  250. package/docs/USAGE.md +47 -2
  251. package/docs/api/core-version.md +1 -1
  252. package/docs/api/exports.json +53 -3
  253. package/docs/api/exposure-filtered-exposure-time.md +105 -0
  254. package/docs/api/facade-develop-joined-parts.md +32 -0
  255. package/docs/api/facade-simulate-capture.md +36 -5
  256. package/docs/api/optics-generic-nd-filter-presets.md +34 -0
  257. package/docs/api/optics-lens-psf-profile.md +3 -1
  258. package/docs/api/output-developed-lens-corrections.md +12 -0
  259. package/docs/api/output-generic-lens-corrections.md +0 -9
  260. package/llms.txt +1 -0
  261. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"system.js","sourceRoot":"","sources":["../../src/stabilization/system.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Generic image stabilization: profiles, disturbance trajectories, the stabilized rotation and its\n * effect on capture timing samples.\n *\n * The parsers validate untrusted input and return the normalized typed contract. Unknown enum values,\n * missing required fields and incompatible scientific data are rejected.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @see docs/STABILIZATION.md for the equations, units, coordinate conventions, known blockers and\n * support limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceBackedFact,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport {\n InvalidScientificInputError,\n requirePositiveInteger\n} from \"../core/validation.js\";\nimport type {\n RasterPoint\n} from \"../output/capture-geometry.js\";\nimport type {\n ResolvedCaptureModeTiming\n} from \"../sensor/capture-mode-timing.js\";\nimport { requireInputKeys, requireInputObject, rejectUnknownFields, rejectUnknownVariantFields } from \"../core/record-validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nexport const STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\nexport const STABILIZATION_DISTURBANCE_TRAJECTORY_VERSION =\n \"0.1.0\" as const;\n\nexport type StabilizationRotationAxis =\n | \"pitch\"\n | \"yaw\"\n | \"roll\";\n\nexport type PhysicalStabilizationArchitecture =\n | \"off\"\n | \"sensor-shift\"\n | \"lens-optical\"\n | \"coordinated-physical\";\n\nexport type StabilizationCaptureKind =\n | \"still\"\n | \"video\";\n\nexport interface StabilizationAngularStateRad {\n pitch: number;\n yaw: number;\n roll: number;\n}\n\nexport interface StabilizationDisturbanceSample {\n timeSecondsFromCaptureReference:\n number;\n angularDisplacementRad:\n StabilizationAngularStateRad;\n}\n\nexport interface StabilizationDisturbanceTrajectory {\n version:\n typeof STABILIZATION_DISTURBANCE_TRAJECTORY_VERSION;\n trajectoryId: string;\n timeReference:\n \"first-opening-boundary-phase\";\n samples:\n readonly StabilizationDisturbanceSample[];\n initialAngularDisplacementIsZero:\n true;\n cameraTranslationIncluded:\n false;\n subjectMotionIncluded:\n false;\n supportStateEncoded:\n false;\n evidence: readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\nexport interface StabilizationAxisResponseProfile {\n axis: StabilizationRotationAxis;\n correctionGain:\n EvidenceBackedFact<number>;\n latencySeconds:\n EvidenceBackedFact<number>;\n maximumCorrectionAngleRad:\n EvidenceBackedFact<number>;\n}\n\nexport type StabilizationPanningPolicy =\n | {\n kind: \"none\";\n }\n | {\n kind:\n \"declared-axis-bypass\";\n axis:\n StabilizationRotationAxis;\n evidence:\n readonly EvidenceProvenance[];\n };\n\nexport interface StabilizationCoordinatedAllocation {\n bodyFraction: number;\n lensFraction: number;\n evidence: readonly EvidenceProvenance[];\n totalCorrectionAppliedOnce:\n true;\n}\n\nexport interface StabilizationSystemProfile {\n schemaVersion:\n typeof STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n profileKind:\n \"generic-synthetic\";\n scientificStatus:\n \"approximation\";\n architecture:\n PhysicalStabilizationArchitecture;\n captureKind:\n StabilizationCaptureKind;\n axisResponses:\n readonly StabilizationAxisResponseProfile[];\n panningPolicy:\n StabilizationPanningPolicy;\n coordinatedAllocation?:\n StabilizationCoordinatedAllocation;\n controlTransientModeled: false;\n spontaneousDriftModeled: false;\n cameraTranslationCorrectionModeled:\n false;\n digitalStabilizationIncluded:\n false;\n supportPolicyIncluded: false;\n stopRatingUsedAsDynamicResponse:\n false;\n evidence: readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\nexport interface CalculateStabilizedRotationTrajectoryInput {\n disturbance:\n StabilizationDisturbanceTrajectory;\n profile:\n StabilizationSystemProfile;\n captureKind:\n StabilizationCaptureKind;\n}\n\nexport interface StabilizationAxisResolution {\n axis: StabilizationRotationAxis;\n disturbanceAngleRad: number;\n delayedMeasuredAngleRad: number;\n requestedCorrectionAngleRad:\n number;\n appliedCorrectionAngleRad:\n number;\n residualAngleRad: number;\n correctionGain: number;\n latencySeconds: number;\n maximumCorrectionAngleRad:\n number;\n bypassedForDeclaredPan:\n boolean;\n correctionLimitReached:\n boolean;\n}\n\nexport interface StabilizedRotationSample {\n timeSecondsFromCaptureReference:\n number;\n disturbanceAngularDisplacementRad:\n StabilizationAngularStateRad;\n appliedCorrectionAngularDisplacementRad:\n StabilizationAngularStateRad;\n residualAngularDisplacementRad:\n StabilizationAngularStateRad;\n axes:\n readonly StabilizationAxisResolution[];\n}\n\nexport interface StabilizedRotationTrajectory {\n profileId: string;\n profileVersion: string;\n trajectoryId: string;\n architecture:\n PhysicalStabilizationArchitecture;\n captureKind:\n StabilizationCaptureKind;\n timeReference:\n \"first-opening-boundary-phase\";\n samples:\n readonly StabilizedRotationSample[];\n correctionModel:\n \"delayed-linear-image-equivalent-angular-response\";\n supportStateConsumed: false;\n translationCorrectionModeled:\n false;\n digitalStabilizationApplied:\n false;\n digitalStabilizationOwnedBy:\n \"downstream-geometric-correction-composition\";\n coordinatedCorrectionDoubleCounted:\n false;\n zeroDisturbanceCanCreateMotion:\n false;\n}\n\nexport interface CalculateStabilizedCaptureTemporalSamplesInput {\n disturbance:\n StabilizationDisturbanceTrajectory;\n profile:\n StabilizationSystemProfile;\n captureKind:\n StabilizationCaptureKind;\n timing:\n ResolvedCaptureModeTiming;\n samplePointsNative:\n readonly RasterPoint[];\n temporalSampleCount: number;\n}\n\nexport interface StabilizedCaptureTemporalNode {\n temporalSampleIndex: number;\n localExposurePhase: number;\n captureTimeSecondsFromReference:\n number;\n normalizedTimeWeight: number;\n timeMeasureSeconds: number;\n stabilization:\n StabilizedRotationSample;\n}\n\nexport interface StabilizedCaptureTemporalPoint {\n destinationPointNative:\n RasterPoint;\n localExposureWindow: {\n startSecondsFromCaptureReference:\n number;\n endSecondsFromCaptureReference:\n number;\n durationSeconds: number;\n };\n nodes:\n readonly StabilizedCaptureTemporalNode[];\n}\n\nexport interface StabilizedCaptureTemporalSamples {\n profileId: string;\n trajectoryId: string;\n captureModeId: string;\n timingProfileId: string;\n captureKind:\n StabilizationCaptureKind;\n architecture:\n PhysicalStabilizationArchitecture;\n timeReference:\n \"first-opening-boundary-phase\";\n quadratureScheme:\n \"uniform-midpoint\";\n temporalSampleCount: number;\n points:\n readonly StabilizedCaptureTemporalPoint[];\n sensorReadoutTimingUsedAsExposureTiming:\n false;\n supportStateConsumed: false;\n translationCorrectionModeled:\n false;\n digitalStabilizationApplied:\n false;\n}\n\nconst AXES =\n new Set<StabilizationRotationAxis>([\n \"pitch\",\n \"yaw\",\n \"roll\"\n ]);\n\nconst ARCHITECTURES =\n new Set<PhysicalStabilizationArchitecture>([\n \"off\",\n \"sensor-shift\",\n \"lens-optical\",\n \"coordinated-physical\"\n ]);\n\nconst CAPTURE_KINDS =\n new Set<StabilizationCaptureKind>([\n \"still\",\n \"video\"\n ]);\n\nfunction requireRecord(\n value: unknown,\n path: string,\n allowedKeys: readonly string[] | null\n): UnknownRecord {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be an object.\"\n );\n }\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as UnknownRecord;\n}\n\nfunction requireNonEmptyString(\n value: unknown,\n path: string\n): string {\n if (\n typeof value !== \"string\" ||\n value.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-empty string.\"\n );\n }\n return value.trim();\n}\n\nfunction requireFinite(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be finite.\"\n );\n }\n return value;\n}\n\nfunction requireNonNegativeFinite(\n value: unknown,\n path: string\n): number {\n const parsed =\n requireFinite(value, path);\n if (parsed < 0) {\n throw new InvalidConfigurationError(\n path +\n \" must be greater than or equal to zero.\"\n );\n }\n return parsed;\n}\n\nfunction requirePositiveFinite(\n value: unknown,\n path: string\n): number {\n const parsed =\n requireFinite(value, path);\n if (parsed <= 0) {\n throw new InvalidConfigurationError(\n path +\n \" must be greater than zero.\"\n );\n }\n return parsed;\n}\n\nfunction requireFraction(\n value: unknown,\n path: string\n): number {\n const parsed =\n requireFinite(value, path);\n if (\n parsed < 0 ||\n parsed > 1\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must lie from zero through one.\"\n );\n }\n return parsed;\n}\n\nfunction parseLimitations(\n value: unknown,\n path: string\n): readonly string[] {\n if (!Array.isArray(value)) {\n throw new InvalidConfigurationError(\n path + \" must be an array.\"\n );\n }\n const parsed =\n value.map((entry, index) =>\n requireNonEmptyString(\n entry,\n path +\n \"[\" +\n index +\n \"]\"\n )\n );\n if (\n new Set(parsed).size !==\n parsed.length\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must not contain duplicates.\"\n );\n }\n return parsed;\n}\n\nfunction parseFractionFact(\n value: unknown,\n path: string\n): EvidenceBackedFact<number> {\n const record =\n requireRecord(value, path, [\"value\", \"evidence\"]);\n return {\n value:\n requireFraction(\n record.value,\n path + \".value\"\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n}\n\nfunction parseNonNegativeFact(\n value: unknown,\n path: string\n): EvidenceBackedFact<number> {\n const record =\n requireRecord(value, path, [\"value\", \"evidence\"]);\n return {\n value:\n requireNonNegativeFinite(\n record.value,\n path + \".value\"\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n}\n\nfunction parsePositiveFact(\n value: unknown,\n path: string\n): EvidenceBackedFact<number> {\n const record =\n requireRecord(value, path, [\"value\", \"evidence\"]);\n return {\n value:\n requirePositiveFinite(\n record.value,\n path + \".value\"\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n}\n\nfunction parseAxis(\n value: unknown,\n path: string\n): StabilizationRotationAxis {\n if (\n typeof value !== \"string\" ||\n !AXES.has(\n value as\n StabilizationRotationAxis\n )\n ) {\n throw new InvalidConfigurationError(\n path + \" is invalid.\"\n );\n }\n return value as\n StabilizationRotationAxis;\n}\n\nfunction parseAxisResponse(\n value: unknown,\n path: string\n): StabilizationAxisResponseProfile {\n const record =\n requireRecord(value, path, [\"axis\", \"correctionGain\", \"latencySeconds\", \"maximumCorrectionAngleRad\"]);\n return {\n axis:\n parseAxis(\n record.axis,\n path + \".axis\"\n ),\n correctionGain:\n parseFractionFact(\n record.correctionGain,\n path +\n \".correctionGain\"\n ),\n latencySeconds:\n parseNonNegativeFact(\n record.latencySeconds,\n path +\n \".latencySeconds\"\n ),\n maximumCorrectionAngleRad:\n parsePositiveFact(\n record\n .maximumCorrectionAngleRad,\n path +\n \".maximumCorrectionAngleRad\"\n )\n };\n}\n\nfunction parsePanningPolicy(\n value: unknown,\n path: string\n): StabilizationPanningPolicy {\n const record =\n requireRecord(value, path, null);\n rejectUnknownVariantFields(record, \"kind\", { none: [\"kind\"], \"declared-axis-bypass\": [\"kind\", \"axis\", \"evidence\"] }, path);\n if (record.kind === \"none\") {\n return {\n kind: \"none\"\n };\n }\n if (\n record.kind ===\n \"declared-axis-bypass\"\n ) {\n return {\n kind:\n \"declared-axis-bypass\",\n axis:\n parseAxis(\n record.axis,\n path + \".axis\"\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n }\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseCoordinatedAllocation(\n value: unknown,\n path: string\n): StabilizationCoordinatedAllocation {\n const record =\n requireRecord(value, path, [\"totalCorrectionAppliedOnce\", \"bodyFraction\", \"lensFraction\", \"evidence\"]);\n if (\n record\n .totalCorrectionAppliedOnce !==\n true\n ) {\n throw new InvalidConfigurationError(\n path +\n \".totalCorrectionAppliedOnce must be true.\"\n );\n }\n const bodyFraction =\n requireFraction(\n record.bodyFraction,\n path + \".bodyFraction\"\n );\n const lensFraction =\n requireFraction(\n record.lensFraction,\n path + \".lensFraction\"\n );\n if (\n Math.abs(\n bodyFraction +\n lensFraction -\n 1\n ) >\n 1e-12\n ) {\n throw new InvalidConfigurationError(\n path +\n \" bodyFraction + lensFraction must equal one.\"\n );\n }\n return {\n bodyFraction,\n lensFraction,\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n ),\n totalCorrectionAppliedOnce:\n true\n };\n}\n\n/**\n * Validates an untrusted declaration and returns the normalized typed contract. Unknown enum values,\n * missing required fields and incompatible scientific data are rejected here.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns StabilizationSystemProfile. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function parseStabilizationSystemProfile(\n value: unknown\n): StabilizationSystemProfile {\n const record =\n requireRecord(\n value,\n \"stabilizationSystemProfile\", [\"schemaVersion\", \"profileKind\", \"scientificStatus\", \"architecture\", \"captureKind\", \"axisResponses\", \"panningPolicy\", \"coordinatedAllocation\", \"profileId\", \"profileVersion\", \"evidence\", \"limitations\", \"controlTransientModeled\", \"spontaneousDriftModeled\", \"cameraTranslationCorrectionModeled\", \"digitalStabilizationIncluded\", \"supportPolicyIncluded\", \"stopRatingUsedAsDynamicResponse\"]\n );\n if (\n record.schemaVersion !==\n STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'stabilizationSystemProfile.schemaVersion must be \"' +\n STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.profileKind !==\n \"generic-synthetic\" ||\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n 'stabilizationSystemProfile schema 0.1.0 requires profileKind \"generic-synthetic\" and scientificStatus \"approximation\".'\n );\n }\n if (\n typeof record.architecture !==\n \"string\" ||\n !ARCHITECTURES.has(\n record.architecture as\n PhysicalStabilizationArchitecture\n )\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.architecture is invalid.\"\n );\n }\n if (\n typeof record.captureKind !==\n \"string\" ||\n !CAPTURE_KINDS.has(\n record.captureKind as\n StabilizationCaptureKind\n )\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.captureKind is invalid.\"\n );\n }\n\n for (\n const key of [\n \"controlTransientModeled\",\n \"spontaneousDriftModeled\",\n \"cameraTranslationCorrectionModeled\",\n \"digitalStabilizationIncluded\",\n \"supportPolicyIncluded\",\n \"stopRatingUsedAsDynamicResponse\"\n ] as const\n ) {\n if (record[key] !== false) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.\" +\n key +\n \" must be false in schema 0.1.0.\"\n );\n }\n }\n\n if (\n !Array.isArray(\n record.axisResponses\n )\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.axisResponses must be an array.\"\n );\n }\n const axisResponses =\n record.axisResponses.map(\n (entry, index) =>\n parseAxisResponse(\n entry,\n \"stabilizationSystemProfile.axisResponses[\" +\n index +\n \"]\"\n )\n );\n const axes =\n axisResponses.map(\n (entry) =>\n entry.axis\n );\n if (\n new Set(axes).size !==\n axes.length\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.axisResponses must not contain duplicate axes.\"\n );\n }\n\n const architecture =\n record.architecture as\n PhysicalStabilizationArchitecture;\n if (\n architecture === \"off\" &&\n axisResponses.length !== 0\n ) {\n throw new InvalidConfigurationError(\n \"An off stabilization profile must not declare axis responses.\"\n );\n }\n if (\n architecture !== \"off\" &&\n axisResponses.length === 0\n ) {\n throw new InvalidConfigurationError(\n \"An enabled physical stabilization profile must declare at least one axis response.\"\n );\n }\n\n const panningPolicy =\n parsePanningPolicy(\n record.panningPolicy,\n \"stabilizationSystemProfile.panningPolicy\"\n );\n if (\n architecture === \"off\" &&\n panningPolicy.kind !== \"none\"\n ) {\n throw new InvalidConfigurationError(\n \"An off stabilization profile must use panningPolicy.kind \\\"none\\\".\"\n );\n }\n if (\n panningPolicy.kind ===\n \"declared-axis-bypass\" &&\n !axisResponses.some(\n (entry) =>\n entry.axis ===\n panningPolicy.axis\n )\n ) {\n throw new InvalidConfigurationError(\n \"Declared panning bypass axis must exist in axisResponses.\"\n );\n }\n\n const coordinatedAllocation =\n record.coordinatedAllocation ===\n undefined\n ? undefined\n : parseCoordinatedAllocation(\n record.coordinatedAllocation,\n \"stabilizationSystemProfile.coordinatedAllocation\"\n );\n if (\n architecture ===\n \"coordinated-physical\" &&\n coordinatedAllocation ===\n undefined\n ) {\n throw new InvalidConfigurationError(\n \"Coordinated physical stabilization requires an explicit body/lens correction allocation.\"\n );\n }\n if (\n architecture !==\n \"coordinated-physical\" &&\n coordinatedAllocation !==\n undefined\n ) {\n throw new InvalidConfigurationError(\n \"Only coordinated physical stabilization may declare coordinatedAllocation.\"\n );\n }\n\n return {\n schemaVersion:\n STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"stabilizationSystemProfile.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"stabilizationSystemProfile.profileVersion\"\n ),\n profileKind:\n \"generic-synthetic\",\n scientificStatus:\n \"approximation\",\n architecture,\n captureKind:\n record.captureKind as\n StabilizationCaptureKind,\n axisResponses,\n panningPolicy,\n ...(coordinatedAllocation ===\n undefined\n ? {}\n : {\n coordinatedAllocation\n }),\n controlTransientModeled:\n false,\n spontaneousDriftModeled:\n false,\n cameraTranslationCorrectionModeled:\n false,\n digitalStabilizationIncluded:\n false,\n supportPolicyIncluded:\n false,\n stopRatingUsedAsDynamicResponse:\n false,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"stabilizationSystemProfile.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"stabilizationSystemProfile.limitations\"\n )\n };\n}\n\nfunction parseAngularState(\n value: unknown,\n path: string\n): StabilizationAngularStateRad {\n const record =\n requireRecord(value, path, [\"pitch\", \"yaw\", \"roll\"]);\n return {\n pitch:\n requireFinite(\n record.pitch,\n path + \".pitch\"\n ),\n yaw:\n requireFinite(\n record.yaw,\n path + \".yaw\"\n ),\n roll:\n requireFinite(\n record.roll,\n path + \".roll\"\n )\n };\n}\n\n/**\n * Validates an untrusted declaration and returns the normalized typed contract. Unknown enum values,\n * missing required fields and incompatible scientific data are rejected here.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns StabilizationDisturbanceTrajectory. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function parseStabilizationDisturbanceTrajectory(\n value: unknown\n): StabilizationDisturbanceTrajectory {\n const record =\n requireRecord(\n value,\n \"stabilizationDisturbanceTrajectory\", [\"version\", \"timeReference\", \"initialAngularDisplacementIsZero\", \"cameraTranslationIncluded\", \"subjectMotionIncluded\", \"supportStateEncoded\", \"samples\", \"trajectoryId\", \"evidence\", \"limitations\"]\n );\n if (\n record.version !==\n STABILIZATION_DISTURBANCE_TRAJECTORY_VERSION ||\n record.timeReference !==\n \"first-opening-boundary-phase\" ||\n record\n .initialAngularDisplacementIsZero !==\n true ||\n record\n .cameraTranslationIncluded !==\n false ||\n record.subjectMotionIncluded !==\n false ||\n record.supportStateEncoded !==\n false\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationDisturbanceTrajectory metadata is invalid for version 0.1.0.\"\n );\n }\n if (\n !Array.isArray(record.samples) ||\n record.samples.length < 2\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationDisturbanceTrajectory.samples must contain at least two samples.\"\n );\n }\n\n let previousTime =\n Number.NEGATIVE_INFINITY;\n const samples =\n record.samples.map(\n (entry, index) => {\n const path =\n \"stabilizationDisturbanceTrajectory.samples[\" +\n index +\n \"]\";\n const sample =\n requireRecord(\n entry,\n path, [\"timeSecondsFromCaptureReference\", \"angularDisplacementRad\"]\n );\n const time =\n requireNonNegativeFinite(\n sample\n .timeSecondsFromCaptureReference,\n path +\n \".timeSecondsFromCaptureReference\"\n );\n if (time <= previousTime) {\n throw new InvalidConfigurationError(\n \"stabilizationDisturbanceTrajectory sample times must be strictly increasing.\"\n );\n }\n previousTime = time;\n return {\n timeSecondsFromCaptureReference:\n time,\n angularDisplacementRad:\n parseAngularState(\n sample\n .angularDisplacementRad,\n path +\n \".angularDisplacementRad\"\n )\n };\n }\n );\n\n const first =\n samples[0]!;\n if (\n first\n .timeSecondsFromCaptureReference !==\n 0 ||\n first\n .angularDisplacementRad\n .pitch !== 0 ||\n first\n .angularDisplacementRad\n .yaw !== 0 ||\n first\n .angularDisplacementRad\n .roll !== 0\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationDisturbanceTrajectory must begin at capture-reference t=0 with zero angular displacement.\"\n );\n }\n\n return {\n version:\n STABILIZATION_DISTURBANCE_TRAJECTORY_VERSION,\n trajectoryId:\n requireNonEmptyString(\n record.trajectoryId,\n \"stabilizationDisturbanceTrajectory.trajectoryId\"\n ),\n timeReference:\n \"first-opening-boundary-phase\",\n samples,\n initialAngularDisplacementIsZero:\n true,\n cameraTranslationIncluded:\n false,\n subjectMotionIncluded:\n false,\n supportStateEncoded:\n false,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"stabilizationDisturbanceTrajectory.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"stabilizationDisturbanceTrajectory.limitations\"\n )\n };\n}\n\n/**\n * Lookup index over a parsed disturbance trajectory, built for evaluation. Support times are copied\n * once into a Float64Array (exact IEEE-754 values). Each lookup is then an O(log n) binary search\n * instead of an O(n) scan. The interpolation arithmetic is unchanged.\n */\ninterface DisturbanceIndex {\n readonly samples:\n StabilizationDisturbanceTrajectory[\"samples\"];\n readonly times: Float64Array;\n}\n\nfunction indexDisturbance(\n trajectory:\n StabilizationDisturbanceTrajectory\n): DisturbanceIndex {\n const times =\n new Float64Array(\n trajectory.samples.length\n );\n for (\n let index = 0;\n index < times.length;\n index += 1\n ) {\n times[index] =\n trajectory.samples[index]!\n .timeSecondsFromCaptureReference;\n }\n return {\n samples:\n trajectory.samples,\n times\n };\n}\n\n/**\n * Returns the left index of the support segment used for `timeSeconds`. Returns -1 for the final support\n * time, which uses its stored value. The chosen segment is exactly the one a first-match linear scan\n * would pick: the smallest `i` with `t[i] <= timeSeconds <= t[i + 1]`. Support times strictly\n * increase, so a time that equals an interior support time uses the segment on its left.\n */\nfunction locateDisturbanceSegment(\n disturbance: DisturbanceIndex,\n timeSeconds: number\n): number {\n const times =\n disturbance.times;\n const lastIndex =\n times.length - 1;\n if (\n timeSeconds < times[0]! ||\n timeSeconds > times[lastIndex]!\n ) {\n throw new InvalidScientificInputError(\n \"Requested stabilization evaluation time lies outside the disturbance trajectory support.\"\n );\n }\n\n if (\n timeSeconds ===\n times[lastIndex]!\n ) {\n return -1;\n }\n\n // Lower bound: first index whose support time is >= timeSeconds.\n let low = 0;\n let high = lastIndex;\n while (low < high) {\n const middle =\n (low + high) >>> 1;\n if (\n times[middle]! >=\n timeSeconds\n ) {\n high = middle;\n } else {\n low = middle + 1;\n }\n }\n const index =\n low === 0 ? 0 : low - 1;\n if (\n !(\n timeSeconds >=\n times[index]! &&\n timeSeconds <=\n times[index + 1]!\n )\n ) {\n throw new InvalidScientificInputError(\n \"Disturbance trajectory interpolation failed.\"\n );\n }\n return index;\n}\n\nfunction interpolateDisturbanceSegment(\n disturbance: DisturbanceIndex,\n segmentIndex: number,\n timeSeconds: number,\n axis:\n StabilizationRotationAxis\n): number {\n const samples =\n disturbance.samples;\n if (segmentIndex < 0) {\n return samples[\n samples.length - 1\n ]!\n .angularDisplacementRad[\n axis\n ];\n }\n const left =\n samples[segmentIndex]!;\n const right =\n samples[\n segmentIndex + 1\n ]!;\n const duration =\n right\n .timeSecondsFromCaptureReference -\n left\n .timeSecondsFromCaptureReference;\n const phase =\n duration === 0\n ? 0\n : (\n timeSeconds -\n left\n .timeSecondsFromCaptureReference\n ) /\n duration;\n const a =\n left\n .angularDisplacementRad[\n axis\n ];\n const b =\n right\n .angularDisplacementRad[\n axis\n ];\n return (\n a +\n (b - a) * phase\n );\n}\n\nfunction interpolateAxis(\n disturbance: DisturbanceIndex,\n timeSeconds: number,\n axis:\n StabilizationRotationAxis\n): number {\n return interpolateDisturbanceSegment(\n disturbance,\n locateDisturbanceSegment(\n disturbance,\n timeSeconds\n ),\n timeSeconds,\n axis\n );\n}\n\nfunction axisValue(\n state:\n StabilizationAngularStateRad,\n axis:\n StabilizationRotationAxis\n): number {\n return state[axis];\n}\n\nfunction setAxisValue(\n state:\n StabilizationAngularStateRad,\n axis:\n StabilizationRotationAxis,\n value: number\n): void {\n state[axis] = value;\n}\n\nfunction clampSymmetric(\n value: number,\n limit: number\n): number {\n return Math.max(\n -limit,\n Math.min(limit, value)\n );\n}\n\ntype AxisResponseIndex = ReadonlyMap<\n StabilizationRotationAxis,\n StabilizationSystemProfile[\"axisResponses\"][number]\n>;\n\n/** Built once per calculation. Later entries win, as with a per-evaluation Map. */\nfunction indexAxisResponses(\n profile:\n StabilizationSystemProfile\n): AxisResponseIndex {\n return new Map(\n profile.axisResponses.map(\n (response) => [\n response.axis,\n response\n ] as const\n )\n );\n}\n\nfunction evaluateAtTime(\n disturbance: DisturbanceIndex,\n profile:\n StabilizationSystemProfile,\n responses: AxisResponseIndex,\n timeSeconds: number\n): StabilizedRotationSample {\n // One segment lookup serves all three axes at the same time.\n const segment =\n locateDisturbanceSegment(\n disturbance,\n timeSeconds\n );\n const current:\n StabilizationAngularStateRad = {\n pitch:\n interpolateDisturbanceSegment(\n disturbance,\n segment,\n timeSeconds,\n \"pitch\"\n ),\n yaw:\n interpolateDisturbanceSegment(\n disturbance,\n segment,\n timeSeconds,\n \"yaw\"\n ),\n roll:\n interpolateDisturbanceSegment(\n disturbance,\n segment,\n timeSeconds,\n \"roll\"\n )\n };\n const correction:\n StabilizationAngularStateRad = {\n pitch: 0,\n yaw: 0,\n roll: 0\n };\n const residual:\n StabilizationAngularStateRad = {\n ...current\n };\n\n const axes =\n [\"pitch\", \"yaw\", \"roll\"] as const;\n const resolvedAxes =\n axes.map((axis) => {\n const response =\n responses.get(axis);\n const bypassed =\n profile.panningPolicy.kind ===\n \"declared-axis-bypass\" &&\n profile.panningPolicy.axis ===\n axis;\n\n if (\n profile.architecture ===\n \"off\" ||\n response === undefined ||\n bypassed\n ) {\n return {\n axis,\n disturbanceAngleRad:\n axisValue(\n current,\n axis\n ),\n delayedMeasuredAngleRad:\n 0,\n requestedCorrectionAngleRad:\n 0,\n appliedCorrectionAngleRad:\n 0,\n residualAngleRad:\n axisValue(\n current,\n axis\n ),\n correctionGain:\n response?.correctionGain\n .value ?? 0,\n latencySeconds:\n response?.latencySeconds\n .value ?? 0,\n maximumCorrectionAngleRad:\n response\n ?.maximumCorrectionAngleRad\n .value ?? 0,\n bypassedForDeclaredPan:\n bypassed,\n correctionLimitReached:\n false\n };\n }\n\n const delayedTime =\n timeSeconds -\n response\n .latencySeconds.value;\n const delayedMeasured =\n delayedTime < 0\n ? 0\n : interpolateAxis(\n disturbance,\n delayedTime,\n axis\n );\n const requested =\n delayedMeasured *\n response\n .correctionGain.value;\n const applied =\n clampSymmetric(\n requested,\n response\n .maximumCorrectionAngleRad\n .value\n );\n const residualAngle =\n axisValue(\n current,\n axis\n ) -\n applied;\n\n setAxisValue(\n correction,\n axis,\n applied\n );\n setAxisValue(\n residual,\n axis,\n residualAngle\n );\n\n return {\n axis,\n disturbanceAngleRad:\n axisValue(\n current,\n axis\n ),\n delayedMeasuredAngleRad:\n delayedMeasured,\n requestedCorrectionAngleRad:\n requested,\n appliedCorrectionAngleRad:\n applied,\n residualAngleRad:\n residualAngle,\n correctionGain:\n response\n .correctionGain.value,\n latencySeconds:\n response\n .latencySeconds.value,\n maximumCorrectionAngleRad:\n response\n .maximumCorrectionAngleRad\n .value,\n bypassedForDeclaredPan:\n false,\n correctionLimitReached:\n applied !== requested\n };\n });\n\n return {\n timeSecondsFromCaptureReference:\n timeSeconds,\n disturbanceAngularDisplacementRad:\n current,\n appliedCorrectionAngularDisplacementRad:\n correction,\n residualAngularDisplacementRad:\n residual,\n axes:\n resolvedAxes\n };\n}\n\n/**\n * Runs the declared generic per-axis controller against an explicit angular disturbance trajectory.\n * Returns the residual motion, with diagnostics for latency and travel limits.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @param input - CalculateStabilizedRotationTrajectoryInput. See that type for coordinates, units and profile binding.\n * @returns CalculationResult<StabilizedRotationTrajectory>. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function calculateStabilizedRotationTrajectory(\n input:\n CalculateStabilizedRotationTrajectoryInput\n): CalculationResult<StabilizedRotationTrajectory> {\n requireInputKeys(input, \"calculateStabilizedRotationTrajectory\", [\"disturbance\", \"profile\", \"captureKind\"]);\n const disturbance =\n parseStabilizationDisturbanceTrajectory(\n input.disturbance\n );\n const profile =\n parseStabilizationSystemProfile(\n input.profile\n );\n\n if (\n input.captureKind !==\n profile.captureKind\n ) {\n throw new InvalidScientificInputError(\n \"captureKind must exactly match the stabilization profile captureKind.\"\n );\n }\n\n const disturbanceIndex =\n indexDisturbance(disturbance);\n const responses =\n indexAxisResponses(profile);\n const samples =\n disturbance.samples.map(\n (sample) =>\n evaluateAtTime(\n disturbanceIndex,\n profile,\n responses,\n sample\n .timeSecondsFromCaptureReference\n )\n );\n\n return approximationResult(\n {\n profileId:\n profile.profileId,\n profileVersion:\n profile.profileVersion,\n trajectoryId:\n disturbance.trajectoryId,\n architecture:\n profile.architecture,\n captureKind:\n input.captureKind,\n timeReference:\n \"first-opening-boundary-phase\",\n samples,\n correctionModel:\n \"delayed-linear-image-equivalent-angular-response\",\n supportStateConsumed:\n false,\n translationCorrectionModeled:\n false,\n digitalStabilizationApplied:\n false,\n digitalStabilizationOwnedBy:\n \"downstream-geometric-correction-composition\",\n coordinatedCorrectionDoubleCounted:\n false,\n zeroDisturbanceCanCreateMotion:\n false\n },\n \"generic-time-domain-physical-stabilization\",\n \"1.0.0\",\n [\n \"The stabilization response is a generic synthetic image-equivalent rotational correction, not a manufacturer-specific IBIS/OIS calibration.\",\n \"Correction uses explicit per-axis gain, latency and symmetric angular correction limits.\",\n \"A coordinated profile allocates one total correction between body and lens for descriptive ownership only; the total correction is applied once.\",\n \"Support state is not an input and never silently toggles stabilization.\",\n \"Declared panning bypass suppresses correction only on the explicitly selected axis; pan intent is never inferred.\",\n \"Camera translation/parallax correction is not modeled because translational image motion depends on scene depth.\",\n \"Digital stabilization is a separate downstream geometric/crop/resampling domain.\",\n \"CIPA-style stop ratings are not used as a dynamic response function.\",\n \"The legacy stabilizationStopsEquivalent approximation remains unchanged.\"\n ]\n );\n}\n\ntype ExposureWindowSample =\n ResolvedCaptureModeTiming[\"exposureWindows\"][\"samples\"][number];\ntype ExposureWindowIndex = ReadonlyMap<\n unknown,\n ReadonlyMap<unknown, readonly ExposureWindowSample[]>\n>;\n\n/**\n * Groups the committed exposure-window samples by native point, once per calculation, and keeps their\n * order. Map keys compare with SameValueZero, so lookups are filtered again with the original `===`\n * test: NaN never matches, and +0 matches -0.\n */\nfunction indexExposureWindows(\n timing:\n ResolvedCaptureModeTiming\n): ExposureWindowIndex {\n requireInputObject(timing, \"timing\");\n requireInputObject(timing.exposureWindows, \"timing.exposureWindows\");\n if (!Array.isArray(timing.exposureWindows.samples)) throw new InvalidConfigurationError(\"timing.exposureWindows.samples must be an array.\");\n timing.exposureWindows.samples.forEach((sample, index) => {\n requireInputObject(sample, \"timing.exposureWindows.samples[\" + index + \"]\");\n requireInputObject(sample.pointNative, \"timing.exposureWindows.samples[\" + index + \"].pointNative\");\n });\n const byX =\n new Map<\n unknown,\n Map<unknown, ExposureWindowSample[]>\n >();\n for (const sample of timing.exposureWindows.samples) {\n let byY =\n byX.get(sample.pointNative.x);\n if (byY === undefined) {\n byY = new Map();\n byX.set(\n sample.pointNative.x,\n byY\n );\n }\n const bucket =\n byY.get(sample.pointNative.y);\n if (bucket === undefined) {\n byY.set(\n sample.pointNative.y,\n [sample]\n );\n } else {\n bucket.push(sample);\n }\n }\n return byX;\n}\n\nfunction localExposureForPoint(\n windows: ExposureWindowIndex,\n point:\n RasterPoint\n): {\n start: number;\n end: number;\n duration: number;\n} {\n const matches =\n (\n windows\n .get(point.x)\n ?.get(point.y) ?? []\n ).filter(\n (sample) =>\n sample.pointNative.x ===\n point.x &&\n sample.pointNative.y ===\n point.y\n );\n if (matches.length !== 1) {\n throw new InvalidScientificInputError(\n \"Each stabilization sample point must match exactly one committed exposure-window sample point.\"\n );\n }\n const match =\n matches[0]!;\n return {\n start:\n match\n .startOffsetSecondsFromOpeningReference,\n end:\n match\n .endOffsetSecondsFromOpeningReference,\n duration:\n match\n .localExposureDurationSeconds\n };\n}\n\n/**\n * Feeds the residual stabilized rotation into the existing local-exposure temporal mapping. Shutter\n * timing is not changed, and no blur radius is invented.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @param input - CalculateStabilizedCaptureTemporalSamplesInput. See that type for coordinates, units and profile binding.\n * @returns CalculationResult<StabilizedCaptureTemporalSamples>. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function calculateStabilizedCaptureTemporalSamples(\n input:\n CalculateStabilizedCaptureTemporalSamplesInput\n): CalculationResult<StabilizedCaptureTemporalSamples> {\n requireInputKeys(input, \"calculateStabilizedCaptureTemporalSamples\", [\"disturbance\", \"profile\", \"captureKind\", \"timing\", \"samplePointsNative\", \"temporalSampleCount\"]);\n requireInputObject(input.timing, \"timing\");\n const disturbance =\n parseStabilizationDisturbanceTrajectory(\n input.disturbance\n );\n const profile =\n parseStabilizationSystemProfile(\n input.profile\n );\n if (\n input.captureKind !==\n profile.captureKind\n ) {\n throw new InvalidScientificInputError(\n \"captureKind must exactly match the stabilization profile captureKind.\"\n );\n }\n requirePositiveInteger(\n \"temporalSampleCount\",\n input.temporalSampleCount\n );\n if (\n !Array.isArray(\n input.samplePointsNative\n ) ||\n input.samplePointsNative.length ===\n 0\n ) {\n throw new InvalidConfigurationError(\n \"samplePointsNative must be a non-empty array.\"\n );\n }\n input.samplePointsNative.forEach((point, index) => requireInputObject(point, \"samplePointsNative[\" + index + \"]\"));\n\n const totalNodeCount =\n input.temporalSampleCount *\n input.samplePointsNative.length;\n if (\n !Number.isSafeInteger(\n totalNodeCount\n )\n ) {\n throw new InvalidScientificInputError(\n \"temporalSampleCount × samplePointsNative.length must remain a safe integer.\"\n );\n }\n\n const disturbanceIndex =\n indexDisturbance(disturbance);\n const responses =\n indexAxisResponses(profile);\n let exposureWindowIndex:\n ExposureWindowIndex | undefined;\n const points =\n input.samplePointsNative.map(\n (point) => {\n exposureWindowIndex ??=\n indexExposureWindows(\n input.timing\n );\n const exposure =\n localExposureForPoint(\n exposureWindowIndex,\n point\n );\n const normalizedTimeWeight =\n 1 /\n input.temporalSampleCount;\n const timeMeasureSeconds =\n exposure.duration /\n input.temporalSampleCount;\n\n const nodes =\n Array.from(\n {\n length:\n input.temporalSampleCount\n },\n (\n _,\n temporalSampleIndex\n ) => {\n const localExposurePhase =\n (\n temporalSampleIndex +\n 0.5\n ) /\n input.temporalSampleCount;\n const captureTime =\n exposure.start +\n localExposurePhase *\n exposure.duration;\n return {\n temporalSampleIndex,\n localExposurePhase,\n captureTimeSecondsFromReference:\n captureTime,\n normalizedTimeWeight,\n timeMeasureSeconds,\n stabilization:\n evaluateAtTime(\n disturbanceIndex,\n profile,\n responses,\n captureTime\n )\n };\n }\n );\n\n return {\n destinationPointNative: {\n ...point\n },\n localExposureWindow: {\n startSecondsFromCaptureReference:\n exposure.start,\n endSecondsFromCaptureReference:\n exposure.end,\n durationSeconds:\n exposure.duration\n },\n nodes\n };\n }\n );\n\n return approximationResult(\n {\n profileId:\n profile.profileId,\n trajectoryId:\n disturbance.trajectoryId,\n captureModeId:\n input.timing.captureModeId,\n timingProfileId:\n input.timing.timingProfileId,\n captureKind:\n input.captureKind,\n architecture:\n profile.architecture,\n timeReference:\n \"first-opening-boundary-phase\",\n quadratureScheme:\n \"uniform-midpoint\",\n temporalSampleCount:\n input.temporalSampleCount,\n points,\n sensorReadoutTimingUsedAsExposureTiming:\n false,\n supportStateConsumed:\n false,\n translationCorrectionModeled:\n false,\n digitalStabilizationApplied:\n false\n },\n \"capture-local-stabilization-temporal-sampling\",\n \"1.0.0\",\n [\n \"Stabilization is evaluated at deterministic midpoint nodes inside each authoritative local exposure window of the exposure-window model.\",\n \"Sensor data-readout timing is not substituted for exposure timing.\",\n \"The result is rotational disturbance/correction/residual state only; it does not itself calculate image-plane mapping, radiance, blur, PSF or output pixels.\",\n \"Translation/parallax, subject motion, shutter shock, support vibration sources and digital stabilization remain separate domains.\"\n ]\n );\n}\n"]}
1
+ {"version":3,"file":"system.js","sourceRoot":"","sources":["../../src/stabilization/system.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Generic image stabilization: profiles, disturbance trajectories, the stabilized rotation and its\n * effect on capture timing samples.\n *\n * The parsers validate untrusted input and return the normalized typed contract. Unknown enum values,\n * missing required fields and incompatible scientific data are rejected.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @see docs/STABILIZATION.md for the equations, units, coordinate conventions, known blockers and\n * support limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceBackedFact,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport {\n InvalidScientificInputError,\n requirePositiveInteger\n} from \"../core/validation.js\";\nimport type {\n RasterPoint\n} from \"../output/capture-geometry.js\";\nimport type {\n ResolvedCaptureModeTiming\n} from \"../sensor/capture-mode-timing.js\";\nimport { requireInputKeys, requireInputObject, rejectUnknownVariantFields, requireConfigRecord as requireRecord, requireTrimmedConfigString as requireNonEmptyString, requireConfigFinite as requireFinite, parseConfigLimitations as parseLimitations, requireConfigFiniteAtLeastZero as requireNonNegativeFinite, requireConfigUnitInterval as requireFraction } from \"../core/record-validation.js\";\nimport { parseNonNegativeFact, parsePositiveFact } from \"../sensor/raw-readout.js\";\n\nexport const STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\nexport const STABILIZATION_DISTURBANCE_TRAJECTORY_VERSION =\n \"0.1.0\" as const;\n\nexport type StabilizationRotationAxis =\n | \"pitch\"\n | \"yaw\"\n | \"roll\";\n\nexport type PhysicalStabilizationArchitecture =\n | \"off\"\n | \"sensor-shift\"\n | \"lens-optical\"\n | \"coordinated-physical\";\n\nexport type StabilizationCaptureKind =\n | \"still\"\n | \"video\";\n\nexport interface StabilizationAngularStateRad {\n pitch: number;\n yaw: number;\n roll: number;\n}\n\nexport interface StabilizationDisturbanceSample {\n timeSecondsFromCaptureReference:\n number;\n angularDisplacementRad:\n StabilizationAngularStateRad;\n}\n\nexport interface StabilizationDisturbanceTrajectory {\n version:\n typeof STABILIZATION_DISTURBANCE_TRAJECTORY_VERSION;\n trajectoryId: string;\n timeReference:\n \"first-opening-boundary-phase\";\n samples:\n readonly StabilizationDisturbanceSample[];\n initialAngularDisplacementIsZero:\n true;\n cameraTranslationIncluded:\n false;\n subjectMotionIncluded:\n false;\n supportStateEncoded:\n false;\n evidence: readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\nexport interface StabilizationAxisResponseProfile {\n axis: StabilizationRotationAxis;\n correctionGain:\n EvidenceBackedFact<number>;\n latencySeconds:\n EvidenceBackedFact<number>;\n maximumCorrectionAngleRad:\n EvidenceBackedFact<number>;\n}\n\nexport type StabilizationPanningPolicy =\n | {\n kind: \"none\";\n }\n | {\n kind:\n \"declared-axis-bypass\";\n axis:\n StabilizationRotationAxis;\n evidence:\n readonly EvidenceProvenance[];\n };\n\nexport interface StabilizationCoordinatedAllocation {\n bodyFraction: number;\n lensFraction: number;\n evidence: readonly EvidenceProvenance[];\n totalCorrectionAppliedOnce:\n true;\n}\n\nexport interface StabilizationSystemProfile {\n schemaVersion:\n typeof STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n profileKind:\n \"generic-synthetic\";\n scientificStatus:\n \"approximation\";\n architecture:\n PhysicalStabilizationArchitecture;\n captureKind:\n StabilizationCaptureKind;\n axisResponses:\n readonly StabilizationAxisResponseProfile[];\n panningPolicy:\n StabilizationPanningPolicy;\n coordinatedAllocation?:\n StabilizationCoordinatedAllocation;\n controlTransientModeled: false;\n spontaneousDriftModeled: false;\n cameraTranslationCorrectionModeled:\n false;\n digitalStabilizationIncluded:\n false;\n supportPolicyIncluded: false;\n stopRatingUsedAsDynamicResponse:\n false;\n evidence: readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\nexport interface CalculateStabilizedRotationTrajectoryInput {\n disturbance:\n StabilizationDisturbanceTrajectory;\n profile:\n StabilizationSystemProfile;\n captureKind:\n StabilizationCaptureKind;\n}\n\nexport interface StabilizationAxisResolution {\n axis: StabilizationRotationAxis;\n disturbanceAngleRad: number;\n delayedMeasuredAngleRad: number;\n requestedCorrectionAngleRad:\n number;\n appliedCorrectionAngleRad:\n number;\n residualAngleRad: number;\n correctionGain: number;\n latencySeconds: number;\n maximumCorrectionAngleRad:\n number;\n bypassedForDeclaredPan:\n boolean;\n correctionLimitReached:\n boolean;\n}\n\nexport interface StabilizedRotationSample {\n timeSecondsFromCaptureReference:\n number;\n disturbanceAngularDisplacementRad:\n StabilizationAngularStateRad;\n appliedCorrectionAngularDisplacementRad:\n StabilizationAngularStateRad;\n residualAngularDisplacementRad:\n StabilizationAngularStateRad;\n axes:\n readonly StabilizationAxisResolution[];\n}\n\nexport interface StabilizedRotationTrajectory {\n profileId: string;\n profileVersion: string;\n trajectoryId: string;\n architecture:\n PhysicalStabilizationArchitecture;\n captureKind:\n StabilizationCaptureKind;\n timeReference:\n \"first-opening-boundary-phase\";\n samples:\n readonly StabilizedRotationSample[];\n correctionModel:\n \"delayed-linear-image-equivalent-angular-response\";\n supportStateConsumed: false;\n translationCorrectionModeled:\n false;\n digitalStabilizationApplied:\n false;\n digitalStabilizationOwnedBy:\n \"downstream-geometric-correction-composition\";\n coordinatedCorrectionDoubleCounted:\n false;\n zeroDisturbanceCanCreateMotion:\n false;\n}\n\nexport interface CalculateStabilizedCaptureTemporalSamplesInput {\n disturbance:\n StabilizationDisturbanceTrajectory;\n profile:\n StabilizationSystemProfile;\n captureKind:\n StabilizationCaptureKind;\n timing:\n ResolvedCaptureModeTiming;\n samplePointsNative:\n readonly RasterPoint[];\n temporalSampleCount: number;\n}\n\nexport interface StabilizedCaptureTemporalNode {\n temporalSampleIndex: number;\n localExposurePhase: number;\n captureTimeSecondsFromReference:\n number;\n normalizedTimeWeight: number;\n timeMeasureSeconds: number;\n stabilization:\n StabilizedRotationSample;\n}\n\nexport interface StabilizedCaptureTemporalPoint {\n destinationPointNative:\n RasterPoint;\n localExposureWindow: {\n startSecondsFromCaptureReference:\n number;\n endSecondsFromCaptureReference:\n number;\n durationSeconds: number;\n };\n nodes:\n readonly StabilizedCaptureTemporalNode[];\n}\n\nexport interface StabilizedCaptureTemporalSamples {\n profileId: string;\n trajectoryId: string;\n captureModeId: string;\n timingProfileId: string;\n captureKind:\n StabilizationCaptureKind;\n architecture:\n PhysicalStabilizationArchitecture;\n timeReference:\n \"first-opening-boundary-phase\";\n quadratureScheme:\n \"uniform-midpoint\";\n temporalSampleCount: number;\n points:\n readonly StabilizedCaptureTemporalPoint[];\n sensorReadoutTimingUsedAsExposureTiming:\n false;\n supportStateConsumed: false;\n translationCorrectionModeled:\n false;\n digitalStabilizationApplied:\n false;\n}\n\nconst AXES =\n new Set<StabilizationRotationAxis>([\n \"pitch\",\n \"yaw\",\n \"roll\"\n ]);\n\nconst ARCHITECTURES =\n new Set<PhysicalStabilizationArchitecture>([\n \"off\",\n \"sensor-shift\",\n \"lens-optical\",\n \"coordinated-physical\"\n ]);\n\nconst CAPTURE_KINDS =\n new Set<StabilizationCaptureKind>([\n \"still\",\n \"video\"\n ]);\n\nfunction parseFractionFact(\n value: unknown,\n path: string\n): EvidenceBackedFact<number> {\n const record =\n requireRecord(value, path, [\"value\", \"evidence\"]);\n return {\n value:\n requireFraction(\n record.value,\n path + \".value\"\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n}\n\nfunction parseAxis(\n value: unknown,\n path: string\n): StabilizationRotationAxis {\n if (\n typeof value !== \"string\" ||\n !AXES.has(\n value as\n StabilizationRotationAxis\n )\n ) {\n throw new InvalidConfigurationError(\n path + \" is invalid.\"\n );\n }\n return value as\n StabilizationRotationAxis;\n}\n\nfunction parseAxisResponse(\n value: unknown,\n path: string\n): StabilizationAxisResponseProfile {\n const record =\n requireRecord(value, path, [\"axis\", \"correctionGain\", \"latencySeconds\", \"maximumCorrectionAngleRad\"]);\n return {\n axis:\n parseAxis(\n record.axis,\n path + \".axis\"\n ),\n correctionGain:\n parseFractionFact(\n record.correctionGain,\n path +\n \".correctionGain\"\n ),\n latencySeconds:\n parseNonNegativeFact(\n record.latencySeconds,\n path +\n \".latencySeconds\"\n ),\n maximumCorrectionAngleRad:\n parsePositiveFact(\n record\n .maximumCorrectionAngleRad,\n path +\n \".maximumCorrectionAngleRad\"\n )\n };\n}\n\nfunction parsePanningPolicy(\n value: unknown,\n path: string\n): StabilizationPanningPolicy {\n const record =\n requireRecord(value, path, null);\n rejectUnknownVariantFields(record, \"kind\", { none: [\"kind\"], \"declared-axis-bypass\": [\"kind\", \"axis\", \"evidence\"] }, path);\n if (record.kind === \"none\") {\n return {\n kind: \"none\"\n };\n }\n if (\n record.kind ===\n \"declared-axis-bypass\"\n ) {\n return {\n kind:\n \"declared-axis-bypass\",\n axis:\n parseAxis(\n record.axis,\n path + \".axis\"\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n )\n };\n }\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseCoordinatedAllocation(\n value: unknown,\n path: string\n): StabilizationCoordinatedAllocation {\n const record =\n requireRecord(value, path, [\"totalCorrectionAppliedOnce\", \"bodyFraction\", \"lensFraction\", \"evidence\"]);\n if (\n record\n .totalCorrectionAppliedOnce !==\n true\n ) {\n throw new InvalidConfigurationError(\n path +\n \".totalCorrectionAppliedOnce must be true.\"\n );\n }\n const bodyFraction =\n requireFraction(\n record.bodyFraction,\n path + \".bodyFraction\"\n );\n const lensFraction =\n requireFraction(\n record.lensFraction,\n path + \".lensFraction\"\n );\n if (\n Math.abs(\n bodyFraction +\n lensFraction -\n 1\n ) >\n 1e-12\n ) {\n throw new InvalidConfigurationError(\n path +\n \" bodyFraction + lensFraction must equal one.\"\n );\n }\n return {\n bodyFraction,\n lensFraction,\n evidence:\n parseEvidenceList(\n record.evidence,\n path + \".evidence\"\n ),\n totalCorrectionAppliedOnce:\n true\n };\n}\n\n/**\n * Validates an untrusted declaration and returns the normalized typed contract. Unknown enum values,\n * missing required fields and incompatible scientific data are rejected here.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns StabilizationSystemProfile. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function parseStabilizationSystemProfile(\n value: unknown\n): StabilizationSystemProfile {\n const record =\n requireRecord(\n value,\n \"stabilizationSystemProfile\", [\"schemaVersion\", \"profileKind\", \"scientificStatus\", \"architecture\", \"captureKind\", \"axisResponses\", \"panningPolicy\", \"coordinatedAllocation\", \"profileId\", \"profileVersion\", \"evidence\", \"limitations\", \"controlTransientModeled\", \"spontaneousDriftModeled\", \"cameraTranslationCorrectionModeled\", \"digitalStabilizationIncluded\", \"supportPolicyIncluded\", \"stopRatingUsedAsDynamicResponse\"]\n );\n if (\n record.schemaVersion !==\n STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'stabilizationSystemProfile.schemaVersion must be \"' +\n STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.profileKind !==\n \"generic-synthetic\" ||\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n 'stabilizationSystemProfile schema 0.1.0 requires profileKind \"generic-synthetic\" and scientificStatus \"approximation\".'\n );\n }\n if (\n typeof record.architecture !==\n \"string\" ||\n !ARCHITECTURES.has(\n record.architecture as\n PhysicalStabilizationArchitecture\n )\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.architecture is invalid.\"\n );\n }\n if (\n typeof record.captureKind !==\n \"string\" ||\n !CAPTURE_KINDS.has(\n record.captureKind as\n StabilizationCaptureKind\n )\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.captureKind is invalid.\"\n );\n }\n\n for (\n const key of [\n \"controlTransientModeled\",\n \"spontaneousDriftModeled\",\n \"cameraTranslationCorrectionModeled\",\n \"digitalStabilizationIncluded\",\n \"supportPolicyIncluded\",\n \"stopRatingUsedAsDynamicResponse\"\n ] as const\n ) {\n if (record[key] !== false) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.\" +\n key +\n \" must be false in schema 0.1.0.\"\n );\n }\n }\n\n if (\n !Array.isArray(\n record.axisResponses\n )\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.axisResponses must be an array.\"\n );\n }\n const axisResponses =\n record.axisResponses.map(\n (entry, index) =>\n parseAxisResponse(\n entry,\n \"stabilizationSystemProfile.axisResponses[\" +\n index +\n \"]\"\n )\n );\n const axes =\n axisResponses.map(\n (entry) =>\n entry.axis\n );\n if (\n new Set(axes).size !==\n axes.length\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationSystemProfile.axisResponses must not contain duplicate axes.\"\n );\n }\n\n const architecture =\n record.architecture as\n PhysicalStabilizationArchitecture;\n if (\n architecture === \"off\" &&\n axisResponses.length !== 0\n ) {\n throw new InvalidConfigurationError(\n \"An off stabilization profile must not declare axis responses.\"\n );\n }\n if (\n architecture !== \"off\" &&\n axisResponses.length === 0\n ) {\n throw new InvalidConfigurationError(\n \"An enabled physical stabilization profile must declare at least one axis response.\"\n );\n }\n\n const panningPolicy =\n parsePanningPolicy(\n record.panningPolicy,\n \"stabilizationSystemProfile.panningPolicy\"\n );\n if (\n architecture === \"off\" &&\n panningPolicy.kind !== \"none\"\n ) {\n throw new InvalidConfigurationError(\n \"An off stabilization profile must use panningPolicy.kind \\\"none\\\".\"\n );\n }\n if (\n panningPolicy.kind ===\n \"declared-axis-bypass\" &&\n !axisResponses.some(\n (entry) =>\n entry.axis ===\n panningPolicy.axis\n )\n ) {\n throw new InvalidConfigurationError(\n \"Declared panning bypass axis must exist in axisResponses.\"\n );\n }\n\n const coordinatedAllocation =\n record.coordinatedAllocation ===\n undefined\n ? undefined\n : parseCoordinatedAllocation(\n record.coordinatedAllocation,\n \"stabilizationSystemProfile.coordinatedAllocation\"\n );\n if (\n architecture ===\n \"coordinated-physical\" &&\n coordinatedAllocation ===\n undefined\n ) {\n throw new InvalidConfigurationError(\n \"Coordinated physical stabilization requires an explicit body/lens correction allocation.\"\n );\n }\n if (\n architecture !==\n \"coordinated-physical\" &&\n coordinatedAllocation !==\n undefined\n ) {\n throw new InvalidConfigurationError(\n \"Only coordinated physical stabilization may declare coordinatedAllocation.\"\n );\n }\n\n return {\n schemaVersion:\n STABILIZATION_SYSTEM_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"stabilizationSystemProfile.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"stabilizationSystemProfile.profileVersion\"\n ),\n profileKind:\n \"generic-synthetic\",\n scientificStatus:\n \"approximation\",\n architecture,\n captureKind:\n record.captureKind as\n StabilizationCaptureKind,\n axisResponses,\n panningPolicy,\n ...(coordinatedAllocation ===\n undefined\n ? {}\n : {\n coordinatedAllocation\n }),\n controlTransientModeled:\n false,\n spontaneousDriftModeled:\n false,\n cameraTranslationCorrectionModeled:\n false,\n digitalStabilizationIncluded:\n false,\n supportPolicyIncluded:\n false,\n stopRatingUsedAsDynamicResponse:\n false,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"stabilizationSystemProfile.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"stabilizationSystemProfile.limitations\"\n )\n };\n}\n\nfunction parseAngularState(\n value: unknown,\n path: string\n): StabilizationAngularStateRad {\n const record =\n requireRecord(value, path, [\"pitch\", \"yaw\", \"roll\"]);\n return {\n pitch:\n requireFinite(\n record.pitch,\n path + \".pitch\"\n ),\n yaw:\n requireFinite(\n record.yaw,\n path + \".yaw\"\n ),\n roll:\n requireFinite(\n record.roll,\n path + \".roll\"\n )\n };\n}\n\n/**\n * Validates an untrusted declaration and returns the normalized typed contract. Unknown enum values,\n * missing required fields and incompatible scientific data are rejected here.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @param value - unknown. Untrusted input; TypeScript types alone are not validation.\n * @returns StabilizationDisturbanceTrajectory. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function parseStabilizationDisturbanceTrajectory(\n value: unknown\n): StabilizationDisturbanceTrajectory {\n const record =\n requireRecord(\n value,\n \"stabilizationDisturbanceTrajectory\", [\"version\", \"timeReference\", \"initialAngularDisplacementIsZero\", \"cameraTranslationIncluded\", \"subjectMotionIncluded\", \"supportStateEncoded\", \"samples\", \"trajectoryId\", \"evidence\", \"limitations\"]\n );\n if (\n record.version !==\n STABILIZATION_DISTURBANCE_TRAJECTORY_VERSION ||\n record.timeReference !==\n \"first-opening-boundary-phase\" ||\n record\n .initialAngularDisplacementIsZero !==\n true ||\n record\n .cameraTranslationIncluded !==\n false ||\n record.subjectMotionIncluded !==\n false ||\n record.supportStateEncoded !==\n false\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationDisturbanceTrajectory metadata is invalid for version 0.1.0.\"\n );\n }\n if (\n !Array.isArray(record.samples) ||\n record.samples.length < 2\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationDisturbanceTrajectory.samples must contain at least two samples.\"\n );\n }\n\n let previousTime =\n Number.NEGATIVE_INFINITY;\n const samples =\n record.samples.map(\n (entry, index) => {\n const path =\n \"stabilizationDisturbanceTrajectory.samples[\" +\n index +\n \"]\";\n const sample =\n requireRecord(\n entry,\n path, [\"timeSecondsFromCaptureReference\", \"angularDisplacementRad\"]\n );\n const time =\n requireNonNegativeFinite(\n sample\n .timeSecondsFromCaptureReference,\n path +\n \".timeSecondsFromCaptureReference\"\n );\n if (time <= previousTime) {\n throw new InvalidConfigurationError(\n \"stabilizationDisturbanceTrajectory sample times must be strictly increasing.\"\n );\n }\n previousTime = time;\n return {\n timeSecondsFromCaptureReference:\n time,\n angularDisplacementRad:\n parseAngularState(\n sample\n .angularDisplacementRad,\n path +\n \".angularDisplacementRad\"\n )\n };\n }\n );\n\n const first =\n samples[0]!;\n if (\n first\n .timeSecondsFromCaptureReference !==\n 0 ||\n first\n .angularDisplacementRad\n .pitch !== 0 ||\n first\n .angularDisplacementRad\n .yaw !== 0 ||\n first\n .angularDisplacementRad\n .roll !== 0\n ) {\n throw new InvalidConfigurationError(\n \"stabilizationDisturbanceTrajectory must begin at capture-reference t=0 with zero angular displacement.\"\n );\n }\n\n return {\n version:\n STABILIZATION_DISTURBANCE_TRAJECTORY_VERSION,\n trajectoryId:\n requireNonEmptyString(\n record.trajectoryId,\n \"stabilizationDisturbanceTrajectory.trajectoryId\"\n ),\n timeReference:\n \"first-opening-boundary-phase\",\n samples,\n initialAngularDisplacementIsZero:\n true,\n cameraTranslationIncluded:\n false,\n subjectMotionIncluded:\n false,\n supportStateEncoded:\n false,\n evidence:\n parseEvidenceList(\n record.evidence,\n \"stabilizationDisturbanceTrajectory.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"stabilizationDisturbanceTrajectory.limitations\"\n )\n };\n}\n\n/**\n * Lookup index over a parsed disturbance trajectory, built for evaluation. Support times are copied\n * once into a Float64Array (exact IEEE-754 values). Each lookup is then an O(log n) binary search\n * instead of an O(n) scan. The interpolation arithmetic is unchanged.\n */\ninterface DisturbanceIndex {\n readonly samples:\n StabilizationDisturbanceTrajectory[\"samples\"];\n readonly times: Float64Array;\n}\n\nfunction indexDisturbance(\n trajectory:\n StabilizationDisturbanceTrajectory\n): DisturbanceIndex {\n const times =\n new Float64Array(\n trajectory.samples.length\n );\n for (\n let index = 0;\n index < times.length;\n index += 1\n ) {\n times[index] =\n trajectory.samples[index]!\n .timeSecondsFromCaptureReference;\n }\n return {\n samples:\n trajectory.samples,\n times\n };\n}\n\n/**\n * Returns the left index of the support segment used for `timeSeconds`. Returns -1 for the final support\n * time, which uses its stored value. The chosen segment is exactly the one a first-match linear scan\n * would pick: the smallest `i` with `t[i] <= timeSeconds <= t[i + 1]`. Support times strictly\n * increase, so a time that equals an interior support time uses the segment on its left.\n */\nfunction locateDisturbanceSegment(\n disturbance: DisturbanceIndex,\n timeSeconds: number\n): number {\n const times =\n disturbance.times;\n const lastIndex =\n times.length - 1;\n if (\n timeSeconds < times[0]! ||\n timeSeconds > times[lastIndex]!\n ) {\n throw new InvalidScientificInputError(\n \"Requested stabilization evaluation time lies outside the disturbance trajectory support.\"\n );\n }\n\n if (\n timeSeconds ===\n times[lastIndex]!\n ) {\n return -1;\n }\n\n // Lower bound: first index whose support time is >= timeSeconds.\n let low = 0;\n let high = lastIndex;\n while (low < high) {\n const middle =\n (low + high) >>> 1;\n if (\n times[middle]! >=\n timeSeconds\n ) {\n high = middle;\n } else {\n low = middle + 1;\n }\n }\n const index =\n low === 0 ? 0 : low - 1;\n if (\n !(\n timeSeconds >=\n times[index]! &&\n timeSeconds <=\n times[index + 1]!\n )\n ) {\n throw new InvalidScientificInputError(\n \"Disturbance trajectory interpolation failed.\"\n );\n }\n return index;\n}\n\nfunction interpolateDisturbanceSegment(\n disturbance: DisturbanceIndex,\n segmentIndex: number,\n timeSeconds: number,\n axis:\n StabilizationRotationAxis\n): number {\n const samples =\n disturbance.samples;\n if (segmentIndex < 0) {\n return samples[\n samples.length - 1\n ]!\n .angularDisplacementRad[\n axis\n ];\n }\n const left =\n samples[segmentIndex]!;\n const right =\n samples[\n segmentIndex + 1\n ]!;\n const duration =\n right\n .timeSecondsFromCaptureReference -\n left\n .timeSecondsFromCaptureReference;\n const phase =\n duration === 0\n ? 0\n : (\n timeSeconds -\n left\n .timeSecondsFromCaptureReference\n ) /\n duration;\n const a =\n left\n .angularDisplacementRad[\n axis\n ];\n const b =\n right\n .angularDisplacementRad[\n axis\n ];\n return (\n a +\n (b - a) * phase\n );\n}\n\nfunction interpolateAxis(\n disturbance: DisturbanceIndex,\n timeSeconds: number,\n axis:\n StabilizationRotationAxis\n): number {\n return interpolateDisturbanceSegment(\n disturbance,\n locateDisturbanceSegment(\n disturbance,\n timeSeconds\n ),\n timeSeconds,\n axis\n );\n}\n\nfunction axisValue(\n state:\n StabilizationAngularStateRad,\n axis:\n StabilizationRotationAxis\n): number {\n return state[axis];\n}\n\nfunction setAxisValue(\n state:\n StabilizationAngularStateRad,\n axis:\n StabilizationRotationAxis,\n value: number\n): void {\n state[axis] = value;\n}\n\nfunction clampSymmetric(\n value: number,\n limit: number\n): number {\n return Math.max(\n -limit,\n Math.min(limit, value)\n );\n}\n\ntype AxisResponseIndex = ReadonlyMap<\n StabilizationRotationAxis,\n StabilizationSystemProfile[\"axisResponses\"][number]\n>;\n\n/** Built once per calculation. Later entries win, as with a per-evaluation Map. */\nfunction indexAxisResponses(\n profile:\n StabilizationSystemProfile\n): AxisResponseIndex {\n return new Map(\n profile.axisResponses.map(\n (response) => [\n response.axis,\n response\n ] as const\n )\n );\n}\n\nfunction evaluateAtTime(\n disturbance: DisturbanceIndex,\n profile:\n StabilizationSystemProfile,\n responses: AxisResponseIndex,\n timeSeconds: number\n): StabilizedRotationSample {\n // One segment lookup serves all three axes at the same time.\n const segment =\n locateDisturbanceSegment(\n disturbance,\n timeSeconds\n );\n const current:\n StabilizationAngularStateRad = {\n pitch:\n interpolateDisturbanceSegment(\n disturbance,\n segment,\n timeSeconds,\n \"pitch\"\n ),\n yaw:\n interpolateDisturbanceSegment(\n disturbance,\n segment,\n timeSeconds,\n \"yaw\"\n ),\n roll:\n interpolateDisturbanceSegment(\n disturbance,\n segment,\n timeSeconds,\n \"roll\"\n )\n };\n const correction:\n StabilizationAngularStateRad = {\n pitch: 0,\n yaw: 0,\n roll: 0\n };\n const residual:\n StabilizationAngularStateRad = {\n ...current\n };\n\n const axes =\n [\"pitch\", \"yaw\", \"roll\"] as const;\n const resolvedAxes =\n axes.map((axis) => {\n const response =\n responses.get(axis);\n const bypassed =\n profile.panningPolicy.kind ===\n \"declared-axis-bypass\" &&\n profile.panningPolicy.axis ===\n axis;\n\n if (\n profile.architecture ===\n \"off\" ||\n response === undefined ||\n bypassed\n ) {\n return {\n axis,\n disturbanceAngleRad:\n axisValue(\n current,\n axis\n ),\n delayedMeasuredAngleRad:\n 0,\n requestedCorrectionAngleRad:\n 0,\n appliedCorrectionAngleRad:\n 0,\n residualAngleRad:\n axisValue(\n current,\n axis\n ),\n correctionGain:\n response?.correctionGain\n .value ?? 0,\n latencySeconds:\n response?.latencySeconds\n .value ?? 0,\n maximumCorrectionAngleRad:\n response\n ?.maximumCorrectionAngleRad\n .value ?? 0,\n bypassedForDeclaredPan:\n bypassed,\n correctionLimitReached:\n false\n };\n }\n\n const delayedTime =\n timeSeconds -\n response\n .latencySeconds.value;\n const delayedMeasured =\n delayedTime < 0\n ? 0\n : interpolateAxis(\n disturbance,\n delayedTime,\n axis\n );\n const requested =\n delayedMeasured *\n response\n .correctionGain.value;\n const applied =\n clampSymmetric(\n requested,\n response\n .maximumCorrectionAngleRad\n .value\n );\n const residualAngle =\n axisValue(\n current,\n axis\n ) -\n applied;\n\n setAxisValue(\n correction,\n axis,\n applied\n );\n setAxisValue(\n residual,\n axis,\n residualAngle\n );\n\n return {\n axis,\n disturbanceAngleRad:\n axisValue(\n current,\n axis\n ),\n delayedMeasuredAngleRad:\n delayedMeasured,\n requestedCorrectionAngleRad:\n requested,\n appliedCorrectionAngleRad:\n applied,\n residualAngleRad:\n residualAngle,\n correctionGain:\n response\n .correctionGain.value,\n latencySeconds:\n response\n .latencySeconds.value,\n maximumCorrectionAngleRad:\n response\n .maximumCorrectionAngleRad\n .value,\n bypassedForDeclaredPan:\n false,\n correctionLimitReached:\n applied !== requested\n };\n });\n\n return {\n timeSecondsFromCaptureReference:\n timeSeconds,\n disturbanceAngularDisplacementRad:\n current,\n appliedCorrectionAngularDisplacementRad:\n correction,\n residualAngularDisplacementRad:\n residual,\n axes:\n resolvedAxes\n };\n}\n\n/**\n * Runs the declared generic per-axis controller against an explicit angular disturbance trajectory.\n * Returns the residual motion, with diagnostics for latency and travel limits.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @param input - CalculateStabilizedRotationTrajectoryInput. See that type for coordinates, units and profile binding.\n * @returns CalculationResult<StabilizedRotationTrajectory>. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function calculateStabilizedRotationTrajectory(\n input:\n CalculateStabilizedRotationTrajectoryInput\n): CalculationResult<StabilizedRotationTrajectory> {\n requireInputKeys(input, \"calculateStabilizedRotationTrajectory\", [\"disturbance\", \"profile\", \"captureKind\"]);\n const disturbance =\n parseStabilizationDisturbanceTrajectory(\n input.disturbance\n );\n const profile =\n parseStabilizationSystemProfile(\n input.profile\n );\n\n if (\n input.captureKind !==\n profile.captureKind\n ) {\n throw new InvalidScientificInputError(\n \"captureKind must exactly match the stabilization profile captureKind.\"\n );\n }\n\n const disturbanceIndex =\n indexDisturbance(disturbance);\n const responses =\n indexAxisResponses(profile);\n const samples =\n disturbance.samples.map(\n (sample) =>\n evaluateAtTime(\n disturbanceIndex,\n profile,\n responses,\n sample\n .timeSecondsFromCaptureReference\n )\n );\n\n return approximationResult(\n {\n profileId:\n profile.profileId,\n profileVersion:\n profile.profileVersion,\n trajectoryId:\n disturbance.trajectoryId,\n architecture:\n profile.architecture,\n captureKind:\n input.captureKind,\n timeReference:\n \"first-opening-boundary-phase\",\n samples,\n correctionModel:\n \"delayed-linear-image-equivalent-angular-response\",\n supportStateConsumed:\n false,\n translationCorrectionModeled:\n false,\n digitalStabilizationApplied:\n false,\n digitalStabilizationOwnedBy:\n \"downstream-geometric-correction-composition\",\n coordinatedCorrectionDoubleCounted:\n false,\n zeroDisturbanceCanCreateMotion:\n false\n },\n \"generic-time-domain-physical-stabilization\",\n \"1.0.0\",\n [\n \"The stabilization response is a generic synthetic image-equivalent rotational correction, not a manufacturer-specific IBIS/OIS calibration.\",\n \"Correction uses explicit per-axis gain, latency and symmetric angular correction limits.\",\n \"A coordinated profile allocates one total correction between body and lens for descriptive ownership only; the total correction is applied once.\",\n \"Support state is not an input and never silently toggles stabilization.\",\n \"Declared panning bypass suppresses correction only on the explicitly selected axis; pan intent is never inferred.\",\n \"Camera translation/parallax correction is not modeled because translational image motion depends on scene depth.\",\n \"Digital stabilization is a separate downstream geometric/crop/resampling domain.\",\n \"CIPA-style stop ratings are not used as a dynamic response function.\",\n \"The legacy stabilizationStopsEquivalent approximation remains unchanged.\"\n ]\n );\n}\n\ntype ExposureWindowSample =\n ResolvedCaptureModeTiming[\"exposureWindows\"][\"samples\"][number];\ntype ExposureWindowIndex = ReadonlyMap<\n unknown,\n ReadonlyMap<unknown, readonly ExposureWindowSample[]>\n>;\n\n/**\n * Groups the committed exposure-window samples by native point, once per calculation, and keeps their\n * order. Map keys compare with SameValueZero, so lookups are filtered again with the original `===`\n * test: NaN never matches, and +0 matches -0.\n */\nfunction indexExposureWindows(\n timing:\n ResolvedCaptureModeTiming\n): ExposureWindowIndex {\n requireInputObject(timing, \"timing\");\n requireInputObject(timing.exposureWindows, \"timing.exposureWindows\");\n if (!Array.isArray(timing.exposureWindows.samples)) throw new InvalidConfigurationError(\"timing.exposureWindows.samples must be an array.\");\n timing.exposureWindows.samples.forEach((sample, index) => {\n requireInputObject(sample, \"timing.exposureWindows.samples[\" + index + \"]\");\n requireInputObject(sample.pointNative, \"timing.exposureWindows.samples[\" + index + \"].pointNative\");\n });\n const byX =\n new Map<\n unknown,\n Map<unknown, ExposureWindowSample[]>\n >();\n for (const sample of timing.exposureWindows.samples) {\n let byY =\n byX.get(sample.pointNative.x);\n if (byY === undefined) {\n byY = new Map();\n byX.set(\n sample.pointNative.x,\n byY\n );\n }\n const bucket =\n byY.get(sample.pointNative.y);\n if (bucket === undefined) {\n byY.set(\n sample.pointNative.y,\n [sample]\n );\n } else {\n bucket.push(sample);\n }\n }\n return byX;\n}\n\nfunction localExposureForPoint(\n windows: ExposureWindowIndex,\n point:\n RasterPoint\n): {\n start: number;\n end: number;\n duration: number;\n} {\n const matches =\n (\n windows\n .get(point.x)\n ?.get(point.y) ?? []\n ).filter(\n (sample) =>\n sample.pointNative.x ===\n point.x &&\n sample.pointNative.y ===\n point.y\n );\n if (matches.length !== 1) {\n throw new InvalidScientificInputError(\n \"Each stabilization sample point must match exactly one committed exposure-window sample point.\"\n );\n }\n const match =\n matches[0]!;\n return {\n start:\n match\n .startOffsetSecondsFromOpeningReference,\n end:\n match\n .endOffsetSecondsFromOpeningReference,\n duration:\n match\n .localExposureDurationSeconds\n };\n}\n\n/**\n * Feeds the residual stabilized rotation into the existing local-exposure temporal mapping. Shutter\n * timing is not changed, and no blur radius is invented.\n *\n * The generic stabilizer takes a declared angular disturbance (camera shake) and applies a per-axis\n * response, latency, travel limits and a panning policy. The leftover (residual) motion feeds the\n * existing temporal mapping. No commercial IBIS (in-body) or OIS (optical) calibration is supplied,\n * no arbitrary \"stops\" rating is used, and body/lens coordination is never inferred.\n * @param input - CalculateStabilizedCaptureTemporalSamplesInput. See that type for coordinates, units and profile binding.\n * @returns CalculationResult<StabilizedCaptureTemporalSamples>. The result states its shape and scientific status; a successful call does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the root export and exact type graph.\n */\nexport function calculateStabilizedCaptureTemporalSamples(\n input:\n CalculateStabilizedCaptureTemporalSamplesInput\n): CalculationResult<StabilizedCaptureTemporalSamples> {\n requireInputKeys(input, \"calculateStabilizedCaptureTemporalSamples\", [\"disturbance\", \"profile\", \"captureKind\", \"timing\", \"samplePointsNative\", \"temporalSampleCount\"]);\n requireInputObject(input.timing, \"timing\");\n const disturbance =\n parseStabilizationDisturbanceTrajectory(\n input.disturbance\n );\n const profile =\n parseStabilizationSystemProfile(\n input.profile\n );\n if (\n input.captureKind !==\n profile.captureKind\n ) {\n throw new InvalidScientificInputError(\n \"captureKind must exactly match the stabilization profile captureKind.\"\n );\n }\n requirePositiveInteger(\n \"temporalSampleCount\",\n input.temporalSampleCount\n );\n if (\n !Array.isArray(\n input.samplePointsNative\n ) ||\n input.samplePointsNative.length ===\n 0\n ) {\n throw new InvalidConfigurationError(\n \"samplePointsNative must be a non-empty array.\"\n );\n }\n input.samplePointsNative.forEach((point, index) => requireInputObject(point, \"samplePointsNative[\" + index + \"]\"));\n\n const totalNodeCount =\n input.temporalSampleCount *\n input.samplePointsNative.length;\n if (\n !Number.isSafeInteger(\n totalNodeCount\n )\n ) {\n throw new InvalidScientificInputError(\n \"temporalSampleCount × samplePointsNative.length must remain a safe integer.\"\n );\n }\n\n const disturbanceIndex =\n indexDisturbance(disturbance);\n const responses =\n indexAxisResponses(profile);\n let exposureWindowIndex:\n ExposureWindowIndex | undefined;\n const points =\n input.samplePointsNative.map(\n (point) => {\n exposureWindowIndex ??=\n indexExposureWindows(\n input.timing\n );\n const exposure =\n localExposureForPoint(\n exposureWindowIndex,\n point\n );\n const normalizedTimeWeight =\n 1 /\n input.temporalSampleCount;\n const timeMeasureSeconds =\n exposure.duration /\n input.temporalSampleCount;\n\n const nodes =\n Array.from(\n {\n length:\n input.temporalSampleCount\n },\n (\n _,\n temporalSampleIndex\n ) => {\n const localExposurePhase =\n (\n temporalSampleIndex +\n 0.5\n ) /\n input.temporalSampleCount;\n const captureTime =\n exposure.start +\n localExposurePhase *\n exposure.duration;\n return {\n temporalSampleIndex,\n localExposurePhase,\n captureTimeSecondsFromReference:\n captureTime,\n normalizedTimeWeight,\n timeMeasureSeconds,\n stabilization:\n evaluateAtTime(\n disturbanceIndex,\n profile,\n responses,\n captureTime\n )\n };\n }\n );\n\n return {\n destinationPointNative: {\n ...point\n },\n localExposureWindow: {\n startSecondsFromCaptureReference:\n exposure.start,\n endSecondsFromCaptureReference:\n exposure.end,\n durationSeconds:\n exposure.duration\n },\n nodes\n };\n }\n );\n\n return approximationResult(\n {\n profileId:\n profile.profileId,\n trajectoryId:\n disturbance.trajectoryId,\n captureModeId:\n input.timing.captureModeId,\n timingProfileId:\n input.timing.timingProfileId,\n captureKind:\n input.captureKind,\n architecture:\n profile.architecture,\n timeReference:\n \"first-opening-boundary-phase\",\n quadratureScheme:\n \"uniform-midpoint\",\n temporalSampleCount:\n input.temporalSampleCount,\n points,\n sensorReadoutTimingUsedAsExposureTiming:\n false,\n supportStateConsumed:\n false,\n translationCorrectionModeled:\n false,\n digitalStabilizationApplied:\n false\n },\n \"capture-local-stabilization-temporal-sampling\",\n \"1.0.0\",\n [\n \"Stabilization is evaluated at deterministic midpoint nodes inside each authoritative local exposure window of the exposure-window model.\",\n \"Sensor data-readout timing is not substituted for exposure timing.\",\n \"The result is rotational disturbance/correction/residual state only; it does not itself calculate image-plane mapping, radiance, blur, PSF or output pixels.\",\n \"Translation/parallax, subject motion, shutter shock, support vibration sources and digital stabilization remain separate domains.\"\n ]\n );\n}\n"]}
@@ -35,6 +35,7 @@ one-call capture, see the [Quick Start](QUICK_START.md). For every export, see t
35
35
  | Blur circle as a share of the frame or on a print | [`calculateBlurShareOfFrame`](api/camera-sensor-equivalence.md#calculateblurshareofframe) | Equal shares of the diagonal look the same at the same output size. |
36
36
  | Pixels left after a centred crop | [`calculateCenteredCrop`](api/output-crop.md#calculatecenteredcrop) | Keeps the aspect ratio to whole pixels. |
37
37
  | Motion blur for a shutter speed | [`calculateProjectedMotionBlur`](api/motion-projected-motion.md#calculateprojectedmotionblur) | Subject position and velocity in metres; blur in mm, and in pixels if you give a pixel pitch. |
38
+ | Shutter time with an ND filter | [`calculateFilteredExposureTime`](api/exposure-filtered-exposure-time.md#calculatefilteredexposuretime) | Pass `GENERIC_ND_FILTER_PROFILES[3 | 6 | 10]` (idealized, exactly 2^-N) or your own front-of-lens filter profile(s), and optionally a shutter dial (for example `GENERIC_THIRD_STOP_SHUTTER_SECONDS`) for the nearest dial value. 1/125 s with a 10-stop filter → ≈ 8.19 s (8 s on the dial). |
38
39
  | Video shutter angle to exposure time | [`calculateShutterAngleExposureSeconds`](api/motion-video-sequence.md#calculateshutterangleexposureseconds) | Positional arguments: frame rate (Hz), angle (degrees). |
39
40
  | Diffraction spot size | [`calculateAiryDisk`](api/optics-diffraction.md#calculateairydisk) | Ideal circular aperture; you choose the wavelength. |
40
41
  | Photons to electrons | [`calculatePhotoelectrons`](api/sensor-signal-noise.md#calculatephotoelectrons) | Mean value; you supply the quantum efficiency. |
@@ -1,6 +1,6 @@
1
1
  # Public API reference
2
2
 
3
- Generated from the exact root exports for **@photivra/engine 2.18.0 / root contract 2.18.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.19.0 / root contract 2.19.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
 
@@ -18,6 +18,7 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
18
18
  | Crop factor, 35 mm-equivalent focal length and crops | [`calculateEquivalentFocalLength35Mm`](api/camera-equivalent-focal-length.md#calculateequivalentfocallength35mm), [`calculateCenteredCrop`](api/output-crop.md#calculatecenteredcrop) |
19
19
  | Equivalent f-number, sensor area and blur as a share of the frame | [`calculateSensorEquivalence`](api/camera-sensor-equivalence.md#calculatesensorequivalence), [`calculateBlurShareOfFrame`](api/camera-sensor-equivalence.md#calculateblurshareofframe) |
20
20
  | Motion blur and shutter speed | [`calculateProjectedMotionBlur`](api/motion-projected-motion.md#calculateprojectedmotionblur), [`calculateShutterAngleExposureSeconds`](api/motion-video-sequence.md#calculateshutterangleexposureseconds) |
21
+ | Shutter time with an ND filter | [`calculateFilteredExposureTime`](api/exposure-filtered-exposure-time.md#calculatefilteredexposuretime) |
21
22
  | Diffraction | [`calculateAiryDisk`](api/optics-diffraction.md#calculateairydisk) |
22
23
  | Sensor signal, noise and SNR | [`calculatePhotoelectrons`](api/sensor-signal-noise.md#calculatephotoelectrons), [`calculateSignalToNoise`](api/sensor-signal-noise.md#calculatesignaltonoise) |
23
24
  | Colour temperature | [`calculateChromaticityFromCorrelatedColorTemperature`](api/color-illuminants.md#calculatechromaticityfromcorrelatedcolortemperature), [`calculateCorrelatedColorTemperature`](api/color-illuminants.md#calculatecorrelatedcolortemperature) |
@@ -1056,6 +1057,18 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1056
1057
  | [`RelativeOpticalExposure`](api/exposure-exposure.md#relativeopticalexposure) | Type |
1057
1058
  | [`RelativeRenderedExposure`](api/exposure-exposure.md#relativerenderedexposure) | Type |
1058
1059
 
1060
+ ## exposure/filtered-exposure-time.ts
1061
+
1062
+ [Detailed contracts](api/exposure-filtered-exposure-time.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/exposure/filtered-exposure-time.ts)
1063
+
1064
+ | Export | Kind |
1065
+ | --- | --- |
1066
+ | [`calculateFilteredExposureTime`](api/exposure-filtered-exposure-time.md#calculatefilteredexposuretime) | Runtime |
1067
+ | [`CalculateFilteredExposureTimeInput`](api/exposure-filtered-exposure-time.md#calculatefilteredexposuretimeinput) | Type |
1068
+ | [`FILTERED_EXPOSURE_DEFAULT_WAVELENGTH_NANOMETERS`](api/exposure-filtered-exposure-time.md#filtered_exposure_default_wavelength_nanometers) | Runtime |
1069
+ | [`FilteredExposureDialSetting`](api/exposure-filtered-exposure-time.md#filteredexposuredialsetting) | Type |
1070
+ | [`FilteredExposureTime`](api/exposure-filtered-exposure-time.md#filteredexposuretime) | Type |
1071
+
1059
1072
  ## exposure/flash-ttl.ts
1060
1073
 
1061
1074
  [Detailed contracts](api/exposure-flash-ttl.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/exposure/flash-ttl.ts)
@@ -1267,6 +1280,14 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1267
1280
  | [`EvaluateColorPatchReflectanceInput`](api/facade-color-patches.md#evaluatecolorpatchreflectanceinput) | Type |
1268
1281
  | [`getColorPatchSet`](api/facade-color-patches.md#getcolorpatchset) | Runtime |
1269
1282
 
1283
+ ## facade/develop-joined-parts.ts
1284
+
1285
+ [Detailed contracts](api/facade-develop-joined-parts.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/develop-joined-parts.ts)
1286
+
1287
+ | Export | Kind |
1288
+ | --- | --- |
1289
+ | [`simulateCaptureFromParts`](api/facade-develop-joined-parts.md#simulatecapturefromparts) | Runtime |
1290
+
1270
1291
  ## facade/display-view-gpu.ts
1271
1292
 
1272
1293
  [Detailed contracts](api/facade-display-view-gpu.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/display-view-gpu.ts)
@@ -1347,6 +1368,7 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1347
1368
  | [`SimulateCaptureFastOption`](api/facade-simulate-capture.md#simulatecapturefastoption) | Type |
1348
1369
  | [`SimulateCaptureFastReport`](api/facade-simulate-capture.md#simulatecapturefastreport) | Type |
1349
1370
  | [`SimulateCaptureLensCatalogueRecord`](api/facade-simulate-capture.md#simulatecapturelenscataloguerecord) | Type |
1371
+ | [`SimulateCaptureLensCorrections`](api/facade-simulate-capture.md#simulatecapturelenscorrections) | Type |
1350
1372
  | [`SimulateCaptureLensDistortion`](api/facade-simulate-capture.md#simulatecapturelensdistortion) | Type |
1351
1373
  | [`SimulateCaptureMetering`](api/facade-simulate-capture.md#simulatecapturemetering) | Type |
1352
1374
  | [`SimulateCaptureMotion`](api/facade-simulate-capture.md#simulatecapturemotion) | Type |
@@ -1739,6 +1761,16 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1739
1761
  | [`resolveFrontOfLensFilterTransmission`](api/optics-front-of-lens-filter.md#resolvefrontoflensfiltertransmission) | Runtime |
1740
1762
  | [`ResolveFrontOfLensFilterTransmissionInput`](api/optics-front-of-lens-filter.md#resolvefrontoflensfiltertransmissioninput) | Type |
1741
1763
 
1764
+ ## optics/generic-nd-filter-presets.ts
1765
+
1766
+ [Detailed contracts](api/optics-generic-nd-filter-presets.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/optics/generic-nd-filter-presets.ts)
1767
+
1768
+ | Export | Kind |
1769
+ | --- | --- |
1770
+ | [`GENERIC_ND_FILTER_PROFILES`](api/optics-generic-nd-filter-presets.md#generic_nd_filter_profiles) | Runtime |
1771
+ | [`GENERIC_ND_FILTER_STOPS`](api/optics-generic-nd-filter-presets.md#generic_nd_filter_stops) | Runtime |
1772
+ | [`GenericNdFilterStops`](api/optics-generic-nd-filter-presets.md#genericndfilterstops) | Type |
1773
+
1742
1774
  ## optics/illumination-vignetting.ts
1743
1775
 
1744
1776
  [Detailed contracts](api/optics-illumination-vignetting.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/optics/illumination-vignetting.ts)
@@ -2095,6 +2127,14 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
2095
2127
  | [`CalculateCenteredCropInput`](api/output-crop.md#calculatecenteredcropinput) | Type |
2096
2128
  | [`CenteredCrop`](api/output-crop.md#centeredcrop) | Type |
2097
2129
 
2130
+ ## output/developed-lens-corrections.ts
2131
+
2132
+ [Detailed contracts](api/output-developed-lens-corrections.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/output/developed-lens-corrections.ts)
2133
+
2134
+ | Export | Kind |
2135
+ | --- | --- |
2136
+ | [`GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM`](api/output-developed-lens-corrections.md#generic_lens_correction_channel_wavelengths_nm) | Runtime |
2137
+
2098
2138
  ## output/generic-lens-corrections.ts
2099
2139
 
2100
2140
  [Detailed contracts](api/output-generic-lens-corrections.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/output/generic-lens-corrections.ts)
@@ -2103,7 +2143,6 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
2103
2143
  | --- | --- |
2104
2144
  | [`createGenericLensCorrectionProfile`](api/output-generic-lens-corrections.md#creategenericlenscorrectionprofile) | Runtime |
2105
2145
  | [`CreateGenericLensCorrectionProfileInput`](api/output-generic-lens-corrections.md#creategenericlenscorrectionprofileinput) | Type |
2106
- | [`GENERIC_LENS_CORRECTION_CHANNEL_WAVELENGTHS_NM`](api/output-generic-lens-corrections.md#generic_lens_correction_channel_wavelengths_nm) | Runtime |
2107
2146
 
2108
2147
  ## output/geometric-transforms.ts
2109
2148
 
@@ -104,6 +104,7 @@ modelling choices (such as "no lens PSF") as `kind: "model"`.
104
104
  | `output.exposureCompensationStops` | 0 | #556: a development exposure push, −2 to +5 stops, on the RAW before white balance (see [Development exposure push](#development-exposure-push-556)). |
105
105
  | `output.diffractionCorrection` | off | #552: `{ wavelengthNm?, regularization?, maximumGain?, kernelRadiusPixels? }`, a bounded deconvolution of the diffraction blur; needs `lens.diffraction`. It never restores detail beyond the diffraction cut-off (see [Sharpening and diffraction correction](#sharpening-and-diffraction-correction-552)). |
106
106
  | `output.sharpening` | off | #552: `{ radiusPixels?, amount?, threshold? }`, an unsharp mask after the tone curve; sRGB output only (see [Sharpening and diffraction correction](#sharpening-and-diffraction-correction-552)). |
107
+ | `output.lensCorrections` | off | #570, with `lens.catalogue`: `{ distortion?, lateralColor?, vignetting? }`, the lens's own corrections on the developed JPEG, PNG and samples; the DNG is never corrected. Works with `output.region` (see [Generic lens catalogue](#generic-lens-catalogue-549)). |
107
108
  | `output.whiteBalance` | `"scene-illuminant"` | Also `"auto"`, `"none"`, `{ kelvin, tint? }` and `{ channelGains }`. |
108
109
  | `output.jpegQuantizationStep` | 2 | JPEG only: constant step 1–255, not a manufacturer quality scale. |
109
110
  | `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)). |
@@ -116,7 +117,7 @@ modelling choices (such as "no lens PSF") as `kind: "model"`.
116
117
  | `motion.angularVelocityRadPerSec` | still | `{ pitch?, yaw?, roll? }` in rad/s (see [Motion](#motion)). |
117
118
  | `motion.shutter` | `"global"` | Or `"rolling"`. |
118
119
  | `motion.rollingShutterSkewSeconds` | the body's readout skew | Rolling only. |
119
- | `signal`, `onProgress` | none | An `AbortSignal` cancels the running task; `onProgress` reports `raw`, `white-balance`, `development` 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. |
120
+ | `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. |
120
121
 
121
122
  Unknown fields are rejected, so a typo never silently falls back to a default.
122
123
 
@@ -217,6 +218,13 @@ and every number is a labelled approximation.
217
218
  - **Cost:** one scene query per kernel tap through the lens field mapping, like `lens.distortion`: a 48 × 48 region of a full frame
218
219
  at 6 µm takes about 1 s with *PV 50 1.2 Pro* and 6 s with *PV 50 1.8* (Apple M5 Pro), against 0.01 s with `lens.prime`. Render
219
220
  regions, or use a coarser `sensor.spectralStepNanometers`.
221
+ - **Lens corrections (#570):** `output: { lensCorrections: { distortion: true, lateralColor: true, vignetting: true } }` applies the
222
+ lens's generic correction profile (`createGenericLensCorrectionProfile`) to the developed linear colour, each correction
223
+ switched on separately, as cameras do for their JPEGs. The RAW and the DNG are never corrected. The image keeps its size and is
224
+ magnified just enough to have no missing pixels (`magnification` in the `output.lensCorrections` assumption, 1 for the barrel
225
+ wide angles); vignetting is corrected to a flat field. Regions and parts are byte-identical to the whole frame. The costs are
226
+ real: stretched corners lose resolution and brightened corners are noisier
227
+ ([DIGITAL_OPTICS_FOUNDATION.md](https://github.com/Photivra/photivra/blob/main/docs/DIGITAL_OPTICS_FOUNDATION.md#lens-corrections-in-the-development-570)).
220
228
  - **Fast method (#568):** `fast: true` (or `lens: { catalogue: { kind: "pv-50-1.8", fast: true } }`) blends the PSF over a field
221
229
  grid and tabulates each site's signal, a labeled approximation within 2.3e-4 of the frame's peak signal of the exact method
222
230
  (measured): a 768 × 512 whole full frame renders within 2× of the same `lens.prime` capture. It needs a still camera, site-center
@@ -252,9 +260,20 @@ the crop factor, so a 50 mm lens is 50 mm on full frame and on APS-C, as when a
252
260
  - **An optional f-number range:** `lens.ideal: { focalLengthMm, widestFNumber, narrowestFNumber }` (either or both, within
253
261
  `IDEAL_LENS_LIMITS`, the widest no larger than the narrowest; each defaults to its bound) narrows that range like a real
254
262
  lens's: `lens.fNumber` must lie in it, and shutter priority and program choose apertures only in it. The assumption then
255
- records the range (`{ lensId, focalLengthMm, widestFNumber, narrowestFNumber }`); without it nothing changes. Program follows
256
- the engine's program line (f/4–f/16) and refuses a range that does not hold it, as for `lens.prime` and `lens.catalogue`; a
257
- range without f/8 takes the reference exposure at its aperture nearest f/8 (the same N²/t).
263
+ records the range (`{ lensId, focalLengthMm, widestFNumber, narrowestFNumber }`); without it nothing changes. A range without
264
+ f/8 takes the reference exposure at its aperture nearest f/8 (the same N²/t). Where that shutter would be shorter than the
265
+ body's shortest (a range narrower than about f/1, such as f/0.5–f/0.9), the anchor takes the shortest shutter instead, a lower
266
+ N²/t that the meter and the exposure modes measure from, so the exposure is the same (#585; refused in every mode before 2.19.0).
267
+ - **Program with a range (#583):** program follows the engine's program line (f/16 1/2000 s … f/8 1/125 s … f/4 1.024 s). A
268
+ range that holds f/4–f/16 keeps it unchanged. Otherwise the line's f/4 and f/16 move to the range (each clamped to it): the
269
+ same shape, with the aperture held at the range's end and the shutter taking up the stops (the same N²/t, so the same
270
+ exposure), still from 1/2000 s to 1.024 s. Beyond the line's ends the resolver holds them, as before (with `iso: "auto"` the
271
+ ISO rises in dim light; with a fixed ISO the capture is under- or overexposed and `exposure.standardExposureDeviationStops`
272
+ says by how much). For example f/8–f/32 gives f/16 1/2000 s … f/16 1/125 s … f/8 1/125 s … f/8 1.024 s. The
273
+ `exposure.programLine` assumption then records the limited line (profile id `"facade-generic-program-line-lens-range"`, with its `nodes`). The same
274
+ applies to the `lens.prime` and `lens.catalogue` ranges that do not hold f/4–f/16 (the 800 mm and 1200 mm-equivalent primes;
275
+ *PV 800 5.6 Pro*, *PV 1200 8 Pro*, *PV 200 5.6*, *PV 300 5.6*, *PV 400 5.6*, *PV 500 5.6*, *PV 600 6.3* and *PV 800 9*),
276
+ which program refused before 2.19.0. An approximation: a generic line, not a manufacturer's program.
258
277
  - **The same blur models as `lens.prime`:** `lens.defocus` (the thin-lens blur circle of `calculateDefocusCircle`), `lens.diffraction`
259
278
  (the Airy pattern) and `lens.vignetting` (a caller profile). Without them the ideal lens renders sharp and evenly lit. It focuses
260
279
  at any distance beyond the focal length (no minimum focus distance; the subject must be at least twice the focal length away, as
@@ -533,7 +552,7 @@ Exposure compensation applies to the meter target first, as with a numeric ISO.
533
552
  | `manual` | Your aperture and shutter; the ISO makes up the exposure (`resolveManualExposureMode`, automatic ISO). |
534
553
  | `aperture-priority` | Your aperture. The shutter follows the meter at the lowest ISO, but no slower than `exposure.autoIso.slowestPreferredShutterSeconds` (required; seconds within the body's shutter range, or `"auto"`, see below); the ISO makes up the rest. At the Auto ISO maximum, `afterMaximumIso` decides: `"allow-slower-shutter"` (the default) lengthens the shutter to reach the target, `"hold-preferred-shutter"` keeps it and leaves the exposure under target (`resolveAperturePriorityAutoIsoExposureMode`). |
535
554
  | `shutter-priority` | Your shutter. The aperture is chosen at the lowest ISO, no wider than the target needs, so it stops at the widest aperture; the ISO makes up the rest (`resolveShutterPriorityExposureMode`, policy `minimum-iso-aperture-first`). |
536
- | `program` | The generic program line at the lowest ISO; beyond the line's end (f/4, 1.024 s) the ISO rises (`resolveProgramAutoExposureMode`, automatic ISO). With `exposure.autoIso.slowestPreferredShutterSeconds` (optional, a number or `"auto"`, #504) the line's shutter is held at it before the ISO rises, and `afterMaximumIso` applies as in aperture priority, never past the line's own shutter. |
555
+ | `program` | The generic program line (limited to the lens's f-number range, #583) at the lowest ISO; beyond the line's end (f/4, 1.024 s) the ISO rises (`resolveProgramAutoExposureMode`, automatic ISO). With `exposure.autoIso.slowestPreferredShutterSeconds` (optional, a number or `"auto"`, #504) the line's shutter is held at it before the ISO rises, and `afterMaximumIso` applies as in aperture priority, never past the line's own shutter. |
537
556
 
538
557
  The result says what happened. `exposure.settings.iso` is the ISO used and `exposure.isoControl` is `"automatic"`.
539
558
  `exposure.autoIso` reports `idealIsoBeforeConstraints`, the Auto ISO range (`autoIsoMinimum`, `autoIsoMaximum`),
@@ -971,10 +990,14 @@ console.log(result.diagnostics.detail); // { diffractionCorrection: {...}, sharp
971
990
  noise; it adds no detail. Not with a wide-gamut `output.colorEncoding` or `output.gamutMapping: "perceptual"`.
972
991
  - **Reported:** the `output.diffractionCorrection` and `output.sharpening` assumptions (settings, cut-off, measured filter
973
992
  response, defaults used), `diagnostics.detail` (ringing, clipping and halo counts) and `diagnostics.options`.
974
- - **Not combinable** with `output.region`; not offered by `simulateDisplayView` or `simulateIdealReference`. The DNG holds the
975
- RAW codes and is unchanged; only `image.samples` (and the JPEG or PNG made from them) change.
976
- - **Cost:** both stages hold the whole developed image, as AHD does. At 256 × 256 on an Apple M5 Pro (Node.js 24.19.0) the
993
+ - **Not combinable** with `output.region`; not offered by `simulateDisplayView` or `simulateIdealReference`. A capture rendered
994
+ in region parts takes them through `simulateCaptureFromParts` (#571, [Developing a capture rendered in parts](#developing-a-capture-rendered-in-parts-571)).
995
+ The DNG holds the RAW codes and is unchanged; only `image.samples` (and the JPEG or PNG made from them) change.
996
+ - **Cost:** both stages need the whole developed image, as AHD does. At 256 × 256 on an Apple M5 Pro (Node.js 24.19.0) the
977
997
  development took 8 ms by default, 15 ms with sharpening and 18–20 ms with diffraction correction (R = 3–5), one run each.
998
+ Since #571 they run row by row in place, with the same sums in the same order (the same bytes as 2.18.0): one developed
999
+ image in memory instead of up to six, and `onProgress` reports each output row as the `diffraction-correction` and
1000
+ `sharpening` stages. At 24 MP see [Developing a capture rendered in parts](#developing-a-capture-rendered-in-parts-571).
978
1001
 
979
1002
  The trade-offs of these and the lens corrections (corner resolution after distortion correction, corner noise after
980
1003
  vignetting correction, residual longitudinal CA, halo overshoot, nothing beyond the cut-off) are measured in
@@ -1865,6 +1888,65 @@ const dng = await serializeSimulatedCaptureDngFromParts(dngFrame, parts);
1865
1888
  console.log(dng.bytes.length);
1866
1889
  ```
1867
1890
 
1891
+ ### Developing a capture rendered in parts (#571)
1892
+
1893
+ `simulateCaptureFromParts(options, parts)` develops the whole frame of `options` from region renders of the same
1894
+ request. It joins the parts' RAW exactly as `serializeSimulatedCaptureDngFromParts` does (the same parts, the same checks),
1895
+ then develops the joined RAW as `simulateCapture(options)` would, including the steps that filter across the whole image and
1896
+ that a region refuses: `output.diffractionCorrection` and `output.sharpening`. The joined RAW is the whole render's RAW, so the
1897
+ result's `image.samples`, JPEG or PNG bytes, `raw` and `plan` are those of the whole-frame capture, bit for bit. Pass the
1898
+ whole request (no `output.region`); render the parts with the same request plus `output.region`, without the detail stages,
1899
+ `output.dng` and auto white balance (none changes the RAW codes; auto white balance is measured here over the joined frame).
1900
+ `output.lensCorrections` (#570) is honored as in the whole-frame capture, bit for bit; a part may keep or drop it (a corrected
1901
+ region only widens its `region.nativeRect`). The corrections run on the whole developed frame and hold a second developed
1902
+ image while they resample it.
1903
+
1904
+ `onProgress` reports `development`, then `diffraction-correction` and `sharpening` once per output row of the whole image
1905
+ (each stage ends with `completedTileCount === totalTileCount`), then `jpeg`; no `raw` stage, since no RAW is rendered. A host
1906
+ can show these as "Applying diffraction correction to the whole image" and "Applying sharpening to the whole image". The
1907
+ lens corrections run between the two and report no stage of their own.
1908
+ `signal` cancels the step. In the result, `diagnostics.providerEvaluationCount` is 0, `diagnostics.timingsMs` are this call's
1909
+ (`raw` is the join), `diagnostics.fast` and the `raw.*` assumptions of how the RAW was rendered are in the parts' results
1910
+ instead, and a `parts` assumption records the join.
1911
+
1912
+ ```ts
1913
+ import { simulateCaptureFromParts, simulateCapture, type SimulateCaptureDngPart, type SimulateCaptureOptions } from "@photivra/engine";
1914
+
1915
+ const whole: SimulateCaptureOptions = { scene: { preset: "slanted-edge" }, lens: { fNumber: 16, diffraction: "circular-aperture" },
1916
+ output: { width: 96, height: 64, format: "jpeg", diffractionCorrection: {}, sharpening: {} } };
1917
+ // Two strips rendered without the whole-image stages (in an application, in separate Web Workers).
1918
+ const parts: SimulateCaptureDngPart[] = await Promise.all([0, 32].map(async (y) => {
1919
+ const part = await simulateCapture({ ...whole, output: { width: 96, height: 64, region: { x: 0, y, width: 96, height: 32 } } });
1920
+ return { raw: part.raw, region: part.region! };
1921
+ }));
1922
+ const developed = await simulateCaptureFromParts({ ...whole, onProgress: ({ stage, completedTileCount, totalTileCount }) => {
1923
+ if (stage === "sharpening") console.log("Applying sharpening to the whole image", completedTileCount / totalTileCount);
1924
+ } }, parts);
1925
+ console.log(developed.image.jpeg!.length); // the bytes of simulateCapture(whole).image.jpeg
1926
+ ```
1927
+
1928
+ Tests compare the result with the whole-frame capture byte for byte: JPEG with both stages, 16-bit sRGB with a thresholded
1929
+ mask, AHD with auto white balance, a development push and the four-spot filter, Display P3 PNG with diffraction correction,
1930
+ DNG with both stages, no stage at all, and a catalogue lens with all three lens corrections and sharpening (parts rendered
1931
+ with and without the corrections); and the row-by-row stages against whole-image passes on odd sizes.
1932
+
1933
+ **Measured at 24 MP** (6000 × 4000 at 6 µm, slanted edge at f/8 with `lens.diffraction`, 8 parts; Apple M5 Pro, Node.js 24.19.0,
1934
+ one thread, a shared machine, two runs; `node scripts/benchmark-joined-development.mjs`):
1935
+
1936
+ | Step | Time | Peak memory (process) |
1937
+ | --- | --- | --- |
1938
+ | Join and develop, no detail stage | 1.9–2.2 s (join 0.13–0.15 s) | 532–551 MiB |
1939
+ | … with sharpening (σ = 1) | 3.3–3.7 s (sharpening 1.9–2.1 s) | 1,080 MiB |
1940
+ | … with diffraction correction (R = 3, the default) | 3.7–3.9 s (correction 2.0 s) | 1,079–1,080 MiB |
1941
+ | … with both | 5.1–5.4 s (development 1.2 s, correction 2.0–2.1 s, sharpening 1.7–1.8 s) | 1,079 MiB |
1942
+ | Whole `simulateCapture` with both, for comparison | 10.0–10.4 s (RAW 4.8–4.9 s) | 924 MiB |
1943
+
1944
+ The peak includes the parts' RAW read back (7 bytes per native site) and the joined RAW. The detail stages' share is the one
1945
+ developed image in 64-bit floats (24 bytes per pixel, 549 MiB at 24 MP), held as before by AHD and the wide-gamut paths. In
1946
+ 2.18.0 the stages held up to six such images: the same whole capture with both stages peaked at 3,670 MB (resident set
1947
+ sampled every 50 ms). The extra pass therefore costs about 5 s on one worker after the parts, against about 10 s to render
1948
+ the whole frame again on one worker.
1949
+
1868
1950
  ### A Print JPEG written in strips
1869
1951
 
1870
1952
  At 1:1 (output size equal to the crop), a Print JPEG's rows can be coded on separate workers.