@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
@@ -0,0 +1,21 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from revola-video/BUILD_NOTES_CRAFT.md: "Fog gradient started
5
+ * *opaque* - a hard black band sliced the frame and cut the clock in half.
6
+ * Now transparent at BOTH ends, and confined to a world band that can't
7
+ * reach the clock." Only the durable half is kept as the claim; the band
8
+ * values themselves are per-scene design decisions.
9
+ */
10
+ export const atmosphereGradientsFadeAtBothEnds: Rule = {
11
+ id: "atmosphere-gradients-fade-at-both-ends",
12
+ claim: "Make full-bleed atmosphere gradients (fog, haze) transparent at both ends and confine them to a declared world band.",
13
+ why: "A fog gradient that started opaque produced a hard black band that sliced the frame and cut the clock in half; band confinement guarantees it can never reach elements in other zones.",
14
+ learnedFrom: "revola-video/BUILD_NOTES_CRAFT.md",
15
+ tier: "craft",
16
+ scope: { kind: "pipeline" },
17
+ enforcement: {
18
+ kind: "prose",
19
+ anchor: { file: "revola-video/src/scenes/craft/S1Graveyard.tsx" },
20
+ },
21
+ };
@@ -0,0 +1,22 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from HOW_I_BUILD_VIDEOS.md ("Audio is the clock... Timing is a pure
5
+ * function of the audio"), merged with act854-video/BUILD_NOTES.md's
6
+ * measure-the-WAV procedure ("to fit a new VO: measure it, then edit only
7
+ * D_INTRO ... D_CLOSE"). The measuring side lives in video-cli's measure
8
+ * command, which derives frame counts from WAV sample counts.
9
+ */
10
+ export const audioIsTheClock: Rule = {
11
+ id: "audio-is-the-clock",
12
+ claim: "Record or generate the voiceover first, measure it, and fit the video to the audio; never re-time audio to fit the video.",
13
+ why: "Reversing the order forces re-recording or hand-stretching audio every time timing shifts, and every feedback round shifts timing; deriving durations from the measured WAV makes a re-time a re-measure.",
14
+ learnedFrom: "HOW_I_BUILD_VIDEOS.md",
15
+ tier: "gate",
16
+ verify: "`ffprobe -show_entries stream=nb_frames <render>` equals `total` in .video/timing.json",
17
+ scope: { kind: "pipeline" },
18
+ enforcement: {
19
+ kind: "prose",
20
+ anchor: { file: "packages/video-cli/src/measure.ts" },
21
+ },
22
+ };
@@ -0,0 +1,21 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from the product-room build: the cold open's in-frame content starts
5
+ * when the browser frame arrives, making its Sequence 142 frames shorter than
6
+ * the section. A CLICK constant derived from the section length sat past the
7
+ * sequence's final rendered frame. The failure mode is the dangerous kind:
8
+ * no error, no missing element, just a beat that never happens.
9
+ */
10
+ export const beatsDeriveFromTheirOwnSequence: Rule = {
11
+ id: "beats-derive-from-their-own-sequence",
12
+ claim: "Compute a beat's frame from the duration of the Sequence it renders in, never from a parent's or a section's length.",
13
+ why: "A click beat derived from its section's length landed 10 frames past the last frame its shorter in-frame sequence ever draws, so the cursor drifted toward the button and the scene cut away before the press - the beat silently did not exist, and nothing failed.",
14
+ learnedFrom: "claude-sessions-digest/product-room-video.md",
15
+ tier: "craft",
16
+ scope: { kind: "pipeline" },
17
+ enforcement: {
18
+ kind: "prose",
19
+ anchor: { file: "revola-video/src/productroom/PRColdOpen.tsx" },
20
+ },
21
+ };
@@ -0,0 +1,21 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from docs/style/CREATIVE_EDGE.md directive 20 ("amazing, move on to
5
+ * the next scene, now you know what I like", "make it match the first 3
6
+ * scenes' animation quality", "i already upgraded scenes 1 and 2 so you can
7
+ * take them as inspo"). The preservation half of the directive is
8
+ * fixes-preserve-approved-elements; this rule owns the propagation half.
9
+ */
10
+ export const bestSceneSetsTheBar: Rule = {
11
+ id: "best-scene-sets-the-bar",
12
+ claim: "The moment a scene is approved it becomes the film's standard: take it as inspiration for every other scene, name it in review, and measure the weakest scene against the strongest every round.",
13
+ why: "'Amazing, move on to the next scene, now you know what I like' and 'make it match the first 3 scenes' animation quality' show approval creating a bar; rounds that ignored it re-litigated settled taste scene by scene.",
14
+ learnedFrom: "docs/style/CREATIVE_EDGE.md",
15
+ tier: "process",
16
+ scope: { kind: "pipeline" },
17
+ enforcement: {
18
+ kind: "prose",
19
+ unanchorable: "A cross-scene quality comparison made during review rounds; no single code location expresses it.",
20
+ },
21
+ };
@@ -0,0 +1,20 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from HOW_I_BUILD_VIDEOS.md: "A same-version repack is a silent wrong
5
+ * pin: npm sees an unchanged dep string, keeps old content locally, and
6
+ * breaks fresh installs elsewhere." Already tool-enforced: freezeKit refuses
7
+ * the overwrite. The rule exists so agents do not work around the refusal.
8
+ */
9
+ export const bumpBeforeRefreeze: Rule = {
10
+ id: "bump-before-refreeze",
11
+ claim: "If kit content changed, bump the kit version before re-freezing; never repack the same version with different bytes.",
12
+ why: "A same-version repack is a silent wrong pin: npm sees an unchanged dep string, keeps old content locally, and breaks fresh installs elsewhere.",
13
+ learnedFrom: "HOW_I_BUILD_VIDEOS.md",
14
+ tier: "process",
15
+ scope: { kind: "pipeline" },
16
+ enforcement: {
17
+ kind: "prose",
18
+ anchor: { file: "packages/video-cli/src/kitShell.ts", symbol: "freezeKit" },
19
+ },
20
+ };
@@ -0,0 +1,21 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from docs/style/CREATIVE_EDGE.md directive 10 ("amazing camera
5
+ * effects", "zoom in, take actions, zoom out - a detailed cinematic
6
+ * dashboard reveal", "each time it's showing typing, the camera should zoom
7
+ * in and follow the typing", against "camera buggy and clumsy" and "it
8
+ * zooms in and suddenly zooms out").
9
+ */
10
+ export const cameraIsTheNarrator: Rule = {
11
+ id: "camera-is-the-narrator",
12
+ claim: "The camera tells the story with few, motivated, committed moves - a push into the element the VO names, a continuous journey through stations, following typing as it happens, a dive through an element into the next scene - each aimed at one subject with dwell time at the destination; unmotivated, whiplash, or decorative in-out moves read as mistakes.",
13
+ why: "'Amazing camera effects' was the recurring ask and 'camera buggy and clumsy ... it zooms in and suddenly zooms out' the recurring complaint; three deliberate moves consistently out-reviewed five micro-keys, and editorial single-subject framing beat crowded ensemble frames.",
14
+ learnedFrom: "docs/style/CREATIVE_EDGE.md",
15
+ tier: "craft",
16
+ scope: { kind: "pipeline" },
17
+ enforcement: {
18
+ kind: "prose",
19
+ unanchorable: "A camera-arc judgment across a scene's key schedule; no single code location expresses it.",
20
+ },
21
+ };
@@ -0,0 +1,22 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from HOW_I_BUILD_VIDEOS.md: "Before a video ships, run check-pin
5
+ * --project <dir>; it fails on a live link, a missing or uncommitted
6
+ * tarball, a lockfile/tarball integrity mismatch..." The tool enforces the
7
+ * checks; the rule makes running it mandatory, which the tool cannot
8
+ * self-enforce.
9
+ */
10
+ export const checkPinBeforeShip: Rule = {
11
+ id: "check-pin-before-ship",
12
+ claim: "Run check-pin --project <dir> before any video ships; ship only on a frozen, committed, integrity-matching tarball pin.",
13
+ why: "Shipping on a live link or stale tarball makes the delivered render non-reproducible: the exact bytes that rendered it cannot be recovered later.",
14
+ learnedFrom: "HOW_I_BUILD_VIDEOS.md",
15
+ tier: "gate",
16
+ verify: "`video check-pin --project <dir>`",
17
+ scope: { kind: "pipeline" },
18
+ enforcement: {
19
+ kind: "prose",
20
+ anchor: { file: "packages/video-cli/src/cli.ts" },
21
+ },
22
+ };
@@ -0,0 +1,21 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from docs/style/CREATIVE_EDGE.md directive 19 ("I showed someone
5
+ * this video and they said they don't get it", "make it more comprehensible
6
+ * so anyone watching understands what scene 5 is trying to communicate",
7
+ * "somehow make it more obvious what Raycast is for"). Visually approved
8
+ * scenes were rebuilt purely for comprehension.
9
+ */
10
+ export const coldViewerClarity: Rule = {
11
+ id: "cold-viewer-clarity",
12
+ claim: "Every scene passes the cold-viewer test: someone outside the company can say what the scene is about; confusion is fixed with orientation copy, clearer visual metaphors, or slower reveals, because clarity and spectacle are the same axis, not a trade.",
13
+ why: "'I showed someone this video and they said they don't get it' triggered rebuilds of scenes that were already visually approved; polish that fails to communicate is not polish.",
14
+ learnedFrom: "docs/style/CREATIVE_EDGE.md",
15
+ tier: "craft",
16
+ scope: { kind: "pipeline" },
17
+ enforcement: {
18
+ kind: "prose",
19
+ unanchorable: "A comprehension judgment requiring an outside-context reading of the scene; no single code location expresses it.",
20
+ },
21
+ };
@@ -0,0 +1,36 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from docs/style/CREATIVE_EDGE.md directive 15: both directions were
5
+ * flagged - overuse ("don't overuse the reveal effect - maybe once or
6
+ * never", "the white flash effect in the last scene is too much", "just
7
+ * don't like that grain effect") and half-commitment ("the blur effect is
8
+ * so minimal and low effort").
9
+ */
10
+ export const commitOrCutEffects: Rule = {
11
+ id: "commit-or-cut-effects",
12
+ claim: "An effect either commits or gets cut: a half-committed effect that barely registers is as much a defect as one stamped on every beat, and film grain is out entirely.",
13
+ why: "Review rounds flagged both failure directions - 'don't overuse the reveal effect' alongside 'the blur effect is so minimal and low effort' - so the only approved states for an effect are absent or unmistakable.",
14
+ learnedFrom: "docs/style/CREATIVE_EDGE.md",
15
+ tier: "craft",
16
+ // The blanket "film grain is out entirely" half of this claim contradicted
17
+ // the shipped kit, which exports and documents `FilmGrain` (video-kit
18
+ // src/craft/stage.tsx), and QGuard renders it twice in Shell.tsx. Unwaived,
19
+ // the projection read as a standing instruction to delete a deliberate,
20
+ // spec'd element - so an agent following CLAUDE.md would strip working
21
+ // work. The ban itself is real client feedback ("just don't like that grain
22
+ // effect", CREATIVE_EDGE directive 15), so it stands everywhere else.
23
+ exceptions: [
24
+ {
25
+ project: "qse-qguard-video",
26
+ decision:
27
+ "client chose ACT854's persistent frame chrome for the QGuard restyle, film grain included - specified in the mounted-once cinematic overlay as a 256px feTurbulence tile at mixBlendMode overlay (motion-brand-spec §6.1)",
28
+ recordedIn: "qse-qguard-video/docs/motion-brand-spec.md",
29
+ },
30
+ ],
31
+ scope: { kind: "pipeline" },
32
+ enforcement: {
33
+ kind: "prose",
34
+ unanchorable: "A commitment-level judgment per effect instance; no single code location expresses it.",
35
+ },
36
+ };
@@ -0,0 +1,19 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from revola-video/BUILD_NOTES_CRAFT.md, the two follow-on fixes to the
5
+ * time remap - "both are the same class of bug (a design frame used where a
6
+ * playback frame was meant)".
7
+ */
8
+ export const convertFramesAcrossClockBoundary: Rule = {
9
+ id: "convert-frames-across-clock-boundary",
10
+ claim: "When design and playback clocks coexist, route every cross-boundary value through the remap: values mirroring scene-internal beats convert design-to-playback, and values measuring the film read the composition timeline.",
11
+ why: "A design frame used where a playback frame is meant drifts silently: raw design-frame cue anchors would have been ~1.5s off picture at 1.34x, and the on-screen counter would have claimed a 60s runtime the 56.6s film does not have.",
12
+ learnedFrom: "revola-video/BUILD_NOTES_CRAFT.md",
13
+ tier: "craft",
14
+ scope: { kind: "pipeline" },
15
+ enforcement: {
16
+ kind: "prose",
17
+ anchor: { file: "revola-video/src/scenes/craft/mix.tsx", symbol: "at1" },
18
+ },
19
+ };
@@ -0,0 +1,21 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from revola-video/BUILD_NOTES_CRAFT.md: "in world space the S1 camera
5
+ * drags the line wherever the last cam key happens to be, so any S1 recut
6
+ * silently moves the seam. Pinning it to the HUD makes the contract a
7
+ * constant." The mechanism is CraftStage's hud prop ("renders in SCREEN
8
+ * space").
9
+ */
10
+ export const crossCutElementsLiveInTheHudLayer: Rule = {
11
+ id: "cross-cut-elements-live-in-the-hud-layer",
12
+ claim: "Render any element that must hold an exact screen position across a scene cut (a seam contract) in the HUD/screen-space layer, never in world space under the camera.",
13
+ why: "In world space the camera drags the element wherever the last key happens to be, so any recut silently moves the seam and invalidates the neighbouring scene's match cut.",
14
+ learnedFrom: "revola-video/BUILD_NOTES_CRAFT.md",
15
+ tier: "craft",
16
+ scope: { kind: "pipeline" },
17
+ enforcement: {
18
+ kind: "prose",
19
+ anchor: { file: "revola-video/src/scenes/craft/craftKit.tsx", symbol: "CraftStage" },
20
+ },
21
+ };
@@ -0,0 +1,22 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from claude-sessions-digest/act854-qpa-video.md: client feedback
5
+ * "Fix the useless cursor presses inside tabs... it presses 3 times on the
6
+ * sidebar... it's confusing" and "at each tab there is a purple thing coming
7
+ * out of the cursor looking like it's pressing something inside the page,
8
+ * but it doesn't, and it looks really bad". Complements
9
+ * rebuild-ui-from-recon-not-screenshots on the interaction side.
10
+ */
11
+ export const cursorClicksRealControls: Rule = {
12
+ id: "cursor-clicks-real-controls",
13
+ claim: "Every cursor click lands on a real, visible control and causes a visible state change; click ripples appear only on genuine navigation clicks, never as decorative presses inside content.",
14
+ why: "Decorative presses that change nothing read as confusing and 'really bad' to clients, and the ripple fix needed a second round because leftover presses survived; interaction realism is what sells a walkthrough as the real product.",
15
+ learnedFrom: "claude-sessions-digest/act854-qpa-video.md",
16
+ tier: "craft",
17
+ scope: { kind: "pipeline" },
18
+ enforcement: {
19
+ kind: "prose",
20
+ anchor: { file: "packages/video-kit/src/pure/walk.ts" },
21
+ },
22
+ };
@@ -0,0 +1,20 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from revola-video/BUILD_NOTES_CRAFT.md: "Cut points are the read's own
5
+ * pauses, not arithmetic. Verified with ffmpeg silencedetect -40dB:0.18 -
6
+ * every one lands inside a real pause." The P_S1...P_S5 playback lengths in
7
+ * tokensCraft.ts are the artifact of this procedure.
8
+ */
9
+ export const cutOnRealAudioPauses: Rule = {
10
+ id: "cut-on-real-audio-pauses",
11
+ claim: "Place scene boundaries inside real pauses in the recorded read, verified with ffmpeg silencedetect, never by arithmetic division of the audio.",
12
+ why: "An arithmetic cut point lands mid-word or mid-breath; verifying against detected silences guarantees each scene change coincides with a pause in the narration.",
13
+ learnedFrom: "revola-video/BUILD_NOTES_CRAFT.md",
14
+ tier: "craft",
15
+ scope: { kind: "pipeline" },
16
+ enforcement: {
17
+ kind: "prose",
18
+ anchor: { file: "revola-video/src/tokensCraft.ts" },
19
+ },
20
+ };
@@ -0,0 +1,21 @@
1
+ import type { Rule } from "../types";
2
+
3
+ /**
4
+ * Mined from docs/style/CREATIVE_EDGE.md directive 14 ("use lighter colors
5
+ * ... very low contrast, it exhausted my eyes", "add more colors, everything
6
+ * looks too dark, but don't go outside the theming", "scene 1 and scene 2
7
+ * look like they come from different videos", "keep artifact colors and the
8
+ * background persistent").
9
+ */
10
+ export const darkButNeverDim: Rule = {
11
+ id: "dark-but-never-dim",
12
+ claim: "The dark cinematic canvas never costs legibility: lift values, use lighter material (white-paper artifacts on the dark shell), keep tonal variety inside the theme, and hold the canvas consistent scene to scene - 'too dark to read comfortably' and 'these scenes look like different videos' are both hard fails.",
13
+ why: "'Very low contrast, it exhausted my eyes' and 'add more colors, everything looks too dark, but don't go outside the theming' show the dark theme failing on comfort while staying on brand; darkness is the style, dimness and canvas drift are the defects.",
14
+ learnedFrom: "docs/style/CREATIVE_EDGE.md",
15
+ tier: "craft",
16
+ scope: { kind: "pipeline" },
17
+ enforcement: {
18
+ kind: "prose",
19
+ unanchorable: "A contrast-and-consistency judgment across scenes at 1080p; no single code location expresses it.",
20
+ },
21
+ };
@@ -0,0 +1,60 @@
1
+ import { join } from "node:path";
2
+ import { describe, expect, test } from "vitest";
3
+ import { toolchainRepoRoot as repoRoot } from "../testSupport";
4
+ import { checkFile } from "../sourceCheck";
5
+ import { dataRadarTagsDeclared } from "./dataRadarTagsDeclared";
6
+
7
+ const check = () => {
8
+ if (dataRadarTagsDeclared.enforcement.kind !== "source") throw new Error("expected a source rule");
9
+ return dataRadarTagsDeclared.enforcement.check;
10
+ };
11
+
12
+ // The rule is PROJECT-wide (final-review I4): a declared element is routinely
13
+ // tagged in a child component, not in the scene module, so the honest
14
+ // source-level claim is "tagged somewhere in this project". Each fixture
15
+ // directory below is its own one-project world (its own plan*.yaml), and any
16
+ // file in it reports that project's findings.
17
+ const runIn = (fixture: string, name: string) => {
18
+ const rel = `packages/video-craft/src/fixtures/${fixture}/${name}`;
19
+ return checkFile(check(), join(repoRoot, rel), rel, repoRoot);
20
+ };
21
+
22
+ describe("dataRadarTagsDeclared", () => {
23
+ test("fires on a names: element id no file in the project tags", () => {
24
+ const findings = runIn("data-radar-tags", "SceneWithGap.tsx");
25
+ expect(findings.map((f) => f.match)).toEqual(["cta"]);
26
+ expect(findings[0].message).toMatch(/declares names: element "cta"/);
27
+ expect(findings[0].message).toMatch(/no data-radar="cta" attribute exists anywhere/);
28
+ // Attributed to the PLAN, where the binding lives and where the author
29
+ // fixes it - not to whichever scene file happened to be parsed.
30
+ expect(findings[0].file).toMatch(/plan\.fixture\.yaml$/);
31
+ });
32
+
33
+ test("a declared id tagged in a SIBLING file of the same project is not a finding", () => {
34
+ // "hero" is declared for the `gap` section but tagged only in
35
+ // SceneClean.tsx. Under the old per-file rule this was a false positive
36
+ // waiting to happen - it is exactly the QGuard shape, where `once`'s
37
+ // login-scanner is tagged in src/artifacts/Stations.tsx.
38
+ const findings = runIn("data-radar-tags", "SceneClean.tsx");
39
+ expect(findings.map((f) => f.match)).toEqual(["cta"]);
40
+ });
41
+
42
+ test("does not fire on a null binding (an honest 'no single subject')", () => {
43
+ const findings = runIn("data-radar-tags", "SceneNullBinding.tsx");
44
+ expect(findings.map((f) => f.match)).toEqual(["cta"]);
45
+ });
46
+
47
+ test("accepts a template-literal tag family, e.g. data-radar={`branch-${kind}`}", () => {
48
+ expect(runIn("data-radar-dynamic", "Branches.tsx")).toEqual([]);
49
+ });
50
+
51
+ test("accepts a tag forwarded through a `dataRadar` prop its call sites pass a literal to", () => {
52
+ expect(runIn("data-radar-forwarded", "Scene.tsx")).toEqual([]);
53
+ });
54
+
55
+ test("reports the site, never a false clean, when data-radar is bound to an expression it cannot evaluate", () => {
56
+ const findings = runIn("data-radar-opaque", "Scene.tsx");
57
+ expect(findings).toHaveLength(1);
58
+ expect(findings[0].message).toMatch(/cannot evaluate/);
59
+ });
60
+ });