davinci-resolve-mcp 2.57.4 → 2.58.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.
- package/AGENTS.md +20 -0
- package/CHANGELOG.md +197 -2
- package/LICENSE +1 -1
- package/README.md +73 -1
- package/bin/davinci-resolve-advanced-mcp.mjs +20 -0
- package/docs/README.md +19 -0
- package/docs/SKILL.md +62 -1
- package/docs/contributing.md +1 -1
- package/docs/guides/control-panel.md +9 -0
- package/docs/kernels/README.md +21 -0
- package/docs/kernels/audio-fairlight-kernel.md +22 -0
- package/docs/kernels/color-grade-kernel.md +51 -0
- package/docs/kernels/fusion-composition-kernel.md +17 -0
- package/docs/kernels/media-pool-ingest-kernel.md +20 -0
- package/docs/kernels/render-deliver-kernel.md +32 -0
- package/docs/kernels/timeline-conform-interchange-kernel.md +39 -0
- package/docs/kernels/timeline-edit-kernel.md +17 -0
- package/docs/process/release-process.md +29 -7
- package/docs/reference/api-coverage.md +1 -1
- package/docs/reference/api-limitations.md +38 -1
- package/install.py +27 -4
- package/package.json +23 -2
- package/resolve-advanced/README.md +194 -0
- package/resolve-advanced/package.json +50 -0
- package/resolve-advanced/server/black-balance.mjs +92 -0
- package/resolve-advanced/server/capabilities.mjs +86 -0
- package/resolve-advanced/server/cdl-io.mjs +76 -0
- package/resolve-advanced/server/contrast-normalize.mjs +180 -0
- package/resolve-advanced/server/db-patch.mjs +91 -0
- package/resolve-advanced/server/deliverable-entities.mjs +86 -0
- package/resolve-advanced/server/deliverable-qc.mjs +270 -0
- package/resolve-advanced/server/editorial.mjs +370 -0
- package/resolve-advanced/server/exposure-level.mjs +129 -0
- package/resolve-advanced/server/extract-frames.mjs +196 -0
- package/resolve-advanced/server/ffprobe-media.mjs +88 -0
- package/resolve-advanced/server/gamut-legal.mjs +112 -0
- package/resolve-advanced/server/grade-body-patch.mjs +246 -0
- package/resolve-advanced/server/grade-transfer.mjs +66 -0
- package/resolve-advanced/server/group-grade-read.mjs +137 -0
- package/resolve-advanced/server/index.mjs +105 -0
- package/resolve-advanced/server/lib.mjs +84 -0
- package/resolve-advanced/server/libs.mjs +65 -0
- package/resolve-advanced/server/lineage-db.mjs +479 -0
- package/resolve-advanced/server/lut-apply.mjs +61 -0
- package/resolve-advanced/server/match-to-reference.mjs +173 -0
- package/resolve-advanced/server/media-inventory.mjs +169 -0
- package/resolve-advanced/server/media-ops.mjs +243 -0
- package/resolve-advanced/server/node-meta-db.mjs +62 -0
- package/resolve-advanced/server/node-provenance.mjs +102 -0
- package/resolve-advanced/server/offline-ref-db.mjs +420 -0
- package/resolve-advanced/server/offline-ref.mjs +179 -0
- package/resolve-advanced/server/project-db.mjs +233 -0
- package/resolve-advanced/server/provenance-audit.mjs +210 -0
- package/resolve-advanced/server/qc-frame.mjs +224 -0
- package/resolve-advanced/server/qc-sampler.mjs +67 -0
- package/resolve-advanced/server/readback.mjs +77 -0
- package/resolve-advanced/server/render-manifest.mjs +93 -0
- package/resolve-advanced/server/reverse-clip-db.mjs +270 -0
- package/resolve-advanced/server/runner-apply-contract.mjs +64 -0
- package/resolve-advanced/server/runner.mjs +244 -0
- package/resolve-advanced/server/saturation-match.mjs +108 -0
- package/resolve-advanced/server/scope-read.mjs +257 -0
- package/resolve-advanced/server/season-look.mjs +96 -0
- package/resolve-advanced/server/shot-intent.mjs +82 -0
- package/resolve-advanced/server/shot-match.mjs +147 -0
- package/resolve-advanced/server/skin-match.mjs +205 -0
- package/resolve-advanced/server/spec-compile.mjs +217 -0
- package/resolve-advanced/server/tone-curve-transfer.mjs +184 -0
- package/resolve-advanced/server/tool-catalog.mjs +265 -0
- package/resolve-advanced/server/tools/audio.mjs +54 -0
- package/resolve-advanced/server/tools/audio_plan.mjs +58 -0
- package/resolve-advanced/server/tools/capabilities.mjs +16 -0
- package/resolve-advanced/server/tools/color_trace.mjs +165 -0
- package/resolve-advanced/server/tools/conform.mjs +291 -0
- package/resolve-advanced/server/tools/deliverable.mjs +105 -0
- package/resolve-advanced/server/tools/drp.mjs +232 -0
- package/resolve-advanced/server/tools/drt.mjs +200 -0
- package/resolve-advanced/server/tools/drx.mjs +943 -0
- package/resolve-advanced/server/tools/editorial.mjs +69 -0
- package/resolve-advanced/server/tools/fairlight.mjs +108 -0
- package/resolve-advanced/server/tools/fusion.mjs +64 -0
- package/resolve-advanced/server/tools/media.mjs +102 -0
- package/resolve-advanced/server/tools/offline_ref.mjs +123 -0
- package/resolve-advanced/server/tools/pipeline.mjs +137 -0
- package/resolve-advanced/server/tools/project_db.mjs +200 -0
- package/resolve-advanced/server/tools/project_read.mjs +212 -0
- package/resolve-advanced/server/tools/provenance.mjs +73 -0
- package/resolve-advanced/server/verify-grade.mjs +113 -0
- package/resolve-advanced/server/white-balance-match.mjs +122 -0
- package/resolve-advanced/vendor/audio/format-converter.js +330 -0
- package/resolve-advanced/vendor/audio/split.js +173 -0
- package/resolve-advanced/vendor/audio/trim.js +188 -0
- package/resolve-advanced/vendor/audio-fairlight/index.js +391 -0
- package/resolve-advanced/vendor/conform-qc/adapters/frame-sampler.js +56 -0
- package/resolve-advanced/vendor/conform-qc/adapters/local-ffmpeg-sampler.js +65 -0
- package/resolve-advanced/vendor/conform-qc/adapters/rendernode-ffmpeg-sampler.js +50 -0
- package/resolve-advanced/vendor/conform-qc/adapters/resolve/driver.py +176 -0
- package/resolve-advanced/vendor/conform-qc/adapters/resolve-driver.js +61 -0
- package/resolve-advanced/vendor/conform-qc/adapters/resolve-headless-driver.js +86 -0
- package/resolve-advanced/vendor/conform-qc/adapters/vision-validator.js +75 -0
- package/resolve-advanced/vendor/conform-qc/cli.js +63 -0
- package/resolve-advanced/vendor/conform-qc/compare/advisory.js +106 -0
- package/resolve-advanced/vendor/conform-qc/compare/decode.js +36 -0
- package/resolve-advanced/vendor/conform-qc/compare/index.js +61 -0
- package/resolve-advanced/vendor/conform-qc/compare/locate.js +70 -0
- package/resolve-advanced/vendor/conform-qc/compare/metrics.js +409 -0
- package/resolve-advanced/vendor/conform-qc/docs/runbook.md +72 -0
- package/resolve-advanced/vendor/conform-qc/index.js +49 -0
- package/resolve-advanced/vendor/conform-qc/knowledge/index.js +110 -0
- package/resolve-advanced/vendor/conform-qc/ops/conform-core.js +137 -0
- package/resolve-advanced/vendor/conform-qc/ops/conform-diff.js +109 -0
- package/resolve-advanced/vendor/conform-qc/ops/insert.js +108 -0
- package/resolve-advanced/vendor/conform-qc/ops/local-conform.js +61 -0
- package/resolve-advanced/vendor/conform-qc/ops/patch.js +80 -0
- package/resolve-advanced/vendor/conform-qc/ops/trigger.js +32 -0
- package/resolve-advanced/vendor/conform-qc/ops/verify.js +105 -0
- package/resolve-advanced/vendor/conform-qc/ops/workflow.js +30 -0
- package/resolve-advanced/vendor/conform-qc/oracle/emulate.js +155 -0
- package/resolve-advanced/vendor/conform-qc/oracle/index.js +38 -0
- package/resolve-advanced/vendor/conform-qc/oracle/resolve.js +196 -0
- package/resolve-advanced/vendor/conform-qc/package.json +16 -0
- package/resolve-advanced/vendor/conform-qc/packaging/emit-aaf.js +30 -0
- package/resolve-advanced/vendor/conform-qc/packaging/emit-fcp7.js +64 -0
- package/resolve-advanced/vendor/conform-qc/packaging/index.js +169 -0
- package/resolve-advanced/vendor/conform-qc/packaging/media-ops.js +56 -0
- package/resolve-advanced/vendor/conform-qc/packaging/otio.js +50 -0
- package/resolve-advanced/vendor/conform-qc/packaging/relink.js +50 -0
- package/resolve-advanced/vendor/conform-qc/packaging/surgical-relink.js +195 -0
- package/resolve-advanced/vendor/conform-qc/parse/index.js +54 -0
- package/resolve-advanced/vendor/conform-qc/parse/merge-dto.js +27 -0
- package/resolve-advanced/vendor/conform-qc/parse/xmeml-geometry.js +256 -0
- package/resolve-advanced/vendor/conform-qc/reference/burnin-ocr.js +100 -0
- package/resolve-advanced/vendor/conform-qc/reference/sidecar.js +37 -0
- package/resolve-advanced/vendor/conform-qc/repair/analysis.js +62 -0
- package/resolve-advanced/vendor/conform-qc/repair/index.js +78 -0
- package/resolve-advanced/vendor/conform-qc/repair/media-analysis.js +139 -0
- package/resolve-advanced/vendor/conform-qc/repair/media-index.js +135 -0
- package/resolve-advanced/vendor/conform-qc/repair/strategies.js +250 -0
- package/resolve-advanced/vendor/conform-qc/report/index.js +133 -0
- package/resolve-advanced/vendor/conform-qc/roles/index.js +96 -0
- package/resolve-advanced/vendor/conform-qc/synthetic/generate.js +233 -0
- package/resolve-advanced/vendor/conform-qc/test/advisory.test.js +85 -0
- package/resolve-advanced/vendor/conform-qc/test/cli.test.js +39 -0
- package/resolve-advanced/vendor/conform-qc/test/compare.test.js +152 -0
- package/resolve-advanced/vendor/conform-qc/test/conform-diff.test.js +70 -0
- package/resolve-advanced/vendor/conform-qc/test/emulate.test.js +51 -0
- package/resolve-advanced/vendor/conform-qc/test/frame-sampler.test.js +30 -0
- package/resolve-advanced/vendor/conform-qc/test/geometry.test.js +112 -0
- package/resolve-advanced/vendor/conform-qc/test/knowledge.test.js +56 -0
- package/resolve-advanced/vendor/conform-qc/test/lifecycle.test.js +110 -0
- package/resolve-advanced/vendor/conform-qc/test/local-ffmpeg-sampler.test.js +66 -0
- package/resolve-advanced/vendor/conform-qc/test/locate.test.js +63 -0
- package/resolve-advanced/vendor/conform-qc/test/media-analysis.test.js +63 -0
- package/resolve-advanced/vendor/conform-qc/test/media-index-normalized.test.js +65 -0
- package/resolve-advanced/vendor/conform-qc/test/media-index-origin.test.js +53 -0
- package/resolve-advanced/vendor/conform-qc/test/metrics-fast.test.js +91 -0
- package/resolve-advanced/vendor/conform-qc/test/oracle-reverse.test.js +86 -0
- package/resolve-advanced/vendor/conform-qc/test/oracle.test.js +136 -0
- package/resolve-advanced/vendor/conform-qc/test/p0-acceptance.test.js +60 -0
- package/resolve-advanced/vendor/conform-qc/test/p1-acceptance.test.js +75 -0
- package/resolve-advanced/vendor/conform-qc/test/p45-patch-acceptance.test.js +102 -0
- package/resolve-advanced/vendor/conform-qc/test/packaging.test.js +133 -0
- package/resolve-advanced/vendor/conform-qc/test/parse-stubs.test.js +28 -0
- package/resolve-advanced/vendor/conform-qc/test/repair-strategies.test.js +128 -0
- package/resolve-advanced/vendor/conform-qc/test/repair.test.js +84 -0
- package/resolve-advanced/vendor/conform-qc/test/report.test.js +52 -0
- package/resolve-advanced/vendor/conform-qc/test/resolve-readback.test.js +71 -0
- package/resolve-advanced/vendor/conform-qc/test/roles.test.js +107 -0
- package/resolve-advanced/vendor/conform-qc/test/runbook.test.js +30 -0
- package/resolve-advanced/vendor/conform-qc/test/scale-residual.test.js +40 -0
- package/resolve-advanced/vendor/conform-qc/test/sidecar.test.js +51 -0
- package/resolve-advanced/vendor/conform-qc/test/smoke.test.js +87 -0
- package/resolve-advanced/vendor/conform-qc/test/surgical-relink.test.js +73 -0
- package/resolve-advanced/vendor/conform-qc/test/synthetic.test.js +98 -0
- package/resolve-advanced/vendor/conform-qc/test/verify.test.js +93 -0
- package/resolve-advanced/vendor/conform-qc/test/vision-validator.test.js +43 -0
- package/resolve-advanced/vendor/conform-qc/test/workflow-driver.test.js +46 -0
- package/resolve-advanced/vendor/conform-qc/toolset/index.js +53 -0
- package/resolve-advanced/vendor/drp-format/README.md +116 -0
- package/resolve-advanced/vendor/drp-format/__tests__/_resolve-verify.js +39 -0
- package/resolve-advanced/vendor/drp-format/__tests__/add-media-clip.test.js +30 -0
- package/resolve-advanced/vendor/drp-format/__tests__/assemble-timeline.test.js +68 -0
- package/resolve-advanced/vendor/drp-format/__tests__/author-project.test.js +57 -0
- package/resolve-advanced/vendor/drp-format/__tests__/composition-text.test.js +98 -0
- package/resolve-advanced/vendor/drp-format/__tests__/diff.test.js +272 -0
- package/resolve-advanced/vendor/drp-format/__tests__/effect-filters-compressed.test.js +143 -0
- package/resolve-advanced/vendor/drp-format/__tests__/fixtures/p0-3-session30-empty-effectfilters.drp +0 -0
- package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-50pct.hex +1 -0
- package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-dynamic.hex +1 -0
- package/resolve-advanced/vendor/drp-format/__tests__/inject-grades.test.js +238 -0
- package/resolve-advanced/vendor/drp-format/__tests__/keyed-dict.test.js +85 -0
- package/resolve-advanced/vendor/drp-format/__tests__/lut-refs.test.js +119 -0
- package/resolve-advanced/vendor/drp-format/__tests__/media-blobs.test.js +25 -0
- package/resolve-advanced/vendor/drp-format/__tests__/media-timemap.test.js +119 -0
- package/resolve-advanced/vendor/drp-format/__tests__/place-fusion-title.test.js +52 -0
- package/resolve-advanced/vendor/drp-format/__tests__/place-generator.test.js +40 -0
- package/resolve-advanced/vendor/drp-format/__tests__/place-transition.test.js +48 -0
- package/resolve-advanced/vendor/drp-format/__tests__/protobuf-wire.test.js +64 -0
- package/resolve-advanced/vendor/drp-format/__tests__/relink-media.test.js +106 -0
- package/resolve-advanced/vendor/drp-format/__tests__/splice-clips.test.js +256 -0
- package/resolve-advanced/vendor/drp-format/assemble-timeline.js +65 -0
- package/resolve-advanced/vendor/drp-format/author-project.js +118 -0
- package/resolve-advanced/vendor/drp-format/composition-text.js +213 -0
- package/resolve-advanced/vendor/drp-format/curves-encoder.js +763 -0
- package/resolve-advanced/vendor/drp-format/diff.js +310 -0
- package/resolve-advanced/vendor/drp-format/drp-packager.js +201 -0
- package/resolve-advanced/vendor/drp-format/drp-validator.js +809 -0
- package/resolve-advanced/vendor/drp-format/effect-encoder.js +640 -0
- package/resolve-advanced/vendor/drp-format/extract-lut-refs.js +119 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.example.js +133 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.js +401 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.test.js +171 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.verify.js +249 -0
- package/resolve-advanced/vendor/drp-format/grade-node-extractor.js +495 -0
- package/resolve-advanced/vendor/drp-format/grade-parameter-decoder.js +774 -0
- package/resolve-advanced/vendor/drp-format/index.js +174 -0
- package/resolve-advanced/vendor/drp-format/inject-grades.js +219 -0
- package/resolve-advanced/vendor/drp-format/keyed-dict.js +227 -0
- package/resolve-advanced/vendor/drp-format/marker-encoder.js +532 -0
- package/resolve-advanced/vendor/drp-format/media-blobs.js +53 -0
- package/resolve-advanced/vendor/drp-format/media-timemap.js +164 -0
- package/resolve-advanced/vendor/drp-format/mp-folder-builder.js +293 -0
- package/resolve-advanced/vendor/drp-format/node-tree-encoder.js +1246 -0
- package/resolve-advanced/vendor/drp-format/package.json +18 -0
- package/resolve-advanced/vendor/drp-format/place-fusion-title.js +131 -0
- package/resolve-advanced/vendor/drp-format/place-generator.js +77 -0
- package/resolve-advanced/vendor/drp-format/place-transition.js +91 -0
- package/resolve-advanced/vendor/drp-format/power-window-encoder.js +776 -0
- package/resolve-advanced/vendor/drp-format/protobuf-wire.js +111 -0
- package/resolve-advanced/vendor/drp-format/qualifier-encoder.js +706 -0
- package/resolve-advanced/vendor/drp-format/relink-media.js +218 -0
- package/resolve-advanced/vendor/drp-format/rich-title-encoder.js +447 -0
- package/resolve-advanced/vendor/drp-format/seq-container-builder.js +572 -0
- package/resolve-advanced/vendor/drp-format/seq-surgery.js +155 -0
- package/resolve-advanced/vendor/drp-format/splice-clips.js +445 -0
- package/resolve-advanced/vendor/drp-format/templates/empty-project.drp +0 -0
- package/resolve-advanced/vendor/drp-format/templates/fusion-title.xml +56 -0
- package/resolve-advanced/vendor/drp-format/templates/generator-solid-color.xml +21 -0
- package/resolve-advanced/vendor/drp-format/templates/media-clip-h264.drp +0 -0
- package/resolve-advanced/vendor/drp-format/templates/transition-cross-dissolve.xml +22 -0
- package/resolve-advanced/vendor/drp-format/tool-registry.descriptor.js +80 -0
- package/resolve-advanced/vendor/drp-format/utils/safe-archive.js +54 -0
- package/resolve-advanced/vendor/drp-format/xml-builder.js +759 -0
- package/resolve-advanced/vendor/drt-format/__tests__/_resolve-verify.js +21 -0
- package/resolve-advanced/vendor/drt-format/__tests__/build.test.js +113 -0
- package/resolve-advanced/vendor/drt-format/__tests__/multi-format.test.js +93 -0
- package/resolve-advanced/vendor/drt-format/__tests__/parse-real-resolve21.test.js +51 -0
- package/resolve-advanced/vendor/drt-format/__tests__/parse.test.js +134 -0
- package/resolve-advanced/vendor/drt-format/__tests__/resolve-versions.test.js +120 -0
- package/resolve-advanced/vendor/drt-format/__tests__/schema-fingerprint.test.js +62 -0
- package/resolve-advanced/vendor/drt-format/__tests__/smoke.test.js +27 -0
- package/resolve-advanced/vendor/drt-format/__tests__/validate.test.js +109 -0
- package/resolve-advanced/vendor/drt-format/capabilities.js +69 -0
- package/resolve-advanced/vendor/drt-format/capability-domains.js +56 -0
- package/resolve-advanced/vendor/drt-format/drt-builder.js +42 -0
- package/resolve-advanced/vendor/drt-format/drt-parser.js +164 -0
- package/resolve-advanced/vendor/drt-format/drt-validator.js +98 -0
- package/resolve-advanced/vendor/drt-format/index.js +45 -0
- package/resolve-advanced/vendor/drt-format/package.json +17 -0
- package/resolve-advanced/vendor/drt-format/resolve-versions.js +153 -0
- package/resolve-advanced/vendor/drt-format/schema-fingerprint.js +74 -0
- package/resolve-advanced/vendor/drt-format/templates/drt-project-shell.xml +124 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/curves-roundtrip.test.js +148 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-face-refinement.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-filmgrain.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-glow.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-lens-flare.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-25.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-75.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-no-lut.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-with-lut.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/hsl-curves-roundtrip.test.js +117 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/lut-refs-roundtrip.test.js +112 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/matte-roundtrip.test.js +167 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/ofx-roundtrip.test.js +215 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/ofx-slugs-discovery.test.js +149 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/power-window-roundtrip.test.js +230 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/qualifier-roundtrip.test.js +226 -0
- package/resolve-advanced/vendor/drx-codec/cdl-exporter.js +470 -0
- package/resolve-advanced/vendor/drx-codec/color-nlp-parser.js +833 -0
- package/resolve-advanced/vendor/drx-codec/data/color-nlp-action-mappings.json +2232 -0
- package/resolve-advanced/vendor/drx-codec/drx-generator.js +4123 -0
- package/resolve-advanced/vendor/drx-codec/drx-merger.js +320 -0
- package/resolve-advanced/vendor/drx-codec/drx-parser.js +1808 -0
- package/resolve-advanced/vendor/drx-codec/extract-custom-curves.js +215 -0
- package/resolve-advanced/vendor/drx-codec/extract-hsl-curves.js +180 -0
- package/resolve-advanced/vendor/drx-codec/extract-lut-refs.js +158 -0
- package/resolve-advanced/vendor/drx-codec/extract-matte-finesse.js +83 -0
- package/resolve-advanced/vendor/drx-codec/extract-ofx-params.js +226 -0
- package/resolve-advanced/vendor/drx-codec/extract-power-window.js +184 -0
- package/resolve-advanced/vendor/drx-codec/extract-qualifier.js +99 -0
- package/resolve-advanced/vendor/drx-codec/index.js +109 -0
- package/resolve-advanced/vendor/drx-codec/node-layout.js +249 -0
- package/resolve-advanced/vendor/drx-codec/resolved-drx-generator.js +393 -0
- package/resolve-advanced/vendor/drx-codec/tool-resolver.js +974 -0
- package/resolve-advanced/vendor/drx-codec/training-examples.js +548 -0
- package/resolve-advanced/vendor/drx-codec/vocabulary-intents.js +539 -0
- package/resolve-advanced/vendor/drx-parameters/CALIBRATION-STATUS.md +319 -0
- package/resolve-advanced/vendor/drx-parameters/DRX-VALUE-SCALING.md +251 -0
- package/resolve-advanced/vendor/drx-parameters/calibrated-ranges.json +17737 -0
- package/resolve-advanced/vendor/drx-parameters/corrector-types.js +120 -0
- package/resolve-advanced/vendor/drx-parameters/index.js +193 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-codec.js +451 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-ids.js +1292 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-ranges.js +570 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-validator.js +392 -0
- package/resolve-advanced/vendor/drx-parameters/resolvefx-registry.json +14973 -0
- package/resolve-advanced/vendor/drx-parameters/tool-registry.descriptor.js +38 -0
- package/resolve-advanced/vendor/drx-parameters/tools/drx-analyzer.js +371 -0
- package/resolve-advanced/vendor/fairlight/index.js +833 -0
- package/resolve-advanced/vendor/fusion-codec/composition-generator.js +401 -0
- package/resolve-advanced/vendor/fusion-codec/templates/blur-region.js +103 -0
- package/resolve-advanced/vendor/fusion-codec/templates/color-correct.js +87 -0
- package/resolve-advanced/vendor/fusion-codec/templates/film-grain.js +106 -0
- package/resolve-advanced/vendor/fusion-codec/templates/lower-third.js +241 -0
- package/resolve-advanced/vendor/fusion-codec/templates/picture-in-picture.js +188 -0
- package/resolve-advanced/vendor/fusion-codec/templates/text-overlay.js +161 -0
- package/resolve-advanced/vendor/fusion-codec/templates/title-card.js +184 -0
- package/resolve-advanced/vendor/fusion-codec/templates/vignette.js +107 -0
- package/resolve-advanced/vendor/fusion-codec/templates/watermark.js +101 -0
- package/scripts/agent-rules/README.md +68 -0
- package/src/analysis_dashboard.py +233 -1
- package/src/granular/common.py +1 -1
- package/src/server.py +479 -29
- package/src/utils/api_truth.py +117 -0
- package/src/utils/cut_ir.py +1 -1
- package/src/utils/failure_tracker.py +0 -2
- package/src/utils/timeline_xml.py +405 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P1.4 — extractPowerWindow tests.
|
|
3
|
+
*
|
|
4
|
+
* 2026-07-01: updated to the TRUE live-calibrated transform scales (multi-point
|
|
5
|
+
* fit 2026-06-22; see test/power-window-transform-calibration.test.mjs):
|
|
6
|
+
* rotate = −UI°/180 · size = 1+(UI−50)×0.08 · aspect = (50−UI)/50 ·
|
|
7
|
+
* pan/tilt = (UI−50)/50 × 4096 · soft = UI × 16 (gradient soft = UI × 100).
|
|
8
|
+
* The generator now writes these scales (registry window ranges were widened to
|
|
9
|
+
* the real DRX spans, removing the old [-1,1] clamp), so generate→parse→extract
|
|
10
|
+
* round-trips UI-exact AND matches what live Resolve stores.
|
|
11
|
+
*
|
|
12
|
+
* Synthesized-input tests exercise edge cases (Circle/Linear collision,
|
|
13
|
+
* SOFT_REF vs SOFT_1 reconciliation); real round-trips live at the bottom.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const test = require('node:test');
|
|
17
|
+
const assert = require('node:assert/strict');
|
|
18
|
+
|
|
19
|
+
const drxParams = require('../../drx-parameters');
|
|
20
|
+
const { extractPowerWindow, _internals } = require('../extract-power-window');
|
|
21
|
+
const { generateDRX } = require('../drx-generator');
|
|
22
|
+
const { parseDRXContent } = require('../drx-parser');
|
|
23
|
+
|
|
24
|
+
const { POWER_WINDOWS, GRADIENT_WINDOW } = drxParams;
|
|
25
|
+
const PW = POWER_WINDOWS;
|
|
26
|
+
const GW = GRADIENT_WINDOW;
|
|
27
|
+
|
|
28
|
+
// Mirrors buildWindowParams' TRUE scales. Builds the flattened param list
|
|
29
|
+
// (ct4 transform + ct3 mask + ct65554 gradient) the extractor sees.
|
|
30
|
+
function synthesize(w) {
|
|
31
|
+
const params = [];
|
|
32
|
+
const add = (id, value) => params.push({ id, value, name: 'pw' });
|
|
33
|
+
const isGradient = w.type === 5;
|
|
34
|
+
if (isGradient) {
|
|
35
|
+
add(GW.TYPE, { F2: 2 });
|
|
36
|
+
if (w.rotate !== undefined && w.rotate !== 0) add(GW.ROTATION, -w.rotate / 180);
|
|
37
|
+
if (w.pan !== undefined && w.pan !== 50) add(GW.HANDLE_1_POS, ((w.pan - 50) / 50) * 4096);
|
|
38
|
+
if (w.tilt !== undefined && w.tilt !== 50) add(GW.HANDLE_2_POS, ((w.tilt - 50) / 50) * 4096);
|
|
39
|
+
if (w.soft1 !== undefined && w.soft1 !== 0) add(GW.SOFTNESS, w.soft1 * 100);
|
|
40
|
+
return params;
|
|
41
|
+
}
|
|
42
|
+
if (w.type !== undefined) add(PW.WINDOW_TYPE, { F2: 2 }); // constant varint flag
|
|
43
|
+
if (w.rotate !== undefined && w.rotate !== 0) add(PW.ROTATE, -w.rotate / 180);
|
|
44
|
+
if (w.size !== undefined && w.size !== 50) add(PW.SIZE, 1 + (w.size - 50) * 0.08);
|
|
45
|
+
if (w.aspect !== undefined && w.aspect !== 50) add(PW.ASPECT, (50 - w.aspect) / 50);
|
|
46
|
+
if (w.pan !== undefined && w.pan !== 50) add(PW.PAN, ((w.pan - 50) / 50) * 4096);
|
|
47
|
+
if (w.tilt !== undefined && w.tilt !== 50) add(PW.TILT, ((w.tilt - 50) / 50) * 4096);
|
|
48
|
+
if (w.type === 2) {
|
|
49
|
+
if (w.soft1 !== undefined && w.soft1 !== 0) add(PW.SOFT_1, w.soft1 * 16);
|
|
50
|
+
if (w.soft2 !== undefined && w.soft2 !== 0) add(PW.SOFT_2, w.soft2 * 16);
|
|
51
|
+
if (w.soft3 !== undefined && w.soft3 !== 0) add(PW.SOFT_3, w.soft3 * 16);
|
|
52
|
+
if (w.soft4 !== undefined && w.soft4 !== 0) add(PW.SOFT_4, w.soft4 * 16);
|
|
53
|
+
} else if (w.soft1 !== undefined && w.soft1 !== 0) {
|
|
54
|
+
add(PW.SOFT_REF, w.soft1 * 16);
|
|
55
|
+
}
|
|
56
|
+
return params;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const TOL = 1e-3;
|
|
60
|
+
function close(a, b) {
|
|
61
|
+
return Math.abs(a - b) < TOL;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
test('extractPowerWindow: circle window — type round-trips', () => {
|
|
65
|
+
const out = extractPowerWindow(synthesize({ type: 1 }));
|
|
66
|
+
assert.ok(out);
|
|
67
|
+
assert.equal(out.type, 1, 'wire flag 2 with no linear mask → Circle');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('extractPowerWindow: linear window — disambiguated by linear-only softness params', () => {
|
|
71
|
+
// The wire type flag is a constant 2 for BOTH circle and linear windows.
|
|
72
|
+
// Without sibling params, the decoder defaults to Circle. With SOFT_2-4 (only
|
|
73
|
+
// emitted by linear masks), Linear is recognized.
|
|
74
|
+
const minimal = extractPowerWindow(synthesize({ type: 2 }));
|
|
75
|
+
assert.equal(minimal.type, 1, 'pure flag alone is ambiguous; defaults to Circle');
|
|
76
|
+
|
|
77
|
+
const withSoftness = extractPowerWindow(synthesize({ type: 2, soft2: 8 }));
|
|
78
|
+
assert.equal(withSoftness.type, 2, 'SOFT_2 disambiguates → Linear');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('extractPowerWindow: gradient window — type 5 via 0x08F0xxxx params', () => {
|
|
82
|
+
const out = extractPowerWindow(synthesize({ type: 5, soft1: 10 }));
|
|
83
|
+
assert.equal(out.type, 5);
|
|
84
|
+
// Gradient softness uses ×100 scale, not ×16.
|
|
85
|
+
assert.ok(close(out.soft1, 10), `expected soft1=10, got ${out.soft1}`);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('extractPowerWindow: SIZE round-trips through 1+(UI−50)×0.08 encoding', () => {
|
|
89
|
+
const out = extractPowerWindow(synthesize({ type: 1, size: 75 }));
|
|
90
|
+
assert.ok(close(out.size, 75), `expected size=75, got ${out.size}`);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('extractPowerWindow: ASPECT round-trips through (50−UI)/50 encoding', () => {
|
|
94
|
+
const out = extractPowerWindow(synthesize({ type: 1, aspect: 75 }));
|
|
95
|
+
assert.ok(close(out.aspect, 75), `expected aspect=75, got ${out.aspect}`);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('extractPowerWindow: PAN/TILT round-trip through ±4096 pixel scaling', () => {
|
|
99
|
+
const out = extractPowerWindow(synthesize({ type: 1, pan: 60, tilt: 40 }));
|
|
100
|
+
assert.ok(close(out.pan, 60), `expected pan=60, got ${out.pan}`);
|
|
101
|
+
assert.ok(close(out.tilt, 40), `expected tilt=40, got ${out.tilt}`);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('extractPowerWindow: ROTATE round-trips through −UI/180 encoding', () => {
|
|
105
|
+
const out = extractPowerWindow(synthesize({ type: 1, rotate: 45 }));
|
|
106
|
+
assert.ok(close(out.rotate, 45));
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('extractPowerWindow: linear with all 4 softness values', () => {
|
|
110
|
+
const input = { type: 2, soft1: 8, soft2: 12, soft3: 6, soft4: 4 };
|
|
111
|
+
const out = extractPowerWindow(synthesize(input));
|
|
112
|
+
assert.ok(close(out.soft1, 8), `soft1: got ${out.soft1}`);
|
|
113
|
+
assert.ok(close(out.soft2, 12), `soft2: got ${out.soft2}`);
|
|
114
|
+
assert.ok(close(out.soft3, 6), `soft3: got ${out.soft3}`);
|
|
115
|
+
assert.ok(close(out.soft4, 4), `soft4: got ${out.soft4}`);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('extractPowerWindow: SOFT_REF and SOFT_1 reconcile — prefer SOFT_REF', () => {
|
|
119
|
+
const params = [
|
|
120
|
+
{ id: PW.WINDOW_TYPE, value: { F2: 2 }, name: 'type' },
|
|
121
|
+
{ id: PW.SOFT_REF, value: 16 * 10, name: 'softRef' }, // UI 10
|
|
122
|
+
{ id: PW.SOFT_1, value: 16 * 99, name: 'soft1' }, // wrong value to detect override
|
|
123
|
+
];
|
|
124
|
+
const out = extractPowerWindow(params);
|
|
125
|
+
assert.ok(close(out.soft1, 10), `SOFT_REF should win: got ${out.soft1}`);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('extractPowerWindow: SOFT_1 alone (no SOFT_REF) surfaces', () => {
|
|
129
|
+
const params = [
|
|
130
|
+
{ id: PW.WINDOW_TYPE, value: { F2: 2 }, name: 'type' },
|
|
131
|
+
{ id: PW.SOFT_1, value: 16 * 7, name: 'soft1' },
|
|
132
|
+
];
|
|
133
|
+
const out = extractPowerWindow(params);
|
|
134
|
+
assert.ok(close(out.soft1, 7));
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('extractPowerWindow: full linear spec round-trips', () => {
|
|
138
|
+
const input = {
|
|
139
|
+
type: 2,
|
|
140
|
+
rotate: 15,
|
|
141
|
+
size: 60,
|
|
142
|
+
aspect: 80,
|
|
143
|
+
pan: 55,
|
|
144
|
+
tilt: 45,
|
|
145
|
+
soft1: 10,
|
|
146
|
+
soft2: 5,
|
|
147
|
+
soft3: 3,
|
|
148
|
+
soft4: 2,
|
|
149
|
+
};
|
|
150
|
+
const out = extractPowerWindow(synthesize(input));
|
|
151
|
+
for (const [k, expected] of Object.entries(input)) {
|
|
152
|
+
assert.ok(close(out[k], expected), `${k}: got ${out[k]} expected ${expected}`);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('extractPowerWindow: returns null on empty/non-window params', () => {
|
|
157
|
+
assert.equal(extractPowerWindow([
|
|
158
|
+
{ id: 100663320, value: 0.5, name: 'lift.r' },
|
|
159
|
+
]), null);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('extractPowerWindow: handles malformed input', () => {
|
|
163
|
+
assert.equal(extractPowerWindow(null), null);
|
|
164
|
+
assert.equal(extractPowerWindow(undefined), null);
|
|
165
|
+
assert.equal(extractPowerWindow([]), null);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('extractPowerWindow: handles BigInt varint type', () => {
|
|
169
|
+
const out = extractPowerWindow([
|
|
170
|
+
{ id: PW.WINDOW_TYPE, value: 2n, name: 'type' },
|
|
171
|
+
]);
|
|
172
|
+
assert.equal(out.type, 1, 'BigInt 2 → UI 1');
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('internals.drxToUiType: wire 2 → UI 1 (no linear softness) or UI 2 (with)', () => {
|
|
176
|
+
assert.equal(_internals.drxToUiType(2), 1, 'default → Circle');
|
|
177
|
+
assert.equal(_internals.drxToUiType(2, true), 2, 'with linear softness → Linear');
|
|
178
|
+
assert.equal(_internals.drxToUiType(3), 3);
|
|
179
|
+
assert.equal(_internals.drxToUiType(5), 5);
|
|
180
|
+
assert.equal(_internals.drxToUiType(2n), 1);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('internals.drxToSize: round-trips around UI 50 (neutral stored 1.0)', () => {
|
|
184
|
+
assert.equal(_internals.drxToSize(1.0), 50);
|
|
185
|
+
assert.ok(close(_internals.drxToSize(3.0), 75));
|
|
186
|
+
assert.ok(close(_internals.drxToSize(-1.0), 25));
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// ─── Real round-trip via generateDRX ─────────────────────────────────────
|
|
190
|
+
|
|
191
|
+
async function roundTrip(window) {
|
|
192
|
+
const xml = await generateDRX({ window }, { label: 'win-rt' });
|
|
193
|
+
const parsed = await parseDRXContent(xml);
|
|
194
|
+
for (const node of parsed.nodes) {
|
|
195
|
+
// Flatten across corrector blocks: ct4 transform + ct3 mask + ct65554 gradient.
|
|
196
|
+
const params = (node.correctors || []).flatMap((c) => c.parameters || []);
|
|
197
|
+
const out = extractPowerWindow(params);
|
|
198
|
+
if (out) return out;
|
|
199
|
+
}
|
|
200
|
+
throw new Error('roundTrip: no window params found');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
test('round-trip: circle window — full transform survives generate→parse→extract', async () => {
|
|
204
|
+
// Same UI values as the live power-window-transform fixture (Size 75 / Aspect 30 /
|
|
205
|
+
// Pan 35 / Tilt 88 / Rotate 49): the generator now stores the live-calibrated values.
|
|
206
|
+
const input = { type: 1, rotate: 49, size: 75, aspect: 30, pan: 35, tilt: 88, soft1: 10 };
|
|
207
|
+
const out = await roundTrip(input);
|
|
208
|
+
assert.equal(out.type, 1);
|
|
209
|
+
for (const k of ['rotate', 'size', 'aspect', 'pan', 'tilt', 'soft1']) {
|
|
210
|
+
assert.ok(close(out[k], input[k]), `${k}: got ${out[k]} expected ${input[k]}`);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test('round-trip: linear window — softness mask rides ct3', async () => {
|
|
215
|
+
const input = { type: 2, soft1: 4.5, soft2: 6.25, soft3: 8.75, soft4: 11 };
|
|
216
|
+
const out = await roundTrip(input);
|
|
217
|
+
assert.equal(out.type, 2);
|
|
218
|
+
for (const k of ['soft1', 'soft2', 'soft3', 'soft4']) {
|
|
219
|
+
assert.ok(close(out[k], input[k]), `${k}: got ${out[k]} expected ${input[k]}`);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('round-trip: gradient window — ct65554 params', async () => {
|
|
224
|
+
const input = { type: 5, pan: 81, tilt: 82, rotate: 83, soft1: 85, opacity: 84 };
|
|
225
|
+
const out = await roundTrip(input);
|
|
226
|
+
assert.equal(out.type, 5);
|
|
227
|
+
for (const k of ['pan', 'tilt', 'rotate', 'soft1', 'opacity']) {
|
|
228
|
+
assert.ok(close(out[k], input[k]), `${k}: got ${out[k]} expected ${input[k]}`);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P1.3 — extractQualifier tests.
|
|
3
|
+
*
|
|
4
|
+
* Two test strategies coexist:
|
|
5
|
+
*
|
|
6
|
+
* 1. Synthesized inputs (tests 1-14 below): construct parameter lists
|
|
7
|
+
* matching what buildQualifierParams WOULD emit and run
|
|
8
|
+
* extractQualifier on them. Exercises edge cases the generator
|
|
9
|
+
* doesn't expose (BigInt values, duplicate hue params, etc).
|
|
10
|
+
*
|
|
11
|
+
* 2. Real round-trip (tests at the bottom, "generate→parse→extract"):
|
|
12
|
+
* SESSION 25 wired buildQualifierParams into createNode, so
|
|
13
|
+
* generateDRX({qualifier:...}) now actually emits a Type 2
|
|
14
|
+
* corrector. These tests round-trip through real generator + parser.
|
|
15
|
+
*
|
|
16
|
+
* Both strategies kept because synthesized is faster + covers BigInt
|
|
17
|
+
* paths the generator doesn't currently produce; round-trip is the
|
|
18
|
+
* ground-truth wire-format proof.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const test = require('node:test');
|
|
22
|
+
const assert = require('node:assert/strict');
|
|
23
|
+
|
|
24
|
+
const drxParams = require('../../drx-parameters');
|
|
25
|
+
const { extractQualifier, _internals } = require('../extract-qualifier');
|
|
26
|
+
const { generateDRX } = require('../drx-generator');
|
|
27
|
+
const { parseDRXContent } = require('../drx-parser');
|
|
28
|
+
|
|
29
|
+
const { HSL_QUALIFIER } = drxParams;
|
|
30
|
+
|
|
31
|
+
// Build the parameter list that buildQualifierParams WOULD emit for a
|
|
32
|
+
// given UI input. Mirrors lines 2367-2395 of drx-generator.js exactly.
|
|
33
|
+
function synthesizeQualifierParams(q) {
|
|
34
|
+
const params = [];
|
|
35
|
+
const add = (id, ui) => {
|
|
36
|
+
if (ui !== undefined) params.push({ id, value: ui / 100, name: 'q' });
|
|
37
|
+
};
|
|
38
|
+
add(HSL_QUALIFIER.HUE_CENTER, q.hueCenter);
|
|
39
|
+
add(HSL_QUALIFIER.HUE_WIDTH, q.hueWidth);
|
|
40
|
+
add(
|
|
41
|
+
HSL_QUALIFIER.HUE_SYM,
|
|
42
|
+
q.hueSymmetry !== undefined ? q.hueSymmetry : (q.hueCenter !== undefined ? 50 : undefined),
|
|
43
|
+
);
|
|
44
|
+
add(HSL_QUALIFIER.HUE_SOFT, q.hueSoft);
|
|
45
|
+
add(HSL_QUALIFIER.SAT_HIGH, q.satHigh);
|
|
46
|
+
add(HSL_QUALIFIER.SAT_LOW, q.satLow);
|
|
47
|
+
add(HSL_QUALIFIER.SAT_HIGH_SOFT, q.satHighSoft);
|
|
48
|
+
add(HSL_QUALIFIER.SAT_LOW_SOFT, q.satLowSoft);
|
|
49
|
+
add(HSL_QUALIFIER.LUM_HIGH, q.lumHigh);
|
|
50
|
+
add(HSL_QUALIFIER.LUM_LOW, q.lumLow);
|
|
51
|
+
add(HSL_QUALIFIER.LUM_HIGH_SOFT, q.lumHighSoft);
|
|
52
|
+
add(HSL_QUALIFIER.LUM_LOW_SOFT, q.lumLowSoft);
|
|
53
|
+
if (q.hueWidth !== undefined) add(HSL_QUALIFIER.HUE_WIDTH_DUP, q.hueWidth);
|
|
54
|
+
if (q.hueSoft !== undefined) add(HSL_QUALIFIER.HUE_SOFT_DUP, q.hueSoft);
|
|
55
|
+
if (params.length > 0) {
|
|
56
|
+
params.push({ id: HSL_QUALIFIER.MODE_FLAG, value: 4, name: 'modeFlag' });
|
|
57
|
+
params.push({ id: HSL_QUALIFIER.QUALIFIER_MODE, value: 0, name: 'qualifierMode' });
|
|
58
|
+
}
|
|
59
|
+
return params;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const TOL = 1e-4;
|
|
63
|
+
|
|
64
|
+
function close(a, b) {
|
|
65
|
+
return Math.abs(a - b) < TOL;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
test('extractQualifier: hue-only selection (8-config 1/8)', () => {
|
|
69
|
+
const input = { hueCenter: 30, hueWidth: 20 };
|
|
70
|
+
const params = synthesizeQualifierParams(input);
|
|
71
|
+
const out = extractQualifier(params);
|
|
72
|
+
assert.ok(out, 'should return non-null');
|
|
73
|
+
assert.ok(close(out.hueCenter, 30));
|
|
74
|
+
assert.ok(close(out.hueWidth, 20));
|
|
75
|
+
// Default hueSymmetry inserted by generator
|
|
76
|
+
assert.ok(close(out.hueSymmetry, 50));
|
|
77
|
+
// Mode flags surface
|
|
78
|
+
assert.equal(out.modeFlag, 4);
|
|
79
|
+
assert.equal(out.mode, 0);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('extractQualifier: saturation-only selection (2/8)', () => {
|
|
83
|
+
const input = { satLow: 25, satHigh: 75 };
|
|
84
|
+
const out = extractQualifier(synthesizeQualifierParams(input));
|
|
85
|
+
assert.ok(close(out.satLow, 25));
|
|
86
|
+
assert.ok(close(out.satHigh, 75));
|
|
87
|
+
assert.equal(out.hueCenter, undefined);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('extractQualifier: luminance-only selection (3/8)', () => {
|
|
91
|
+
const input = { lumLow: 30, lumHigh: 80 };
|
|
92
|
+
const out = extractQualifier(synthesizeQualifierParams(input));
|
|
93
|
+
assert.ok(close(out.lumLow, 30));
|
|
94
|
+
assert.ok(close(out.lumHigh, 80));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('extractQualifier: all three axes bounded (4/8)', () => {
|
|
98
|
+
const input = {
|
|
99
|
+
hueCenter: 45, hueWidth: 30,
|
|
100
|
+
satLow: 20, satHigh: 80,
|
|
101
|
+
lumLow: 15, lumHigh: 85,
|
|
102
|
+
};
|
|
103
|
+
const out = extractQualifier(synthesizeQualifierParams(input));
|
|
104
|
+
for (const [k, expected] of Object.entries(input)) {
|
|
105
|
+
assert.ok(close(out[k], expected), `${k}: got ${out[k]}, expected ${expected}`);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('extractQualifier: with softness on all axes (5/8)', () => {
|
|
110
|
+
const input = {
|
|
111
|
+
hueCenter: 30, hueWidth: 20, hueSoft: 10,
|
|
112
|
+
satLow: 25, satHigh: 75, satLowSoft: 5, satHighSoft: 5,
|
|
113
|
+
lumLow: 30, lumHigh: 70, lumLowSoft: 8, lumHighSoft: 8,
|
|
114
|
+
};
|
|
115
|
+
const out = extractQualifier(synthesizeQualifierParams(input));
|
|
116
|
+
for (const [k, expected] of Object.entries(input)) {
|
|
117
|
+
assert.ok(close(out[k], expected), `${k}: got ${out[k]}, expected ${expected}`);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('extractQualifier: extreme hue near 0 (6/8)', () => {
|
|
122
|
+
const input = { hueCenter: 0, hueWidth: 10 };
|
|
123
|
+
const out = extractQualifier(synthesizeQualifierParams(input));
|
|
124
|
+
assert.ok(close(out.hueCenter, 0));
|
|
125
|
+
assert.ok(close(out.hueWidth, 10));
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('extractQualifier: extreme hue near 100 (7/8)', () => {
|
|
129
|
+
const input = { hueCenter: 100, hueWidth: 10 };
|
|
130
|
+
const out = extractQualifier(synthesizeQualifierParams(input));
|
|
131
|
+
assert.ok(close(out.hueCenter, 100));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('extractQualifier: full-range cover-everything (8/8)', () => {
|
|
135
|
+
const input = {
|
|
136
|
+
hueCenter: 50, hueWidth: 100, hueSoft: 50, hueSymmetry: 50,
|
|
137
|
+
satLow: 0, satHigh: 100, satLowSoft: 0, satHighSoft: 0,
|
|
138
|
+
lumLow: 0, lumHigh: 100, lumLowSoft: 0, lumHighSoft: 0,
|
|
139
|
+
};
|
|
140
|
+
const out = extractQualifier(synthesizeQualifierParams(input));
|
|
141
|
+
for (const [k, expected] of Object.entries(input)) {
|
|
142
|
+
assert.ok(close(out[k], expected), `${k}: got ${out[k]}, expected ${expected}`);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('extractQualifier: returns null when no qualifier params present', () => {
|
|
147
|
+
assert.equal(extractQualifier([
|
|
148
|
+
{ id: 100663320, value: 0.5, name: 'lift.r' },
|
|
149
|
+
]), null);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test('extractQualifier: handles malformed input', () => {
|
|
153
|
+
assert.equal(extractQualifier(null), null);
|
|
154
|
+
assert.equal(extractQualifier(undefined), null);
|
|
155
|
+
assert.equal(extractQualifier([]), null);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('extractQualifier: handles BigInt varint values', () => {
|
|
159
|
+
// Parser surfaces varints as BigInt in some code paths.
|
|
160
|
+
const params = [
|
|
161
|
+
{ id: HSL_QUALIFIER.MODE_FLAG, value: 4n, name: 'modeFlag' },
|
|
162
|
+
{ id: HSL_QUALIFIER.QUALIFIER_MODE, value: 0n, name: 'qualifierMode' },
|
|
163
|
+
];
|
|
164
|
+
const out = extractQualifier(params);
|
|
165
|
+
assert.equal(out.modeFlag, 4);
|
|
166
|
+
assert.equal(out.mode, 0);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('extractQualifier: duplicate hue params do not override canonical', () => {
|
|
170
|
+
// HUE_WIDTH_DUP appears AFTER HUE_WIDTH in the generator's emission;
|
|
171
|
+
// canonical should win. Test with a deliberately wrong dup value.
|
|
172
|
+
const params = [
|
|
173
|
+
{ id: HSL_QUALIFIER.HUE_WIDTH, value: 0.25, name: 'hueWidth' }, // 25
|
|
174
|
+
{ id: HSL_QUALIFIER.HUE_WIDTH_DUP, value: 0.99, name: 'hueWidthDup' }, // wrong
|
|
175
|
+
];
|
|
176
|
+
const out = extractQualifier(params);
|
|
177
|
+
assert.ok(close(out.hueWidth, 25), `hueWidth canonical should win: got ${out.hueWidth}`);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('internals.drxToUi: BigInt input handled', () => {
|
|
181
|
+
assert.equal(_internals.drxToUi(0.5), 50);
|
|
182
|
+
assert.equal(_internals.drxToUi(0.25), 25);
|
|
183
|
+
// BigInt should be coerced
|
|
184
|
+
assert.equal(_internals.drxToUi(BigInt(0)), 0);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test('internals.varintToNumber: handles BigInt and number', () => {
|
|
188
|
+
assert.equal(_internals.varintToNumber(4n), 4);
|
|
189
|
+
assert.equal(_internals.varintToNumber(4), 4);
|
|
190
|
+
assert.equal(_internals.varintToNumber('foo'), 0);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// ─── Real round-trip via generateDRX (Session 25 wiring) ─────────────────
|
|
194
|
+
|
|
195
|
+
async function roundTrip(qualifier) {
|
|
196
|
+
const xml = await generateDRX({ qualifier }, { label: 'qual-rt' });
|
|
197
|
+
const parsed = await parseDRXContent(xml);
|
|
198
|
+
for (const node of parsed.nodes) {
|
|
199
|
+
for (const corrector of node.correctors) {
|
|
200
|
+
if (corrector.type !== 2) continue;
|
|
201
|
+
const out = extractQualifier(corrector.parameters);
|
|
202
|
+
if (out) return out;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
throw new Error('roundTrip: no Type 2 qualifier corrector found');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
test('round-trip: hue + sat + lum bounded survives generate→parse→extract', async () => {
|
|
209
|
+
const input = { hueCenter: 30, hueWidth: 25, satLow: 20, satHigh: 80, lumLow: 10, lumHigh: 90 };
|
|
210
|
+
const out = await roundTrip(input);
|
|
211
|
+
for (const [k, v] of Object.entries(input)) {
|
|
212
|
+
assert.ok(close(out[k], v), `${k}: got ${out[k]}, expected ${v}`);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('round-trip: full spec with softness on all axes', async () => {
|
|
217
|
+
const input = {
|
|
218
|
+
hueCenter: 45, hueWidth: 30, hueSoft: 15,
|
|
219
|
+
satLow: 25, satHigh: 75, satLowSoft: 8, satHighSoft: 8,
|
|
220
|
+
lumLow: 20, lumHigh: 80, lumLowSoft: 10, lumHighSoft: 10,
|
|
221
|
+
};
|
|
222
|
+
const out = await roundTrip(input);
|
|
223
|
+
for (const [k, v] of Object.entries(input)) {
|
|
224
|
+
assert.ok(close(out[k], v), `${k}: got ${out[k]}, expected ${v}`);
|
|
225
|
+
}
|
|
226
|
+
});
|