@photivra/engine 2.12.0 → 2.14.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 (148) hide show
  1. package/CHANGELOG.md +144 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +7 -7
  4. package/SECURITY.md +1 -1
  5. package/THIRD_PARTY.md +3 -0
  6. package/dist/camera/lens-projection.js +2 -1
  7. package/dist/camera/lens-projection.js.map +1 -1
  8. package/dist/capture/dng-import.js +1 -1
  9. package/dist/capture/dng-import.js.map +1 -1
  10. package/dist/capture/export-jpeg.d.ts +1 -1
  11. package/dist/capture/export-jpeg.js +6 -4
  12. package/dist/capture/export-jpeg.js.map +1 -1
  13. package/dist/capture/host-yield-cadence.js +1 -1
  14. package/dist/capture/host-yield-cadence.js.map +1 -1
  15. package/dist/capture/native-environment-optical-stage.js +1 -1
  16. package/dist/capture/native-environment-optical-stage.js.map +1 -1
  17. package/dist/capture/native-raw.js +1 -1
  18. package/dist/capture/native-raw.js.map +1 -1
  19. package/dist/capture/packed-sensor-raw.js +3 -3
  20. package/dist/capture/packed-sensor-raw.js.map +1 -1
  21. package/dist/capture/sensor-raw-producer.js +1 -1
  22. package/dist/capture/sensor-raw-producer.js.map +1 -1
  23. package/dist/color/capture-color.js +3 -3
  24. package/dist/color/capture-color.js.map +1 -1
  25. package/dist/color/chromatic-adaptation.js +2 -2
  26. package/dist/color/chromatic-adaptation.js.map +1 -1
  27. package/dist/color/color-matching-functions.js +1 -1
  28. package/dist/color/color-matching-functions.js.map +1 -1
  29. package/dist/color/colorimetry-math.js +2 -2
  30. package/dist/color/colorimetry-math.js.map +1 -1
  31. package/dist/color/illuminants.js +3 -3
  32. package/dist/color/illuminants.js.map +1 -1
  33. package/dist/color/rgb-color-spaces.js +1 -1
  34. package/dist/color/rgb-color-spaces.js.map +1 -1
  35. package/dist/color/sensor-color-development.js +1 -1
  36. package/dist/color/sensor-color-development.js.map +1 -1
  37. package/dist/core/record-validation.js +3 -3
  38. package/dist/core/record-validation.js.map +1 -1
  39. package/dist/core/version.d.ts +1 -1
  40. package/dist/core/version.js +1 -1
  41. package/dist/core/version.js.map +1 -1
  42. package/dist/equipment/generic-prime-lenses.js +3 -3
  43. package/dist/equipment/generic-prime-lenses.js.map +1 -1
  44. package/dist/equipment/generic-tier-assets.d.ts +23 -1
  45. package/dist/equipment/generic-tier-assets.js +58 -30
  46. package/dist/equipment/generic-tier-assets.js.map +1 -1
  47. package/dist/equipment/generic-tier-presets.d.ts +6 -3
  48. package/dist/equipment/generic-tier-presets.js +26 -13
  49. package/dist/equipment/generic-tier-presets.js.map +1 -1
  50. package/dist/exposure/auto-iso-slowest-shutter.d.ts +120 -0
  51. package/dist/exposure/auto-iso-slowest-shutter.js +217 -0
  52. package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -0
  53. package/dist/exposure/exposure-mode-resolver.d.ts +57 -1
  54. package/dist/exposure/exposure-mode-resolver.js +238 -33
  55. package/dist/exposure/exposure-mode-resolver.js.map +1 -1
  56. package/dist/exposure/flash-ttl.js +1 -1
  57. package/dist/exposure/flash-ttl.js.map +1 -1
  58. package/dist/exposure/flash.js +1 -1
  59. package/dist/exposure/flash.js.map +1 -1
  60. package/dist/facade/chart-material-layers.js +2 -2
  61. package/dist/facade/chart-material-layers.js.map +1 -1
  62. package/dist/facade/chart-radiance-batch.js +1 -1
  63. package/dist/facade/chart-radiance-batch.js.map +1 -1
  64. package/dist/facade/chart-scenes.d.ts +45 -8
  65. package/dist/facade/chart-scenes.js +101 -44
  66. package/dist/facade/chart-scenes.js.map +1 -1
  67. package/dist/facade/color-patches.d.ts +129 -0
  68. package/dist/facade/color-patches.js +209 -0
  69. package/dist/facade/color-patches.js.map +1 -0
  70. package/dist/facade/diffraction-provider.js +12 -13
  71. package/dist/facade/diffraction-provider.js.map +1 -1
  72. package/dist/facade/display-view-gpu.js +1 -1
  73. package/dist/facade/display-view-gpu.js.map +1 -1
  74. package/dist/facade/display-view.d.ts +27 -0
  75. package/dist/facade/display-view.js +234 -65
  76. package/dist/facade/display-view.js.map +1 -1
  77. package/dist/facade/scene-radiance.js +2 -2
  78. package/dist/facade/scene-radiance.js.map +1 -1
  79. package/dist/facade/simulate-capture.d.ts +139 -12
  80. package/dist/facade/simulate-capture.js +209 -36
  81. package/dist/facade/simulate-capture.js.map +1 -1
  82. package/dist/facade/simulate-display-view.js +2 -2
  83. package/dist/facade/simulate-display-view.js.map +1 -1
  84. package/dist/gpu/chart-composite-gpu.js +2 -2
  85. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  86. package/dist/gpu/display-view-composite-material-module.js +1 -1
  87. package/dist/gpu/display-view-composite-material-module.js.map +1 -1
  88. package/dist/gpu/display-view-quality-gpu.d.ts +2 -1
  89. package/dist/gpu/display-view-quality-gpu.js +24 -14
  90. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  91. package/dist/gpu/image-kernel-execution.js +2 -2
  92. package/dist/gpu/image-kernel-execution.js.map +1 -1
  93. package/dist/gpu/temporal-sum-gpu.js +23 -23
  94. package/dist/gpu/webgpu-runtime.js +1 -1
  95. package/dist/gpu/webgpu-runtime.js.map +1 -1
  96. package/dist/gpu/wgsl-chart-composite-kernel.js +318 -318
  97. package/dist/gpu/wgsl-chart-composite-kernel.js.map +1 -1
  98. package/dist/gpu/wgsl-chart-kernel.js +117 -117
  99. package/dist/gpu/wgsl-chart-kernel.js.map +1 -1
  100. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +13 -1
  101. package/dist/gpu/wgsl-display-view-quality-kernel.js +522 -488
  102. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  103. package/dist/gpu/wgsl-display-view-speed-kernel.js +248 -248
  104. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  105. package/dist/gpu/wgsl-kernels.js +203 -203
  106. package/dist/gpu/wgsl-kernels.js.map +1 -1
  107. package/dist/gpu/wgsl-sensor-kernel.js +302 -302
  108. package/dist/gpu/wgsl-sensor-kernel.js.map +1 -1
  109. package/dist/index.d.ts +8 -5
  110. package/dist/index.js +6 -3
  111. package/dist/index.js.map +1 -1
  112. package/dist/motion/temporal-exposure-sum.js +1 -1
  113. package/dist/motion/temporal-exposure-sum.js.map +1 -1
  114. package/dist/optics/diffraction-psf-profile.js +4 -4
  115. package/dist/optics/diffraction-psf-profile.js.map +1 -1
  116. package/dist/optics/front-of-lens-filter.js +1 -1
  117. package/dist/optics/front-of-lens-filter.js.map +1 -1
  118. package/dist/optics/irradiance-convolution.d.ts +10 -0
  119. package/dist/optics/irradiance-convolution.js +49 -14
  120. package/dist/optics/irradiance-convolution.js.map +1 -1
  121. package/dist/output/native-capture-sdr.js +1 -1
  122. package/dist/output/native-capture-sdr.js.map +1 -1
  123. package/dist/output/png-encoder.js +2 -2
  124. package/dist/output/png-encoder.js.map +1 -1
  125. package/dist/output/print-jpeg.js +13 -10
  126. package/dist/output/print-jpeg.js.map +1 -1
  127. package/dist/output/text-metadata.d.ts +22 -2
  128. package/dist/output/text-metadata.js +58 -9
  129. package/dist/output/text-metadata.js.map +1 -1
  130. package/dist/sensor/fixed-pattern-noise.js +1 -1
  131. package/dist/sensor/fixed-pattern-noise.js.map +1 -1
  132. package/dist/sensor/readout-exposure-linkage.js +1 -1
  133. package/dist/sensor/readout-exposure-linkage.js.map +1 -1
  134. package/docs/API_REFERENCE.md +49 -1
  135. package/docs/QUICK_START.md +104 -9
  136. package/docs/USAGE.md +241 -2
  137. package/docs/api/core-version.md +1 -1
  138. package/docs/api/equipment-generic-tier-assets.md +41 -1
  139. package/docs/api/equipment-generic-tier-presets.md +11 -3
  140. package/docs/api/exports.json +172 -2
  141. package/docs/api/exposure-auto-iso-slowest-shutter.md +139 -0
  142. package/docs/api/exposure-exposure-mode-resolver.md +68 -0
  143. package/docs/api/facade-chart-scenes.md +36 -5
  144. package/docs/api/facade-color-patches.md +150 -0
  145. package/docs/api/facade-simulate-capture.md +140 -9
  146. package/docs/api/output-text-metadata.md +34 -0
  147. package/llms.txt +1 -0
  148. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  # Public API reference
2
2
 
3
- Generated from the exact root exports for **@photivra/engine 2.12.0 / root contract 2.12.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.14.0 / root contract 2.14.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
 
@@ -846,10 +846,14 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
846
846
 
847
847
  | Export | Kind |
848
848
  | --- | --- |
849
+ | [`GENERIC_THIRD_STOP_ISO_SETTINGS`](api/equipment-generic-tier-assets.md#generic_third_stop_iso_settings) | Runtime |
850
+ | [`GENERIC_THIRD_STOP_SHUTTER_SECONDS`](api/equipment-generic-tier-assets.md#generic_third_stop_shutter_seconds) | Runtime |
851
+ | [`GENERIC_WHOLE_STOP_ISO_SETTINGS`](api/equipment-generic-tier-assets.md#generic_whole_stop_iso_settings) | Runtime |
849
852
  | [`GenericEquipmentTier`](api/equipment-generic-tier-assets.md#genericequipmenttier) | Type |
850
853
  | [`GenericEquipmentTierPreset`](api/equipment-generic-tier-assets.md#genericequipmenttierpreset) | Type |
851
854
  | [`GenericTierBodyAssets`](api/equipment-generic-tier-assets.md#generictierbodyassets) | Type |
852
855
  | [`GenericTierLensAssets`](api/equipment-generic-tier-assets.md#generictierlensassets) | Type |
856
+ | [`GenericTierPresetVersion`](api/equipment-generic-tier-assets.md#generictierpresetversion) | Type |
853
857
  | [`GenericVersionedAsset`](api/equipment-generic-tier-assets.md#genericversionedasset) | Type |
854
858
 
855
859
  ## equipment/generic-tier-presets.ts
@@ -860,6 +864,7 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
860
864
  | --- | --- |
861
865
  | [`createGenericEquipmentTierSelection`](api/equipment-generic-tier-presets.md#creategenericequipmenttierselection) | Runtime |
862
866
  | [`GENERIC_EQUIPMENT_TIER_PRESET_VERSION`](api/equipment-generic-tier-presets.md#generic_equipment_tier_preset_version) | Runtime |
867
+ | [`GENERIC_EQUIPMENT_TIER_PRESET_VERSIONS`](api/equipment-generic-tier-presets.md#generic_equipment_tier_preset_versions) | Runtime |
863
868
  | [`GENERIC_EQUIPMENT_TIERS`](api/equipment-generic-tier-presets.md#generic_equipment_tiers) | Runtime |
864
869
  | [`GenericEquipmentTierProfileReference`](api/equipment-generic-tier-presets.md#genericequipmenttierprofilereference) | Type |
865
870
  | [`GenericEquipmentTierSelection`](api/equipment-generic-tier-presets.md#genericequipmenttierselection) | Type |
@@ -918,6 +923,20 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
918
923
  | [`GenericReleaseDriveMode`](api/equipment-release-capabilities.md#genericreleasedrivemode) | Type |
919
924
  | [`parseGenericReleaseCapabilityProfile`](api/equipment-release-capabilities.md#parsegenericreleasecapabilityprofile) | Runtime |
920
925
 
926
+ ## exposure/auto-iso-slowest-shutter.ts
927
+
928
+ [Detailed contracts](api/exposure-auto-iso-slowest-shutter.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/exposure/auto-iso-slowest-shutter.ts)
929
+
930
+ | Export | Kind |
931
+ | --- | --- |
932
+ | [`AUTO_ISO_SLOWEST_SHUTTER_MAXIMUM_BIAS_STOPS`](api/exposure-auto-iso-slowest-shutter.md#auto_iso_slowest_shutter_maximum_bias_stops) | Runtime |
933
+ | [`AUTO_ISO_SLOWEST_SHUTTER_MODEL_VERSION`](api/exposure-auto-iso-slowest-shutter.md#auto_iso_slowest_shutter_model_version) | Runtime |
934
+ | [`AutoIsoSlowestShutterBlurBudget`](api/exposure-auto-iso-slowest-shutter.md#autoisoslowestshutterblurbudget) | Type |
935
+ | [`AutoIsoSlowestShutterEstimate`](api/exposure-auto-iso-slowest-shutter.md#autoisoslowestshutterestimate) | Type |
936
+ | [`estimateAutoIsoSlowestShutter`](api/exposure-auto-iso-slowest-shutter.md#estimateautoisoslowestshutter) | Runtime |
937
+ | [`EstimateAutoIsoSlowestShutterInput`](api/exposure-auto-iso-slowest-shutter.md#estimateautoisoslowestshutterinput) | Type |
938
+ | [`GENERIC_HANDHELD_ANGULAR_VELOCITY_RAD_PER_SEC`](api/exposure-auto-iso-slowest-shutter.md#generic_handheld_angular_velocity_rad_per_sec) | Runtime |
939
+
921
940
  ## exposure/exposure-duration-control.ts
922
941
 
923
942
  [Detailed contracts](api/exposure-exposure-duration-control.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/exposure/exposure-duration-control.ts)
@@ -941,6 +960,7 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
941
960
  | [`AperturePriorityAutoIsoPolicy`](api/exposure-exposure-mode-resolver.md#aperturepriorityautoisopolicy) | Type |
942
961
  | [`AperturePriorityExposureModeResolution`](api/exposure-exposure-mode-resolver.md#aperturepriorityexposuremoderesolution) | Type |
943
962
  | [`AutoIsoBaselinePolicy`](api/exposure-exposure-mode-resolver.md#autoisobaselinepolicy) | Type |
963
+ | [`AutoIsoLimits`](api/exposure-exposure-mode-resolver.md#autoisolimits) | Type |
944
964
  | [`EXPOSURE_MODE_RESOLVER_VERSION`](api/exposure-exposure-mode-resolver.md#exposure_mode_resolver_version) | Runtime |
945
965
  | [`ExposureResolutionConstraint`](api/exposure-exposure-mode-resolver.md#exposureresolutionconstraint) | Type |
946
966
  | [`ExposureTargetResidual`](api/exposure-exposure-mode-resolver.md#exposuretargetresidual) | Type |
@@ -952,6 +972,7 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
952
972
  | [`ProgramAutoExposureModeResolution`](api/exposure-exposure-mode-resolver.md#programautoexposuremoderesolution) | Type |
953
973
  | [`ProgramAutoIsoControl`](api/exposure-exposure-mode-resolver.md#programautoisocontrol) | Type |
954
974
  | [`ProgramLineSelectionDiagnostics`](api/exposure-exposure-mode-resolver.md#programlineselectiondiagnostics) | Type |
975
+ | [`ProgramSlowestPreferredShutterPolicy`](api/exposure-exposure-mode-resolver.md#programslowestpreferredshutterpolicy) | Type |
955
976
  | [`RelativeExposureControlAnchor`](api/exposure-exposure-mode-resolver.md#relativeexposurecontrolanchor) | Type |
956
977
  | [`resolveAperturePriorityAutoIsoExposureMode`](api/exposure-exposure-mode-resolver.md#resolveaperturepriorityautoisoexposuremode) | Runtime |
957
978
  | [`ResolveAperturePriorityAutoIsoExposureModeInput`](api/exposure-exposure-mode-resolver.md#resolveaperturepriorityautoisoexposuremodeinput) | Type |
@@ -1157,6 +1178,8 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1157
1178
  | [`ChartScenePresetId`](api/facade-chart-scenes.md#chartscenepresetid) | Type |
1158
1179
  | [`ChartSlantedSquare`](api/facade-chart-scenes.md#chartslantedsquare) | Type |
1159
1180
  | [`CheckerboardChartScene`](api/facade-chart-scenes.md#checkerboardchartscene) | Type |
1181
+ | [`ColorPatchesChartScene`](api/facade-chart-scenes.md#colorpatcheschartscene) | Type |
1182
+ | [`ColorPatchReflectance`](api/facade-chart-scenes.md#colorpatchreflectance) | Type |
1160
1183
  | [`CompositeChartElement`](api/facade-chart-scenes.md#compositechartelement) | Type |
1161
1184
  | [`CompositeChartScene`](api/facade-chart-scenes.md#compositechartscene) | Type |
1162
1185
  | [`DeadLeavesChartScene`](api/facade-chart-scenes.md#deadleaveschartscene) | Type |
@@ -1175,6 +1198,25 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1175
1198
  | [`UniformChartScene`](api/facade-chart-scenes.md#uniformchartscene) | Type |
1176
1199
  | [`ZonePlateChartScene`](api/facade-chart-scenes.md#zoneplatechartscene) | Type |
1177
1200
 
1201
+ ## facade/color-patches.ts
1202
+
1203
+ [Detailed contracts](api/facade-color-patches.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/color-patches.ts)
1204
+
1205
+ | Export | Kind |
1206
+ | --- | --- |
1207
+ | [`COLOR_PATCH_IDS`](api/facade-color-patches.md#color_patch_ids) | Runtime |
1208
+ | [`COLOR_PATCH_SET_ID`](api/facade-color-patches.md#color_patch_set_id) | Runtime |
1209
+ | [`COLOR_PATCH_SET_VERSION`](api/facade-color-patches.md#color_patch_set_version) | Runtime |
1210
+ | [`COLOR_PATCH_WAVELENGTH_RANGE_NANOMETERS`](api/facade-color-patches.md#color_patch_wavelength_range_nanometers) | Runtime |
1211
+ | [`ColorPatch`](api/facade-color-patches.md#colorpatch) | Type |
1212
+ | [`ColorPatchGroup`](api/facade-color-patches.md#colorpatchgroup) | Type |
1213
+ | [`ColorPatchId`](api/facade-color-patches.md#colorpatchid) | Type |
1214
+ | [`ColorPatchSet`](api/facade-color-patches.md#colorpatchset) | Type |
1215
+ | [`ColorPatchSpectralTerm`](api/facade-color-patches.md#colorpatchspectralterm) | Type |
1216
+ | [`evaluateColorPatchReflectance`](api/facade-color-patches.md#evaluatecolorpatchreflectance) | Runtime |
1217
+ | [`EvaluateColorPatchReflectanceInput`](api/facade-color-patches.md#evaluatecolorpatchreflectanceinput) | Type |
1218
+ | [`getColorPatchSet`](api/facade-color-patches.md#getcolorpatchset) | Runtime |
1219
+
1178
1220
  ## facade/display-view-gpu.ts
1179
1221
 
1180
1222
  [Detailed contracts](api/facade-display-view-gpu.md) · [Source](https://github.com/Photivra/photivra/blob/main/src/facade/display-view-gpu.ts)
@@ -1234,11 +1276,14 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1234
1276
  | [`SIMULATE_CAPTURE_DEFAULT_ILLUMINANCE_LUX`](api/facade-simulate-capture.md#simulate_capture_default_illuminance_lux) | Runtime |
1235
1277
  | [`SIMULATE_CAPTURE_FACADE_VERSION`](api/facade-simulate-capture.md#simulate_capture_facade_version) | Runtime |
1236
1278
  | [`SIMULATE_CAPTURE_FAST_OPTIONS`](api/facade-simulate-capture.md#simulate_capture_fast_options) | Runtime |
1279
+ | [`SIMULATE_CAPTURE_METERING_MODES`](api/facade-simulate-capture.md#simulate_capture_metering_modes) | Runtime |
1237
1280
  | [`SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS`](api/facade-simulate-capture.md#simulate_display_view_default_samples_per_axis) | Runtime |
1238
1281
  | [`simulateCapture`](api/facade-simulate-capture.md#simulatecapture) | Runtime |
1239
1282
  | [`SimulateCaptureAssumption`](api/facade-simulate-capture.md#simulatecaptureassumption) | Type |
1240
1283
  | [`SimulateCaptureAutoIsoAfterMaximum`](api/facade-simulate-capture.md#simulatecaptureautoisoaftermaximum) | Type |
1241
1284
  | [`SimulateCaptureAutoIsoReport`](api/facade-simulate-capture.md#simulatecaptureautoisoreport) | Type |
1285
+ | [`SimulateCaptureAutomaticSlowestShutterOptions`](api/facade-simulate-capture.md#simulatecaptureautomaticslowestshutteroptions) | Type |
1286
+ | [`SimulateCaptureAutomaticSlowestShutterReport`](api/facade-simulate-capture.md#simulatecaptureautomaticslowestshutterreport) | Type |
1242
1287
  | [`SimulateCaptureBorderHandling`](api/facade-simulate-capture.md#simulatecaptureborderhandling) | Type |
1243
1288
  | [`SimulateCaptureColorEncoding`](api/facade-simulate-capture.md#simulatecapturecolorencoding) | Type |
1244
1289
  | [`SimulateCaptureCostOption`](api/facade-simulate-capture.md#simulatecapturecostoption) | Type |
@@ -1249,6 +1294,7 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
1249
1294
  | [`SimulateCaptureFastOption`](api/facade-simulate-capture.md#simulatecapturefastoption) | Type |
1250
1295
  | [`SimulateCaptureFastReport`](api/facade-simulate-capture.md#simulatecapturefastreport) | Type |
1251
1296
  | [`SimulateCaptureLensDistortion`](api/facade-simulate-capture.md#simulatecapturelensdistortion) | Type |
1297
+ | [`SimulateCaptureMetering`](api/facade-simulate-capture.md#simulatecapturemetering) | Type |
1252
1298
  | [`SimulateCaptureMotion`](api/facade-simulate-capture.md#simulatecapturemotion) | Type |
1253
1299
  | [`SimulateCaptureOptions`](api/facade-simulate-capture.md#simulatecaptureoptions) | Type |
1254
1300
  | [`SimulateCaptureOutputFormat`](api/facade-simulate-capture.md#simulatecaptureoutputformat) | Type |
@@ -2172,6 +2218,8 @@ Start here to find a function by task. [Using Photivra from an agent](AGENT_GUID
2172
2218
 
2173
2219
  | Export | Kind |
2174
2220
  | --- | --- |
2221
+ | [`addJpegTextMetadata`](api/output-text-metadata.md#addjpegtextmetadata) | Runtime |
2222
+ | [`addPngTextMetadata`](api/output-text-metadata.md#addpngtextmetadata) | Runtime |
2175
2223
  | [`OutputTextMetadata`](api/output-text-metadata.md#outputtextmetadata) | Type |
2176
2224
 
2177
2225
  ## processing/demosaic.ts
@@ -48,7 +48,7 @@ the example above is [simulate-capture.mjs](examples/simulate-capture.mjs).
48
48
  | `raw` | The packed native RAW: codes, black levels, saturation flags and per-phase white levels |
49
49
  | `plan` | The native RAW plan the engine executed |
50
50
  | `request` | The complete underlying request: `environmentRaw` (the native environment RAW input), `siteInput(index)` (rebuilds the physical input of any sensor site), `development` (the RAW development input) and `whiteBalanceState` |
51
- | `exposure` | Mode, resolved settings, EV100, `isoControl` (`"manual"` or `"automatic"`) and, with `iso: "auto"`, `autoIso` (how the ISO was chosen and what limited it), metered scene luminance, the deviation from the standard exposure in stops (`standardExposureDeviationStops`) and the exposure-mode resolver's full output |
51
+ | `exposure` | Mode, resolved settings, EV100, `isoControl` (`"manual"` or `"automatic"`) and, with `iso: "auto"`, `autoIso` (how the ISO was chosen and what limited it), metered scene luminance, the deviation from the standard exposure in stops (`standardExposureDeviationStops`), the illuminance at which the settings give the standard exposure (`standardExposureIlluminanceLux`), from 2.14 the deviation from the standard exposure of an 18 % grey card under the scene's illuminance (`greyCardDeviationStops`, incident metering) and the exposure-mode resolver's full output |
52
52
  | `scene` | Chart parameters, illuminant, distance, framed size and the scene's SHA-256 digest (it covers caller illuminant and reflectance spectra; see `sourceSha256`) |
53
53
  | `diagnostics` | Radiance query count, highlight and rendering counters, per-stage timings (`timingsMs`) and, from 2.1, the opt-ins that ran (`options`); see [Cost of each option](#cost-of-each-option) |
54
54
  | `provenance` | Status (`approximation`), camera preset identity, evidence, the composed contracts in order, and limitations |
@@ -75,10 +75,11 @@ modelling choices (such as "no lens PSF") as `kind: "model"`.
75
75
  | `lens.defocus` | off | `{ model: "geometric-disc" }`: defocus of the scene plane as the geometric blur disc (see [Optics](#optics)). `simulateCapture` and `simulateDisplayView` render it. |
76
76
  | `lens.diffraction` | off | 2.1: `"circular-aperture"` or `{ kind: "circular-aperture", kernelRadiusSamples, fast }`: diffraction blur of an ideal lens at the resolved f-number (see [Optics](#optics)). `aperture` is accepted as a deprecated alias of `kind` until 3.0.0. |
77
77
  | `exposure.mode` | `"manual"` | Also `"aperture-priority"`, `"shutter-priority"`, `"program"`. |
78
- | `exposure.iso` | 100 | Selects the body's ISO readout regime (gain and read noise). `"auto"` lets Auto ISO choose it from the meter in any mode (see [Auto ISO](#auto-iso-516)). |
79
- | `exposure.autoIso` | none | `aperture-priority` with `iso: "auto"` only, and required there: `{ slowestPreferredShutterSeconds, afterMaximumIso? }` (see [Auto ISO](#auto-iso-516)). |
78
+ | `exposure.iso` | 100 | Selects the body's ISO readout regime (gain and read noise). From 2.14 the tier bodies (preset 2.1.0) take the third-stop settings `GENERIC_THIRD_STOP_ISO_SETTINGS` (100, 125, 160, 200 … up to the body's maximum: 6400, 12 800 or 25 600). `"auto"` lets Auto ISO choose it from the meter in any mode (see [Auto ISO](#auto-iso-516)); it steps in whole stops unless `exposure.autoIso.isoSteps: "third-stop"`. |
79
+ | `exposure.autoIso` | none | With `iso: "auto"` only. `aperture-priority` requires `{ slowestPreferredShutterSeconds, afterMaximumIso? }`, and `program` takes them optionally; the slowest shutter may be `"auto"`, set by `automaticSlowestShutter`. Every mode takes `limits: { maximum, minimum? }`, the photographer's Auto ISO range (see [Auto ISO](#auto-iso-516)). |
80
80
  | `exposure.shutterSeconds` | 1/125 | Used in `manual` and `shutter-priority`. |
81
81
  | `exposure.compensationStops` | 0 | Applied to the meter target. |
82
+ | `exposure.metering` | `"scene-average"` | 2.14: or `"grey-card"`, incident metering: the meter reads an 18 % grey card under the scene's illuminance instead of the scene, so the automatic modes and Auto ISO land on `greyCardDeviationStops` = 0 (see [Exposure](#exposure)). Reported as `exposure.metering`. |
82
83
  | `scene` | required | A chart preset or a caller function (below). |
83
84
  | `subjectDistanceM` | 5 | Distance of the scene plane. |
84
85
  | `chartSize` | fill the frame | 2.3: `{ widthM, heightM?, surroundReflectance? }` places the chart at its physical size (see [Fixed-size chart](#fixed-size-chart-23)). |
@@ -173,6 +174,10 @@ real products, and carry no brand:
173
174
  to 135 mm, f/32 beyond. Any f-number inside the range is accepted; `fNumbers` lists the marked
174
175
  third-stop values within it (`GENERIC_PRIME_THIRD_STOP_F_NUMBERS`: 1, 1.1, 1.2, 1.4, …, 22, 25, 29, 32,
175
176
  the conventional rounded values of 2^(k/6)). An f-number outside the range is rejected.
177
+ - **Third-stop dials (2.14):** `GENERIC_THIRD_STOP_ISO_SETTINGS` lists the bodies' ISO settings (the rounded values of
178
+ 100·2^(k/3)), and `GENERIC_THIRD_STOP_SHUTTER_SECONDS` the standard third-stop shutter times from 1/8000 s to 30 s
179
+ (the rounded values of 2^(k/3) s: 1/8000, 1/6400, 1/5000, … 1/13, 1/10, 1/8, 1/6, 1/5, 1/4, 0.3, 0.4 … 25, 30). The
180
+ bodies' shutters are continuous over 1/8000–30 s and take each value as the exact time.
176
181
  - **Minimum focus** = max(0.10 m, f·(1 + 1/0.15)): the thin-lens object distance at 0.15× magnification,
177
182
  never closer than 10 cm (`GENERIC_PRIME_MINIMUM_FOCUS`). A subject or focus distance below it is
178
183
  rejected. This is a generic thin-lens approximation, measured from the lens, not a real lens's
@@ -368,6 +373,39 @@ The facade meters the scene like a reflected-light meter:
368
373
  used: minus the compensation (−⅔ for +⅔ stop), plus any step or limit the resolver hit (the slowest shutter, the ISO
369
374
  range). It is `null` only when the metered luminance is 0, which has no standard exposure. The display view reports
370
375
  the same value.
376
+ - `exposure.standardExposureIlluminanceLux` is the illuminance at which the settings used give that standard exposure:
377
+ E·L_ref/L = E·2^Δ, with E the request's `illuminanceLux` and L_ref = 10·N²/(0.65·t·S). A chart, reflectance function
378
+ or material scene has radiance reflectance × E-scaled illuminant / π, so its metered luminance is proportional to E,
379
+ and the same request at this illuminance meters at Δ = 0 (to rounding: the metering quadrature is the same at both
380
+ illuminances). With the defaults it is the default illuminance; the marked f/11 gives 2^0.919 times it, about
381
+ 40 612 lux. It is `null` for a black scene and for a `radiance-function` scene, whose radiance does not depend on the
382
+ illuminance. It can exceed the 1e7 lux `illuminanceLux` accepts. The display view reports the same value.
383
+ - `exposure.greyCardDeviationStops` (2.14) is the same deviation for incident metering: the light falling on the scene,
384
+ as an 18 % grey card or a hand-held incident meter reads it, instead of the scene's own luminance. It uses the grey
385
+ card's luminance L = 0.18·E/π (a Lambertian reflector; E the request's `illuminanceLux`) in place of the metered L:
386
+ Δ_grey = log₂(L_ref/(0.18·E/π)), L_ref = 10·N²/(0.65·t·S). Same sign: positive is darker (under). It depends only on
387
+ the settings used and the illuminance, never on the scene's reflectances, so a chart's white paper cannot fool it.
388
+ With the default settings and illuminance it is exactly 0 (the default illuminance is defined from this grey card,
389
+ below); each stop of shutter, aperture or ISO, and each halving of the illuminance, moves it by one stop. It is `null`
390
+ for a `radiance-function` scene, whose radiance ignores the illuminance. The display view reports the same value.
391
+ - **By default the automatic modes meter the scene** (`exposure.metering: "scene-average"`: the body's
392
+ 16 × 16-zone meter, `meteredSceneLuminanceCdPerSquareMeter`), exactly as before 2.14, and `greyCardDeviationStops`
393
+ reports where their exposure sits against the grey card. On a scene brighter than 18 % grey they expose darker
394
+ than the grey card: a uniform 90 % white gives log₂(0.9/0.18) ≈ +2.32, and the app's round 4 All-in-one chart on
395
+ 90 % white paper about +1.78 (its metered luminance is 3.4 times the grey card's).
396
+ - **`exposure.metering: "grey-card"` (2.14) meters by the grey card**: every meter zone reads L = 0.18·E/π, so
397
+ aperture priority, shutter priority and program, with a fixed ISO or Auto ISO, choose settings with
398
+ `greyCardDeviationStops` = 0 whatever the scene's reflectances, as a manual exposure at the default settings and
399
+ illuminance has. What is left is the mode's own steps and limits: the resolvers set a continuous shutter or
400
+ aperture, so only rounding remains unless the lens or shutter range stops them (shutter priority at 1/125 s and
401
+ 5000 lx would need f/3.9 and stops at f/4, 0.10 stop under); Auto ISO chooses whole-stop ISOs, so up to half a
402
+ stop remains, and that remainder is the Auto ISO report's `residualStops`, with `limitingConstraint` naming
403
+ `iso-grid-quantization` or the ISO limit. Compensation still applies (+⅔ gives −⅔). Manual exposure ignores the
404
+ meter, so the option changes nothing there except Auto ISO. `meteredSceneLuminanceCdPerSquareMeter`,
405
+ `standardExposureDeviationStops` and `standardExposureIlluminanceLux` still describe the scene's own luminance.
406
+ A `radiance-function` scene is refused, since its radiance ignores the illuminance. The capture reports
407
+ `exposure.metering`, and the assumption `exposure.meteringSource` gives the card's luminance. When the option is
408
+ omitted, nothing is added to the assumptions, so 2.13 requests give the same assumptions and bytes.
371
409
 
372
410
  DC-004 ties the reference level to an 18 % grey (Explanation 1 and 2.2). The default illuminance
373
411
  puts an 18 % Lambertian grey card, whose luminance is L = 0.18·E/π, exactly at that luminance:
@@ -400,9 +438,9 @@ Exposure compensation applies to the meter target first, as with a numeric ISO.
400
438
  | Mode | With `iso: "auto"` |
401
439
  | --- | --- |
402
440
  | `manual` | Your aperture and shutter; the ISO makes up the exposure (`resolveManualExposureMode`, automatic ISO). |
403
- | `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); 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`). The engine does not choose a slowest shutter for you. |
441
+ | `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`). |
404
442
  | `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`). |
405
- | `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). |
443
+ | `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. |
406
444
 
407
445
  The result says what happened. `exposure.settings.iso` is the ISO used and `exposure.isoControl` is `"automatic"`.
408
446
  `exposure.autoIso` reports `idealIsoBeforeConstraints`, the Auto ISO range (`autoIsoMinimum`, `autoIsoMaximum`),
@@ -414,6 +452,14 @@ A display view, an ideal reference and every `output.region` part of the same re
414
452
  they resolve the same exposure and report the same values. Requests without `"auto"` are unchanged: their
415
453
  `isoControl` is `"manual"` and they have no `autoIso`.
416
454
 
455
+ **Your own limits (#505).** `exposure.autoIso.limits: { maximum, minimum? }` caps Auto ISO, and optionally raises its
456
+ floor, in any mode, as cameras' "maximum sensitivity" settings do. It is your choice, kept apart from the body's Auto
457
+ ISO range: both limits must be selectable ISOs of the body inside that range (`minimum` at most `maximum`, default the
458
+ body's minimum), or the request fails with `InvalidConfigurationError`; nothing is clipped. When the ISO stops at your
459
+ limit, `limitingConstraint` is `"user-iso-maximum"` (or `"user-iso-minimum"`), distinct from the body's `"iso-maximum"`,
460
+ and `exposure.autoIso.limits` repeats the range used. In aperture priority, `afterMaximumIso` applies at your maximum
461
+ just as at the body's. Without `limits` nothing changes. A separate cap for flash is not part of this.
462
+
417
463
  ```ts
418
464
  import { simulateCapture } from "@photivra/engine";
419
465
 
@@ -427,22 +473,62 @@ const dusk = await simulateCapture({
427
473
  console.log(dusk.exposure.settings, dusk.exposure.isoControl, dusk.exposure.autoIso?.limitingConstraint);
428
474
  ```
429
475
 
476
+ ```ts
477
+ import { simulateCapture } from "@photivra/engine";
478
+
479
+ const night = await simulateCapture({
480
+ exposure: { mode: "program", iso: "auto", autoIso: { limits: { maximum: 6400 } } },
481
+ scene: { preset: "uniform" },
482
+ illuminanceLux: 0.5,
483
+ output: { width: 8, height: 8 }
484
+ });
485
+ // ISO 6400, "user-iso-maximum", { minimum: 100, maximum: 6400 }
486
+ console.log(night.exposure.settings.iso, night.exposure.autoIso?.limitingConstraint, night.exposure.autoIso?.limits);
487
+ ```
488
+
489
+ **An automatic slowest shutter (#504).** `slowestPreferredShutterSeconds: "auto"` lets the engine choose it from the lens,
490
+ the pixel pitch and the hand's shake, through its camera-shake model (`estimateAutoIsoSlowestShutter`, see
491
+ [USAGE](USAGE.md#automatic-slowest-shutter-504)). It does not use the 1/focal-length rule of thumb: the shutter is the time
492
+ at which the shake blur equals the budget. `exposure.autoIso.automaticSlowestShutter` sets `fasterByStops` (−2 to +2, as
493
+ cameras' faster/slower bias; default 0), `blurBudgetPixels` (default 1), `angularVelocityRadPerSec` and
494
+ `stabilizationStopsEquivalent` (default 0). The default hand, 4.39 °/s, is a cited generic value for a phone held in two
495
+ hands, not a measurement of you, so pass your own when you know it. `exposure.autoIso.automaticSlowestShutter` in the result
496
+ reports the derived, biased and used times.
497
+
498
+ ```ts
499
+ import { simulateCapture } from "@photivra/engine";
500
+
501
+ const handheld = await simulateCapture({
502
+ exposure: { mode: "aperture-priority", iso: "auto",
503
+ autoIso: { slowestPreferredShutterSeconds: "auto", automaticSlowestShutter: { fasterByStops: -1, stabilizationStopsEquivalent: 3 } } },
504
+ lens: { fNumber: 4 },
505
+ scene: { preset: "uniform" },
506
+ illuminanceLux: 20,
507
+ output: { width: 8, height: 8 }
508
+ });
509
+ console.log(handheld.exposure.autoIso?.automaticSlowestShutter, handheld.exposure.settings);
510
+ ```
511
+
430
512
  ## Scene presets
431
513
 
432
514
  All charts are analytic patterns written by the engine; no third-party chart data is bundled. Each
433
515
  is a flat Lambertian reflector (it looks equally bright from every direction). Neutral reflectances
434
- are spectrally flat.
516
+ are spectrally flat. Where a preset takes a reflectance spectrum (`uniform`, `patches`), it accepts a
517
+ neutral number, a caller spectrum (`{ kind: "tabulated" }` or `{ kind: "function" }`, 380–780 nm at
518
+ least) or, from 2.14, a built-in color patch `{ kind: "color-patch", patchId }` (see
519
+ [Color patches](https://github.com/Photivra/photivra/blob/main/docs/COLOR_PATCHES.md)).
435
520
 
436
521
  | Preset | Parameters (defaults) | Definition |
437
522
  | --- | --- | --- |
438
- | `uniform` | `reflectance` (0.18) | One reflectance or caller spectrum everywhere. |
523
+ | `uniform` | `reflectance` (0.18) | One reflectance, caller spectrum or built-in colour patch everywhere. |
439
524
  | `slanted-edge` | `angleDegrees` (5), `darkReflectance` (0.15), `lightReflectance` (0.6) | An edge through the centre, tilted clockwise from vertical: light where u·cos θ − v·sin θ ≥ 0. The geometry follows the slanted-edge method described by Burns (2000), also used by ISO 12233 (a few degrees of slant, 4:1 contrast by default). |
440
525
  | `siemens-star` | `cycles` (36), `radiusFraction` (0.9), `darkReflectance` (0.05), `lightReflectance` (0.8), `backgroundReflectance` (0.18) | Alternating sectors of angular width π/cycles inside radius `radiusFraction` × frame half-height. |
441
526
  | `step-wedge` | `steps` (11), `minimumReflectance` (0.03), `maximumReflectance` (0.9), `spacing` (`equal-density`) | Equal-width vertical steps from left to right. Equal density spaces D = −log₁₀ R evenly; `linear` spaces R evenly. |
442
527
  | `grey-ramp` | `minimumReflectance` (0.03), `maximumReflectance` (0.9) | Reflectance linear in u, represented by 1024 equal levels. |
443
528
  | `checkerboard` | `squaresAcross` (8), `darkReflectance` (0.05), `lightReflectance` (0.8) | Square cells, light at the top-left. |
444
529
  | `point-grid` | `columns` (5), `rows` (3), `radius` (0.01), `pointReflectance` (0.9), `backgroundReflectance` (0.02) | Small disks centred in equal cells, for PSF and defocus inspection. |
445
- | `patches` | `patches` (required), `columns`, `gapFraction` (0.1), `backgroundReflectance` (0.18) | Caller reflectance per patch, row-major. Use it for a ColorChecker-like chart with reflectance data you are entitled to use; the engine does not ship such data because its licence is unclear. |
530
+ | `patches` | `patches` (required), `columns`, `gapFraction` (0.1), `backgroundReflectance` (0.18) | Caller reflectance per patch, row-major. Use it for a chart with reflectance data you are entitled to use; the engine does not ship third-party chart data because its licence is unclear. |
531
+ | `color-patches` | `patchIds` (all 30), `columns` (min(6, count)), `gapFraction` (0.1), `backgroundReflectance` (0.18) | 2.14: Photivra's own 30 color patches (neutral ramp, strong and soft primaries and secondaries, skin tones, memory colors, two near the sRGB gamut edge) drawn like `patches`. Each is an analytic reflectance spectrum; see [Color patches](https://github.com/Photivra/photivra/blob/main/docs/COLOR_PATCHES.md) for the formula, the parameters and the code, name, CIELAB (D65) and sRGB of every patch. |
446
532
 
447
533
  ### Chart elements and composite charts (2.3)
448
534
 
@@ -689,6 +775,10 @@ console.log(shot.image.png?.length, shot.assumptions.find((a) => a.id === "outpu
689
775
  | `copyright` | XMP `dc:rights` | `Copyright` | Copyright tag (ASCII only); XMP `dc:rights` |
690
776
  | `comment` | COM segment and XMP `exif:UserComment` | `Comment` | XMP `exif:UserComment` |
691
777
 
778
+ To add the same text to a JPEG or PNG you encoded yourself (for example a full-size file joined from
779
+ `output.region` parts), call `addJpegTextMetadata(jpeg, metadata)` or `addPngTextMetadata(png, metadata)` (#388).
780
+ They are the functions `output.metadata` uses, so the bytes are the same, and they check the text by the same rules.
781
+
692
782
  Each field is optional, but at least one must be set. A field is a non-empty string of at most
693
783
  2048 UTF-8 bytes. Lone UTF-16 surrogates (which have no UTF-8 form), NUL, U+FFFE, U+FFFF and control
694
784
  characters other than line feed (`\n`) are rejected with an `InvalidConfigurationError` that names the
@@ -803,6 +893,11 @@ The optics options feed only what the environment site contract accepts:
803
893
  scene; a test checks it to 1e-12 per site. With camera rotation, a projection or distortion, or
804
894
  vignetting, the per-tap quadrature runs instead (much slower). `request.diffraction` holds the profile,
805
895
  the equivalent `sampled-local` PSF and which execution ran.
896
+ - The convolution runs in 32-row bands and computes only each band's own values, not the 2R rows and
897
+ columns of padding around it (#419; the values are bit-identical to the full-grid convolution's). On a
898
+ function scene with the Quality options at 1 µm and f/16 (R 32), 96 × 72, `diagnostics.timingsMs.diffraction`
899
+ went from 6.3 s to 0.62 s (medians of 5, one thread, a shared Mac); the tabulated capture's four
900
+ verification sites went from medians of 0.41–0.54 s to 4–5 ms at R 29–32.
806
901
  - Not modelled: defocus, aberrations, pupil clipping, a polygonal (bladed) aperture (the tiers declare
807
902
  no blade count) and, unless `sensor.pixelAperture` is `"box"` (2.3), the pixel aperture (each site
808
903
  is sampled at its centre). It cannot be
@@ -894,7 +989,7 @@ The optics options feed only what the environment site contract accepts:
894
989
  request fails and names the radius it needed.
895
990
  - A 24 MP frame costs proportionally more. Render it in parts across workers, as for diffraction.
896
991
  - Off the tabulated path (caller reflectance or radiance functions), the provider gathers only each 32-row band's
897
- own values, not the 2R extra rows `calculateIrradianceConvolution` would return (#419). On a 256 × 171
992
+ own values, not the 2R extra rows a full-grid convolution would return (#419). On a 256 × 171
898
993
  function scene the convolution took 0.3 s at R 8, 3.5 s at R 32 and 12.9 s at R 64.
899
994
  - It cannot be combined with `lens.pupilSampling` (the rays already render defocus) or `lens.psf` (a caller PSF
900
995
  declares its own defocus). It can be combined with `lens.diffraction`.