@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.
- package/README.md +56 -0
- package/dist/anchors.js +69 -0
- package/dist/corpus.js +91 -0
- package/dist/projectDoc.js +83 -0
- package/dist/projectDocSync.js +39 -0
- package/dist/projectMeta.js +37 -0
- package/dist/provenance.js +41 -0
- package/dist/radar-check-ids.json +34 -0
- package/dist/registry.js +307 -0
- package/dist/rules/animatedBarChartTightBox.js +15 -0
- package/dist/rules/animatedBarChartWhenNotToUse.js +15 -0
- package/dist/rules/animatedBarChartWhenToUse.js +15 -0
- package/dist/rules/animatedLineChartWhenNotToUse.js +15 -0
- package/dist/rules/animatedLineChartWhenToUse.js +15 -0
- package/dist/rules/approvedSfxPaletteOnly.js +15 -0
- package/dist/rules/atmosphereGradientsFadeAtBothEnds.js +15 -0
- package/dist/rules/audioIsTheClock.js +16 -0
- package/dist/rules/beatsDeriveFromTheirOwnSequence.js +15 -0
- package/dist/rules/bestSceneSetsTheBar.js +15 -0
- package/dist/rules/bumpBeforeRefreeze.js +15 -0
- package/dist/rules/cameraIsTheNarrator.js +15 -0
- package/dist/rules/checkPinBeforeShip.js +16 -0
- package/dist/rules/coldViewerClarity.js +15 -0
- package/dist/rules/commitOrCutEffects.js +29 -0
- package/dist/rules/convertFramesAcrossClockBoundary.js +15 -0
- package/dist/rules/crossCutElementsLiveInTheHudLayer.js +15 -0
- package/dist/rules/cursorClicksRealControls.js +15 -0
- package/dist/rules/cutOnRealAudioPauses.js +15 -0
- package/dist/rules/darkButNeverDim.js +15 -0
- package/dist/rules/dataRadarTagsDeclared.js +193 -0
- package/dist/rules/declareAVerticalZoneMap.js +15 -0
- package/dist/rules/deleteRejectedRigsCompletely.js +15 -0
- package/dist/rules/deriveSeamsDontMeasure.js +17 -0
- package/dist/rules/deterministicSceneSource.js +65 -0
- package/dist/rules/diegeticSoundForOnscreenActions.js +15 -0
- package/dist/rules/distinctTransitionPerBeat.js +15 -0
- package/dist/rules/downloadOrDrawRichAssets.js +15 -0
- package/dist/rules/elementOnscreenForItsVoSentence.js +17 -0
- package/dist/rules/emitBuildNotes.js +15 -0
- package/dist/rules/energyFromTimingNotPartCount.js +15 -0
- package/dist/rules/evidenceBeforeClaimingFixed.js +15 -0
- package/dist/rules/exactPeerLockstep.js +15 -0
- package/dist/rules/firstPassIsADraft.js +15 -0
- package/dist/rules/fixCrowdingByRebandingNotNudging.js +15 -0
- package/dist/rules/fixesPreserveApprovedElements.js +15 -0
- package/dist/rules/floatingNotBoxed.js +15 -0
- package/dist/rules/focusBeatsRecedeTheContext.js +15 -0
- package/dist/rules/fontVarsBrandRemocn.js +15 -0
- package/dist/rules/geometricSeamsNotCrossfades.js +23 -0
- package/dist/rules/geometrySidecarExportsTyped.js +36 -0
- package/dist/rules/glowIsAFocalAccent.js +22 -0
- package/dist/rules/heroFillsTheFrame.js +17 -0
- package/dist/rules/htmlMasksForAnimatedCounters.js +15 -0
- package/dist/rules/impactStackOnPayoffs.js +15 -0
- package/dist/rules/interactiveTargetsAreDeclaredData.js +15 -0
- package/dist/rules/interpolateLiteralKeysMonotonic.js +79 -0
- package/dist/rules/latenessIsStructuralOverlapTheBeats.js +15 -0
- package/dist/rules/lessTextMoreVisualizations.js +15 -0
- package/dist/rules/liveLinkDuplicateReactAlias.js +15 -0
- package/dist/rules/make2dElements3d.js +15 -0
- package/dist/rules/masterMixLoudnessTarget.js +17 -0
- package/dist/rules/measureAlignmentDontEyeball.js +15 -0
- package/dist/rules/motionCarriesWeightAndMeaning.js +15 -0
- package/dist/rules/motionDensityFloor.js +15 -0
- package/dist/rules/neverEditTierBVendored.js +15 -0
- package/dist/rules/neverRestateDerivedFrameNumbersInComments.js +15 -0
- package/dist/rules/noAiGradientLook.js +15 -0
- package/dist/rules/noColoredFlashToHideACut.js +22 -0
- package/dist/rules/noDoubleFrameShift.js +126 -0
- package/dist/rules/noDuplicateMotionPrimitives.js +15 -0
- package/dist/rules/noLinearMotion.js +22 -0
- package/dist/rules/noNestedSvgFilters.js +93 -0
- package/dist/rules/noRepeatedAssetAcrossShots.js +15 -0
- package/dist/rules/noShorthandWithUndefinedLonghand.js +93 -0
- package/dist/rules/noStackedFadesAtACut.js +24 -0
- package/dist/rules/noStaticHolds.js +17 -0
- package/dist/rules/occlusionVisibleElements.js +17 -0
- package/dist/rules/oneContinuousVoTrack.js +15 -0
- package/dist/rules/onePunchPerMomentClass.js +15 -0
- package/dist/rules/oneRenderPerRound.js +15 -0
- package/dist/rules/openStaticAfterAHardCut.js +22 -0
- package/dist/rules/openingsAndClosingsCarryMore.js +15 -0
- package/dist/rules/persistentDeviceFrames.js +15 -0
- package/dist/rules/pixelDiffAnEmptyBandFirst.js +15 -0
- package/dist/rules/planIsPublishedNotGating.js +15 -0
- package/dist/rules/poweredByRevolaWatermark.js +15 -0
- package/dist/rules/predrawContentPresentAtTheCut.js +17 -0
- package/dist/rules/premiumSurfacesNotFlatBorders.js +15 -0
- package/dist/rules/radarDispositionsAreHumanOnly.js +17 -0
- package/dist/rules/realAssetsNotPlaceholders.js +15 -0
- package/dist/rules/rebuildUiFromReconNotScreenshots.js +15 -0
- package/dist/rules/reconStrandsRunInParallel.js +15 -0
- package/dist/rules/registryBeforeHandrolling.js +15 -0
- package/dist/rules/remapRateEndpointFormula.js +15 -0
- package/dist/rules/remocnContentTailwindChrome.js +15 -0
- package/dist/rules/retimeOnlyViaPlaybackOrDesignTokens.js +15 -0
- package/dist/rules/reviewTheRenderByFrameSweep.js +15 -0
- package/dist/rules/rollingNumberBoundedSequence.js +17 -0
- package/dist/rules/rollingNumberSequenceLayoutNone.js +16 -0
- package/dist/rules/rollingNumberTightBoxAlignment.js +15 -0
- package/dist/rules/rollingNumberWhenNotToUse.js +17 -0
- package/dist/rules/rollingNumberWhenToUse.js +17 -0
- package/dist/rules/sameFamilySameProject.js +15 -0
- package/dist/rules/sampleBrandFromProduct.js +15 -0
- package/dist/rules/sampleVelocityFromPreviousFramePosition.js +15 -0
- package/dist/rules/sceneRootTagDeclared.js +41 -0
- package/dist/rules/scrubDemoDataToGenericRoles.js +15 -0
- package/dist/rules/selfReviewThePlanForGaps.js +15 -0
- package/dist/rules/sourceArchivedBeforeBrief.js +17 -0
- package/dist/rules/statisticsSelfExplanatory.js +15 -0
- package/dist/rules/stopsAsRelativeSpacing.js +15 -0
- package/dist/rules/theWholeCanvasWorks.js +15 -0
- package/dist/rules/themePerSection.js +22 -0
- package/dist/rules/thesisDeclaredInBrief.js +17 -0
- package/dist/rules/tierARequiresPropUnreachableEdit.js +15 -0
- package/dist/rules/tinyBodyCopyAsRuledLines.js +15 -0
- package/dist/rules/titlesPinnedOutsideCameraPush.js +15 -0
- package/dist/rules/tokensNotRawHexes.js +60 -0
- package/dist/rules/typeTokenDefaultedParamsAsString.js +15 -0
- package/dist/rules/varyKitChoreographyAcrossSections.js +15 -0
- package/dist/rules/varyTheVisualizationGrammar.js +15 -0
- package/dist/rules/verifyCheapRenderDear.js +15 -0
- package/dist/rules/voAddressesTheViewer.js +15 -0
- package/dist/rules/voIsAPerformance.js +15 -0
- package/dist/rules/voScriptLocksSpokenWords.js +15 -0
- package/dist/rules/wrappersPreserveChildGeometry.js +15 -0
- package/dist/sourceCheck.js +47 -0
- package/dist/sourceCitations.js +68 -0
- package/dist/stageProjection.js +69 -0
- package/dist/stages.js +163 -0
- package/dist/testSupport.js +6 -0
- package/dist/types.js +0 -0
- package/dist/variants.js +8 -0
- package/dist/waiverProjection.js +20 -0
- package/package.json +32 -0
- package/src/anchors.test.ts +119 -0
- package/src/anchors.ts +110 -0
- package/src/corpus.test.ts +96 -0
- package/src/corpus.ts +149 -0
- package/src/corpusProject.test.ts +103 -0
- package/src/creativeEdge.test.ts +58 -0
- package/src/distBuild.test.ts +86 -0
- package/src/docStatus.test.ts +81 -0
- package/src/drift.test.ts +124 -0
- package/src/fixtures/data-radar-dynamic/Branches.tsx +14 -0
- package/src/fixtures/data-radar-dynamic/plan.fixture.yaml +16 -0
- package/src/fixtures/data-radar-forwarded/Scene.tsx +19 -0
- package/src/fixtures/data-radar-forwarded/plan.fixture.yaml +13 -0
- package/src/fixtures/data-radar-opaque/Scene.tsx +15 -0
- package/src/fixtures/data-radar-opaque/plan.fixture.yaml +10 -0
- package/src/fixtures/data-radar-tags/SceneClean.tsx +10 -0
- package/src/fixtures/data-radar-tags/SceneNullBinding.tsx +12 -0
- package/src/fixtures/data-radar-tags/SceneWithGap.tsx +11 -0
- package/src/fixtures/data-radar-tags/plan.fixture.yaml +29 -0
- package/src/fixtures/deterministic-scene.tsx +15 -0
- package/src/fixtures/double-shift/aliased.tsx +13 -0
- package/src/fixtures/double-shift/assigned.tsx +13 -0
- package/src/fixtures/double-shift/clean.tsx +19 -0
- package/src/fixtures/double-shift/destructured.tsx +12 -0
- package/src/fixtures/double-shift/elementAccess.tsx +12 -0
- package/src/fixtures/double-shift/layout.ts +24 -0
- package/src/fixtures/double-shift/mechanism-prefix.tsx.txt +458 -0
- package/src/fixtures/double-shift/wrapped.tsx +15 -0
- package/src/fixtures/geometry-sidecar-missing-export.ts +10 -0
- package/src/fixtures/geometry-sidecar-missing-type.ts +7 -0
- package/src/fixtures/geometry-sidecar-valid.ts +6 -0
- package/src/fixtures/interpolate-ascending.tsx +6 -0
- package/src/fixtures/interpolate-descending.tsx +8 -0
- package/src/fixtures/interpolate-identifier-keys.tsx +9 -0
- package/src/fixtures/nested-filters-broken.tsx +11 -0
- package/src/fixtures/nested-filters-fixed.tsx +8 -0
- package/src/fixtures/nested-filters-html-wrapper.tsx +14 -0
- package/src/fixtures/nested-filters-html.tsx +7 -0
- package/src/fixtures/nested-filters-siblings.tsx +12 -0
- package/src/fixtures/nondeterministic-scene.tsx +14 -0
- package/src/fixtures/nondeterministic-variants.tsx +16 -0
- package/src/fixtures/raw-hex-scene.tsx +10 -0
- package/src/fixtures/scene-root-declared/SceneHook.tsx +9 -0
- package/src/fixtures/scene-root-declared/plan.fixture.yaml +10 -0
- package/src/fixtures/scene-root-missing/SceneHook.tsx +11 -0
- package/src/fixtures/scene-root-missing/plan.fixture.yaml +10 -0
- package/src/fixtures/scene-root-no-names/SceneHook.tsx +6 -0
- package/src/fixtures/scene-root-no-names/plan.fixture.yaml +6 -0
- package/src/fixtures/scene-root-shell/SceneHook.tsx +8 -0
- package/src/fixtures/scene-root-shell/Shell.tsx +9 -0
- package/src/fixtures/scene-root-shell/plan.fixture.yaml +10 -0
- package/src/fixtures/shorthand-undefined-clean.tsx +23 -0
- package/src/fixtures/shorthand-undefined-longhand.tsx +17 -0
- package/src/fixtures/token-scene.tsx +9 -0
- package/src/includeCoverage.test.ts +176 -0
- package/src/learnedFrom.test.ts +32 -0
- package/src/projectDoc.test.ts +230 -0
- package/src/projectDoc.ts +152 -0
- package/src/projectDocSync.test.ts +152 -0
- package/src/projectDocSync.ts +79 -0
- package/src/projectMeta.test.ts +75 -0
- package/src/projectMeta.ts +53 -0
- package/src/provenance.ts +85 -0
- package/src/radar-check-ids.json +34 -0
- package/src/registry.test.ts +207 -0
- package/src/registry.ts +352 -0
- package/src/rules/animatedBarChartTightBox.ts +14 -0
- package/src/rules/animatedBarChartWhenNotToUse.ts +14 -0
- package/src/rules/animatedBarChartWhenToUse.ts +14 -0
- package/src/rules/animatedLineChartWhenNotToUse.ts +14 -0
- package/src/rules/animatedLineChartWhenToUse.ts +14 -0
- package/src/rules/approvedSfxPaletteOnly.ts +23 -0
- package/src/rules/atmosphereGradientsFadeAtBothEnds.ts +21 -0
- package/src/rules/audioIsTheClock.ts +22 -0
- package/src/rules/beatsDeriveFromTheirOwnSequence.ts +21 -0
- package/src/rules/bestSceneSetsTheBar.ts +21 -0
- package/src/rules/bumpBeforeRefreeze.ts +20 -0
- package/src/rules/cameraIsTheNarrator.ts +21 -0
- package/src/rules/checkPinBeforeShip.ts +22 -0
- package/src/rules/coldViewerClarity.ts +21 -0
- package/src/rules/commitOrCutEffects.ts +36 -0
- package/src/rules/convertFramesAcrossClockBoundary.ts +19 -0
- package/src/rules/crossCutElementsLiveInTheHudLayer.ts +21 -0
- package/src/rules/cursorClicksRealControls.ts +22 -0
- package/src/rules/cutOnRealAudioPauses.ts +20 -0
- package/src/rules/darkButNeverDim.ts +21 -0
- package/src/rules/dataRadarTagsDeclared.test.ts +60 -0
- package/src/rules/dataRadarTagsDeclared.ts +341 -0
- package/src/rules/declareAVerticalZoneMap.ts +19 -0
- package/src/rules/deleteRejectedRigsCompletely.ts +19 -0
- package/src/rules/deriveSeamsDontMeasure.ts +23 -0
- package/src/rules/deterministicSceneSource.test.ts +58 -0
- package/src/rules/deterministicSceneSource.ts +82 -0
- package/src/rules/diegeticSoundForOnscreenActions.ts +21 -0
- package/src/rules/distinctTransitionPerBeat.ts +21 -0
- package/src/rules/downloadOrDrawRichAssets.ts +22 -0
- package/src/rules/elementOnscreenForItsVoSentence.ts +25 -0
- package/src/rules/emitBuildNotes.ts +19 -0
- package/src/rules/energyFromTimingNotPartCount.ts +20 -0
- package/src/rules/evidenceBeforeClaimingFixed.ts +23 -0
- package/src/rules/exactPeerLockstep.ts +19 -0
- package/src/rules/firstPassIsADraft.ts +20 -0
- package/src/rules/fixCrowdingByRebandingNotNudging.ts +20 -0
- package/src/rules/fixesPreserveApprovedElements.ts +24 -0
- package/src/rules/floatingNotBoxed.ts +21 -0
- package/src/rules/focusBeatsRecedeTheContext.ts +20 -0
- package/src/rules/fontVarsBrandRemocn.ts +20 -0
- package/src/rules/geometricSeamsNotCrossfades.ts +28 -0
- package/src/rules/geometrySidecarExportsTyped.test.ts +37 -0
- package/src/rules/geometrySidecarExportsTyped.ts +59 -0
- package/src/rules/glowIsAFocalAccent.ts +28 -0
- package/src/rules/heroFillsTheFrame.ts +24 -0
- package/src/rules/htmlMasksForAnimatedCounters.ts +21 -0
- package/src/rules/impactStackOnPayoffs.ts +26 -0
- package/src/rules/interactiveTargetsAreDeclaredData.ts +21 -0
- package/src/rules/interpolateLiteralKeysMonotonic.test.ts +49 -0
- package/src/rules/interpolateLiteralKeysMonotonic.ts +98 -0
- package/src/rules/latenessIsStructuralOverlapTheBeats.ts +20 -0
- package/src/rules/lessTextMoreVisualizations.ts +22 -0
- package/src/rules/liveLinkDuplicateReactAlias.ts +22 -0
- package/src/rules/make2dElements3d.ts +21 -0
- package/src/rules/masterMixLoudnessTarget.ts +22 -0
- package/src/rules/measureAlignmentDontEyeball.ts +20 -0
- package/src/rules/motionCarriesWeightAndMeaning.ts +21 -0
- package/src/rules/motionDensityFloor.ts +20 -0
- package/src/rules/neverEditTierBVendored.ts +20 -0
- package/src/rules/neverRestateDerivedFrameNumbersInComments.ts +20 -0
- package/src/rules/noAiGradientLook.ts +22 -0
- package/src/rules/noColoredFlashToHideACut.ts +29 -0
- package/src/rules/noDoubleFrameShift.test.ts +95 -0
- package/src/rules/noDoubleFrameShift.ts +193 -0
- package/src/rules/noDuplicateMotionPrimitives.ts +19 -0
- package/src/rules/noLinearMotion.ts +29 -0
- package/src/rules/noNestedSvgFilters.test.ts +47 -0
- package/src/rules/noNestedSvgFilters.ts +138 -0
- package/src/rules/noRepeatedAssetAcrossShots.ts +19 -0
- package/src/rules/noShorthandWithUndefinedLonghand.test.ts +35 -0
- package/src/rules/noShorthandWithUndefinedLonghand.ts +140 -0
- package/src/rules/noStackedFadesAtACut.ts +30 -0
- package/src/rules/noStaticHolds.ts +24 -0
- package/src/rules/occlusionVisibleElements.ts +26 -0
- package/src/rules/oneContinuousVoTrack.ts +20 -0
- package/src/rules/onePunchPerMomentClass.ts +20 -0
- package/src/rules/oneRenderPerRound.ts +46 -0
- package/src/rules/openStaticAfterAHardCut.ts +29 -0
- package/src/rules/openingsAndClosingsCarryMore.ts +21 -0
- package/src/rules/persistentDeviceFrames.ts +20 -0
- package/src/rules/pixelDiffAnEmptyBandFirst.ts +20 -0
- package/src/rules/planIsPublishedNotGating.ts +32 -0
- package/src/rules/poweredByRevolaWatermark.ts +19 -0
- package/src/rules/predrawContentPresentAtTheCut.ts +21 -0
- package/src/rules/premiumSurfacesNotFlatBorders.ts +20 -0
- package/src/rules/radarDispositionsAreHumanOnly.ts +28 -0
- package/src/rules/realAssetsNotPlaceholders.ts +21 -0
- package/src/rules/rebuildUiFromReconNotScreenshots.ts +21 -0
- package/src/rules/reconStrandsRunInParallel.ts +63 -0
- package/src/rules/registryBeforeHandrolling.ts +20 -0
- package/src/rules/remapRateEndpointFormula.ts +19 -0
- package/src/rules/remocnContentTailwindChrome.ts +19 -0
- package/src/rules/retimeOnlyViaPlaybackOrDesignTokens.ts +18 -0
- package/src/rules/reviewTheRenderByFrameSweep.ts +23 -0
- package/src/rules/rollingNumberBoundedSequence.ts +21 -0
- package/src/rules/rollingNumberSequenceLayoutNone.ts +22 -0
- package/src/rules/rollingNumberTightBoxAlignment.ts +19 -0
- package/src/rules/rollingNumberWhenNotToUse.ts +24 -0
- package/src/rules/rollingNumberWhenToUse.ts +23 -0
- package/src/rules/sameFamilySameProject.ts +20 -0
- package/src/rules/sampleBrandFromProduct.ts +19 -0
- package/src/rules/sampleVelocityFromPreviousFramePosition.ts +21 -0
- package/src/rules/sceneRootTagDeclared.test.ts +43 -0
- package/src/rules/sceneRootTagDeclared.ts +78 -0
- package/src/rules/scrubDemoDataToGenericRoles.ts +19 -0
- package/src/rules/selfReviewThePlanForGaps.ts +47 -0
- package/src/rules/sourceArchivedBeforeBrief.ts +24 -0
- package/src/rules/statisticsSelfExplanatory.ts +18 -0
- package/src/rules/stopsAsRelativeSpacing.ts +21 -0
- package/src/rules/theWholeCanvasWorks.ts +21 -0
- package/src/rules/themePerSection.ts +28 -0
- package/src/rules/thesisDeclaredInBrief.ts +25 -0
- package/src/rules/tierARequiresPropUnreachableEdit.ts +20 -0
- package/src/rules/tinyBodyCopyAsRuledLines.ts +19 -0
- package/src/rules/titlesPinnedOutsideCameraPush.ts +22 -0
- package/src/rules/tokensNotRawHexes.test.ts +51 -0
- package/src/rules/tokensNotRawHexes.ts +89 -0
- package/src/rules/typeTokenDefaultedParamsAsString.ts +21 -0
- package/src/rules/varyKitChoreographyAcrossSections.ts +21 -0
- package/src/rules/varyTheVisualizationGrammar.ts +22 -0
- package/src/rules/verifyCheapRenderDear.ts +18 -0
- package/src/rules/voAddressesTheViewer.ts +18 -0
- package/src/rules/voIsAPerformance.ts +21 -0
- package/src/rules/voScriptLocksSpokenWords.ts +21 -0
- package/src/rules/wrappersPreserveChildGeometry.ts +22 -0
- package/src/sourceCheck.test.ts +50 -0
- package/src/sourceCheck.ts +55 -0
- package/src/sourceCitations.test.ts +747 -0
- package/src/sourceCitations.ts +217 -0
- package/src/stageProjection.ts +112 -0
- package/src/stages.test.ts +68 -0
- package/src/stages.ts +207 -0
- package/src/testSupport.ts +16 -0
- package/src/types.ts +181 -0
- package/src/variants.test.ts +24 -0
- package/src/variants.ts +13 -0
- package/src/waiverProjection.test.ts +59 -0
- package/src/waiverProjection.ts +45 -0
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import { AbsoluteFill, useCurrentFrame, spring, interpolate, interpolateColors, Easing } from "remotion";
|
|
3
|
+
import { FrameCam, CinematicStage, DustMotes, RingPulse, punchScale, rgba, type CamKey } from "@revola/video-kit/craft";
|
|
4
|
+
import { RevolaWatermark, spr, lerp, window4, SPRING } from "@revola/video-kit/react";
|
|
5
|
+
import {
|
|
6
|
+
windowFor,
|
|
7
|
+
cue,
|
|
8
|
+
expectCues,
|
|
9
|
+
WALL,
|
|
10
|
+
LIT_AT_OPEN,
|
|
11
|
+
DOCK_CELLS,
|
|
12
|
+
cellX,
|
|
13
|
+
cellY,
|
|
14
|
+
ZONE,
|
|
15
|
+
FOOTER_TEXT_X,
|
|
16
|
+
FPS,
|
|
17
|
+
} from "../layout";
|
|
18
|
+
import { EX } from "../tokens";
|
|
19
|
+
import { TIER } from "../text";
|
|
20
|
+
import { geometry } from "./scene.mechanism.geometry";
|
|
21
|
+
|
|
22
|
+
expectCues("mechanism", 4);
|
|
23
|
+
|
|
24
|
+
// VERTICAL ZONE MAP (declare-a-vertical-zone-map, values from ZONE in
|
|
25
|
+
// src/layout.ts):
|
|
26
|
+
// copy band ZONE.copy - HUD kicker + headline, SCREEN SPACE only.
|
|
27
|
+
// breath band ZONE.breath - nothing enters, ever.
|
|
28
|
+
// stage band ZONE.stage - the persistent GPU wall, the job ticket, the
|
|
29
|
+
// hex mark, the dock ignition. Camera keys below
|
|
30
|
+
// are chosen so the world never rises past the
|
|
31
|
+
// breath band at any key's extreme.
|
|
32
|
+
// footer band ZONE.footer - footnote (left) + Revola watermark (right),
|
|
33
|
+
// SCREEN SPACE only.
|
|
34
|
+
|
|
35
|
+
const SEC = "mechanism" as const;
|
|
36
|
+
if (geometry.sectionId !== SEC) {
|
|
37
|
+
throw new Error(`mechanism: geometry sidecar declares "${geometry.sectionId}", scene renders "${SEC}"`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The ticket's authored (design-space) size and its two flight stations.
|
|
41
|
+
const TICKET_W = 340;
|
|
42
|
+
const TICKET_H = 224;
|
|
43
|
+
const STATION = { x: 1400, y: 520 } as const; // scan station, right third of the stage band
|
|
44
|
+
const ENTER = { x: 2320, y: 430 } as const; // off-frame right, above the station
|
|
45
|
+
|
|
46
|
+
const WALL_W = WALL.cols * WALL.cellW + (WALL.cols - 1) * WALL.gapX;
|
|
47
|
+
const WALL_H = WALL.rows * WALL.cellH + (WALL.rows - 1) * WALL.gapY;
|
|
48
|
+
|
|
49
|
+
// The single receiving slot: the ticket docks flush into the first dark cell
|
|
50
|
+
// of the cluster; the remaining cluster cells ignite in cascade from it.
|
|
51
|
+
const SLOT = DOCK_CELLS[0];
|
|
52
|
+
const slotCx = cellX(SLOT) + WALL.cellW / 2;
|
|
53
|
+
const slotCy = cellY(SLOT) + WALL.cellH / 2;
|
|
54
|
+
|
|
55
|
+
/** The Expanse hex-cluster mark, hand-authored from the committed brand SVG
|
|
56
|
+
* (02_assets/brand/expanse-logo.svg, wheel only, no wordmark) so its spin-in
|
|
57
|
+
* runs on the frame clock instead of the source file's CSS keyframes
|
|
58
|
+
* (deterministic-scene-source). */
|
|
59
|
+
const HexMark: React.FC<{ size: number; ink: string }> = ({ size, ink }) => (
|
|
60
|
+
<svg width={size} height={size} viewBox="0 0 100 100">
|
|
61
|
+
<circle cx="50" cy="50" r="35" stroke={ink} strokeWidth="4.5" fill="none" />
|
|
62
|
+
{[0, 60, 120, 180, 240, 300].map((deg) => (
|
|
63
|
+
<g key={deg} transform={`rotate(${deg} 50 50)`}>
|
|
64
|
+
<line x1="50" y1="50" x2="50" y2="15" stroke={ink} strokeWidth="4.5" />
|
|
65
|
+
<circle cx="50" cy="15" r="8" fill={ink} />
|
|
66
|
+
</g>
|
|
67
|
+
))}
|
|
68
|
+
<circle cx="50" cy="50" r="16" fill={ink} />
|
|
69
|
+
</svg>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
/** One wall cell. Same grid constants as every scene (the persistent set);
|
|
73
|
+
* dock-cluster cells are the dark material the ticket lands in, and ignite
|
|
74
|
+
* coral in a cascade after contact. */
|
|
75
|
+
const Cell: React.FC<{ i: number; lf: number; landF: number }> = ({ i, lf, landF }) => {
|
|
76
|
+
const isLit = LIT_AT_OPEN.includes(i);
|
|
77
|
+
const dockIdx = DOCK_CELLS.indexOf(i);
|
|
78
|
+
const isDock = dockIdx >= 0;
|
|
79
|
+
|
|
80
|
+
const ignite = isDock
|
|
81
|
+
? spring({ frame: Math.max(0, lf - landF - dockIdx * 4), fps: FPS, config: { damping: 13, mass: 0.7 } })
|
|
82
|
+
: 0;
|
|
83
|
+
|
|
84
|
+
// Idle living motion on lit cells: a slow phase-offset shimmer, seeded by
|
|
85
|
+
// index (no-static-holds without a second competing subject).
|
|
86
|
+
const shimmer = isLit ? 0.82 + 0.18 * Math.sin(lf * 0.06 + i * 1.7) : 0;
|
|
87
|
+
|
|
88
|
+
const base = isDock ? interpolateColors(ignite, [0, 1], [EX.buttonBg, EX.coral]) : isLit ? EX.coral : EX.cellUnlit;
|
|
89
|
+
const punch = isDock ? 1 + Math.sin(Math.min(1, ignite) * Math.PI) * 0.07 : 1;
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div
|
|
93
|
+
style={{
|
|
94
|
+
position: "absolute",
|
|
95
|
+
left: cellX(i),
|
|
96
|
+
top: cellY(i),
|
|
97
|
+
width: WALL.cellW,
|
|
98
|
+
height: WALL.cellH,
|
|
99
|
+
transform: `scale(${punch})`,
|
|
100
|
+
borderRadius: 8,
|
|
101
|
+
backgroundColor: base,
|
|
102
|
+
border: `1px solid ${isLit || ignite > 0.3 ? rgba(EX.white, 0.45) : EX.hairline}`,
|
|
103
|
+
boxShadow:
|
|
104
|
+
ignite > 0.05
|
|
105
|
+
? `0 10px 26px ${rgba(EX.ink, 0.16)}, 0 0 ${26 * ignite}px ${rgba(EX.coral, 0.55 * ignite)}`
|
|
106
|
+
: `0 10px 26px ${rgba(EX.ink, 0.1)}`,
|
|
107
|
+
}}
|
|
108
|
+
>
|
|
109
|
+
{/* Board detailing: dashed carrier outline, corner standoffs, die. */}
|
|
110
|
+
<svg width="100%" height="100%" style={{ position: "absolute", inset: 0, opacity: isLit ? 0.75 * shimmer : isDock ? 0.5 : 0.35 }}>
|
|
111
|
+
<rect
|
|
112
|
+
x="8"
|
|
113
|
+
y="8"
|
|
114
|
+
width={WALL.cellW - 16}
|
|
115
|
+
height={WALL.cellH - 16}
|
|
116
|
+
rx="3"
|
|
117
|
+
stroke={isLit || ignite > 0.3 ? EX.white : EX.inkMuted}
|
|
118
|
+
fill="none"
|
|
119
|
+
strokeWidth="1"
|
|
120
|
+
strokeDasharray="2 3"
|
|
121
|
+
/>
|
|
122
|
+
{[
|
|
123
|
+
[14, 14],
|
|
124
|
+
[WALL.cellW - 14, 14],
|
|
125
|
+
[14, WALL.cellH - 14],
|
|
126
|
+
[WALL.cellW - 14, WALL.cellH - 14],
|
|
127
|
+
].map(([x, y]) => (
|
|
128
|
+
<circle key={`${x}-${y}`} cx={x} cy={y} r="2" fill={isLit || ignite > 0.3 ? EX.white : EX.inkMuted} />
|
|
129
|
+
))}
|
|
130
|
+
<rect
|
|
131
|
+
x={WALL.cellW / 2 - 34}
|
|
132
|
+
y={WALL.cellH / 2 - 26}
|
|
133
|
+
width={68}
|
|
134
|
+
height={52}
|
|
135
|
+
rx="3"
|
|
136
|
+
fill={isLit || ignite > 0.3 ? rgba(EX.white, 0.25) : rgba(EX.ink, 0.06)}
|
|
137
|
+
/>
|
|
138
|
+
</svg>
|
|
139
|
+
{/* Top sheen so the slab reads as material, not flat fill. */}
|
|
140
|
+
<div
|
|
141
|
+
style={{
|
|
142
|
+
position: "absolute",
|
|
143
|
+
inset: 0,
|
|
144
|
+
borderRadius: 8,
|
|
145
|
+
background: `linear-gradient(180deg, ${rgba(EX.white, isLit ? 0.22 : 0.4)} 0%, transparent 38%)`,
|
|
146
|
+
}}
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export const S2Mechanism: React.FC = () => {
|
|
153
|
+
const frame = useCurrentFrame();
|
|
154
|
+
const win = windowFor(SEC);
|
|
155
|
+
const lf = frame - win.from;
|
|
156
|
+
|
|
157
|
+
const c0 = cue(SEC, 0); // "Expanse predicts resource fit and failure risk"
|
|
158
|
+
const c1 = cue(SEC, 1); // "the" (breath cue) - hex mark docks, scan starts
|
|
159
|
+
const c2 = cue(SEC, 2); // "moment a job is submitted" - readouts + T+0ms
|
|
160
|
+
const c3 = cue(SEC, 3); // "so more work lands on the same hardware"
|
|
161
|
+
const endF = win.durationInFrames;
|
|
162
|
+
|
|
163
|
+
// ---- job-ticket flight, evaluated as a pure function of frame so motion
|
|
164
|
+
// blur samples the PREVIOUS frame's real position, never a curve-parameter
|
|
165
|
+
// delta (sample-velocity-from-previous-frame-position).
|
|
166
|
+
// Negative predraw start (predraw-content-present-at-the-cut): the elegant
|
|
167
|
+
// spring is slow and heavy, so the flight begins well before the window and
|
|
168
|
+
// the ticket is docked at the station, fully settled and inside the frame,
|
|
169
|
+
// before its own sentence (cue 0) starts speaking.
|
|
170
|
+
const tEnter = c0 - 64;
|
|
171
|
+
const dockScale = WALL.cellW / TICKET_W;
|
|
172
|
+
const ticketAt = (f: number) => {
|
|
173
|
+
const e = spr(f, tEnter, FPS, SPRING.elegant);
|
|
174
|
+
const d = spr(f, c3, FPS, SPRING.elegant);
|
|
175
|
+
const x = STATION.x + (1 - e) * (ENTER.x - STATION.x) + d * (slotCx - STATION.x);
|
|
176
|
+
const y =
|
|
177
|
+
STATION.y +
|
|
178
|
+
(1 - e) * (ENTER.y - STATION.y) -
|
|
179
|
+
Math.sin(e * Math.PI) * 70 +
|
|
180
|
+
d * (slotCy - STATION.y) -
|
|
181
|
+
Math.sin(d * Math.PI) * 120;
|
|
182
|
+
const rot = (1 - e) * 9 - Math.sin(d * Math.PI) * 6;
|
|
183
|
+
const scale = (0.92 + 0.08 * e) * (1 + d * (dockScale - 1));
|
|
184
|
+
return { x, y, rot, scale, d };
|
|
185
|
+
};
|
|
186
|
+
const tk = ticketAt(lf);
|
|
187
|
+
const tkPrev = ticketAt(lf - 1);
|
|
188
|
+
const tkSpeed = Math.hypot(tk.x - tkPrev.x, tk.y - tkPrev.y);
|
|
189
|
+
const tkBlur = tkSpeed > 16 ? Math.min(3.5, (tkSpeed - 16) * 0.09) : 0;
|
|
190
|
+
|
|
191
|
+
// Contact: the frame the dock spring has essentially landed. Squash +
|
|
192
|
+
// ring pulse + cascade all key off this one moment (impact-stack-on-payoffs).
|
|
193
|
+
const landF = c3 + 14;
|
|
194
|
+
const landSquash = punchScale(lf, landF, 0.06, 9);
|
|
195
|
+
// After contact the ticket fuses into the slot cell: it fades as the cell
|
|
196
|
+
// ignites, so the clicked object literally BECOMES the set's next state.
|
|
197
|
+
const tkFade = interpolate(lf, [landF + 4, landF + 16], [1, 0], {
|
|
198
|
+
extrapolateLeft: "clamp",
|
|
199
|
+
extrapolateRight: "clamp",
|
|
200
|
+
easing: Easing.inOut(Easing.quad),
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// ---- hex mark: spins in beside the ticket on cue 1, then holds while the
|
|
204
|
+
// scanline it drives crosses the card.
|
|
205
|
+
// Enter early enough (overlapping cue 0) that the snappy spring is fully
|
|
206
|
+
// settled and the mark at opacity 1 before its breath cue (cue 1) begins.
|
|
207
|
+
const hex = spr(lf, c1 - 22, FPS, SPRING.snappy);
|
|
208
|
+
const hexSpin = (1 - hex) * -240;
|
|
209
|
+
|
|
210
|
+
// ---- scanline across the card (the scene's one focal glow, with the dock
|
|
211
|
+
// ignition: glow-is-a-focal-accent).
|
|
212
|
+
const scanT = interpolate(lf, [c1, c1 + 26], [0, 1], {
|
|
213
|
+
extrapolateLeft: "clamp",
|
|
214
|
+
extrapolateRight: "clamp",
|
|
215
|
+
easing: Easing.inOut(Easing.cubic),
|
|
216
|
+
});
|
|
217
|
+
const scanAlpha = window4(lf, c1 - 2, c1 + 4, c1 + 22, c1 + 30);
|
|
218
|
+
|
|
219
|
+
// ---- readout typing, staggered mono rows on cue 2.
|
|
220
|
+
const row1 = "RESOURCE FIT · PREDICTED";
|
|
221
|
+
const row2 = "FAILURE RISK · LOW";
|
|
222
|
+
// Typing overlaps the scan beat (lateness-is-structural-overlap-the-beats)
|
|
223
|
+
// so both rows are fully typed, opacity 1 and settled before cue 2 - the
|
|
224
|
+
// sentence that names the readout - starts speaking.
|
|
225
|
+
const typed1 = row1.slice(0, Math.round(lerp(lf, [c2 - 26, c2 - 10], [0, row1.length])));
|
|
226
|
+
const typed2 = row2.slice(0, Math.round(lerp(lf, [c2 - 20, c2 - 4], [0, row2.length])));
|
|
227
|
+
const rowSettled1 = spr(lf, c2 - 26, FPS, SPRING.snappy);
|
|
228
|
+
const rowSettled2 = spr(lf, c2 - 20, FPS, SPRING.snappy);
|
|
229
|
+
|
|
230
|
+
// ---- T+0ms stamp on the spoken submission beat (cue 2), gone by dock.
|
|
231
|
+
const stampIn = spr(lf, c2, FPS, SPRING.bouncy);
|
|
232
|
+
const stampOut = interpolate(lf, [c3, c3 + 8], [1, 0], {
|
|
233
|
+
extrapolateLeft: "clamp",
|
|
234
|
+
extrapolateRight: "clamp",
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// ---- camera: open static (two equal keys), one committed push into the
|
|
238
|
+
// ticket while it is scanned (dwell), one follow to the slot, then the
|
|
239
|
+
// pull-back that unlock inherits (camera-is-the-narrator).
|
|
240
|
+
const camKeys: CamKey[] = [
|
|
241
|
+
{ f: 0, scale: 1.24, cx: WALL.x + WALL_W / 2 + 180, cy: 560 },
|
|
242
|
+
{ f: 12, scale: 1.24, cx: WALL.x + WALL_W / 2 + 180, cy: 560 },
|
|
243
|
+
{ f: c1, scale: 1.52, cx: STATION.x - 70, cy: STATION.y + 40 },
|
|
244
|
+
{ f: c3, scale: 1.52, cx: STATION.x - 70, cy: STATION.y + 40 },
|
|
245
|
+
{ f: landF + 6, scale: 1.66, cx: slotCx + 60, cy: slotCy - 10 },
|
|
246
|
+
{ f: endF, scale: 1.3, cx: WALL.x + WALL_W / 2, cy: WALL.y + WALL_H / 2 + 60 },
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
const cells = useMemo(() => Array.from({ length: WALL.cols * WALL.rows }, (_, i) => i), []);
|
|
250
|
+
|
|
251
|
+
// Ruled body lines of the manifest (tiny-body-copy-as-ruled-lines), widths
|
|
252
|
+
// seeded by index - real text is reserved for the header and readout rows.
|
|
253
|
+
const ruled = [0.94, 0.72, 0.86, 0.6, 0.78];
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<AbsoluteFill style={{ backgroundColor: EX.paper }}>
|
|
257
|
+
<FrameCam frame={lf} keys={camKeys} breathe>
|
|
258
|
+
<CinematicStage frame={lf} base={EX.paper} warmth={0.45} grid={false} />
|
|
259
|
+
<DustMotes frame={lf} color={EX.inkMuted} />
|
|
260
|
+
|
|
261
|
+
{/* The persistent GPU wall - on screen at frame 0, no re-entry. */}
|
|
262
|
+
<div
|
|
263
|
+
style={{
|
|
264
|
+
position: "absolute",
|
|
265
|
+
left: 0,
|
|
266
|
+
top: 0,
|
|
267
|
+
width: 1920,
|
|
268
|
+
height: 1080,
|
|
269
|
+
}}
|
|
270
|
+
>
|
|
271
|
+
{/* Long-throw ground shadow under the whole cluster. */}
|
|
272
|
+
<div
|
|
273
|
+
style={{
|
|
274
|
+
position: "absolute",
|
|
275
|
+
left: WALL.x - 50,
|
|
276
|
+
top: WALL.y - 30,
|
|
277
|
+
width: WALL_W + 100,
|
|
278
|
+
height: WALL_H + 110,
|
|
279
|
+
background: `radial-gradient(ellipse at 50% 55%, ${rgba(EX.ink, 0.1)} 0%, transparent 70%)`,
|
|
280
|
+
}}
|
|
281
|
+
/>
|
|
282
|
+
{cells.map((i) => (
|
|
283
|
+
<Cell key={i} i={i} lf={lf} landF={landF} />
|
|
284
|
+
))}
|
|
285
|
+
<RingPulse frame={lf} at={landF} x={slotCx} y={slotCy} maxRadius={260} color={rgba(EX.coral, 0.8)} />
|
|
286
|
+
</div>
|
|
287
|
+
|
|
288
|
+
{/* THE JOB TICKET - flies in from off-frame right, is scanned, then
|
|
289
|
+
slots flush into the dark cluster. */}
|
|
290
|
+
<div
|
|
291
|
+
data-radar="job-ticket"
|
|
292
|
+
style={{
|
|
293
|
+
position: "absolute",
|
|
294
|
+
left: tk.x - TICKET_W / 2,
|
|
295
|
+
top: tk.y - TICKET_H / 2,
|
|
296
|
+
width: TICKET_W,
|
|
297
|
+
height: TICKET_H,
|
|
298
|
+
transform: `rotate(${tk.rot}deg) scale(${tk.scale * landSquash})`,
|
|
299
|
+
transformOrigin: "50% 50%",
|
|
300
|
+
opacity: tkFade,
|
|
301
|
+
borderRadius: 14,
|
|
302
|
+
backgroundColor: EX.white,
|
|
303
|
+
// Premium layered surface: contact + ambient shadow, hairline
|
|
304
|
+
// ring; the top sheen is the gradient div below. Matte white -
|
|
305
|
+
// the glow budget belongs to the scanline and the ignition.
|
|
306
|
+
boxShadow: `0 2px 4px ${rgba(EX.ink, 0.08)}, 0 24px 48px ${rgba(EX.ink, 0.16)}, 0 0 0 1px ${EX.hairline}`,
|
|
307
|
+
filter: tkBlur > 0.3 ? `blur(${tkBlur}px)` : "none",
|
|
308
|
+
overflow: "hidden",
|
|
309
|
+
}}
|
|
310
|
+
>
|
|
311
|
+
<div
|
|
312
|
+
style={{
|
|
313
|
+
position: "absolute",
|
|
314
|
+
inset: 0,
|
|
315
|
+
borderRadius: 14,
|
|
316
|
+
background: `linear-gradient(175deg, ${rgba(EX.white, 0.9)} 0%, transparent 30%)`,
|
|
317
|
+
pointerEvents: "none",
|
|
318
|
+
}}
|
|
319
|
+
/>
|
|
320
|
+
<div style={{ position: "absolute", inset: 0, padding: 22, display: "flex", flexDirection: "column" }}>
|
|
321
|
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
|
322
|
+
<div style={{ ...TIER.label, fontSize: 17, color: EX.ink }}>JOB · SUBMIT</div>
|
|
323
|
+
<div style={{ ...TIER.label, fontSize: 13, color: EX.inkMuted }}>QUEUE · TRAIN</div>
|
|
324
|
+
</div>
|
|
325
|
+
{/* Manifest body: fine ruled lines only. */}
|
|
326
|
+
<div style={{ display: "flex", flexDirection: "column", gap: 11, marginTop: 20, flex: 1 }}>
|
|
327
|
+
{ruled.map((w, i) => (
|
|
328
|
+
<div
|
|
329
|
+
key={i}
|
|
330
|
+
style={{
|
|
331
|
+
height: 3,
|
|
332
|
+
width: `${w * 100}%`,
|
|
333
|
+
borderRadius: 2,
|
|
334
|
+
backgroundColor: EX.cellUnlit,
|
|
335
|
+
}}
|
|
336
|
+
/>
|
|
337
|
+
))}
|
|
338
|
+
</div>
|
|
339
|
+
{/* The two prediction readouts, typed on in mono at cue 2. */}
|
|
340
|
+
<div data-radar="fit-risk-readout" style={{ display: "flex", flexDirection: "column", gap: 7 }}>
|
|
341
|
+
<div
|
|
342
|
+
style={{
|
|
343
|
+
...TIER.label,
|
|
344
|
+
fontSize: 15,
|
|
345
|
+
color: EX.ink,
|
|
346
|
+
opacity: Math.min(1, rowSettled1 * 1.4),
|
|
347
|
+
transform: `translateY(${(1 - rowSettled1) * 6}px)`,
|
|
348
|
+
}}
|
|
349
|
+
>
|
|
350
|
+
<span style={{ color: EX.coral }}>●</span> {typed1}
|
|
351
|
+
</div>
|
|
352
|
+
<div
|
|
353
|
+
style={{
|
|
354
|
+
...TIER.label,
|
|
355
|
+
fontSize: 15,
|
|
356
|
+
color: EX.ink,
|
|
357
|
+
opacity: Math.min(1, rowSettled2 * 1.4),
|
|
358
|
+
transform: `translateY(${(1 - rowSettled2) * 6}px)`,
|
|
359
|
+
}}
|
|
360
|
+
>
|
|
361
|
+
<span style={{ color: EX.coral }}>●</span> {typed2}
|
|
362
|
+
</div>
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
{/* The coral scanline the hex mark drives across the card. */}
|
|
366
|
+
{scanAlpha > 0 && (
|
|
367
|
+
<div
|
|
368
|
+
style={{
|
|
369
|
+
position: "absolute",
|
|
370
|
+
left: 0,
|
|
371
|
+
right: 0,
|
|
372
|
+
top: `${scanT * 100}%`,
|
|
373
|
+
height: 3,
|
|
374
|
+
backgroundColor: EX.coral,
|
|
375
|
+
boxShadow: `0 0 14px 2px ${rgba(EX.coral, 0.7)}`,
|
|
376
|
+
opacity: scanAlpha,
|
|
377
|
+
}}
|
|
378
|
+
/>
|
|
379
|
+
)}
|
|
380
|
+
{scanAlpha > 0 && (
|
|
381
|
+
<div
|
|
382
|
+
style={{
|
|
383
|
+
position: "absolute",
|
|
384
|
+
left: 0,
|
|
385
|
+
right: 0,
|
|
386
|
+
top: 0,
|
|
387
|
+
height: `${scanT * 100}%`,
|
|
388
|
+
background: `linear-gradient(180deg, transparent 60%, ${rgba(EX.coral, 0.08)} 100%)`,
|
|
389
|
+
opacity: scanAlpha,
|
|
390
|
+
}}
|
|
391
|
+
/>
|
|
392
|
+
)}
|
|
393
|
+
</div>
|
|
394
|
+
|
|
395
|
+
{/* The hex-cluster mark docks beside the ticket and scans it. It
|
|
396
|
+
rides the ticket's flight offset so the pair reads as one rig. */}
|
|
397
|
+
<div
|
|
398
|
+
data-radar="expanse-hex-mark"
|
|
399
|
+
style={{
|
|
400
|
+
position: "absolute",
|
|
401
|
+
left: tk.x - TICKET_W / 2 - 76,
|
|
402
|
+
top: tk.y - TICKET_H / 2 - 8,
|
|
403
|
+
width: 60,
|
|
404
|
+
height: 60,
|
|
405
|
+
opacity: Math.min(1, hex * 1.5) * tkFade,
|
|
406
|
+
transform: `rotate(${hexSpin}deg) scale(${(0.7 + 0.3 * hex) * tk.scale})`,
|
|
407
|
+
transformOrigin: "50% 50%",
|
|
408
|
+
}}
|
|
409
|
+
>
|
|
410
|
+
<HexMark size={60} ink={EX.ink} />
|
|
411
|
+
</div>
|
|
412
|
+
|
|
413
|
+
{/* T+0ms - the point IS submission time. Stamps on its spoken beat. */}
|
|
414
|
+
{stampIn > 0.01 && stampOut > 0.01 && (
|
|
415
|
+
<div
|
|
416
|
+
style={{
|
|
417
|
+
position: "absolute",
|
|
418
|
+
left: tk.x + TICKET_W / 2 + 18,
|
|
419
|
+
top: tk.y - 16,
|
|
420
|
+
transform: `scale(${stampIn})`,
|
|
421
|
+
transformOrigin: "0% 50%",
|
|
422
|
+
opacity: stampOut,
|
|
423
|
+
...TIER.stat,
|
|
424
|
+
fontSize: 22,
|
|
425
|
+
color: EX.coral,
|
|
426
|
+
backgroundColor: EX.white,
|
|
427
|
+
padding: "6px 14px",
|
|
428
|
+
borderRadius: 8,
|
|
429
|
+
boxShadow: `0 6px 16px ${rgba(EX.ink, 0.12)}, 0 0 0 1px ${EX.hairline}`,
|
|
430
|
+
}}
|
|
431
|
+
>
|
|
432
|
+
T+0ms
|
|
433
|
+
</div>
|
|
434
|
+
)}
|
|
435
|
+
</FrameCam>
|
|
436
|
+
|
|
437
|
+
{/* HUD - screen space, outside the camera (titles-pinned-outside-camera-push). */}
|
|
438
|
+
<div style={{ position: "absolute", inset: 0, pointerEvents: "none" }}>
|
|
439
|
+
<div style={{ position: "absolute", left: 60, top: 60 }}>
|
|
440
|
+
<div style={{ ...TIER.label, color: EX.inkMuted, marginBottom: 10 }}>02/03 - THE MECHANISM</div>
|
|
441
|
+
<div style={{ ...TIER.label, fontSize: 24, color: EX.ink }}>PREDICT AT SUBMISSION</div>
|
|
442
|
+
</div>
|
|
443
|
+
|
|
444
|
+
<div style={{ position: "absolute", left: FOOTER_TEXT_X.left, top: ZONE.footer.top + 30 }}>
|
|
445
|
+
<div style={{ ...TIER.footnote, color: EX.inkMuted }}>
|
|
446
|
+
Expanse - cluster intelligence at job-submission time.
|
|
447
|
+
</div>
|
|
448
|
+
</div>
|
|
449
|
+
|
|
450
|
+
<div style={{ position: "absolute", left: FOOTER_TEXT_X.right, top: ZONE.footer.top + 10 }}>
|
|
451
|
+
<RevolaWatermark tone="onLight" />
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
</AbsoluteFill>
|
|
455
|
+
);
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
export default S2Mechanism;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useCurrentFrame } from "remotion";
|
|
3
|
+
import { SECTION_WINDOWS, windowFor } from "./layout";
|
|
4
|
+
|
|
5
|
+
// Mutation: the `from` read hides inside helper wrappers - one over
|
|
6
|
+
// windowFor(), one over SECTION_WINDOWS - and call sites only see a clean
|
|
7
|
+
// function name.
|
|
8
|
+
const sectionStart = () => windowFor("mechanism").from;
|
|
9
|
+
const firstStart = () => SECTION_WINDOWS[0].from;
|
|
10
|
+
|
|
11
|
+
export const Wrapped: React.FC = () => {
|
|
12
|
+
const frame = useCurrentFrame();
|
|
13
|
+
const lf = frame - sectionStart() + firstStart();
|
|
14
|
+
return <div style={{ opacity: lf > 0 ? 1 : 0 }} />;
|
|
15
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Missing violation: no `geometry` export at all, e.g. a sidecar file that
|
|
2
|
+
// was scaffolded but never filled in, or a helper named something else.
|
|
3
|
+
import type { SceneGeometry } from "@revola/video-kit/pure";
|
|
4
|
+
|
|
5
|
+
const localOnly: SceneGeometry = {
|
|
6
|
+
sectionId: "once",
|
|
7
|
+
exit: { object: "instrument-card", x: 960, y: 540, scale: 1.18 },
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default localOnly;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Missing violation: exports `geometry`, but with no `SceneGeometry` type
|
|
2
|
+
// annotation, so a shape drift at a call site would not be caught at compile
|
|
3
|
+
// time.
|
|
4
|
+
export const geometry = {
|
|
5
|
+
sectionId: "once",
|
|
6
|
+
exit: { object: "instrument-card", x: 960, y: 540, scale: 1.18 },
|
|
7
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Strictly ascending literal ranges, including a negative start: clean.
|
|
2
|
+
declare const interpolate: (frame: number, input: number[], output: number[]) => number;
|
|
3
|
+
declare const frame: number;
|
|
4
|
+
|
|
5
|
+
export const x = interpolate(frame, [0, 134, 136, 200], [0, 1, 1, 0]);
|
|
6
|
+
export const y = interpolate(frame, [-20, -10, 0], [0, 0.5, 1]);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// A literal input range that is not strictly ascending: interpolate() throws
|
|
2
|
+
// at runtime when this frame range is reached. The BUILD_NOTES_CRAFT case:
|
|
3
|
+
// HERO_AT (134) retimed earlier than TILT_END (136) in a literal key array.
|
|
4
|
+
declare const interpolate: (frame: number, input: number[], output: number[]) => number;
|
|
5
|
+
declare const frame: number;
|
|
6
|
+
|
|
7
|
+
export const x = interpolate(frame, [0, 136, 134, 200], [0, 1, 1, 0]);
|
|
8
|
+
export const y = interpolate(frame, [-10, -20], [0, 1]);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Identifier-composed ranges are out of scope: proving them monotonic would
|
|
2
|
+
// need constant folding across declarations, so the check stays literal-only.
|
|
3
|
+
declare const interpolate: (frame: number, input: number[], output: number[]) => number;
|
|
4
|
+
declare const frame: number;
|
|
5
|
+
|
|
6
|
+
const TILT_END = 136;
|
|
7
|
+
const HERO_AT = 134;
|
|
8
|
+
|
|
9
|
+
export const x = interpolate(frame, [0, TILT_END, HERO_AT, 200], [0, 1, 1, 0]);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Reproduction of the bug in revola-video BUILD_NOTES_CRAFT.md, S2 pass 2:
|
|
2
|
+
// "a CSS-filtered <g> wrapping children that ALSO have CSS filters makes Chrome
|
|
3
|
+
// drop those children silently - the first cursor build rendered nothing while
|
|
4
|
+
// its group rendered fine".
|
|
5
|
+
export const Cursor = () => (
|
|
6
|
+
<svg viewBox="0 0 100 100">
|
|
7
|
+
<g style={{ filter: "drop-shadow(0 0 6px #9C33FF)" }}>
|
|
8
|
+
<path d="M0 0 L10 30" style={{ filter: "blur(2px)" }} />
|
|
9
|
+
</g>
|
|
10
|
+
</svg>
|
|
11
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// The false-positive shape corpus calibration hit three times (Scene4_Mechanism,
|
|
2
|
+
// S2Turn, S4Proof): a CSS-filtered HTML wrapper around a whole <svg> whose child
|
|
3
|
+
// carries its own filter. The wrapper's filter composites the rendered svg at the
|
|
4
|
+
// HTML level, so nothing is dropped - all three shipped scenes render correctly.
|
|
5
|
+
// Only a filtered ancestor INSIDE the <svg> subtree triggers the Chrome bug.
|
|
6
|
+
export const Hero = () => (
|
|
7
|
+
<div style={{ filter: "blur(4px)" }}>
|
|
8
|
+
<svg viewBox="0 0 100 100">
|
|
9
|
+
<text x="50" y="50" style={{ filter: "drop-shadow(0 0 6px #9C33FF)" }}>
|
|
10
|
+
hi
|
|
11
|
+
</text>
|
|
12
|
+
</svg>
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Nested CSS filters in plain HTML render fine - the silent-drop bug is
|
|
2
|
+
// SVG-specific. The rule must not fire outside an <svg>.
|
|
3
|
+
export const Card = () => (
|
|
4
|
+
<div style={{ filter: "drop-shadow(0 0 6px #9C33FF)" }}>
|
|
5
|
+
<span style={{ filter: "blur(2px)" }}>hello</span>
|
|
6
|
+
</div>
|
|
7
|
+
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Two filtered SIBLINGS are fine - only a filtered ancestor wrapping a
|
|
2
|
+
// filtered descendant triggers the Chrome bug. This fixture guards the
|
|
3
|
+
// most likely false-positive shape: the check matching an element against
|
|
4
|
+
// itself or against a non-ancestor.
|
|
5
|
+
export const Cursor = () => (
|
|
6
|
+
<svg viewBox="0 0 100 100">
|
|
7
|
+
<g>
|
|
8
|
+
<path d="M0 0 L10 30" style={{ filter: "blur(2px)" }} />
|
|
9
|
+
<path d="M10 0 L20 30" style={{ filter: "drop-shadow(0 0 6px #9C33FF)" }} />
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
12
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
export const Jitter: React.FC = () => {
|
|
4
|
+
const seed = Math.random();
|
|
5
|
+
const now = Date.now();
|
|
6
|
+
const stamp = new Date();
|
|
7
|
+
const bare = new Date; // no parens: still an argless construction
|
|
8
|
+
void bare;
|
|
9
|
+
return (
|
|
10
|
+
<div style={{ opacity: seed }}>
|
|
11
|
+
{now} {stamp.toISOString()}
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
// Evasion spellings the check deliberately does NOT flag (see the rule's
|
|
4
|
+
// "Deliberate limitation" note). This fixture pins that boundary: if the
|
|
5
|
+
// check is ever extended to resolve these, the companion test must flip.
|
|
6
|
+
const M = Math;
|
|
7
|
+
const { random } = Math;
|
|
8
|
+
|
|
9
|
+
export const Variants: React.FC = () => {
|
|
10
|
+
const a = M.random();
|
|
11
|
+
const b = random();
|
|
12
|
+
const c = Math["random"]();
|
|
13
|
+
const d = globalThis.Date.now();
|
|
14
|
+
const e = new Date(undefined as unknown as number);
|
|
15
|
+
return <div>{a + b + c + d + e.getTime()}</div>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// A scene that hard-codes palette hexes instead of referencing the token
|
|
2
|
+
// module. One in a plain string prop, one inside a template-literal gradient.
|
|
3
|
+
// The pure-white drop-shadow is NOT a violation: white/black glint constants
|
|
4
|
+
// are not palette (the dark regrade shipped with them unchanged).
|
|
5
|
+
export const Panel = () => (
|
|
6
|
+
<div style={{ background: "#0E1420" }}>
|
|
7
|
+
<div style={{ backgroundImage: `linear-gradient(180deg, #9C33FF 0%, transparent 100%)` }} />
|
|
8
|
+
<div style={{ boxShadow: "0 0 12px #fff", borderColor: "#000000" }} />
|
|
9
|
+
</div>
|
|
10
|
+
);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// The convention: no whole-scene camera transform, so the root AbsoluteFill
|
|
2
|
+
// declares data-radar-scene-root="static".
|
|
3
|
+
export default function SceneHook() {
|
|
4
|
+
return (
|
|
5
|
+
<div data-radar-scene-root="static" style={{ position: "absolute", inset: 0 }}>
|
|
6
|
+
<div data-radar="hero" style={{ width: 900, height: 500 }} />
|
|
7
|
+
</div>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// A radar-adopting scene (its plan declares a names: binding) whose source
|
|
2
|
+
// nowhere carries the scene-space contract tag: radar:scene refuses this at
|
|
3
|
+
// setup. (The tag's literal name must not appear even in a comment here -
|
|
4
|
+
// the check is textual containment over the whole project's source.)
|
|
5
|
+
export default function SceneHook() {
|
|
6
|
+
return (
|
|
7
|
+
<div style={{ position: "absolute", inset: 0 }}>
|
|
8
|
+
<div data-radar="hero" style={{ width: 900, height: 500 }} />
|
|
9
|
+
</div>
|
|
10
|
+
);
|
|
11
|
+
}
|