@revola-ai/video-craft 0.2.1

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 (340) hide show
  1. package/README.md +56 -0
  2. package/dist/anchors.js +69 -0
  3. package/dist/corpus.js +91 -0
  4. package/dist/projectDoc.js +83 -0
  5. package/dist/projectDocSync.js +39 -0
  6. package/dist/projectMeta.js +37 -0
  7. package/dist/provenance.js +41 -0
  8. package/dist/radar-check-ids.json +34 -0
  9. package/dist/registry.js +307 -0
  10. package/dist/rules/animatedBarChartTightBox.js +15 -0
  11. package/dist/rules/animatedBarChartWhenNotToUse.js +15 -0
  12. package/dist/rules/animatedBarChartWhenToUse.js +15 -0
  13. package/dist/rules/animatedLineChartWhenNotToUse.js +15 -0
  14. package/dist/rules/animatedLineChartWhenToUse.js +15 -0
  15. package/dist/rules/approvedSfxPaletteOnly.js +15 -0
  16. package/dist/rules/atmosphereGradientsFadeAtBothEnds.js +15 -0
  17. package/dist/rules/audioIsTheClock.js +16 -0
  18. package/dist/rules/beatsDeriveFromTheirOwnSequence.js +15 -0
  19. package/dist/rules/bestSceneSetsTheBar.js +15 -0
  20. package/dist/rules/bumpBeforeRefreeze.js +15 -0
  21. package/dist/rules/cameraIsTheNarrator.js +15 -0
  22. package/dist/rules/checkPinBeforeShip.js +16 -0
  23. package/dist/rules/coldViewerClarity.js +15 -0
  24. package/dist/rules/commitOrCutEffects.js +29 -0
  25. package/dist/rules/convertFramesAcrossClockBoundary.js +15 -0
  26. package/dist/rules/crossCutElementsLiveInTheHudLayer.js +15 -0
  27. package/dist/rules/cursorClicksRealControls.js +15 -0
  28. package/dist/rules/cutOnRealAudioPauses.js +15 -0
  29. package/dist/rules/darkButNeverDim.js +15 -0
  30. package/dist/rules/dataRadarTagsDeclared.js +193 -0
  31. package/dist/rules/declareAVerticalZoneMap.js +15 -0
  32. package/dist/rules/deleteRejectedRigsCompletely.js +15 -0
  33. package/dist/rules/deriveSeamsDontMeasure.js +17 -0
  34. package/dist/rules/deterministicSceneSource.js +65 -0
  35. package/dist/rules/diegeticSoundForOnscreenActions.js +15 -0
  36. package/dist/rules/distinctTransitionPerBeat.js +15 -0
  37. package/dist/rules/downloadOrDrawRichAssets.js +15 -0
  38. package/dist/rules/elementOnscreenForItsVoSentence.js +17 -0
  39. package/dist/rules/emitBuildNotes.js +15 -0
  40. package/dist/rules/energyFromTimingNotPartCount.js +15 -0
  41. package/dist/rules/evidenceBeforeClaimingFixed.js +15 -0
  42. package/dist/rules/exactPeerLockstep.js +15 -0
  43. package/dist/rules/firstPassIsADraft.js +15 -0
  44. package/dist/rules/fixCrowdingByRebandingNotNudging.js +15 -0
  45. package/dist/rules/fixesPreserveApprovedElements.js +15 -0
  46. package/dist/rules/floatingNotBoxed.js +15 -0
  47. package/dist/rules/focusBeatsRecedeTheContext.js +15 -0
  48. package/dist/rules/fontVarsBrandRemocn.js +15 -0
  49. package/dist/rules/geometricSeamsNotCrossfades.js +23 -0
  50. package/dist/rules/geometrySidecarExportsTyped.js +36 -0
  51. package/dist/rules/glowIsAFocalAccent.js +22 -0
  52. package/dist/rules/heroFillsTheFrame.js +17 -0
  53. package/dist/rules/htmlMasksForAnimatedCounters.js +15 -0
  54. package/dist/rules/impactStackOnPayoffs.js +15 -0
  55. package/dist/rules/interactiveTargetsAreDeclaredData.js +15 -0
  56. package/dist/rules/interpolateLiteralKeysMonotonic.js +79 -0
  57. package/dist/rules/latenessIsStructuralOverlapTheBeats.js +15 -0
  58. package/dist/rules/lessTextMoreVisualizations.js +15 -0
  59. package/dist/rules/liveLinkDuplicateReactAlias.js +15 -0
  60. package/dist/rules/make2dElements3d.js +15 -0
  61. package/dist/rules/masterMixLoudnessTarget.js +17 -0
  62. package/dist/rules/measureAlignmentDontEyeball.js +15 -0
  63. package/dist/rules/motionCarriesWeightAndMeaning.js +15 -0
  64. package/dist/rules/motionDensityFloor.js +15 -0
  65. package/dist/rules/neverEditTierBVendored.js +15 -0
  66. package/dist/rules/neverRestateDerivedFrameNumbersInComments.js +15 -0
  67. package/dist/rules/noAiGradientLook.js +15 -0
  68. package/dist/rules/noColoredFlashToHideACut.js +22 -0
  69. package/dist/rules/noDoubleFrameShift.js +126 -0
  70. package/dist/rules/noDuplicateMotionPrimitives.js +15 -0
  71. package/dist/rules/noLinearMotion.js +22 -0
  72. package/dist/rules/noNestedSvgFilters.js +93 -0
  73. package/dist/rules/noRepeatedAssetAcrossShots.js +15 -0
  74. package/dist/rules/noShorthandWithUndefinedLonghand.js +93 -0
  75. package/dist/rules/noStackedFadesAtACut.js +24 -0
  76. package/dist/rules/noStaticHolds.js +17 -0
  77. package/dist/rules/occlusionVisibleElements.js +17 -0
  78. package/dist/rules/oneContinuousVoTrack.js +15 -0
  79. package/dist/rules/onePunchPerMomentClass.js +15 -0
  80. package/dist/rules/oneRenderPerRound.js +15 -0
  81. package/dist/rules/openStaticAfterAHardCut.js +22 -0
  82. package/dist/rules/openingsAndClosingsCarryMore.js +15 -0
  83. package/dist/rules/persistentDeviceFrames.js +15 -0
  84. package/dist/rules/pixelDiffAnEmptyBandFirst.js +15 -0
  85. package/dist/rules/planIsPublishedNotGating.js +15 -0
  86. package/dist/rules/poweredByRevolaWatermark.js +15 -0
  87. package/dist/rules/predrawContentPresentAtTheCut.js +17 -0
  88. package/dist/rules/premiumSurfacesNotFlatBorders.js +15 -0
  89. package/dist/rules/radarDispositionsAreHumanOnly.js +17 -0
  90. package/dist/rules/realAssetsNotPlaceholders.js +15 -0
  91. package/dist/rules/rebuildUiFromReconNotScreenshots.js +15 -0
  92. package/dist/rules/reconStrandsRunInParallel.js +15 -0
  93. package/dist/rules/registryBeforeHandrolling.js +15 -0
  94. package/dist/rules/remapRateEndpointFormula.js +15 -0
  95. package/dist/rules/remocnContentTailwindChrome.js +15 -0
  96. package/dist/rules/retimeOnlyViaPlaybackOrDesignTokens.js +15 -0
  97. package/dist/rules/reviewTheRenderByFrameSweep.js +15 -0
  98. package/dist/rules/rollingNumberBoundedSequence.js +17 -0
  99. package/dist/rules/rollingNumberSequenceLayoutNone.js +16 -0
  100. package/dist/rules/rollingNumberTightBoxAlignment.js +15 -0
  101. package/dist/rules/rollingNumberWhenNotToUse.js +17 -0
  102. package/dist/rules/rollingNumberWhenToUse.js +17 -0
  103. package/dist/rules/sameFamilySameProject.js +15 -0
  104. package/dist/rules/sampleBrandFromProduct.js +15 -0
  105. package/dist/rules/sampleVelocityFromPreviousFramePosition.js +15 -0
  106. package/dist/rules/sceneRootTagDeclared.js +41 -0
  107. package/dist/rules/scrubDemoDataToGenericRoles.js +15 -0
  108. package/dist/rules/selfReviewThePlanForGaps.js +15 -0
  109. package/dist/rules/sourceArchivedBeforeBrief.js +17 -0
  110. package/dist/rules/statisticsSelfExplanatory.js +15 -0
  111. package/dist/rules/stopsAsRelativeSpacing.js +15 -0
  112. package/dist/rules/theWholeCanvasWorks.js +15 -0
  113. package/dist/rules/themePerSection.js +22 -0
  114. package/dist/rules/thesisDeclaredInBrief.js +17 -0
  115. package/dist/rules/tierARequiresPropUnreachableEdit.js +15 -0
  116. package/dist/rules/tinyBodyCopyAsRuledLines.js +15 -0
  117. package/dist/rules/titlesPinnedOutsideCameraPush.js +15 -0
  118. package/dist/rules/tokensNotRawHexes.js +60 -0
  119. package/dist/rules/typeTokenDefaultedParamsAsString.js +15 -0
  120. package/dist/rules/varyKitChoreographyAcrossSections.js +15 -0
  121. package/dist/rules/varyTheVisualizationGrammar.js +15 -0
  122. package/dist/rules/verifyCheapRenderDear.js +15 -0
  123. package/dist/rules/voAddressesTheViewer.js +15 -0
  124. package/dist/rules/voIsAPerformance.js +15 -0
  125. package/dist/rules/voScriptLocksSpokenWords.js +15 -0
  126. package/dist/rules/wrappersPreserveChildGeometry.js +15 -0
  127. package/dist/sourceCheck.js +47 -0
  128. package/dist/sourceCitations.js +68 -0
  129. package/dist/stageProjection.js +69 -0
  130. package/dist/stages.js +163 -0
  131. package/dist/testSupport.js +6 -0
  132. package/dist/types.js +0 -0
  133. package/dist/variants.js +8 -0
  134. package/dist/waiverProjection.js +20 -0
  135. package/package.json +32 -0
  136. package/src/anchors.test.ts +119 -0
  137. package/src/anchors.ts +110 -0
  138. package/src/corpus.test.ts +96 -0
  139. package/src/corpus.ts +149 -0
  140. package/src/corpusProject.test.ts +103 -0
  141. package/src/creativeEdge.test.ts +58 -0
  142. package/src/distBuild.test.ts +86 -0
  143. package/src/docStatus.test.ts +81 -0
  144. package/src/drift.test.ts +124 -0
  145. package/src/fixtures/data-radar-dynamic/Branches.tsx +14 -0
  146. package/src/fixtures/data-radar-dynamic/plan.fixture.yaml +16 -0
  147. package/src/fixtures/data-radar-forwarded/Scene.tsx +19 -0
  148. package/src/fixtures/data-radar-forwarded/plan.fixture.yaml +13 -0
  149. package/src/fixtures/data-radar-opaque/Scene.tsx +15 -0
  150. package/src/fixtures/data-radar-opaque/plan.fixture.yaml +10 -0
  151. package/src/fixtures/data-radar-tags/SceneClean.tsx +10 -0
  152. package/src/fixtures/data-radar-tags/SceneNullBinding.tsx +12 -0
  153. package/src/fixtures/data-radar-tags/SceneWithGap.tsx +11 -0
  154. package/src/fixtures/data-radar-tags/plan.fixture.yaml +29 -0
  155. package/src/fixtures/deterministic-scene.tsx +15 -0
  156. package/src/fixtures/double-shift/aliased.tsx +13 -0
  157. package/src/fixtures/double-shift/assigned.tsx +13 -0
  158. package/src/fixtures/double-shift/clean.tsx +19 -0
  159. package/src/fixtures/double-shift/destructured.tsx +12 -0
  160. package/src/fixtures/double-shift/elementAccess.tsx +12 -0
  161. package/src/fixtures/double-shift/layout.ts +24 -0
  162. package/src/fixtures/double-shift/mechanism-prefix.tsx.txt +458 -0
  163. package/src/fixtures/double-shift/wrapped.tsx +15 -0
  164. package/src/fixtures/geometry-sidecar-missing-export.ts +10 -0
  165. package/src/fixtures/geometry-sidecar-missing-type.ts +7 -0
  166. package/src/fixtures/geometry-sidecar-valid.ts +6 -0
  167. package/src/fixtures/interpolate-ascending.tsx +6 -0
  168. package/src/fixtures/interpolate-descending.tsx +8 -0
  169. package/src/fixtures/interpolate-identifier-keys.tsx +9 -0
  170. package/src/fixtures/nested-filters-broken.tsx +11 -0
  171. package/src/fixtures/nested-filters-fixed.tsx +8 -0
  172. package/src/fixtures/nested-filters-html-wrapper.tsx +14 -0
  173. package/src/fixtures/nested-filters-html.tsx +7 -0
  174. package/src/fixtures/nested-filters-siblings.tsx +12 -0
  175. package/src/fixtures/nondeterministic-scene.tsx +14 -0
  176. package/src/fixtures/nondeterministic-variants.tsx +16 -0
  177. package/src/fixtures/raw-hex-scene.tsx +10 -0
  178. package/src/fixtures/scene-root-declared/SceneHook.tsx +9 -0
  179. package/src/fixtures/scene-root-declared/plan.fixture.yaml +10 -0
  180. package/src/fixtures/scene-root-missing/SceneHook.tsx +11 -0
  181. package/src/fixtures/scene-root-missing/plan.fixture.yaml +10 -0
  182. package/src/fixtures/scene-root-no-names/SceneHook.tsx +6 -0
  183. package/src/fixtures/scene-root-no-names/plan.fixture.yaml +6 -0
  184. package/src/fixtures/scene-root-shell/SceneHook.tsx +8 -0
  185. package/src/fixtures/scene-root-shell/Shell.tsx +9 -0
  186. package/src/fixtures/scene-root-shell/plan.fixture.yaml +10 -0
  187. package/src/fixtures/shorthand-undefined-clean.tsx +23 -0
  188. package/src/fixtures/shorthand-undefined-longhand.tsx +17 -0
  189. package/src/fixtures/token-scene.tsx +9 -0
  190. package/src/includeCoverage.test.ts +176 -0
  191. package/src/learnedFrom.test.ts +32 -0
  192. package/src/projectDoc.test.ts +230 -0
  193. package/src/projectDoc.ts +152 -0
  194. package/src/projectDocSync.test.ts +152 -0
  195. package/src/projectDocSync.ts +79 -0
  196. package/src/projectMeta.test.ts +75 -0
  197. package/src/projectMeta.ts +53 -0
  198. package/src/provenance.ts +85 -0
  199. package/src/radar-check-ids.json +34 -0
  200. package/src/registry.test.ts +207 -0
  201. package/src/registry.ts +352 -0
  202. package/src/rules/animatedBarChartTightBox.ts +14 -0
  203. package/src/rules/animatedBarChartWhenNotToUse.ts +14 -0
  204. package/src/rules/animatedBarChartWhenToUse.ts +14 -0
  205. package/src/rules/animatedLineChartWhenNotToUse.ts +14 -0
  206. package/src/rules/animatedLineChartWhenToUse.ts +14 -0
  207. package/src/rules/approvedSfxPaletteOnly.ts +23 -0
  208. package/src/rules/atmosphereGradientsFadeAtBothEnds.ts +21 -0
  209. package/src/rules/audioIsTheClock.ts +22 -0
  210. package/src/rules/beatsDeriveFromTheirOwnSequence.ts +21 -0
  211. package/src/rules/bestSceneSetsTheBar.ts +21 -0
  212. package/src/rules/bumpBeforeRefreeze.ts +20 -0
  213. package/src/rules/cameraIsTheNarrator.ts +21 -0
  214. package/src/rules/checkPinBeforeShip.ts +22 -0
  215. package/src/rules/coldViewerClarity.ts +21 -0
  216. package/src/rules/commitOrCutEffects.ts +36 -0
  217. package/src/rules/convertFramesAcrossClockBoundary.ts +19 -0
  218. package/src/rules/crossCutElementsLiveInTheHudLayer.ts +21 -0
  219. package/src/rules/cursorClicksRealControls.ts +22 -0
  220. package/src/rules/cutOnRealAudioPauses.ts +20 -0
  221. package/src/rules/darkButNeverDim.ts +21 -0
  222. package/src/rules/dataRadarTagsDeclared.test.ts +60 -0
  223. package/src/rules/dataRadarTagsDeclared.ts +341 -0
  224. package/src/rules/declareAVerticalZoneMap.ts +19 -0
  225. package/src/rules/deleteRejectedRigsCompletely.ts +19 -0
  226. package/src/rules/deriveSeamsDontMeasure.ts +23 -0
  227. package/src/rules/deterministicSceneSource.test.ts +58 -0
  228. package/src/rules/deterministicSceneSource.ts +82 -0
  229. package/src/rules/diegeticSoundForOnscreenActions.ts +21 -0
  230. package/src/rules/distinctTransitionPerBeat.ts +21 -0
  231. package/src/rules/downloadOrDrawRichAssets.ts +22 -0
  232. package/src/rules/elementOnscreenForItsVoSentence.ts +25 -0
  233. package/src/rules/emitBuildNotes.ts +19 -0
  234. package/src/rules/energyFromTimingNotPartCount.ts +20 -0
  235. package/src/rules/evidenceBeforeClaimingFixed.ts +23 -0
  236. package/src/rules/exactPeerLockstep.ts +19 -0
  237. package/src/rules/firstPassIsADraft.ts +20 -0
  238. package/src/rules/fixCrowdingByRebandingNotNudging.ts +20 -0
  239. package/src/rules/fixesPreserveApprovedElements.ts +24 -0
  240. package/src/rules/floatingNotBoxed.ts +21 -0
  241. package/src/rules/focusBeatsRecedeTheContext.ts +20 -0
  242. package/src/rules/fontVarsBrandRemocn.ts +20 -0
  243. package/src/rules/geometricSeamsNotCrossfades.ts +28 -0
  244. package/src/rules/geometrySidecarExportsTyped.test.ts +37 -0
  245. package/src/rules/geometrySidecarExportsTyped.ts +59 -0
  246. package/src/rules/glowIsAFocalAccent.ts +28 -0
  247. package/src/rules/heroFillsTheFrame.ts +24 -0
  248. package/src/rules/htmlMasksForAnimatedCounters.ts +21 -0
  249. package/src/rules/impactStackOnPayoffs.ts +26 -0
  250. package/src/rules/interactiveTargetsAreDeclaredData.ts +21 -0
  251. package/src/rules/interpolateLiteralKeysMonotonic.test.ts +49 -0
  252. package/src/rules/interpolateLiteralKeysMonotonic.ts +98 -0
  253. package/src/rules/latenessIsStructuralOverlapTheBeats.ts +20 -0
  254. package/src/rules/lessTextMoreVisualizations.ts +22 -0
  255. package/src/rules/liveLinkDuplicateReactAlias.ts +22 -0
  256. package/src/rules/make2dElements3d.ts +21 -0
  257. package/src/rules/masterMixLoudnessTarget.ts +22 -0
  258. package/src/rules/measureAlignmentDontEyeball.ts +20 -0
  259. package/src/rules/motionCarriesWeightAndMeaning.ts +21 -0
  260. package/src/rules/motionDensityFloor.ts +20 -0
  261. package/src/rules/neverEditTierBVendored.ts +20 -0
  262. package/src/rules/neverRestateDerivedFrameNumbersInComments.ts +20 -0
  263. package/src/rules/noAiGradientLook.ts +22 -0
  264. package/src/rules/noColoredFlashToHideACut.ts +29 -0
  265. package/src/rules/noDoubleFrameShift.test.ts +95 -0
  266. package/src/rules/noDoubleFrameShift.ts +193 -0
  267. package/src/rules/noDuplicateMotionPrimitives.ts +19 -0
  268. package/src/rules/noLinearMotion.ts +29 -0
  269. package/src/rules/noNestedSvgFilters.test.ts +47 -0
  270. package/src/rules/noNestedSvgFilters.ts +138 -0
  271. package/src/rules/noRepeatedAssetAcrossShots.ts +19 -0
  272. package/src/rules/noShorthandWithUndefinedLonghand.test.ts +35 -0
  273. package/src/rules/noShorthandWithUndefinedLonghand.ts +140 -0
  274. package/src/rules/noStackedFadesAtACut.ts +30 -0
  275. package/src/rules/noStaticHolds.ts +24 -0
  276. package/src/rules/occlusionVisibleElements.ts +26 -0
  277. package/src/rules/oneContinuousVoTrack.ts +20 -0
  278. package/src/rules/onePunchPerMomentClass.ts +20 -0
  279. package/src/rules/oneRenderPerRound.ts +46 -0
  280. package/src/rules/openStaticAfterAHardCut.ts +29 -0
  281. package/src/rules/openingsAndClosingsCarryMore.ts +21 -0
  282. package/src/rules/persistentDeviceFrames.ts +20 -0
  283. package/src/rules/pixelDiffAnEmptyBandFirst.ts +20 -0
  284. package/src/rules/planIsPublishedNotGating.ts +32 -0
  285. package/src/rules/poweredByRevolaWatermark.ts +19 -0
  286. package/src/rules/predrawContentPresentAtTheCut.ts +21 -0
  287. package/src/rules/premiumSurfacesNotFlatBorders.ts +20 -0
  288. package/src/rules/radarDispositionsAreHumanOnly.ts +28 -0
  289. package/src/rules/realAssetsNotPlaceholders.ts +21 -0
  290. package/src/rules/rebuildUiFromReconNotScreenshots.ts +21 -0
  291. package/src/rules/reconStrandsRunInParallel.ts +63 -0
  292. package/src/rules/registryBeforeHandrolling.ts +20 -0
  293. package/src/rules/remapRateEndpointFormula.ts +19 -0
  294. package/src/rules/remocnContentTailwindChrome.ts +19 -0
  295. package/src/rules/retimeOnlyViaPlaybackOrDesignTokens.ts +18 -0
  296. package/src/rules/reviewTheRenderByFrameSweep.ts +23 -0
  297. package/src/rules/rollingNumberBoundedSequence.ts +21 -0
  298. package/src/rules/rollingNumberSequenceLayoutNone.ts +22 -0
  299. package/src/rules/rollingNumberTightBoxAlignment.ts +19 -0
  300. package/src/rules/rollingNumberWhenNotToUse.ts +24 -0
  301. package/src/rules/rollingNumberWhenToUse.ts +23 -0
  302. package/src/rules/sameFamilySameProject.ts +20 -0
  303. package/src/rules/sampleBrandFromProduct.ts +19 -0
  304. package/src/rules/sampleVelocityFromPreviousFramePosition.ts +21 -0
  305. package/src/rules/sceneRootTagDeclared.test.ts +43 -0
  306. package/src/rules/sceneRootTagDeclared.ts +78 -0
  307. package/src/rules/scrubDemoDataToGenericRoles.ts +19 -0
  308. package/src/rules/selfReviewThePlanForGaps.ts +47 -0
  309. package/src/rules/sourceArchivedBeforeBrief.ts +24 -0
  310. package/src/rules/statisticsSelfExplanatory.ts +18 -0
  311. package/src/rules/stopsAsRelativeSpacing.ts +21 -0
  312. package/src/rules/theWholeCanvasWorks.ts +21 -0
  313. package/src/rules/themePerSection.ts +28 -0
  314. package/src/rules/thesisDeclaredInBrief.ts +25 -0
  315. package/src/rules/tierARequiresPropUnreachableEdit.ts +20 -0
  316. package/src/rules/tinyBodyCopyAsRuledLines.ts +19 -0
  317. package/src/rules/titlesPinnedOutsideCameraPush.ts +22 -0
  318. package/src/rules/tokensNotRawHexes.test.ts +51 -0
  319. package/src/rules/tokensNotRawHexes.ts +89 -0
  320. package/src/rules/typeTokenDefaultedParamsAsString.ts +21 -0
  321. package/src/rules/varyKitChoreographyAcrossSections.ts +21 -0
  322. package/src/rules/varyTheVisualizationGrammar.ts +22 -0
  323. package/src/rules/verifyCheapRenderDear.ts +18 -0
  324. package/src/rules/voAddressesTheViewer.ts +18 -0
  325. package/src/rules/voIsAPerformance.ts +21 -0
  326. package/src/rules/voScriptLocksSpokenWords.ts +21 -0
  327. package/src/rules/wrappersPreserveChildGeometry.ts +22 -0
  328. package/src/sourceCheck.test.ts +50 -0
  329. package/src/sourceCheck.ts +55 -0
  330. package/src/sourceCitations.test.ts +747 -0
  331. package/src/sourceCitations.ts +217 -0
  332. package/src/stageProjection.ts +112 -0
  333. package/src/stages.test.ts +68 -0
  334. package/src/stages.ts +207 -0
  335. package/src/testSupport.ts +16 -0
  336. package/src/types.ts +181 -0
  337. package/src/variants.test.ts +24 -0
  338. package/src/variants.ts +13 -0
  339. package/src/waiverProjection.test.ts +59 -0
  340. package/src/waiverProjection.ts +45 -0
package/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # @revola-ai/video-craft
2
+
3
+ Durable craft knowledge for building videos in this repo, as machine-checked rules.
4
+
5
+ ## Adding a rule
6
+
7
+ Pick the track that fits, then finish with the shared steps below.
8
+
9
+ **Prose rule, anchored** (a lesson that points at live code):
10
+ copy `src/rules/deriveSeamsDontMeasure.ts`. Anchor to a durable home - an
11
+ exported kit symbol or a long-lived helper - over a scene-local constant.
12
+ If an anchor later dangles, re-anchor it to where the evidence now lives;
13
+ never flip it to `unanchorable` to silence the test.
14
+
15
+ **Prose rule, unanchorable** (process guidance with no code to point at):
16
+ copy `src/rules/deleteRejectedRigsCompletely.ts`. The `unanchorable` string
17
+ must say why, and when to re-anchor if that changes.
18
+
19
+ **Source rule** (mechanically checkable in scene source):
20
+ copy `src/rules/noNestedSvgFilters.ts`. Also required: a fixture pair under
21
+ `src/fixtures/` (broken shape fires, fixed shape does not, plus a
22
+ false-positive guard), a `src/rules/<name>.test.ts`, and a clean run over the
23
+ corpus - `src/corpus.test.ts` fails on any finding that is not a justified
24
+ `KNOWN_EXCEPTIONS` entry naming a recorded follow-up. `include` globs are
25
+ explicit per project; `exclude` is the coarse escape hatch for files a rule
26
+ never applies to.
27
+
28
+ **Component rule** (feeds a kit sidecar): set
29
+ `scope: { kind: "component", slug, field }`. `whenToUse` and `whenNotToUse`
30
+ allow one rule each per component - pick the crispest sentence.
31
+
32
+ **Shared steps, in order:**
33
+
34
+ 1. Register the rule in `src/registry.ts`.
35
+ 2. Run `npx tsx packages/video-craft/scripts/generate.ts` (validates the
36
+ registry, then rewrites the outputs below).
37
+ 3. Run `./node_modules/.bin/tsc -p tsconfig.json --noEmit` - vitest does NOT
38
+ typecheck, and a malformed `Rule` literal is a type error, not a test
39
+ failure.
40
+ 4. Run `./node_modules/.bin/vitest run packages/video-craft`.
41
+ 5. Add a back-reference (`(Rule: \`<id>\`.)`) to the notes passage it was
42
+ mined from.
43
+
44
+ Skipping step 2 makes the drift tests fail with a stale-file diff: run the
45
+ generator, never hand-edit the generated files.
46
+
47
+ ## Outputs (machine-owned - do not hand-edit)
48
+
49
+ - `packages/video-kit/src/motion/<slug>.meta.ts` - one per component with rules.
50
+ - The `craft:begin pipeline` block in `HOW_I_BUILD_VIDEOS.md`.
51
+
52
+ Component rules are discoverable through the sidecars, pipeline rules through
53
+ the doc block; `src/registry.ts` is the complete list.
54
+
55
+ Every rule needs a `learnedFrom`: a rule with no origin is an opinion, not
56
+ knowledge. The verifier fails if that file disappears.
@@ -0,0 +1,69 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { Project, ts } from "ts-morph";
4
+ import { isUpstreamProvenance, upstreamCitationError } from "./provenance.js";
5
+ function provenanceError(path, root) {
6
+ if (isUpstreamProvenance(path)) {
7
+ const malformed = upstreamCitationError(path);
8
+ return malformed ? `is a malformed upstream citation (${malformed})` : void 0;
9
+ }
10
+ return existsSync(join(root, path)) ? void 0 : "does not exist";
11
+ }
12
+ function verifyAnchors(rules, root) {
13
+ const errors = [];
14
+ const project = new Project({
15
+ useInMemoryFileSystem: false,
16
+ skipAddingFilesFromTsConfig: true,
17
+ compilerOptions: { allowJs: true, jsx: ts.JsxEmit.ReactJSX }
18
+ });
19
+ for (const rule of rules) {
20
+ if (rule.learnedFrom) {
21
+ const bad = provenanceError(rule.learnedFrom, root);
22
+ if (bad) {
23
+ errors.push(`rule "${rule.id}": learnedFrom "${rule.learnedFrom}" ${bad}`);
24
+ }
25
+ }
26
+ for (const ex of rule.exceptions ?? []) {
27
+ const badRecord = provenanceError(ex.recordedIn, root);
28
+ if (badRecord) {
29
+ errors.push(
30
+ `rule "${rule.id}": exception recordedIn "${ex.recordedIn}" ${badRecord}`
31
+ );
32
+ }
33
+ const badProject = provenanceError(ex.project, root);
34
+ if (badProject) {
35
+ errors.push(`rule "${rule.id}": exception project "${ex.project}" ${badProject}`);
36
+ }
37
+ }
38
+ if (rule.enforcement.kind !== "prose") continue;
39
+ if (!("anchor" in rule.enforcement)) continue;
40
+ const { file, symbol } = rule.enforcement.anchor;
41
+ if (isUpstreamProvenance(file)) {
42
+ const malformed = upstreamCitationError(file);
43
+ if (malformed) {
44
+ errors.push(
45
+ `rule "${rule.id}": anchor file "${file}" is a malformed upstream citation (${malformed})`
46
+ );
47
+ }
48
+ continue;
49
+ }
50
+ const abs = join(root, file);
51
+ if (!existsSync(abs)) {
52
+ errors.push(`rule "${rule.id}": anchor file "${file}" does not exist`);
53
+ continue;
54
+ }
55
+ if (!symbol) continue;
56
+ const source = project.getSourceFile(abs) ?? project.addSourceFileAtPath(abs);
57
+ const exported = source.getExportedDeclarations().has(symbol);
58
+ const local = source.getVariableDeclaration(symbol) !== void 0 || source.getFunction(symbol) !== void 0 || source.getInterface(symbol) !== void 0 || source.getTypeAlias(symbol) !== void 0;
59
+ if (!exported && !local) {
60
+ errors.push(
61
+ `rule "${rule.id}": anchor symbol "${symbol}" no longer exists in "${file}" - re-anchor the rule to where the evidence now lives; do not flip it to unanchorable`
62
+ );
63
+ }
64
+ }
65
+ return errors;
66
+ }
67
+ export {
68
+ verifyAnchors
69
+ };
package/dist/corpus.js ADDED
@@ -0,0 +1,91 @@
1
+ import { RULES } from "./registry.js";
2
+ import { matchedFiles, runSourceCheck } from "./sourceCheck.js";
3
+ const HEX_RULE = "tokens-not-raw-hexes";
4
+ const PANEL_FILL = "dark panel fill predates the rule; follow-up: tokenize into CK";
5
+ const BG_RESTATED = "raw restatement of CK.bg (#0b0b0d) predates the rule; follow-up: reference the token";
6
+ const HUE_RESTATED = "avatar hue pair restates CK accent tokens raw; predates the rule; follow-up: reference the tokens";
7
+ const LAVENDER = "lavender text tint (#c9b8fb) has no CK token yet; predates the rule; follow-up: tokenize into CK";
8
+ const ROCKET = "rocket illustration fill has no CK token yet; predates the rule; follow-up: tokenize into CK";
9
+ const KNOWN_EXCEPTIONS = [
10
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S3Line.tsx", match: "#15141d", justification: PANEL_FILL },
11
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S3Line.tsx", match: "#1c1a26", justification: PANEL_FILL },
12
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S3Line.tsx", match: "#14131c", justification: PANEL_FILL },
13
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S4Proof.tsx", match: "#16151e", justification: PANEL_FILL },
14
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S2Turn.tsx", match: "#0b0b0d", justification: BG_RESTATED },
15
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S4Proof.tsx", match: "#0b0b0d", justification: BG_RESTATED },
16
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/craftKit.tsx", match: "#0b0b0d", justification: BG_RESTATED },
17
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S5Mirror.tsx", match: "#8B5CF6", justification: HUE_RESTATED },
18
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S5Mirror.tsx", match: "#5CA4F6", justification: HUE_RESTATED },
19
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S5Mirror.tsx", match: "#5fd39a", justification: HUE_RESTATED },
20
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S5Mirror.tsx", match: "#f8b8aa", justification: HUE_RESTATED },
21
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S5Mirror.tsx", match: "#f5d67a", justification: HUE_RESTATED },
22
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/S5Mirror.tsx", match: "#c9b8fb", justification: LAVENDER },
23
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/ink.tsx", match: "#f5c66d", justification: ROCKET },
24
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/ink.tsx", match: "#2a2833", justification: ROCKET },
25
+ { rule: HEX_RULE, file: "revola-video/src/scenes/craft/ink.tsx", match: "#bda6ff", justification: ROCKET },
26
+ // v2 (build2) frame-windowed carrier/hero binding: the tag is gated off over
27
+ // the seam-flight/vacate window (so hero-size never measures the shrinking
28
+ // carrier and no post-cue pose trips a geometry check), which a string literal
29
+ // cannot express; the runtime tag coverage (radar:scene tag-coverage, 22/22)
30
+ // still verifies every binding against sampled frames during its cues.
31
+ // Follow-up: remotion-videos-emp (source-evaluable hero/carrier windows).
32
+ {
33
+ rule: "data-radar-tags-declared",
34
+ file: "rcp-fund7-video/src/scenes/insurers.tsx",
35
+ match: 'data-radar={f < T_VACATE ? "insurer-edifice" : undefined}',
36
+ justification: "frame-windowed carrier tag gated off during the closing travel; runtime tag-coverage (22/22) verifies insurer-edifice during its cues. follow-up: remotion-videos-s300"
37
+ },
38
+ {
39
+ rule: "data-radar-tags-declared",
40
+ file: "rcp-fund7-video/src/surfaces.tsx",
41
+ match: "data-radar={radarId}",
42
+ justification: "Panel forwards its tag via the radarId prop (call sites pass literals); the gate only traces props named dataRadar. Runtime tag-coverage verifies the bindings. follow-up: remotion-videos-s300 (rename prop to dataRadar)"
43
+ }
44
+ ];
45
+ function corpusFindings(root) {
46
+ const out = [];
47
+ for (const rule of RULES) {
48
+ if (rule.enforcement.kind !== "source") continue;
49
+ for (const finding of runSourceCheck(rule.enforcement.check, root)) {
50
+ out.push({ ...finding, rule: rule.id });
51
+ }
52
+ }
53
+ return out;
54
+ }
55
+ const findingKey = (f) => `${f.rule}|${f.file}|${f.match}`;
56
+ const scopedInclude = (include, projectName) => include.flatMap((glob) => {
57
+ const [head, ...rest] = glob.split("/");
58
+ if (head === projectName) return [glob];
59
+ if (head === "*" || head === "**") return [[projectName, ...rest].join("/")];
60
+ return [];
61
+ });
62
+ function scanProject(root, projectName) {
63
+ const findings = [];
64
+ const excused = [];
65
+ const coveredRules = [];
66
+ const uncoveredRules = [];
67
+ const scanned = /* @__PURE__ */ new Set();
68
+ const excusedKeys = new Set(KNOWN_EXCEPTIONS.map(findingKey));
69
+ for (const rule of RULES) {
70
+ if (rule.enforcement.kind !== "source") continue;
71
+ const include = scopedInclude(rule.enforcement.check.include, projectName);
72
+ if (include.length === 0) {
73
+ uncoveredRules.push(rule.id);
74
+ continue;
75
+ }
76
+ coveredRules.push(rule.id);
77
+ const check = { ...rule.enforcement.check, include };
78
+ for (const abs of matchedFiles(check, root)) scanned.add(abs);
79
+ for (const finding of runSourceCheck(check, root)) {
80
+ const f = { ...finding, rule: rule.id };
81
+ (excusedKeys.has(findingKey(f)) ? excused : findings).push(f);
82
+ }
83
+ }
84
+ return { findings, excused, coveredRules, uncoveredRules, scannedFiles: scanned.size };
85
+ }
86
+ export {
87
+ KNOWN_EXCEPTIONS,
88
+ corpusFindings,
89
+ findingKey,
90
+ scanProject
91
+ };
@@ -0,0 +1,83 @@
1
+ const exceptionLines = (r, indent) => (r.exceptions ?? []).map(
2
+ (ex) => `${indent}- waived in \`${ex.project}\`: ${ex.decision} (recorded: \`${ex.recordedIn}\`)`
3
+ );
4
+ function spliceBlock(doc, marker, body) {
5
+ const begin = `<!-- craft:begin ${marker} -->`;
6
+ const end = `<!-- craft:end ${marker} -->`;
7
+ const from = doc.indexOf(begin);
8
+ if (from === -1) throw new Error(`marker "craft:begin ${marker}" not found`);
9
+ const to = doc.indexOf(end, from);
10
+ if (to === -1) throw new Error(`marker "craft:end ${marker}" not found`);
11
+ return doc.slice(0, from + begin.length) + "\n" + body + "\n" + doc.slice(to);
12
+ }
13
+ function renderClaudeMdBlock(rules, { compact = true } = {}) {
14
+ const pipeline = rules.filter((r) => r.scope.kind === "pipeline").sort((a, b) => a.id.localeCompare(b.id));
15
+ const of = (tier) => pipeline.filter((r) => r.tier === tier);
16
+ const isWaived = (r) => (r.exceptions ?? []).length > 0;
17
+ const section = (heading, body) => body.length === 0 ? [] : [...heading, ``, ...body, ``];
18
+ const full = (r) => [`- ${r.claim} (\`${r.id}\`)`, ...exceptionLines(r, " ")].join("\n");
19
+ const compacted = (rs, label) => {
20
+ if (rs.length === 0) return [];
21
+ if (!compact) return rs.map(full);
22
+ const waived = rs.filter(isWaived);
23
+ const plain = rs.filter((r) => !isWaived(r));
24
+ return [
25
+ ...waived.map(full),
26
+ ...waived.length && plain.length ? [``] : [],
27
+ ...plain.length ? [
28
+ // Wording is load-bearing and was wrong in review twice over. "further"
29
+ // dangles in a tier with no waived rules above it (process has none).
30
+ // And the lookup recipe must key on what the reader HOLDS - an id -
31
+ // not on the heading text: renderPipelineBlock emits `### <claim>`, so
32
+ // the id appears only in the `Rule id:` line two lines below. Naming
33
+ // the wrong token would send every lookup into a 139 KB scan, which is
34
+ // the one thing this compaction cannot afford to get wrong.
35
+ `${plain.length} more ${label} rule${plain.length === 1 ? "" : "s"} bind${plain.length === 1 ? "s" : ""} this work, listed by id below. To read one, search HOW_I_BUILD_VIDEOS.md for its id in a \`Rule id:\` line - the headings there are the claims themselves, so the id is not a heading. That is the only doc carrying each rule's why and provenance; the per-stage sheets under \`docs/rules/stages/\` carry the claims, scoped by stage. Every id here is a rule you are accountable to, not a suggestion.`,
36
+ ``,
37
+ plain.map((r) => `\`${r.id}\``).join(", ")
38
+ ] : []
39
+ ];
40
+ };
41
+ return [
42
+ `<!-- This block is generated from packages/video-craft/src/rules/. Do not edit it here. -->`,
43
+ ``,
44
+ ...section(
45
+ [
46
+ `### Gates - if you remember nothing else`,
47
+ ``,
48
+ `Each line below has cost a rebuild round. Every one is settled by running something, not by reading the diff: run the check.`
49
+ ],
50
+ of("gate").map(
51
+ (r) => [`- ${r.claim} (\`${r.id}\`)`, ` - verify: ${r.verify}`, ...exceptionLines(r, " ")].join("\n")
52
+ )
53
+ ),
54
+ ...section([`### Craft rules`], compacted(of("craft"), "craft")),
55
+ ...section([`### Process rules`], compacted(of("process"), "process"))
56
+ ].join("\n").trimEnd();
57
+ }
58
+ function renderPipelineBlock(rules) {
59
+ const pipeline = rules.filter((r) => r.scope.kind === "pipeline").sort((a, b) => a.id.localeCompare(b.id));
60
+ return [
61
+ `<!-- This block is generated from packages/video-craft/src/rules/. Do not edit it here. -->`,
62
+ ``,
63
+ ...pipeline.flatMap((r) => [
64
+ `### ${r.claim}`,
65
+ ``,
66
+ r.why,
67
+ ``,
68
+ // The tier is restated here rather than only in the CLAUDE.md projection
69
+ // so the reference doc and the injected block cannot disagree about how
70
+ // much a rule weighs - a reader who arrives via a rule id from a build
71
+ // note lands here, not there.
72
+ `Learned from \`${r.learnedFrom}\`. Rule id: \`${r.id}\`. Tier: ${r.tier}.`,
73
+ ...r.verify ? [``, `Verify: ${r.verify}`] : [],
74
+ ...(r.exceptions ?? []).length > 0 ? [``, ...exceptionLines(r, "")] : [],
75
+ ``
76
+ ])
77
+ ].join("\n").trimEnd();
78
+ }
79
+ export {
80
+ renderClaudeMdBlock,
81
+ renderPipelineBlock,
82
+ spliceBlock
83
+ };
@@ -0,0 +1,39 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { renderClaudeMdBlock, renderPipelineBlock, spliceBlock } from "./projectDoc.js";
4
+ import { RULES } from "./registry.js";
5
+ function syncProjectedDocs(targetRoot, opts) {
6
+ const updated = [];
7
+ const skipped = [];
8
+ const claudePath = join(targetRoot, "CLAUDE.md");
9
+ if (!existsSync(claudePath)) {
10
+ throw new Error(
11
+ `CLAUDE.md does not exist in ${targetRoot} - rules:sync splices into existing files and never creates them. Create CLAUDE.md with the craft markers (<!-- craft:begin claude-md --> / <!-- craft:end claude-md -->) first.`
12
+ );
13
+ }
14
+ const howPath = join(targetRoot, "HOW_I_BUILD_VIDEOS.md");
15
+ const hasHow = existsSync(howPath);
16
+ writeFileSync(
17
+ claudePath,
18
+ spliceBlock(readFileSync(claudePath, "utf8"), "claude-md", renderClaudeMdBlock(RULES, { compact: hasHow })),
19
+ "utf8"
20
+ );
21
+ updated.push("CLAUDE.md");
22
+ if (opts?.claudeMdOnly) {
23
+ return { updated, skipped };
24
+ }
25
+ if (!hasHow) {
26
+ skipped.push({ file: "HOW_I_BUILD_VIDEOS.md", reason: "not present in target" });
27
+ } else {
28
+ writeFileSync(
29
+ howPath,
30
+ spliceBlock(readFileSync(howPath, "utf8"), "pipeline", renderPipelineBlock(RULES)),
31
+ "utf8"
32
+ );
33
+ updated.push("HOW_I_BUILD_VIDEOS.md");
34
+ }
35
+ return { updated, skipped };
36
+ }
37
+ export {
38
+ syncProjectedDocs
39
+ };
@@ -0,0 +1,37 @@
1
+ import { COMPONENT_VARIANTS } from "./variants.js";
2
+ const forComponent = (rules, slug, field) => rules.filter((r) => r.scope.kind === "component" && r.scope.slug === slug && r.scope.field === field).sort((a, b) => a.id.localeCompare(b.id)).map((r) => r.claim);
3
+ function componentSlugs(rules) {
4
+ const slugs = /* @__PURE__ */ new Set();
5
+ for (const rule of rules) {
6
+ if (rule.scope.kind === "component") slugs.add(rule.scope.slug);
7
+ }
8
+ return [...slugs].sort();
9
+ }
10
+ const lit = (s) => JSON.stringify(s);
11
+ function renderComponentMeta(rules, slug) {
12
+ const whenToUse = forComponent(rules, slug, "whenToUse")[0] ?? "";
13
+ const whenNotToUse = forComponent(rules, slug, "whenNotToUse")[0] ?? "";
14
+ const gotchas = forComponent(rules, slug, "gotcha");
15
+ const name = slug.replace(/-([a-z])/g, (_, c) => c.toUpperCase()) + "Meta";
16
+ const variants = COMPONENT_VARIANTS[slug] ?? [];
17
+ return [
18
+ `// GENERATED FILE - DO NOT EDIT.`,
19
+ `// Source of truth: packages/video-craft/src/rules/. Regenerate with:`,
20
+ `// npx tsx packages/video-craft/scripts/generate.ts`,
21
+ `// Edits here are reverted by the drift test in packages/video-craft/src/drift.test.ts.`,
22
+ ``,
23
+ `export const ${name} = {`,
24
+ ` whenToUse: ${lit(whenToUse)},`,
25
+ ` whenNotToUse: ${lit(whenNotToUse)},`,
26
+ ` gotchas: [`,
27
+ ...gotchas.map((g) => ` ${lit(g)},`),
28
+ ` ],`,
29
+ ` variants: [${variants.map((v) => lit(v)).join(", ")}] as string[],`,
30
+ `};`,
31
+ ``
32
+ ].join("\n");
33
+ }
34
+ export {
35
+ componentSlugs,
36
+ renderComponentMeta
37
+ };
@@ -0,0 +1,41 @@
1
+ const UPSTREAM_PROVENANCE_ROOTS = [
2
+ // Video projects that stayed in remotion-videos.
3
+ "revola-video",
4
+ "expanse-video",
5
+ "qse-video",
6
+ "act854-video",
7
+ "datapeak-video",
8
+ "klaviyo-segments-video",
9
+ "qpa-video",
10
+ "reverence-video",
11
+ "enjamb-teaser",
12
+ "workday-harness-video",
13
+ "rcp-fund7-video",
14
+ // Pre-split working documents that stayed with the video projects.
15
+ "claude-sessions-digest"
16
+ ];
17
+ const UPSTREAM_ISSUE_PREFIX = "remotion-videos-";
18
+ function isUpstreamIssue(id) {
19
+ return id.startsWith(UPSTREAM_ISSUE_PREFIX);
20
+ }
21
+ function isUpstreamProvenance(path) {
22
+ return UPSTREAM_PROVENANCE_ROOTS.some(
23
+ (root) => path === root || path.startsWith(`${root}/`)
24
+ );
25
+ }
26
+ function upstreamCitationError(path) {
27
+ if (path.includes("\\")) return "contains a backslash";
28
+ const segments = path.split("/");
29
+ if (segments.some((s) => s === "")) return "has an empty path segment";
30
+ if (segments.some((s) => s === "." || s === "..")) {
31
+ return "contains a relative segment";
32
+ }
33
+ return void 0;
34
+ }
35
+ export {
36
+ UPSTREAM_ISSUE_PREFIX,
37
+ UPSTREAM_PROVENANCE_ROOTS,
38
+ isUpstreamIssue,
39
+ isUpstreamProvenance,
40
+ upstreamCitationError
41
+ };
@@ -0,0 +1,34 @@
1
+ [
2
+ "alignment-group",
3
+ "attachment-offset",
4
+ "band-breach",
5
+ "blank-region-hold",
6
+ "brand-provenance",
7
+ "brief-structure",
8
+ "case-system",
9
+ "contract-satisfiable",
10
+ "copy-tracks-the-read",
11
+ "crowding-legibility",
12
+ "dead-frame-at-cut",
13
+ "edge-touch",
14
+ "fade-stack-at-cut",
15
+ "frame-count",
16
+ "group-member-count",
17
+ "hero-regression",
18
+ "hero-size",
19
+ "loudness",
20
+ "occlusion",
21
+ "placeholder-content",
22
+ "rebanding-conflict",
23
+ "scene-serves-thesis",
24
+ "seam-continuity",
25
+ "seam-fidelity",
26
+ "sibling-overlap",
27
+ "snap",
28
+ "static-hold",
29
+ "tag-coverage",
30
+ "text-fit",
31
+ "thesis-fidelity",
32
+ "viz-declared",
33
+ "vo-element-sync"
34
+ ]