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.
Files changed (328) hide show
  1. package/AGENTS.md +20 -0
  2. package/CHANGELOG.md +197 -2
  3. package/LICENSE +1 -1
  4. package/README.md +73 -1
  5. package/bin/davinci-resolve-advanced-mcp.mjs +20 -0
  6. package/docs/README.md +19 -0
  7. package/docs/SKILL.md +62 -1
  8. package/docs/contributing.md +1 -1
  9. package/docs/guides/control-panel.md +9 -0
  10. package/docs/kernels/README.md +21 -0
  11. package/docs/kernels/audio-fairlight-kernel.md +22 -0
  12. package/docs/kernels/color-grade-kernel.md +51 -0
  13. package/docs/kernels/fusion-composition-kernel.md +17 -0
  14. package/docs/kernels/media-pool-ingest-kernel.md +20 -0
  15. package/docs/kernels/render-deliver-kernel.md +32 -0
  16. package/docs/kernels/timeline-conform-interchange-kernel.md +39 -0
  17. package/docs/kernels/timeline-edit-kernel.md +17 -0
  18. package/docs/process/release-process.md +29 -7
  19. package/docs/reference/api-coverage.md +1 -1
  20. package/docs/reference/api-limitations.md +38 -1
  21. package/install.py +27 -4
  22. package/package.json +23 -2
  23. package/resolve-advanced/README.md +194 -0
  24. package/resolve-advanced/package.json +50 -0
  25. package/resolve-advanced/server/black-balance.mjs +92 -0
  26. package/resolve-advanced/server/capabilities.mjs +86 -0
  27. package/resolve-advanced/server/cdl-io.mjs +76 -0
  28. package/resolve-advanced/server/contrast-normalize.mjs +180 -0
  29. package/resolve-advanced/server/db-patch.mjs +91 -0
  30. package/resolve-advanced/server/deliverable-entities.mjs +86 -0
  31. package/resolve-advanced/server/deliverable-qc.mjs +270 -0
  32. package/resolve-advanced/server/editorial.mjs +370 -0
  33. package/resolve-advanced/server/exposure-level.mjs +129 -0
  34. package/resolve-advanced/server/extract-frames.mjs +196 -0
  35. package/resolve-advanced/server/ffprobe-media.mjs +88 -0
  36. package/resolve-advanced/server/gamut-legal.mjs +112 -0
  37. package/resolve-advanced/server/grade-body-patch.mjs +246 -0
  38. package/resolve-advanced/server/grade-transfer.mjs +66 -0
  39. package/resolve-advanced/server/group-grade-read.mjs +137 -0
  40. package/resolve-advanced/server/index.mjs +105 -0
  41. package/resolve-advanced/server/lib.mjs +84 -0
  42. package/resolve-advanced/server/libs.mjs +65 -0
  43. package/resolve-advanced/server/lineage-db.mjs +479 -0
  44. package/resolve-advanced/server/lut-apply.mjs +61 -0
  45. package/resolve-advanced/server/match-to-reference.mjs +173 -0
  46. package/resolve-advanced/server/media-inventory.mjs +169 -0
  47. package/resolve-advanced/server/media-ops.mjs +243 -0
  48. package/resolve-advanced/server/node-meta-db.mjs +62 -0
  49. package/resolve-advanced/server/node-provenance.mjs +102 -0
  50. package/resolve-advanced/server/offline-ref-db.mjs +420 -0
  51. package/resolve-advanced/server/offline-ref.mjs +179 -0
  52. package/resolve-advanced/server/project-db.mjs +233 -0
  53. package/resolve-advanced/server/provenance-audit.mjs +210 -0
  54. package/resolve-advanced/server/qc-frame.mjs +224 -0
  55. package/resolve-advanced/server/qc-sampler.mjs +67 -0
  56. package/resolve-advanced/server/readback.mjs +77 -0
  57. package/resolve-advanced/server/render-manifest.mjs +93 -0
  58. package/resolve-advanced/server/reverse-clip-db.mjs +270 -0
  59. package/resolve-advanced/server/runner-apply-contract.mjs +64 -0
  60. package/resolve-advanced/server/runner.mjs +244 -0
  61. package/resolve-advanced/server/saturation-match.mjs +108 -0
  62. package/resolve-advanced/server/scope-read.mjs +257 -0
  63. package/resolve-advanced/server/season-look.mjs +96 -0
  64. package/resolve-advanced/server/shot-intent.mjs +82 -0
  65. package/resolve-advanced/server/shot-match.mjs +147 -0
  66. package/resolve-advanced/server/skin-match.mjs +205 -0
  67. package/resolve-advanced/server/spec-compile.mjs +217 -0
  68. package/resolve-advanced/server/tone-curve-transfer.mjs +184 -0
  69. package/resolve-advanced/server/tool-catalog.mjs +265 -0
  70. package/resolve-advanced/server/tools/audio.mjs +54 -0
  71. package/resolve-advanced/server/tools/audio_plan.mjs +58 -0
  72. package/resolve-advanced/server/tools/capabilities.mjs +16 -0
  73. package/resolve-advanced/server/tools/color_trace.mjs +165 -0
  74. package/resolve-advanced/server/tools/conform.mjs +291 -0
  75. package/resolve-advanced/server/tools/deliverable.mjs +105 -0
  76. package/resolve-advanced/server/tools/drp.mjs +232 -0
  77. package/resolve-advanced/server/tools/drt.mjs +200 -0
  78. package/resolve-advanced/server/tools/drx.mjs +943 -0
  79. package/resolve-advanced/server/tools/editorial.mjs +69 -0
  80. package/resolve-advanced/server/tools/fairlight.mjs +108 -0
  81. package/resolve-advanced/server/tools/fusion.mjs +64 -0
  82. package/resolve-advanced/server/tools/media.mjs +102 -0
  83. package/resolve-advanced/server/tools/offline_ref.mjs +123 -0
  84. package/resolve-advanced/server/tools/pipeline.mjs +137 -0
  85. package/resolve-advanced/server/tools/project_db.mjs +200 -0
  86. package/resolve-advanced/server/tools/project_read.mjs +212 -0
  87. package/resolve-advanced/server/tools/provenance.mjs +73 -0
  88. package/resolve-advanced/server/verify-grade.mjs +113 -0
  89. package/resolve-advanced/server/white-balance-match.mjs +122 -0
  90. package/resolve-advanced/vendor/audio/format-converter.js +330 -0
  91. package/resolve-advanced/vendor/audio/split.js +173 -0
  92. package/resolve-advanced/vendor/audio/trim.js +188 -0
  93. package/resolve-advanced/vendor/audio-fairlight/index.js +391 -0
  94. package/resolve-advanced/vendor/conform-qc/adapters/frame-sampler.js +56 -0
  95. package/resolve-advanced/vendor/conform-qc/adapters/local-ffmpeg-sampler.js +65 -0
  96. package/resolve-advanced/vendor/conform-qc/adapters/rendernode-ffmpeg-sampler.js +50 -0
  97. package/resolve-advanced/vendor/conform-qc/adapters/resolve/driver.py +176 -0
  98. package/resolve-advanced/vendor/conform-qc/adapters/resolve-driver.js +61 -0
  99. package/resolve-advanced/vendor/conform-qc/adapters/resolve-headless-driver.js +86 -0
  100. package/resolve-advanced/vendor/conform-qc/adapters/vision-validator.js +75 -0
  101. package/resolve-advanced/vendor/conform-qc/cli.js +63 -0
  102. package/resolve-advanced/vendor/conform-qc/compare/advisory.js +106 -0
  103. package/resolve-advanced/vendor/conform-qc/compare/decode.js +36 -0
  104. package/resolve-advanced/vendor/conform-qc/compare/index.js +61 -0
  105. package/resolve-advanced/vendor/conform-qc/compare/locate.js +70 -0
  106. package/resolve-advanced/vendor/conform-qc/compare/metrics.js +409 -0
  107. package/resolve-advanced/vendor/conform-qc/docs/runbook.md +72 -0
  108. package/resolve-advanced/vendor/conform-qc/index.js +49 -0
  109. package/resolve-advanced/vendor/conform-qc/knowledge/index.js +110 -0
  110. package/resolve-advanced/vendor/conform-qc/ops/conform-core.js +137 -0
  111. package/resolve-advanced/vendor/conform-qc/ops/conform-diff.js +109 -0
  112. package/resolve-advanced/vendor/conform-qc/ops/insert.js +108 -0
  113. package/resolve-advanced/vendor/conform-qc/ops/local-conform.js +61 -0
  114. package/resolve-advanced/vendor/conform-qc/ops/patch.js +80 -0
  115. package/resolve-advanced/vendor/conform-qc/ops/trigger.js +32 -0
  116. package/resolve-advanced/vendor/conform-qc/ops/verify.js +105 -0
  117. package/resolve-advanced/vendor/conform-qc/ops/workflow.js +30 -0
  118. package/resolve-advanced/vendor/conform-qc/oracle/emulate.js +155 -0
  119. package/resolve-advanced/vendor/conform-qc/oracle/index.js +38 -0
  120. package/resolve-advanced/vendor/conform-qc/oracle/resolve.js +196 -0
  121. package/resolve-advanced/vendor/conform-qc/package.json +16 -0
  122. package/resolve-advanced/vendor/conform-qc/packaging/emit-aaf.js +30 -0
  123. package/resolve-advanced/vendor/conform-qc/packaging/emit-fcp7.js +64 -0
  124. package/resolve-advanced/vendor/conform-qc/packaging/index.js +169 -0
  125. package/resolve-advanced/vendor/conform-qc/packaging/media-ops.js +56 -0
  126. package/resolve-advanced/vendor/conform-qc/packaging/otio.js +50 -0
  127. package/resolve-advanced/vendor/conform-qc/packaging/relink.js +50 -0
  128. package/resolve-advanced/vendor/conform-qc/packaging/surgical-relink.js +195 -0
  129. package/resolve-advanced/vendor/conform-qc/parse/index.js +54 -0
  130. package/resolve-advanced/vendor/conform-qc/parse/merge-dto.js +27 -0
  131. package/resolve-advanced/vendor/conform-qc/parse/xmeml-geometry.js +256 -0
  132. package/resolve-advanced/vendor/conform-qc/reference/burnin-ocr.js +100 -0
  133. package/resolve-advanced/vendor/conform-qc/reference/sidecar.js +37 -0
  134. package/resolve-advanced/vendor/conform-qc/repair/analysis.js +62 -0
  135. package/resolve-advanced/vendor/conform-qc/repair/index.js +78 -0
  136. package/resolve-advanced/vendor/conform-qc/repair/media-analysis.js +139 -0
  137. package/resolve-advanced/vendor/conform-qc/repair/media-index.js +135 -0
  138. package/resolve-advanced/vendor/conform-qc/repair/strategies.js +250 -0
  139. package/resolve-advanced/vendor/conform-qc/report/index.js +133 -0
  140. package/resolve-advanced/vendor/conform-qc/roles/index.js +96 -0
  141. package/resolve-advanced/vendor/conform-qc/synthetic/generate.js +233 -0
  142. package/resolve-advanced/vendor/conform-qc/test/advisory.test.js +85 -0
  143. package/resolve-advanced/vendor/conform-qc/test/cli.test.js +39 -0
  144. package/resolve-advanced/vendor/conform-qc/test/compare.test.js +152 -0
  145. package/resolve-advanced/vendor/conform-qc/test/conform-diff.test.js +70 -0
  146. package/resolve-advanced/vendor/conform-qc/test/emulate.test.js +51 -0
  147. package/resolve-advanced/vendor/conform-qc/test/frame-sampler.test.js +30 -0
  148. package/resolve-advanced/vendor/conform-qc/test/geometry.test.js +112 -0
  149. package/resolve-advanced/vendor/conform-qc/test/knowledge.test.js +56 -0
  150. package/resolve-advanced/vendor/conform-qc/test/lifecycle.test.js +110 -0
  151. package/resolve-advanced/vendor/conform-qc/test/local-ffmpeg-sampler.test.js +66 -0
  152. package/resolve-advanced/vendor/conform-qc/test/locate.test.js +63 -0
  153. package/resolve-advanced/vendor/conform-qc/test/media-analysis.test.js +63 -0
  154. package/resolve-advanced/vendor/conform-qc/test/media-index-normalized.test.js +65 -0
  155. package/resolve-advanced/vendor/conform-qc/test/media-index-origin.test.js +53 -0
  156. package/resolve-advanced/vendor/conform-qc/test/metrics-fast.test.js +91 -0
  157. package/resolve-advanced/vendor/conform-qc/test/oracle-reverse.test.js +86 -0
  158. package/resolve-advanced/vendor/conform-qc/test/oracle.test.js +136 -0
  159. package/resolve-advanced/vendor/conform-qc/test/p0-acceptance.test.js +60 -0
  160. package/resolve-advanced/vendor/conform-qc/test/p1-acceptance.test.js +75 -0
  161. package/resolve-advanced/vendor/conform-qc/test/p45-patch-acceptance.test.js +102 -0
  162. package/resolve-advanced/vendor/conform-qc/test/packaging.test.js +133 -0
  163. package/resolve-advanced/vendor/conform-qc/test/parse-stubs.test.js +28 -0
  164. package/resolve-advanced/vendor/conform-qc/test/repair-strategies.test.js +128 -0
  165. package/resolve-advanced/vendor/conform-qc/test/repair.test.js +84 -0
  166. package/resolve-advanced/vendor/conform-qc/test/report.test.js +52 -0
  167. package/resolve-advanced/vendor/conform-qc/test/resolve-readback.test.js +71 -0
  168. package/resolve-advanced/vendor/conform-qc/test/roles.test.js +107 -0
  169. package/resolve-advanced/vendor/conform-qc/test/runbook.test.js +30 -0
  170. package/resolve-advanced/vendor/conform-qc/test/scale-residual.test.js +40 -0
  171. package/resolve-advanced/vendor/conform-qc/test/sidecar.test.js +51 -0
  172. package/resolve-advanced/vendor/conform-qc/test/smoke.test.js +87 -0
  173. package/resolve-advanced/vendor/conform-qc/test/surgical-relink.test.js +73 -0
  174. package/resolve-advanced/vendor/conform-qc/test/synthetic.test.js +98 -0
  175. package/resolve-advanced/vendor/conform-qc/test/verify.test.js +93 -0
  176. package/resolve-advanced/vendor/conform-qc/test/vision-validator.test.js +43 -0
  177. package/resolve-advanced/vendor/conform-qc/test/workflow-driver.test.js +46 -0
  178. package/resolve-advanced/vendor/conform-qc/toolset/index.js +53 -0
  179. package/resolve-advanced/vendor/drp-format/README.md +116 -0
  180. package/resolve-advanced/vendor/drp-format/__tests__/_resolve-verify.js +39 -0
  181. package/resolve-advanced/vendor/drp-format/__tests__/add-media-clip.test.js +30 -0
  182. package/resolve-advanced/vendor/drp-format/__tests__/assemble-timeline.test.js +68 -0
  183. package/resolve-advanced/vendor/drp-format/__tests__/author-project.test.js +57 -0
  184. package/resolve-advanced/vendor/drp-format/__tests__/composition-text.test.js +98 -0
  185. package/resolve-advanced/vendor/drp-format/__tests__/diff.test.js +272 -0
  186. package/resolve-advanced/vendor/drp-format/__tests__/effect-filters-compressed.test.js +143 -0
  187. package/resolve-advanced/vendor/drp-format/__tests__/fixtures/p0-3-session30-empty-effectfilters.drp +0 -0
  188. package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-50pct.hex +1 -0
  189. package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-dynamic.hex +1 -0
  190. package/resolve-advanced/vendor/drp-format/__tests__/inject-grades.test.js +238 -0
  191. package/resolve-advanced/vendor/drp-format/__tests__/keyed-dict.test.js +85 -0
  192. package/resolve-advanced/vendor/drp-format/__tests__/lut-refs.test.js +119 -0
  193. package/resolve-advanced/vendor/drp-format/__tests__/media-blobs.test.js +25 -0
  194. package/resolve-advanced/vendor/drp-format/__tests__/media-timemap.test.js +119 -0
  195. package/resolve-advanced/vendor/drp-format/__tests__/place-fusion-title.test.js +52 -0
  196. package/resolve-advanced/vendor/drp-format/__tests__/place-generator.test.js +40 -0
  197. package/resolve-advanced/vendor/drp-format/__tests__/place-transition.test.js +48 -0
  198. package/resolve-advanced/vendor/drp-format/__tests__/protobuf-wire.test.js +64 -0
  199. package/resolve-advanced/vendor/drp-format/__tests__/relink-media.test.js +106 -0
  200. package/resolve-advanced/vendor/drp-format/__tests__/splice-clips.test.js +256 -0
  201. package/resolve-advanced/vendor/drp-format/assemble-timeline.js +65 -0
  202. package/resolve-advanced/vendor/drp-format/author-project.js +118 -0
  203. package/resolve-advanced/vendor/drp-format/composition-text.js +213 -0
  204. package/resolve-advanced/vendor/drp-format/curves-encoder.js +763 -0
  205. package/resolve-advanced/vendor/drp-format/diff.js +310 -0
  206. package/resolve-advanced/vendor/drp-format/drp-packager.js +201 -0
  207. package/resolve-advanced/vendor/drp-format/drp-validator.js +809 -0
  208. package/resolve-advanced/vendor/drp-format/effect-encoder.js +640 -0
  209. package/resolve-advanced/vendor/drp-format/extract-lut-refs.js +119 -0
  210. package/resolve-advanced/vendor/drp-format/grade-encoder.example.js +133 -0
  211. package/resolve-advanced/vendor/drp-format/grade-encoder.js +401 -0
  212. package/resolve-advanced/vendor/drp-format/grade-encoder.test.js +171 -0
  213. package/resolve-advanced/vendor/drp-format/grade-encoder.verify.js +249 -0
  214. package/resolve-advanced/vendor/drp-format/grade-node-extractor.js +495 -0
  215. package/resolve-advanced/vendor/drp-format/grade-parameter-decoder.js +774 -0
  216. package/resolve-advanced/vendor/drp-format/index.js +174 -0
  217. package/resolve-advanced/vendor/drp-format/inject-grades.js +219 -0
  218. package/resolve-advanced/vendor/drp-format/keyed-dict.js +227 -0
  219. package/resolve-advanced/vendor/drp-format/marker-encoder.js +532 -0
  220. package/resolve-advanced/vendor/drp-format/media-blobs.js +53 -0
  221. package/resolve-advanced/vendor/drp-format/media-timemap.js +164 -0
  222. package/resolve-advanced/vendor/drp-format/mp-folder-builder.js +293 -0
  223. package/resolve-advanced/vendor/drp-format/node-tree-encoder.js +1246 -0
  224. package/resolve-advanced/vendor/drp-format/package.json +18 -0
  225. package/resolve-advanced/vendor/drp-format/place-fusion-title.js +131 -0
  226. package/resolve-advanced/vendor/drp-format/place-generator.js +77 -0
  227. package/resolve-advanced/vendor/drp-format/place-transition.js +91 -0
  228. package/resolve-advanced/vendor/drp-format/power-window-encoder.js +776 -0
  229. package/resolve-advanced/vendor/drp-format/protobuf-wire.js +111 -0
  230. package/resolve-advanced/vendor/drp-format/qualifier-encoder.js +706 -0
  231. package/resolve-advanced/vendor/drp-format/relink-media.js +218 -0
  232. package/resolve-advanced/vendor/drp-format/rich-title-encoder.js +447 -0
  233. package/resolve-advanced/vendor/drp-format/seq-container-builder.js +572 -0
  234. package/resolve-advanced/vendor/drp-format/seq-surgery.js +155 -0
  235. package/resolve-advanced/vendor/drp-format/splice-clips.js +445 -0
  236. package/resolve-advanced/vendor/drp-format/templates/empty-project.drp +0 -0
  237. package/resolve-advanced/vendor/drp-format/templates/fusion-title.xml +56 -0
  238. package/resolve-advanced/vendor/drp-format/templates/generator-solid-color.xml +21 -0
  239. package/resolve-advanced/vendor/drp-format/templates/media-clip-h264.drp +0 -0
  240. package/resolve-advanced/vendor/drp-format/templates/transition-cross-dissolve.xml +22 -0
  241. package/resolve-advanced/vendor/drp-format/tool-registry.descriptor.js +80 -0
  242. package/resolve-advanced/vendor/drp-format/utils/safe-archive.js +54 -0
  243. package/resolve-advanced/vendor/drp-format/xml-builder.js +759 -0
  244. package/resolve-advanced/vendor/drt-format/__tests__/_resolve-verify.js +21 -0
  245. package/resolve-advanced/vendor/drt-format/__tests__/build.test.js +113 -0
  246. package/resolve-advanced/vendor/drt-format/__tests__/multi-format.test.js +93 -0
  247. package/resolve-advanced/vendor/drt-format/__tests__/parse-real-resolve21.test.js +51 -0
  248. package/resolve-advanced/vendor/drt-format/__tests__/parse.test.js +134 -0
  249. package/resolve-advanced/vendor/drt-format/__tests__/resolve-versions.test.js +120 -0
  250. package/resolve-advanced/vendor/drt-format/__tests__/schema-fingerprint.test.js +62 -0
  251. package/resolve-advanced/vendor/drt-format/__tests__/smoke.test.js +27 -0
  252. package/resolve-advanced/vendor/drt-format/__tests__/validate.test.js +109 -0
  253. package/resolve-advanced/vendor/drt-format/capabilities.js +69 -0
  254. package/resolve-advanced/vendor/drt-format/capability-domains.js +56 -0
  255. package/resolve-advanced/vendor/drt-format/drt-builder.js +42 -0
  256. package/resolve-advanced/vendor/drt-format/drt-parser.js +164 -0
  257. package/resolve-advanced/vendor/drt-format/drt-validator.js +98 -0
  258. package/resolve-advanced/vendor/drt-format/index.js +45 -0
  259. package/resolve-advanced/vendor/drt-format/package.json +17 -0
  260. package/resolve-advanced/vendor/drt-format/resolve-versions.js +153 -0
  261. package/resolve-advanced/vendor/drt-format/schema-fingerprint.js +74 -0
  262. package/resolve-advanced/vendor/drt-format/templates/drt-project-shell.xml +124 -0
  263. package/resolve-advanced/vendor/drx-codec/__tests__/curves-roundtrip.test.js +148 -0
  264. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-face-refinement.drx +58 -0
  265. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-filmgrain.drx +58 -0
  266. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-glow.drx +58 -0
  267. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-lens-flare.drx +58 -0
  268. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-25.drx +58 -0
  269. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-75.drx +58 -0
  270. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-no-lut.drx +58 -0
  271. package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-with-lut.drx +58 -0
  272. package/resolve-advanced/vendor/drx-codec/__tests__/hsl-curves-roundtrip.test.js +117 -0
  273. package/resolve-advanced/vendor/drx-codec/__tests__/lut-refs-roundtrip.test.js +112 -0
  274. package/resolve-advanced/vendor/drx-codec/__tests__/matte-roundtrip.test.js +167 -0
  275. package/resolve-advanced/vendor/drx-codec/__tests__/ofx-roundtrip.test.js +215 -0
  276. package/resolve-advanced/vendor/drx-codec/__tests__/ofx-slugs-discovery.test.js +149 -0
  277. package/resolve-advanced/vendor/drx-codec/__tests__/power-window-roundtrip.test.js +230 -0
  278. package/resolve-advanced/vendor/drx-codec/__tests__/qualifier-roundtrip.test.js +226 -0
  279. package/resolve-advanced/vendor/drx-codec/cdl-exporter.js +470 -0
  280. package/resolve-advanced/vendor/drx-codec/color-nlp-parser.js +833 -0
  281. package/resolve-advanced/vendor/drx-codec/data/color-nlp-action-mappings.json +2232 -0
  282. package/resolve-advanced/vendor/drx-codec/drx-generator.js +4123 -0
  283. package/resolve-advanced/vendor/drx-codec/drx-merger.js +320 -0
  284. package/resolve-advanced/vendor/drx-codec/drx-parser.js +1808 -0
  285. package/resolve-advanced/vendor/drx-codec/extract-custom-curves.js +215 -0
  286. package/resolve-advanced/vendor/drx-codec/extract-hsl-curves.js +180 -0
  287. package/resolve-advanced/vendor/drx-codec/extract-lut-refs.js +158 -0
  288. package/resolve-advanced/vendor/drx-codec/extract-matte-finesse.js +83 -0
  289. package/resolve-advanced/vendor/drx-codec/extract-ofx-params.js +226 -0
  290. package/resolve-advanced/vendor/drx-codec/extract-power-window.js +184 -0
  291. package/resolve-advanced/vendor/drx-codec/extract-qualifier.js +99 -0
  292. package/resolve-advanced/vendor/drx-codec/index.js +109 -0
  293. package/resolve-advanced/vendor/drx-codec/node-layout.js +249 -0
  294. package/resolve-advanced/vendor/drx-codec/resolved-drx-generator.js +393 -0
  295. package/resolve-advanced/vendor/drx-codec/tool-resolver.js +974 -0
  296. package/resolve-advanced/vendor/drx-codec/training-examples.js +548 -0
  297. package/resolve-advanced/vendor/drx-codec/vocabulary-intents.js +539 -0
  298. package/resolve-advanced/vendor/drx-parameters/CALIBRATION-STATUS.md +319 -0
  299. package/resolve-advanced/vendor/drx-parameters/DRX-VALUE-SCALING.md +251 -0
  300. package/resolve-advanced/vendor/drx-parameters/calibrated-ranges.json +17737 -0
  301. package/resolve-advanced/vendor/drx-parameters/corrector-types.js +120 -0
  302. package/resolve-advanced/vendor/drx-parameters/index.js +193 -0
  303. package/resolve-advanced/vendor/drx-parameters/parameter-codec.js +451 -0
  304. package/resolve-advanced/vendor/drx-parameters/parameter-ids.js +1292 -0
  305. package/resolve-advanced/vendor/drx-parameters/parameter-ranges.js +570 -0
  306. package/resolve-advanced/vendor/drx-parameters/parameter-validator.js +392 -0
  307. package/resolve-advanced/vendor/drx-parameters/resolvefx-registry.json +14973 -0
  308. package/resolve-advanced/vendor/drx-parameters/tool-registry.descriptor.js +38 -0
  309. package/resolve-advanced/vendor/drx-parameters/tools/drx-analyzer.js +371 -0
  310. package/resolve-advanced/vendor/fairlight/index.js +833 -0
  311. package/resolve-advanced/vendor/fusion-codec/composition-generator.js +401 -0
  312. package/resolve-advanced/vendor/fusion-codec/templates/blur-region.js +103 -0
  313. package/resolve-advanced/vendor/fusion-codec/templates/color-correct.js +87 -0
  314. package/resolve-advanced/vendor/fusion-codec/templates/film-grain.js +106 -0
  315. package/resolve-advanced/vendor/fusion-codec/templates/lower-third.js +241 -0
  316. package/resolve-advanced/vendor/fusion-codec/templates/picture-in-picture.js +188 -0
  317. package/resolve-advanced/vendor/fusion-codec/templates/text-overlay.js +161 -0
  318. package/resolve-advanced/vendor/fusion-codec/templates/title-card.js +184 -0
  319. package/resolve-advanced/vendor/fusion-codec/templates/vignette.js +107 -0
  320. package/resolve-advanced/vendor/fusion-codec/templates/watermark.js +101 -0
  321. package/scripts/agent-rules/README.md +68 -0
  322. package/src/analysis_dashboard.py +233 -1
  323. package/src/granular/common.py +1 -1
  324. package/src/server.py +479 -29
  325. package/src/utils/api_truth.py +117 -0
  326. package/src/utils/cut_ir.py +1 -1
  327. package/src/utils/failure_tracker.py +0 -2
  328. package/src/utils/timeline_xml.py +405 -0
@@ -0,0 +1,774 @@
1
+ /**
2
+ * DaVinci Resolve Grade Parameter Decoder
3
+ *
4
+ * Comprehensive decoder for extracting color grading parameters from DRP Body data.
5
+ * Maps protobuf field IDs to actual color grading controls including:
6
+ * - Primary color wheels (Lift, Gamma, Gain, Offset)
7
+ * - Primary adjustments (Saturation, Hue, Contrast, Pivot, Luminance Mix)
8
+ * - Log wheels (Shadow, Midtone, Highlight)
9
+ * - Custom curves (RGB, Hue vs Sat, Lum vs Sat, etc.)
10
+ * - Qualifiers (HSL, 3D, Luminance)
11
+ * - Power Windows (Circle, Linear, Polygon, Curve, Gradient)
12
+ *
13
+ * Based on reverse-engineering of DaVinci Resolve 18/19 DRP protobuf format.
14
+ *
15
+ * @module grade-parameter-decoder
16
+ */
17
+
18
+ const { parseGradeBody, parseProtobuf, initZstd } = require('./grade-node-extractor');
19
+
20
+ // ═══════════════════════════════════════════════════════════════════════════
21
+ // FIELD ID MAPPINGS - Based on Resolve Protobuf Analysis
22
+ // ═══════════════════════════════════════════════════════════════════════════
23
+
24
+ /**
25
+ * Corrector Type IDs (Field 9.Field 1.Field 1)
26
+ */
27
+ const CORRECTOR_TYPE = {
28
+ PRIMARY: 1, // Primary color wheels
29
+ CONTRAST: 2, // Contrast adjustment
30
+ SATURATION: 3, // Saturation adjustment
31
+ HUE: 4, // Hue rotation
32
+ LUM_MIX: 5, // Luminance mix
33
+ OFFSET: 6, // Offset wheels
34
+ LOG: 7, // Log wheels (Shadow/Mid/Highlight)
35
+ CURVES: 18, // Custom curves
36
+ QUALIFIER: 20, // HSL Qualifier
37
+ WINDOW: 25, // Power window
38
+ TRACKER: 26, // Tracking data
39
+ OFX: 30, // OFX plugin
40
+ LUT: 40, // LUT reference
41
+ };
42
+
43
+ /**
44
+ * Primary Color Wheel Fields (inside corrector type 1)
45
+ *
46
+ * Each wheel has 4 floats: R, G, B, Master
47
+ * Neutral values are 1.0 for master, 0.0 for RGB offsets
48
+ */
49
+ const PRIMARY_WHEELS = {
50
+ // Lift wheel - affects shadows
51
+ LIFT_R: { field: 1, subfield: 1, neutral: 0.0 },
52
+ LIFT_G: { field: 1, subfield: 2, neutral: 0.0 },
53
+ LIFT_B: { field: 1, subfield: 3, neutral: 0.0 },
54
+ LIFT_MASTER: { field: 1, subfield: 4, neutral: 1.0 },
55
+
56
+ // Gamma wheel - affects midtones
57
+ GAMMA_R: { field: 2, subfield: 1, neutral: 0.0 },
58
+ GAMMA_G: { field: 2, subfield: 2, neutral: 0.0 },
59
+ GAMMA_B: { field: 2, subfield: 3, neutral: 0.0 },
60
+ GAMMA_MASTER: { field: 2, subfield: 4, neutral: 1.0 },
61
+
62
+ // Gain wheel - affects highlights
63
+ GAIN_R: { field: 3, subfield: 1, neutral: 0.0 },
64
+ GAIN_G: { field: 3, subfield: 2, neutral: 0.0 },
65
+ GAIN_B: { field: 3, subfield: 3, neutral: 0.0 },
66
+ GAIN_MASTER: { field: 3, subfield: 4, neutral: 1.0 },
67
+
68
+ // Offset wheel - global offset
69
+ OFFSET_R: { field: 4, subfield: 1, neutral: 0.0 },
70
+ OFFSET_G: { field: 4, subfield: 2, neutral: 0.0 },
71
+ OFFSET_B: { field: 4, subfield: 3, neutral: 0.0 },
72
+ OFFSET_MASTER: { field: 4, subfield: 4, neutral: 0.0 },
73
+ };
74
+
75
+ /**
76
+ * Primary Adjustment Fields
77
+ */
78
+ const PRIMARY_ADJUSTMENTS = {
79
+ CONTRAST: { field: 5, neutral: 1.0, range: [0.0, 4.0] },
80
+ PIVOT: { field: 6, neutral: 0.435, range: [0.0, 1.0] },
81
+ SATURATION: { field: 7, neutral: 50.0, range: [0.0, 100.0] },
82
+ HUE: { field: 8, neutral: 50.0, range: [0.0, 100.0] },
83
+ LUM_MIX: { field: 9, neutral: 0.0, range: [0.0, 100.0] },
84
+ MIDTONE_DETAIL: { field: 10, neutral: 0.0, range: [-100.0, 100.0] },
85
+ COLOR_BOOST: { field: 11, neutral: 0.0, range: [0.0, 100.0] },
86
+ SHADOW_SAT: { field: 12, neutral: 50.0, range: [0.0, 100.0] },
87
+ HIGHLIGHT_SAT: { field: 13, neutral: 50.0, range: [0.0, 100.0] },
88
+ };
89
+
90
+ /**
91
+ * Log Wheel Fields (inside corrector type 7)
92
+ */
93
+ const LOG_WHEELS = {
94
+ // Shadow wheel
95
+ SHADOW_R: { field: 1, subfield: 1, neutral: 0.0 },
96
+ SHADOW_G: { field: 1, subfield: 2, neutral: 0.0 },
97
+ SHADOW_B: { field: 1, subfield: 3, neutral: 0.0 },
98
+ SHADOW_MASTER: { field: 1, subfield: 4, neutral: 0.0 },
99
+
100
+ // Midtone wheel
101
+ MIDTONE_R: { field: 2, subfield: 1, neutral: 0.0 },
102
+ MIDTONE_G: { field: 2, subfield: 2, neutral: 0.0 },
103
+ MIDTONE_B: { field: 2, subfield: 3, neutral: 0.0 },
104
+ MIDTONE_MASTER: { field: 2, subfield: 4, neutral: 0.0 },
105
+
106
+ // Highlight wheel
107
+ HIGHLIGHT_R: { field: 3, subfield: 1, neutral: 0.0 },
108
+ HIGHLIGHT_G: { field: 3, subfield: 2, neutral: 0.0 },
109
+ HIGHLIGHT_B: { field: 3, subfield: 3, neutral: 0.0 },
110
+ HIGHLIGHT_MASTER: { field: 3, subfield: 4, neutral: 0.0 },
111
+
112
+ // Log adjustments
113
+ LOW_RANGE: { field: 4, neutral: 0.0 },
114
+ HIGH_RANGE: { field: 5, neutral: 1.0 },
115
+ };
116
+
117
+ /**
118
+ * Curve Types (inside corrector type 18)
119
+ */
120
+ const CURVE_TYPES = {
121
+ CUSTOM: 1, // Luminance/overall curve
122
+ RED: 2, // Red channel curve
123
+ GREEN: 3, // Green channel curve
124
+ BLUE: 4, // Blue channel curve
125
+ HUE_VS_HUE: 5, // Hue vs Hue
126
+ HUE_VS_SAT: 6, // Hue vs Saturation
127
+ HUE_VS_LUM: 7, // Hue vs Luminance
128
+ LUM_VS_SAT: 8, // Luminance vs Saturation
129
+ SAT_VS_SAT: 9, // Saturation vs Saturation
130
+ SAT_VS_LUM: 10, // Saturation vs Luminance
131
+ };
132
+
133
+ /**
134
+ * HSL Qualifier Fields (inside corrector type 20)
135
+ */
136
+ const HSL_QUALIFIER = {
137
+ ENABLED: { field: 1, neutral: false },
138
+
139
+ // Hue range
140
+ HUE_CENTER: { field: 2, neutral: 0.0, range: [0.0, 360.0] },
141
+ HUE_WIDTH: { field: 3, neutral: 30.0, range: [0.0, 180.0] },
142
+ HUE_SOFT: { field: 4, neutral: 0.0, range: [0.0, 100.0] },
143
+
144
+ // Saturation range
145
+ SAT_LOW: { field: 5, neutral: 0.0, range: [0.0, 100.0] },
146
+ SAT_HIGH: { field: 6, neutral: 100.0, range: [0.0, 100.0] },
147
+ SAT_LOW_SOFT: { field: 7, neutral: 0.0, range: [0.0, 100.0] },
148
+ SAT_HIGH_SOFT: { field: 8, neutral: 0.0, range: [0.0, 100.0] },
149
+
150
+ // Luminance range
151
+ LUM_LOW: { field: 9, neutral: 0.0, range: [0.0, 100.0] },
152
+ LUM_HIGH: { field: 10, neutral: 100.0, range: [0.0, 100.0] },
153
+ LUM_LOW_SOFT: { field: 11, neutral: 0.0, range: [0.0, 100.0] },
154
+ LUM_HIGH_SOFT: { field: 12, neutral: 0.0, range: [0.0, 100.0] },
155
+
156
+ // Matte options
157
+ INVERT: { field: 13, neutral: false },
158
+ MATTE_FINESSE: { field: 14, neutral: 0.0, range: [0.0, 100.0] },
159
+ DENOISE: { field: 15, neutral: 0.0, range: [0.0, 100.0] },
160
+ SHRINK_GROW: { field: 16, neutral: 0.0, range: [-100.0, 100.0] },
161
+ };
162
+
163
+ /**
164
+ * Power Window Types (inside corrector type 25)
165
+ */
166
+ const WINDOW_TYPES = {
167
+ CIRCLE: 1,
168
+ LINEAR: 2,
169
+ POLYGON: 3,
170
+ CURVE: 4,
171
+ GRADIENT: 5,
172
+ };
173
+
174
+ /**
175
+ * Power Window Fields
176
+ */
177
+ const WINDOW_FIELDS = {
178
+ TYPE: { field: 1 },
179
+ ENABLED: { field: 2, neutral: true },
180
+
181
+ // Transform
182
+ PAN_X: { field: 3, neutral: 0.0 },
183
+ PAN_Y: { field: 4, neutral: 0.0 },
184
+ ZOOM_X: { field: 5, neutral: 1.0 },
185
+ ZOOM_Y: { field: 6, neutral: 1.0 },
186
+ ROTATION: { field: 7, neutral: 0.0 },
187
+ ANCHOR_X: { field: 8, neutral: 0.5 },
188
+ ANCHOR_Y: { field: 9, neutral: 0.5 },
189
+
190
+ // Circle/Linear specific
191
+ RADIUS_X: { field: 10, neutral: 0.25 },
192
+ RADIUS_Y: { field: 11, neutral: 0.25 },
193
+ SOFTNESS: { field: 12, neutral: 0.0 },
194
+ INSIDE_SOFTNESS: { field: 13, neutral: 0.0 },
195
+ OUTSIDE_SOFTNESS: { field: 14, neutral: 0.0 },
196
+
197
+ // Linear specific
198
+ ANGLE: { field: 15, neutral: 0.0 },
199
+ POSITION: { field: 16, neutral: 0.5 },
200
+
201
+ // Polygon/Curve specific
202
+ POINTS: { field: 20 }, // Nested array of points
203
+
204
+ // Common
205
+ INVERT: { field: 30, neutral: false },
206
+ };
207
+
208
+ // ═══════════════════════════════════════════════════════════════════════════
209
+ // DECODER FUNCTIONS
210
+ // ═══════════════════════════════════════════════════════════════════════════
211
+
212
+ /**
213
+ * Decode color wheels from corrector parameters
214
+ *
215
+ * @param {Array} fields - Parsed protobuf fields from corrector
216
+ * @param {Object} wheelDef - Wheel field definitions (PRIMARY_WHEELS or LOG_WHEELS)
217
+ * @returns {Object} Decoded wheel values
218
+ */
219
+ function decodeColorWheels(fields, wheelDef) {
220
+ const wheels = {};
221
+
222
+ // Group fields by wheel number
223
+ const wheelFields = {};
224
+ for (const field of fields) {
225
+ if (!wheelFields[field.fieldNum]) {
226
+ wheelFields[field.fieldNum] = [];
227
+ }
228
+ wheelFields[field.fieldNum].push(field);
229
+ }
230
+
231
+ // Extract each wheel's values
232
+ for (const [name, def] of Object.entries(wheelDef)) {
233
+ const wheelField = wheelFields[def.field];
234
+ if (wheelField && wheelField[0]?.nested) {
235
+ const subFields = wheelField[0].nested;
236
+ for (const sf of subFields) {
237
+ if (sf.fieldNum === def.subfield && (sf.type === 'float' || sf.type === 'double')) {
238
+ wheels[name] = sf.value;
239
+ }
240
+ }
241
+ }
242
+
243
+ // Default to neutral if not found
244
+ if (wheels[name] === undefined) {
245
+ wheels[name] = def.neutral;
246
+ }
247
+ }
248
+
249
+ return wheels;
250
+ }
251
+
252
+ /**
253
+ * Decode primary adjustments from corrector parameters
254
+ *
255
+ * @param {Array} fields - Parsed protobuf fields
256
+ * @returns {Object} Decoded adjustment values
257
+ */
258
+ function decodePrimaryAdjustments(fields) {
259
+ const adjustments = {};
260
+
261
+ for (const [name, def] of Object.entries(PRIMARY_ADJUSTMENTS)) {
262
+ const field = fields.find((f) => f.fieldNum === def.field);
263
+ if (field && (field.type === 'float' || field.type === 'double')) {
264
+ adjustments[name] = field.value;
265
+ } else {
266
+ adjustments[name] = def.neutral;
267
+ }
268
+ }
269
+
270
+ return adjustments;
271
+ }
272
+
273
+ /**
274
+ * Decode HSL qualifier settings
275
+ *
276
+ * @param {Array} fields - Parsed protobuf fields from qualifier corrector
277
+ * @returns {Object} Decoded qualifier settings
278
+ */
279
+ function decodeHSLQualifier(fields) {
280
+ const qualifier = {};
281
+
282
+ for (const [name, def] of Object.entries(HSL_QUALIFIER)) {
283
+ const field = fields.find((f) => f.fieldNum === def.field);
284
+
285
+ if (field) {
286
+ if (def.neutral === false || def.neutral === true) {
287
+ qualifier[name] = field.value === 1;
288
+ } else if (field.type === 'float' || field.type === 'double') {
289
+ qualifier[name] = field.value;
290
+ } else if (field.type === 'varint') {
291
+ qualifier[name] = field.value;
292
+ }
293
+ } else {
294
+ qualifier[name] = def.neutral;
295
+ }
296
+ }
297
+
298
+ return qualifier;
299
+ }
300
+
301
+ /**
302
+ * Decode power window settings
303
+ *
304
+ * @param {Array} fields - Parsed protobuf fields from window corrector
305
+ * @returns {Object} Decoded window settings
306
+ */
307
+ function decodePowerWindow(fields) {
308
+ const window = {
309
+ type: 'unknown',
310
+ enabled: true,
311
+ transform: {},
312
+ shape: {},
313
+ invert: false,
314
+ };
315
+
316
+ for (const field of fields) {
317
+ switch (field.fieldNum) {
318
+ case WINDOW_FIELDS.TYPE.field:
319
+ window.type = Object.keys(WINDOW_TYPES).find(
320
+ (k) => WINDOW_TYPES[k] === field.value
321
+ ) || 'unknown';
322
+ break;
323
+ case WINDOW_FIELDS.ENABLED.field:
324
+ window.enabled = field.value === 1;
325
+ break;
326
+ case WINDOW_FIELDS.PAN_X.field:
327
+ window.transform.panX = field.value;
328
+ break;
329
+ case WINDOW_FIELDS.PAN_Y.field:
330
+ window.transform.panY = field.value;
331
+ break;
332
+ case WINDOW_FIELDS.ZOOM_X.field:
333
+ window.transform.zoomX = field.value;
334
+ break;
335
+ case WINDOW_FIELDS.ZOOM_Y.field:
336
+ window.transform.zoomY = field.value;
337
+ break;
338
+ case WINDOW_FIELDS.ROTATION.field:
339
+ window.transform.rotation = field.value;
340
+ break;
341
+ case WINDOW_FIELDS.RADIUS_X.field:
342
+ window.shape.radiusX = field.value;
343
+ break;
344
+ case WINDOW_FIELDS.RADIUS_Y.field:
345
+ window.shape.radiusY = field.value;
346
+ break;
347
+ case WINDOW_FIELDS.SOFTNESS.field:
348
+ window.shape.softness = field.value;
349
+ break;
350
+ case WINDOW_FIELDS.INSIDE_SOFTNESS.field:
351
+ window.shape.insideSoftness = field.value;
352
+ break;
353
+ case WINDOW_FIELDS.OUTSIDE_SOFTNESS.field:
354
+ window.shape.outsideSoftness = field.value;
355
+ break;
356
+ case WINDOW_FIELDS.ANGLE.field:
357
+ window.shape.angle = field.value;
358
+ break;
359
+ case WINDOW_FIELDS.POSITION.field:
360
+ window.shape.position = field.value;
361
+ break;
362
+ case WINDOW_FIELDS.POINTS.field:
363
+ if (field.nested) {
364
+ window.shape.points = decodeWindowPoints(field.nested);
365
+ }
366
+ break;
367
+ case WINDOW_FIELDS.INVERT.field:
368
+ window.invert = field.value === 1;
369
+ break;
370
+ }
371
+ }
372
+
373
+ return window;
374
+ }
375
+
376
+ /**
377
+ * Decode window polygon/curve points
378
+ *
379
+ * @param {Array} fields - Nested point data
380
+ * @returns {Array} Array of {x, y} points
381
+ */
382
+ function decodeWindowPoints(fields) {
383
+ const points = [];
384
+
385
+ for (const field of fields) {
386
+ if (field.nested) {
387
+ const point = { x: 0, y: 0 };
388
+ for (const pf of field.nested) {
389
+ if (pf.fieldNum === 1) point.x = pf.value;
390
+ if (pf.fieldNum === 2) point.y = pf.value;
391
+ }
392
+ points.push(point);
393
+ }
394
+ }
395
+
396
+ return points;
397
+ }
398
+
399
+ /**
400
+ * Decode curve control points
401
+ *
402
+ * @param {Array} fields - Curve data fields
403
+ * @returns {Object} Curve definition with type and points
404
+ */
405
+ function decodeCurve(fields) {
406
+ const curve = {
407
+ type: 'CUSTOM',
408
+ enabled: true,
409
+ points: [],
410
+ interpolation: 'bezier',
411
+ };
412
+
413
+ for (const field of fields) {
414
+ switch (field.fieldNum) {
415
+ case 1:
416
+ curve.type = Object.keys(CURVE_TYPES).find(
417
+ (k) => CURVE_TYPES[k] === field.value
418
+ ) || 'CUSTOM';
419
+ break;
420
+ case 2:
421
+ curve.enabled = field.value === 1;
422
+ break;
423
+ case 3:
424
+ if (field.nested) {
425
+ curve.points = decodeCurvePoints(field.nested);
426
+ }
427
+ break;
428
+ case 4:
429
+ curve.interpolation = field.value === 1 ? 'linear' : 'bezier';
430
+ break;
431
+ }
432
+ }
433
+
434
+ return curve;
435
+ }
436
+
437
+ /**
438
+ * Decode curve control points with handles
439
+ *
440
+ * @param {Array} fields - Point data
441
+ * @returns {Array} Array of curve points with handles
442
+ */
443
+ function decodeCurvePoints(fields) {
444
+ const points = [];
445
+
446
+ for (const field of fields) {
447
+ if (field.nested) {
448
+ const point = {
449
+ x: 0,
450
+ y: 0,
451
+ handleInX: 0,
452
+ handleInY: 0,
453
+ handleOutX: 0,
454
+ handleOutY: 0,
455
+ };
456
+
457
+ for (const pf of field.nested) {
458
+ switch (pf.fieldNum) {
459
+ case 1: point.x = pf.value; break;
460
+ case 2: point.y = pf.value; break;
461
+ case 3: point.handleInX = pf.value; break;
462
+ case 4: point.handleInY = pf.value; break;
463
+ case 5: point.handleOutX = pf.value; break;
464
+ case 6: point.handleOutY = pf.value; break;
465
+ }
466
+ }
467
+
468
+ points.push(point);
469
+ }
470
+ }
471
+
472
+ return points;
473
+ }
474
+
475
+ /**
476
+ * Decode a complete color corrector node
477
+ *
478
+ * @param {Object} corrector - Corrector data from grade-node-extractor
479
+ * @returns {Object} Fully decoded corrector with all parameters
480
+ */
481
+ function decodeCorrector(corrector) {
482
+ const decoded = {
483
+ type: corrector.type,
484
+ typeId: corrector.typeId,
485
+ enabled: corrector.enabled,
486
+ values: {},
487
+ };
488
+
489
+ switch (corrector.typeId) {
490
+ case CORRECTOR_TYPE.PRIMARY:
491
+ decoded.values.wheels = decodeColorWheels(corrector.values || [], PRIMARY_WHEELS);
492
+ break;
493
+
494
+ case CORRECTOR_TYPE.LOG:
495
+ decoded.values.wheels = decodeColorWheels(corrector.values || [], LOG_WHEELS);
496
+ break;
497
+
498
+ case CORRECTOR_TYPE.CONTRAST:
499
+ case CORRECTOR_TYPE.SATURATION:
500
+ case CORRECTOR_TYPE.HUE:
501
+ case CORRECTOR_TYPE.LUM_MIX:
502
+ case CORRECTOR_TYPE.OFFSET:
503
+ decoded.values = decodePrimaryAdjustments(corrector.values || []);
504
+ break;
505
+
506
+ case CORRECTOR_TYPE.CURVES:
507
+ decoded.values.curves = [];
508
+ for (const field of corrector.values || []) {
509
+ if (field.nested) {
510
+ decoded.values.curves.push(decodeCurve(field.nested));
511
+ }
512
+ }
513
+ break;
514
+
515
+ case CORRECTOR_TYPE.QUALIFIER:
516
+ decoded.values.qualifier = decodeHSLQualifier(corrector.values || []);
517
+ break;
518
+
519
+ case CORRECTOR_TYPE.WINDOW:
520
+ decoded.values.window = decodePowerWindow(corrector.values || []);
521
+ break;
522
+
523
+ case CORRECTOR_TYPE.LUT:
524
+ decoded.values.lut = decodeLUTReference(corrector.values || []);
525
+ break;
526
+
527
+ default:
528
+ // Keep raw values for unknown types
529
+ decoded.values.raw = corrector.values;
530
+ }
531
+
532
+ return decoded;
533
+ }
534
+
535
+ /**
536
+ * Decode LUT reference
537
+ *
538
+ * @param {Array} fields - LUT corrector fields
539
+ * @returns {Object} LUT reference with path and strength
540
+ */
541
+ function decodeLUTReference(fields) {
542
+ const lut = {
543
+ path: null,
544
+ strength: 1.0,
545
+ inputColorSpace: null,
546
+ outputColorSpace: null,
547
+ };
548
+
549
+ for (const field of fields) {
550
+ switch (field.fieldNum) {
551
+ case 1:
552
+ if (field.raw) {
553
+ lut.path = field.raw.toString('utf-8').replace(/\x00/g, '');
554
+ }
555
+ break;
556
+ case 2:
557
+ lut.strength = field.value;
558
+ break;
559
+ case 3:
560
+ if (field.raw) {
561
+ lut.inputColorSpace = field.raw.toString('utf-8').replace(/\x00/g, '');
562
+ }
563
+ break;
564
+ case 4:
565
+ if (field.raw) {
566
+ lut.outputColorSpace = field.raw.toString('utf-8').replace(/\x00/g, '');
567
+ }
568
+ break;
569
+ }
570
+ }
571
+
572
+ return lut;
573
+ }
574
+
575
+ /**
576
+ * Decode all parameters from a grade body
577
+ *
578
+ * @param {string} hexData - Hex-encoded Body data from DRP
579
+ * @returns {Promise<Object>} Complete decoded grade data
580
+ */
581
+ async function decodeGradeParameters(hexData) {
582
+ const gradeData = await parseGradeBody(hexData);
583
+
584
+ const decoded = {
585
+ nodes: [],
586
+ connections: gradeData.connections || [],
587
+ metadata: {
588
+ nodeCount: gradeData.nodes?.length || 0,
589
+ hasCorrections: false,
590
+ },
591
+ };
592
+
593
+ for (const node of gradeData.nodes || []) {
594
+ const decodedNode = {
595
+ id: node.id,
596
+ index: node.index,
597
+ label: node.label,
598
+ posX: node.posX,
599
+ posY: node.posY,
600
+ enabled: node.enabled,
601
+ timestamp: node.timestamp,
602
+ correctors: [],
603
+ };
604
+
605
+ for (const param of node.parameters || []) {
606
+ const decodedCorrector = decodeCorrector(param);
607
+ decodedNode.correctors.push(decodedCorrector);
608
+
609
+ // Check if any correction is non-neutral
610
+ if (decodedCorrector.enabled && hasNonNeutralValues(decodedCorrector)) {
611
+ decoded.metadata.hasCorrections = true;
612
+ }
613
+ }
614
+
615
+ decoded.nodes.push(decodedNode);
616
+ }
617
+
618
+ return decoded;
619
+ }
620
+
621
+ /**
622
+ * Check if a corrector has non-neutral values
623
+ *
624
+ * @param {Object} corrector - Decoded corrector
625
+ * @returns {boolean} True if corrector has adjustments
626
+ */
627
+ function hasNonNeutralValues(corrector) {
628
+ const values = corrector.values;
629
+
630
+ // Check wheels
631
+ if (values.wheels) {
632
+ for (const [key, value] of Object.entries(values.wheels)) {
633
+ const def = PRIMARY_WHEELS[key] || LOG_WHEELS[key];
634
+ if (def && Math.abs(value - def.neutral) > 0.001) {
635
+ return true;
636
+ }
637
+ }
638
+ }
639
+
640
+ // Check adjustments
641
+ for (const [key, def] of Object.entries(PRIMARY_ADJUSTMENTS)) {
642
+ if (values[key] !== undefined && Math.abs(values[key] - def.neutral) > 0.001) {
643
+ return true;
644
+ }
645
+ }
646
+
647
+ // Check curves
648
+ if (values.curves?.length > 0) {
649
+ for (const curve of values.curves) {
650
+ if (curve.points?.length > 2) return true;
651
+ }
652
+ }
653
+
654
+ // Check qualifier
655
+ if (values.qualifier?.ENABLED) {
656
+ return true;
657
+ }
658
+
659
+ // Check window
660
+ if (values.window?.enabled) {
661
+ return true;
662
+ }
663
+
664
+ // Check LUT
665
+ if (values.lut?.path) {
666
+ return true;
667
+ }
668
+
669
+ return false;
670
+ }
671
+
672
+ /**
673
+ * Format decoded parameters for display
674
+ *
675
+ * @param {Object} decoded - Decoded grade data
676
+ * @returns {string} Human-readable format
677
+ */
678
+ function formatDecodedGrade(decoded) {
679
+ const lines = [];
680
+
681
+ lines.push(`Grade Data (${decoded.nodes.length} nodes)`);
682
+ lines.push(`Has Corrections: ${decoded.metadata.hasCorrections}`);
683
+ lines.push('');
684
+
685
+ for (const node of decoded.nodes) {
686
+ lines.push(`═══ Node ${node.id} (${node.label || 'Unlabeled'}) ═══`);
687
+ lines.push(` Enabled: ${node.enabled}`);
688
+ lines.push(` Position: (${node.posX}, ${node.posY})`);
689
+
690
+ for (const corrector of node.correctors) {
691
+ lines.push(` ─── ${corrector.type} (${corrector.enabled ? 'ON' : 'OFF'}) ───`);
692
+
693
+ if (corrector.values.wheels) {
694
+ lines.push(' Wheels:');
695
+ for (const [name, value] of Object.entries(corrector.values.wheels)) {
696
+ if (typeof value === 'number' && Math.abs(value) > 0.001) {
697
+ lines.push(` ${name}: ${value.toFixed(4)}`);
698
+ }
699
+ }
700
+ }
701
+
702
+ if (corrector.values.qualifier) {
703
+ lines.push(' HSL Qualifier:');
704
+ const q = corrector.values.qualifier;
705
+ lines.push(` Hue: ${q.HUE_CENTER}° ± ${q.HUE_WIDTH}°`);
706
+ lines.push(` Sat: ${q.SAT_LOW}-${q.SAT_HIGH}`);
707
+ lines.push(` Lum: ${q.LUM_LOW}-${q.LUM_HIGH}`);
708
+ }
709
+
710
+ if (corrector.values.window) {
711
+ const w = corrector.values.window;
712
+ lines.push(` Window: ${w.type}`);
713
+ lines.push(` Pan: (${w.transform.panX?.toFixed(3)}, ${w.transform.panY?.toFixed(3)})`);
714
+ lines.push(` Zoom: (${w.transform.zoomX?.toFixed(3)}, ${w.transform.zoomY?.toFixed(3)})`);
715
+ lines.push(` Rotation: ${w.transform.rotation?.toFixed(1)}°`);
716
+ }
717
+
718
+ if (corrector.values.curves?.length > 0) {
719
+ lines.push(` Curves: ${corrector.values.curves.length}`);
720
+ for (const curve of corrector.values.curves) {
721
+ lines.push(` ${curve.type}: ${curve.points.length} points`);
722
+ }
723
+ }
724
+
725
+ if (corrector.values.lut?.path) {
726
+ lines.push(` LUT: ${corrector.values.lut.path}`);
727
+ lines.push(` Strength: ${corrector.values.lut.strength}`);
728
+ }
729
+ }
730
+
731
+ lines.push('');
732
+ }
733
+
734
+ if (decoded.connections.length > 0) {
735
+ lines.push('Connections:');
736
+ for (const conn of decoded.connections) {
737
+ lines.push(` Node ${conn.sourceNode} → Node ${conn.targetNode}`);
738
+ }
739
+ }
740
+
741
+ return lines.join('\n');
742
+ }
743
+
744
+ // ═══════════════════════════════════════════════════════════════════════════
745
+ // EXPORTS
746
+ // ═══════════════════════════════════════════════════════════════════════════
747
+
748
+ module.exports = {
749
+ // Main decoder
750
+ decodeGradeParameters,
751
+
752
+ // Sub-decoders
753
+ decodeColorWheels,
754
+ decodePrimaryAdjustments,
755
+ decodeHSLQualifier,
756
+ decodePowerWindow,
757
+ decodeCurve,
758
+ decodeLUTReference,
759
+ decodeCorrector,
760
+
761
+ // Utilities
762
+ hasNonNeutralValues,
763
+ formatDecodedGrade,
764
+
765
+ // Constants
766
+ CORRECTOR_TYPE,
767
+ PRIMARY_WHEELS,
768
+ PRIMARY_ADJUSTMENTS,
769
+ LOG_WHEELS,
770
+ CURVE_TYPES,
771
+ HSL_QUALIFIER,
772
+ WINDOW_TYPES,
773
+ WINDOW_FIELDS,
774
+ };