mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
* feat(studio): mirror canvas z-order actions into timeline lanes, badge z overrides
Track order = default paint order; authored z = advanced override.
- timelineZMirror.ts: pure resolver mapping a successful z-menu action to a
timeline lane move — closest track in the action's direction that is free
over the clip's whole span, else a new lane adjacent to the crossed
neighbor; temporal-overlap scope (default pending product sign-off, see
module doc); visual zone only; same-file reference scoping; persistTrack
via the shared authored-space rules. null for non-clips (menu stays
z-only) and at-extreme/no-overlap cases.
- useCanvasZOrderTimelineMirror.ts: after the z commit resolves, the mirror
persists the lane move through the same machinery as a timeline lane drag
(optimistic store update, authoredTrack refresh, rollback); inserts reuse
commitTrackInsert's renumber via a shared buildTrackInsertEdits core. Both
writes share one coalesce key (zReorderCoalesceKey) and fold into ONE undo
entry (test proves it over the real history reducer). The mirror never
triggers the lane->z stacking sync, so it cannot fight the z values the
action just set.
- timelineZOverride.ts + TimelineClip badge: clips whose paint order
contradicts lane order among temporally-overlapping same-context visual
neighbors (laneIsAbove XOR paintsAbove, the stacking-sync predicates) show
a 'z' badge — authored z overrides are surfaced instead of silently
disagreeing with the timeline.
- Timeline.tsx track derivations extracted to useTimelineTrackDerivations
(600-line cap).
* fix(studio): fold mirrored z-order gestures into one undo entry across slow persists
Live verification caught the z write and the mirrored lane write splitting
into two undo entries: the mirror runs after the z persist's server round
trip, which exceeds editHistory's default 300ms coalesce window under real
latency (the unit test's deterministic clock sat inside it).
zReorderCoalesceKey now mints a per-gesture-unique key (monotonic seq, the
laneChangeGestureSeq precedent) and both records carry coalesceMs Infinity —
distinct gestures can never merge, and one gesture always folds regardless
of write latency. coalesceMs threaded through the persist chain alongside
coalesceKey. Also hardens the existing lane-drag move->z fold, which had the
same latent split. Fold test now simulates a 400ms gap (failed before the
fix, passes after); a two-separate-gestures test asserts two entries.
* feat(studio): flashless lane mirror, z-order menu icons, close-gap track menu
- Track-only batch moves (the z-mirror's lane hop and the insert renumber)
skip the GSAP fallback round-trip and the preview reload entirely — the
renderer never reads data-track-index, and the live DOM patch + optimistic
store update cover the UI. Mixed batches keep current behavior. Kills the
canvas blink on mirrored Bring/Send actions (live-verified: an
iframe-scoped marker survives the whole gesture).
- The four z-order menu items get 16px stroke icons (single layer diamond +
directional arrow for Forward/Backward; pierced two-layer stack for
Front/Back); labels unchanged — they are the industry-standard names.
- New track context menu on empty lane space: 'Close gap' (shifts the next
clip and every clip after it on that lane left by the clicked gap's width;
leading gaps count, so a single clip with empty space before it compacts
to 0) and 'Close all gaps' (whole lane contiguous from 0). Pure gap math
in timelineGaps.ts; persists through the drag path's atomic batch move
(one undo per action); refuses when a clip that must shift is locked;
items disable when there is nothing to close.
* fix(studio): rebind-only preview sync for unmutated timing edits, classical z-menu order
Timing edits that rewrote NO GSAP positions (gap closes and moves of
selector-addressed caption clips, zero-delta batches, comps without a
rewritable script) full-reloaded the preview — and the rerun-current-scripts
attempt was wrong for real compositions: re-executing init-style scripts
(three.js scenes, caption engines) is exactly the unsafe case, verified live
by doubled init warnings and a fallback reload anyway.
The correct observation: when mutated === false the existing __timelines are
still valid — only the runtime's clip visibility windows are stale, and the
live DOM timing attributes were already patched. So the no-mutation path now
runs applySoftReloadFinalization only (seek + __hfForceTimelineRebind +
manual-edits reapply), extracted from the soft-reload machinery — zero
script execution. This also un-blinks comps with no GSAP script at all,
which previously always remounted. Rewritten-script soft reloads,
cannot-soft-reload, otherFileChanged, and mutation failures keep their
existing behavior. gsapSoftReload's undo/redo restore section moved verbatim
to gsapUndoRestore.ts for the 600-line cap.
Also: z-order menu items reordered to the classical arrangement (Bring to
Front, Bring Forward, Send Backward, Send to Back).
Live-verified on a three.js-heavy composition: Close-all-gaps shifted 4
caption clips with correct cumulative amounts, the preview iframe was never
remounted (marker survived), and one undo reverted everything.
* fix(studio): bound forward/backward mirror to a one-element step
User-specified semantic: Bring Forward / Send Backward move the clip past
EXACTLY ONE element. The mirror's lane target is now bounded by the next
temporally-overlapping element beyond the crossed neighbor: a free lane
strictly between the two is taken (closest to the neighbor), and when they
are back-to-back a new track is inserted immediately beyond the crossed
element — never past the second one. Previously the resolver took the
closest free lane anywhere beyond the neighbor, which could carry the track
past a second element while the z action only stepped past one — a
track/paint contradiction our own zOverride badge would flag. Front/back
keep whole-set semantics (past everything; back stays above the audio
zone). End-to-end test pins the 3-stacked case through commitZMirrorLaneMove
to the persisted renumbered tracks.
* feat(studio): permanent gap-menu rows with hover and click-select gap highlights
- TrackGapContextMenu always renders both rows; an inapplicable action dims
with a tooltip ("No gap here" / lock reason / "No gaps on this track")
instead of vanishing into a one-item menu. Width badge only when a gap
exists under the pointer.
- Hovering an ACTIONABLE row highlights the strip(s) it would close in the
timeline: the single gap for Close gap, every current gap (leading included)
for Close all gaps. New resolveAllGapIntervals in timelineGaps.ts reports
present-state intervals (epsilon-tolerant, overlap-safe), distinct from
resolveAllTrackGaps' post-compaction starts.
- Click-selecting a single clip paints a quieter tint over its lane's gaps
(suppressed for marquee multi-selection and during drags; the gap-menu hover
wins on its own lane). Derivation lives in useTimelineGapHighlights with the
pure buildTimelineGapStrips exported and unit-tested.
- Strips render in TimelineCanvas with the drop-placeholder geometry (row top
+ clip inset), dashed accent for hover, faint tint for selection.
- Timeline.tsx stayed under the 600-line cap by extracting the scroll-viewport
plumbing (ResizeObserver width + shortcut-hint sync) into
useTimelineScrollViewport, behavior unchanged.
* feat(studio): stronger capcut-style timeline zoom steps
One button press / pinch gesture now moves the zoom meaningfully: step
factors 1.25x/0.8x -> 1.5x/(2/3) (kept reciprocal so in+out round-trips) and
pinch sensitivity 0.0035 -> 0.007. Addresses "zooming several times to get
anywhere" feedback; cursor anchoring unchanged.
* feat(studio): three-way z sync — layers drags mirror timeline lanes, panel tracks live z edits
Completes the layers/canvas/timeline sync triangle: the Layers panel was the
one surface whose reorders never reached the timeline, and the one that went
stale when the other two wrote z flashlessly.
- Layers drag -> minimal z + equal-jump lane mirror. handleReorder now uses
the canvas menu's realization core via resolveZOrderReposition (one
between-z write when a strict gap exists, band-safe scoped renumber
otherwise) instead of computeReorderZValues' all-sibling stamp — that
helper is deleted, completing the #2347 unification follow-up. The drop
then mirrors into a timeline lane move through the same machinery as the
canvas menu (new resolveRepositionLaneMove: the clip lands on a free lane
strictly between its NEW paint neighbors' lanes — nearest clip siblings in
the desired render order, decorations skipped — else a track insert at
that boundary; audio zone never crossed). Both writes share one
per-gesture zReorderCoalesceKey with an unbounded fold window, so a drag
is exactly ONE undo entry; useCanvasZOrderTimelineMirror's plumbing is
factored into useMirrorLaneMoveCommit and reused by the new
useLayerReorderTimelineMirror. A same-slot drop is a hard no-op (new
order-equality guard in resolveZOrderReposition).
- Panel staleness fix: flashless z commits (skipReload) reload nothing and
bump no refreshKey, so the panel's z-sorted order went stale while paused.
handleDomZIndexReorderCommit now bumps a store zEditVersion on apply AND
rollback; the panel re-collects on it. Verified live: the panel re-sorts
the instant a drag commits and again on undo.
- Layer click reveal (useLayerRevealOverride): clicking a layer that stays
hidden at the current frame (animation-parked opacity, non-clip
display/visibility hides, hidden ancestors) temporarily forces the chain
visible with live inline styles — exact priors restored on deselect, on
another reveal, on play, and on unmount; never persisted (file diff == 0
verified live). Clips keep the existing seek-into-window behavior; the
override applies on a short defer so a seek-revealed clip needs none.
- layerOrdering's unused hasExplicitZIndex probe (zero callers) removed.
Live-verified on a bed copy: a 2-position layers drag wrote exactly one
element (z 6->23 + data-track-index 15->2), the timeline lane moved without
a reload, and a single Cmd+Z restored the file byte-identically.
* feat(studio): full-track selection highlight, borderless gap hover strips
- Click-selecting a clip now lights the WHOLE lane minus its clips — leading
gap, inter-clip gaps, and the open space after the last clip to the rendered
end (new resolveLaneEmptyIntervals; displayDuration threaded into the strip
derivation). Still click-only: any drag/resize suppresses the strips, and a
marquee multi-select never shows them.
- The gap-menu hover strips drop the dashed border (user feedback) — fill only,
nudged to 0.18 alpha to keep the same visual weight.
* feat(studio): selected layer paints on top via a reader-transparent z lift
Clicking a layer in the Layers tab now shows the element as if it were at the
very top of the stack while selected — whatever its authored z or panel
position — extending the reveal override (which already forced hidden chains
visible) with a temporary inline z lift:
- liftElementToTop parks the TRUE effective z in data-hf-reveal-prior-z and
writes a far-top inline z; a static element gets a layout-preserving
position:relative with its prior parked in data-hf-reveal-prior-pos. Only
the RENDERER sees the lift: all three studio z readers
(readTimelineElementZIndex, getElementZIndex, readEffectiveZIndex) return
the parked prior while the attribute is present, so the canvas z-menu, the
zOverride badge, the lane mirror, the stacking sync, and the panel sort
keep reasoning on the element's real z.
- Strictly ephemeral: exact priors restored on deselect / another reveal /
play / unmount, each property only while it still holds the value the
override wrote (a later real edit is never clobbered). File diff == 0
verified live across a full lift/restore cycle.
- A z-reorder commit CONSUMES an active lift (handleDomZIndexReorderCommit
reads the parked position for its persist-position:relative static check,
then drops the attributes) — the committed z becomes the truth and the
later restore is a guarded no-op.
* fix(studio): flashless undo/redo — three full-reload causes in the soft-restore path
Cmd+Z blinked the canvas on essentially every undo. Three independent causes
in applyUndoRestoreToPreview, each sufficient on its own:
1. Master-view path gate: activeCompPath is NULL at the master view, so the
'paths[0] === activeCompPath' eligibility check could never match the
index.html restore and every default-view undo full-reloaded at the first
gate. Normalized to the codebase-wide 'activeCompPath ?? "index.html"'.
2. Nested identity innerHTML check: the diff compared each identified
element's innerHTML, but the composition root wraps every clip — any child
change re-detected at the root rejected the restore. Change detection now
compares only each element's OWN attribute surface; structure/text
integrity is still guaranteed by the normalize-residual whole-doc pass
(text nodes, added/removed elements, and un-identified attrs all remain
after normalization and force the full reload).
3. id-only identity: elements addressed by data-hf-id / selector (no DOM id)
fell outside the diff entirely. Identity is now id OR data-hf-id, with the
live sync resolving either.
Also stop re-running an UNCHANGED GSAP script: attribute-only restores (z,
lane, timing, style — the overwhelmingly common undo) now use the rebind-only
finalization (seek + __hfForceTimelineRebind + manual reapply, zero script
execution — the same path as flashless timing edits), instead of tearing down
and rebuilding live timelines or full-reloading when the script can't be
scoped. A restore whose script text genuinely changed still re-runs it via
applySoftReload, and structural restores (split/delete) still full-reload.
Live-verified on the bed (iframe marker): gap-close undo AND redo both keep
the iframe mounted, live DOM lands on the restored values, disk restored
byte-identically.
* feat(studio): left breathing pad before t=0, double zoom sensitivity again
TRACKS_LEFT_PAD (48px) — the horizontal sibling of TRACKS_TOP_PAD: empty lane
surface between the sticky gutter and the ruler's 00:00 / the first clips,
scrolling WITH the content.
- The lanes and the ruler realize it as a plain flow spacer between the
sticky gutter cell and the time-mapped content div, so every
content-relative computation (clip left = t*pps, beat lines, lane-menu
time, clip drag deltas) is untouched by construction.
- Canvas-space overlays shift by the pad: playhead (getTimelinePlayheadLeft),
gap strips, drop placeholder, snap guide, range highlight, marquee clip
rects, beat SVG; the insert line spans the pad.
- Every pointer->time inverse subtracts it symmetrically: seekFromX, razor,
range/marquee anchors, asset drops, and the zoom-anchor gutter basis; fit
pps and the display width account for the consumed viewport width.
- Live-verified: t=0 clip edge, the 00:00 tick, and the playhead line center
all sit at GUTTER + TRACKS_LEFT_PAD, and a ruler click lands the playhead
center exactly under the pointer.
Also doubles the timeline zoom sensitivity again (user feedback after
feel-testing the first bump): button steps 1.5x/(2/3) -> 2x/0.5, pinch
0.007 -> 0.014.
* fix(studio): left pad renders as true empty space, not lane surface
The pad before t=0 inherited each row's background and bottom border from the
row wrapper, so it read as track lanes. Lane visuals now live on the cells:
the sticky gutter keeps its own separator (header column stays delineated),
the time-mapped content div carries the row background + separator, and the
pad spacer stays transparent — bare shell background, no lines. The
new-track insertion line also starts at the pad's end instead of crossing it.
* fix(studio): no vertical line in the ruler band before 00:00
The ruler corner's right border drew the header-boundary line through the
ruler strip, so the band didn't read as starting at 00:00. Dropped it — the
boundary line belongs to the track rows below; the ruler stays completely
clean from the panel edge to the first tick, matching the empty left pad.
* refactor(studio): remove the timeline z-override badge
User decision: the "z" chip on clips never earned its place — dropped
entirely (timelineZOverride.ts + test deleted, TimelineClip badge rendering
and the zOverrideKeys derivation/threading removed). This also eliminates the
review's D2 finding at the root: the badge's cross-document comparison
(stackingContextId ?? null collides across source files in the expanded view)
produced false positives, and there is no longer a detector to mis-fire.
overlapsInTime/paintsAbove lose their export (the badge was their only
external consumer); the paint-order predicate itself is unchanged.
* fix(studio): collision-free expanded child lanes and host-window gap floors
Review findings D1 (blocker) and 4.
- D1: buildChildElements assigned expanded children synthetic display rows as
`host.track + index` — integers that can EQUAL a real clip's lane in another
file (host on 0 with two children puts child #2 on 1). Lane grouping merges
purely by track number, so the collision fused clips from different source
files into one display lane, and lane-scoped actions (the gap menu) then
batch-persisted a foreign file's clip. Children now take FRACTIONS strictly
between the host's lane and the next integer — structurally unable to
collide with any normalized lane, while still rendering as ordered rows
under the host. Regression test pins the reviewer's exact two-file scenario.
- Finding 4: gap math compacted toward absolute 0, but an expanded child's
display time is host-anchored — close/compact could drag it before its host
window and persist a wrong (even negative) local time. All gap functions
now take a lane FLOOR (laneGapFloor: 0 for ordinary lanes, the children's
expandedParentStart for child lanes — single-origin per lane post-D1),
threaded through the menu model, hover highlights, selected-lane strips,
and both commits. Close-gap shifts clamp at the gap's own left edge.
* fix(studio): scope mirror references, insert writes, and crossed-neighbor identity
Review findings 1, 2, and 3.
- Finding 1: buildTrackInsertEdits normalized the FULL display set and
persisted every shifted clip — writing host-lane numbers into OTHER
composition files when expanded children were showing. The renumber write
set is now the edited element's own source file (the sanctioned multi-write
converges one FILE to lane space, never neighbors' files); foreign clips
keep their authored tracks and re-derive display lanes. The locked-clip
refusal scopes the same way. Expanded-origin elements refuse the insert
outright (a new lane is a host-space renumber, meaningless in the child's
file), and the mirrors restrict an expanded child's lane candidates to its
own siblings' lanes — a sub-comp child still mirrors WITHIN its sub-comp
(persisting the sibling's authored track) but can never land on a host lane
with no same-file occupant. authoredTrackForLane's offset fallback rounds:
fractional synthetic rows must never leak fractions into data-track-index.
- Finding 2: the mirror comparison sets required only sameSourceFile, but a
file can contain several CSS stacking contexts and leaf z is only
comparable within one. Both resolvers now scope by samePaintScope — same
source file AND same stackingContextId (the file check also stops null root
contexts of different files from comparing equal in the expanded view).
- Finding 3: the crossed-neighbor key was derived without selectorIndex, so
duplicate class selectors (.sub) resolved to occurrence 0 — a different
clip. The key now carries getSelectorIndex, matching how z-reorder entries
derive theirs.
* fix(studio): z-to-lane gestures are one serialized transaction gated on durable persists
Review findings 5 and 7.
- Finding 5: commitDomEditPatchBatches resolved successfully even when the
server matched NO patch target — the z write never reached disk (the
preview reloads to reconverge) yet the lane mirror still ran, desyncing
track order from what actually paints. The commit now resolves a durability
report ({allMatched, changed}; the save queue and commit types are generic
over the result), and the mirror phase is skipped on allMatched === false.
- Finding 7: the z persist rides the DOM-edit save queue while the lane move
rides the timeline/SDK path — two queues, so a second rapid gesture's z
write could land BETWEEN the first gesture's z and lane phases. Every
z-to-lane gesture (canvas z-order menu AND Layers-panel drag) now runs
through runZLaneGesture: a single module-level tail that serializes the
COMPLETE two-phase transaction, with unit tests for ordering, the
durability gate, and queue resilience to failed gestures. The timeline
lane-drag's inverse (move-then-z-sync) shares its phases' await ordering
already; cross-gesture serialization for that path is noted as follow-up.
- LayersPanel's pure sort helpers moved to layersPanelSort.ts (600-line cap).
* fix(studio): multi-clip GSAP batch mutations roll back on late failure
Review finding 6. finishGroupTimingGsapFallback mutates files sequentially
per clip; a late per-clip failure left the earlier rewrites on disk with no
aggregate history entry — unreachable by undo. foldGsapMutationIntoHistory
already snapshots every touched path before mutating; on a mutation failure
it now restores each path whose disk content changed (all-or-nothing batch),
reports restore errors without masking the original failure, and rethrows.
Regression test drives a two-clip batch whose second rewrite fails and
asserts the first clip's write is restored byte-identically.
* fix(studio): scope mirror inserts to their lane zone
* fix(studio): unify source-scoped clip identity
* fix(studio): isolate track insert topology
* fix(studio): harden timeline paint synchronization
---------
Co-authored-by: Miguel Angel Simon Sierra <miguel.sierra@heygen.com>
711 lines
38 KiB
JSON
711 lines
38 KiB
JSON
{
|
|
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/config-schema.json",
|
|
"entry": [
|
|
"packages/producer/src/**/*.test.ts",
|
|
"packages/aws-lambda/src/**/*.test.ts",
|
|
"packages/gcp-cloud-run/src/**/*.test.ts",
|
|
"packages/producer/src/regression-harness.ts",
|
|
"packages/producer/src/regression-harness-distributed.test.ts",
|
|
"packages/producer/src/regression-harness-lambda-local.ts",
|
|
"packages/producer/src/transparency-test.ts",
|
|
"packages/producer/src/parity-harness.ts",
|
|
"packages/producer/src/parity-fixtures.ts",
|
|
"packages/producer/src/perf-gate.ts",
|
|
"packages/producer/src/runtime-conformance.ts",
|
|
"packages/producer/src/benchmark.ts",
|
|
"packages/producer/scripts/generate-font-data.ts",
|
|
"packages/producer/we-render.mjs",
|
|
"packages/producer/scripts/validate-fast-video.ts",
|
|
"packages/cli/scripts/generate-font-data.ts",
|
|
"packages/engine/scripts/test-fitTextFontSize-browser.ts",
|
|
"packages/aws-lambda/scripts/*.ts",
|
|
// Built as standalone IIFE for the browser-side sandbox runtime;
|
|
// referenced by file path (not import) in build-hyperframes-runtime-artifact.ts.
|
|
"packages/core/src/runtime/entry.ts",
|
|
// Bundled as a standalone IIFE by the position-edits render artifact
|
|
// generator; referenced by file path rather than imported by TypeScript.
|
|
"packages/core/stubs/position-edits-render-entry.ts",
|
|
// In-page audit scripts read as raw strings and injected via
|
|
// page.addScriptTag (see layout.ts / validate.ts) — referenced by file
|
|
// path, never imported, so they have no import-graph referrer.
|
|
"packages/cli/src/commands/layout-audit.browser.js",
|
|
"packages/cli/src/commands/contrast-audit.browser.js",
|
|
"packages/cli/src/commands/motion-sample.browser.js",
|
|
// Worker entry points loaded dynamically by their *Pool.ts companions.
|
|
"packages/producer/src/services/pngDecodeBlitWorker.ts",
|
|
"packages/producer/src/services/shaderTransitionWorker.ts",
|
|
// Off-main-thread /health endpoint, spawned by path from healthWorker.ts.
|
|
"packages/producer/src/services/healthWorkerThread.ts",
|
|
// Test fixture worker, spawned by path via the pools' workerEntryPath
|
|
// option from the crash-recovery tests; has no import-graph referrer.
|
|
"packages/producer/src/services/__fixtures__/crashOnMessageWorker.mjs",
|
|
"scripts/*.{ts,mjs,js}",
|
|
"scripts/*/run.mjs",
|
|
// Keyframe UI components — wired dynamically via EaseCurveSection/MotionPanel.
|
|
"packages/studio/src/components/editor/KeyframeDiamond.tsx",
|
|
"packages/studio/src/components/editor/SpringEaseEditor.tsx",
|
|
// NLE notice — rendered conditionally via NLEContext/EditorShell when timeline is first shown.
|
|
"packages/studio/src/components/nle/TimelineEditorNotice.tsx",
|
|
// Zoom hook extracted for downstream razor-blade PRs (#1330, #1331).
|
|
"packages/studio/src/player/components/useTimelineZoom.ts",
|
|
// Cached O(1) GSAP target lookup, replacing O(n²) inline checks.
|
|
// Consumers migrate in a follow-up once useDomGeometryCommits adopts it.
|
|
"packages/studio/src/hooks/gsapTargetCache.ts",
|
|
// Preview helper consumed dynamically from the studio iframe bridge.
|
|
"packages/studio/src/hooks/gsapRuntimePreview.ts",
|
|
],
|
|
"ignorePatterns": [
|
|
"docs/**",
|
|
// Chrome browser binaries downloaded by puppeteer — not project source.
|
|
"chrome/**",
|
|
// Standalone spike scripts and benchmark runners used during R&D.
|
|
"packages/engine/spikes/**",
|
|
"packages/producer/de-*.mjs",
|
|
"packages/producer/tests/**",
|
|
"packages/player/tests/**",
|
|
"packages/engine/tests/**",
|
|
"skills/**/test-corpus/**",
|
|
"skills/**/scripts/**",
|
|
// Agent-invoked motion-graphics tools co-located with their docs (run via
|
|
// `node <path>` per grounding/PROTOCOL.md / categories/maps/module.md
|
|
// prose), not import-graph reachable.
|
|
"skills/motion-graphics/grounding/**",
|
|
"skills/motion-graphics/categories/**",
|
|
// Agent-invoked reference materials (template + motion-primitive HTML, catalogs),
|
|
// forked by path by the frame-worker per SKILL.md prose, not import-graph reachable.
|
|
"skills/music-to-video/references/**",
|
|
// Bundled @font-face data (read at runtime via fs.readFileSync, invisible
|
|
// to the import graph) + its manual rebuild tool.
|
|
"skills/**/fonts/**",
|
|
// Golden snapshot files: data consumed by toMatchFileSnapshot, not importable modules.
|
|
"packages/**/__goldens__/**",
|
|
"registry/**",
|
|
"examples/**",
|
|
"packages/sdk/examples/**",
|
|
".github/workflows/fixtures/**",
|
|
// Auto-generated TS client for the HeyGen cloud API. Regenerated by
|
|
// experiment-framework/scripts/generate_hyperframes_cli_client.py via
|
|
// the sync-hyperframes-codegen.yml workflow; complexity/dead-code
|
|
// findings on this file are not actionable from this repo.
|
|
"packages/cli/src/cloud/_gen/**",
|
|
],
|
|
"ignoreExports": [
|
|
// Public player-state types are consumed by package users outside this
|
|
// workspace. Keep the barrel stable even when no in-repo import needs it.
|
|
{
|
|
"file": "packages/studio/src/player/index.ts",
|
|
"exports": ["ZoomMode"],
|
|
},
|
|
// Part of useTimelineEditing's inferred public return type; consumers invoke
|
|
// handleTimelineGroupResize without importing the change type directly.
|
|
{
|
|
"file": "packages/studio/src/hooks/useTimelineGroupEditing.ts",
|
|
"exports": ["TimelineGroupResizeChange"],
|
|
},
|
|
{
|
|
"file": "packages/studio/src/player/components/timelineGroupEditing.ts",
|
|
"exports": [
|
|
"buildTimelineGroupResizeMembers",
|
|
"resolveTimelineGroupResizeChanges",
|
|
"applyTimelineGroupResizePreview",
|
|
],
|
|
},
|
|
{
|
|
"file": "packages/studio/src/player/components/timelineEditing.ts",
|
|
"exports": [
|
|
"selectTimelineElementsInMarquee",
|
|
"TimelineGroupResizeEdge",
|
|
"TimelineGroupTimingMember",
|
|
],
|
|
},
|
|
{
|
|
"file": "packages/studio/src/player/lib/timelineElementHelpers.ts",
|
|
"exports": ["furthestClipEndFromDocument", "furthestClipEndFromSource"],
|
|
},
|
|
{
|
|
"file": "packages/studio/src/components/sidebar/AssetContextMenu.tsx",
|
|
"exports": ["DeleteConfirm"],
|
|
},
|
|
{
|
|
"file": "packages/studio/src/utils/timelineAssetDrop.ts",
|
|
"exports": [
|
|
"setCompositionDurationToContent",
|
|
"extendCompositionDurationIfNeeded",
|
|
"fitTimelineAssetGeometry",
|
|
"resolveTimelineAssetCompositionSize",
|
|
],
|
|
},
|
|
{
|
|
"file": "packages/studio/src/components/sidebar/assetHelpers.ts",
|
|
"exports": ["truncateMiddle", "formatDuration"],
|
|
},
|
|
{
|
|
"file": "packages/studio/src/utils/studioHelpers.ts",
|
|
"exports": ["resolveDroppedAssetDimensions"],
|
|
},
|
|
// drawElementService is the bottom of the fast-capture Graphite stack
|
|
// (#1917): its consumers (frameCapture in #1919) land two PRs upstack, so
|
|
// a per-PR audit diffing against the merge base sees these exports as
|
|
// unused. Consumed for real once the stack merges; safe to drop this
|
|
// entry after #1919 lands.
|
|
{
|
|
"file": "packages/engine/src/services/drawElementService.ts",
|
|
"exports": [
|
|
"instrumentAcceleratedCanvases",
|
|
"injectDrawElementCanvas",
|
|
"captureDrawElementFrame",
|
|
"initDrawElementWorkerEncode",
|
|
"cleanupDrawElementWorkerEncode",
|
|
"produceDrawElementFrame",
|
|
],
|
|
},
|
|
// CLI command files: every command exports a const `examples` per the
|
|
// convention documented in CLAUDE.md. This is a namespace barrel, not a
|
|
// collision.
|
|
{ "file": "packages/cli/src/commands/*.ts", "exports": ["examples"] },
|
|
// Options type for the render-queue hook's public startRender callback —
|
|
// consumed structurally by callers (StudioRightPanel), not by import.
|
|
{
|
|
"file": "packages/studio/src/components/renders/useRenderQueue.ts",
|
|
"exports": ["StartRenderOptions"],
|
|
},
|
|
// Independent ML model managers each declare their own DEFAULT_MODEL /
|
|
// MODELS_DIR / ensureModel for their model namespace.
|
|
{
|
|
"file": "packages/cli/src/{background-removal,tts,whisper}/manager.ts",
|
|
"exports": ["DEFAULT_MODEL", "MODELS_DIR", "ensureModel"],
|
|
},
|
|
// `isPathInside` is documented as exported-for-tests only in fileServer.ts;
|
|
// it has different semantics (symlink resolution) from utils/paths.ts.
|
|
{
|
|
"file": "packages/producer/src/services/fileServer.ts",
|
|
"exports": ["isPathInside"],
|
|
},
|
|
// `sampledAlphaIsFullyOpaque` is exported for direct unit testing of the
|
|
// 1/2/3-frame byte-count gate and per-frame stride logic; the pixel-level
|
|
// contract is too load-bearing to only exercise through `webmAlphaAdvisory`.
|
|
{
|
|
"file": "packages/cli/src/utils/webmAlphaCheck.ts",
|
|
"exports": ["sampledAlphaIsFullyOpaque"],
|
|
},
|
|
// Studio telemetry: consumed by useRenderQueue.ts / StudioFeedbackBar.tsx
|
|
// (deep relative imports) but fallow's static analyzer doesn't trace
|
|
// them. Same path-resolution quirk — trackStudioSessionStart from the
|
|
// same file resolves fine.
|
|
{
|
|
"file": "packages/studio/src/telemetry/events.ts",
|
|
"exports": ["trackStudioRenderStart", "trackStudioFeedback"],
|
|
},
|
|
// domEditingLayers: these exports are consumed via the browser iframe
|
|
// runtime context (not traceable by static import analysis from the
|
|
// studio entry point) or re-exported through the domEditing barrel but
|
|
// have no downstream consumers yet.
|
|
{
|
|
"file": "packages/studio/src/components/editor/domEditingLayers.ts",
|
|
"exports": [
|
|
"isEditableTextLeaf",
|
|
"collectDomEditTextFields",
|
|
"buildElementLabel",
|
|
"refreshDomEditSelection",
|
|
],
|
|
},
|
|
// domEditing barrel: re-exports consumed throughout the studio but
|
|
// fallow's static analyzer can't trace re-exports through barrel files.
|
|
{
|
|
"file": "packages/studio/src/components/editor/domEditing.ts",
|
|
"exports": ["*"],
|
|
},
|
|
// Exported for render.test.ts (exported-for-tests pattern).
|
|
{
|
|
"file": "packages/cli/src/commands/render.ts",
|
|
"exports": [
|
|
"resolveBrowserGpuForCli",
|
|
"renderLocal",
|
|
"checkRenderResolutionPreflight",
|
|
"renderLintContinuationHint",
|
|
],
|
|
},
|
|
// initThreeDProjectionInPage: passed to page.evaluate() for browser-side execution —
|
|
// Puppeteer serializes it at runtime, not an import-graph consumer.
|
|
{
|
|
"file": "packages/engine/src/services/threeDProjection.ts",
|
|
"exports": ["initThreeDProjectionInPage"],
|
|
},
|
|
// captureCost.ts: constants and helpers consumed by the runCaptureCalibration
|
|
// orchestration function and tests, but the entry-point graph doesn't
|
|
// reach them because the orchestrator's caller resolves them dynamically.
|
|
{
|
|
"file": "packages/producer/src/services/render/captureCost.ts",
|
|
"exports": [
|
|
"CAPTURE_CALIBRATION_TARGET_MS",
|
|
"MAX_MEASURED_CAPTURE_COST_MULTIPLIER",
|
|
"CAPTURE_CALIBRATION_PROTOCOL_TIMEOUT_MS",
|
|
"measureCaptureCostFromSession",
|
|
"logCaptureCalibrationResult",
|
|
"createFailedCaptureCalibrationEstimate",
|
|
],
|
|
},
|
|
// gsapParserExports.ts is the public-API barrel that re-exports constants,
|
|
// types, and utilities from gsapConstants, gsapSerialize, and springEase.
|
|
// The re-exports are intentional public API consumed by callers outside the
|
|
// changed-file set (e.g. studio, aws-lambda) and therefore appear unused
|
|
// to fallow's static analysis of the PR diff.
|
|
{
|
|
"file": "packages/parsers/src/gsapParserExports.ts",
|
|
"exports": [
|
|
"PROPERTY_GROUPS",
|
|
"classifyPropertyGroup",
|
|
"classifyTweenPropertyGroup",
|
|
"SPRING_PRESETS",
|
|
"generateSpringEaseData",
|
|
"GsapMethod",
|
|
"GsapKeyframesData",
|
|
"GsapKeyframeFormat",
|
|
"PropertyGroupName",
|
|
"SpringPreset",
|
|
],
|
|
},
|
|
// Shared test helpers consumed by gsapParser.test.ts (same file,
|
|
// fallow doesn't trace intra-file test consumption).
|
|
{
|
|
"file": "packages/parsers/src/gsapParser.test-helpers.ts",
|
|
"exports": [
|
|
"expectKeyframe",
|
|
"expectKeyframesFormat",
|
|
"convertAndReparse",
|
|
"parseSplitAndAssert",
|
|
],
|
|
},
|
|
// hfIds: EXCLUDED_TAGS is consumed by tests (htmlParser.test.ts) and
|
|
// hfIdPersist.ts but fallow's static analyzer may not trace all consumers.
|
|
{
|
|
"file": "packages/parsers/src/hfIds.ts",
|
|
"exports": ["EXCLUDED_TAGS", "mintHfId"],
|
|
},
|
|
// Shared timeline components extracted for downstream PRs in the
|
|
// razor-blade stack (#1330, #1331). Consumers live on those branches.
|
|
{
|
|
"file": "packages/studio/src/player/components/timelineCallbacks.ts",
|
|
"exports": ["*"],
|
|
},
|
|
// Shared timeline DOM barrel for downstream consumers; fallow does not
|
|
// trace all re-export-only modules.
|
|
{
|
|
"file": "packages/studio/src/player/lib/timelineDOM.ts",
|
|
"exports": ["*"],
|
|
},
|
|
// gsapTargetCache: cached O(1) GSAP target lookup, consumed by
|
|
// useDomEditCommits and intended to replace the local copy in
|
|
// useDomGeometryCommits once callers migrate.
|
|
{
|
|
"file": "packages/studio/src/hooks/gsapTargetCache.ts",
|
|
"exports": ["isElementGsapTargeted"],
|
|
},
|
|
// Re-exports from useDomEditCommits: barrel-style re-exports
|
|
// consumed by downstream studio code.
|
|
{
|
|
"file": "packages/studio/src/hooks/useDomEditCommits.ts",
|
|
"exports": ["GSAP_CSS_FALLBACK_BLOCKED_MESSAGE", "PersistDomEditOperations"],
|
|
},
|
|
{
|
|
"file": "packages/studio/src/utils/timelineElementSplit.ts",
|
|
"exports": ["buildPatchTarget", "readFileContent"],
|
|
},
|
|
// freezeUrl and freezeLocalFile are public API re-exported from the figma
|
|
// barrel (index.ts) for Task 4 manifest flow and the /figma skill integration;
|
|
// not yet imported by current code outside the module.
|
|
{
|
|
"file": "packages/core/src/figma/freeze.ts",
|
|
"exports": ["freezeUrl", "freezeLocalFile"],
|
|
},
|
|
// mediaDir, typeDirPath, isFigmaManifestRecord: re-exported from the figma
|
|
// barrel (index.ts) via manifest.ts per Task 8 wiring. Consumed only by the
|
|
// /figma skill integration, not by code in the current codebase.
|
|
{
|
|
"file": "packages/core/src/figma/manifest.ts",
|
|
"exports": ["mediaDir", "typeDirPath", "isFigmaManifestRecord"],
|
|
},
|
|
],
|
|
"ignoreDependencies": [
|
|
// Runtime/dynamic deps not visible to static analysis: tsup `external`,
|
|
// dynamic require() resolution, peer/static-file consumption in tests,
|
|
// and bun-hoisted workspace devDeps (e.g. happy-dom in root package.json
|
|
// resolves for every workspace, so workspaces don't redeclare it).
|
|
// Required by @puppeteer/browsers and puppeteer-core at runtime; listed
|
|
// as a direct dep to guarantee installation even when transitive
|
|
// resolution fails (corrupted cache, dedup edge cases).
|
|
"debug",
|
|
"puppeteer",
|
|
"puppeteer-core",
|
|
"esbuild",
|
|
"giget",
|
|
"gsap",
|
|
"happy-dom",
|
|
"ffmpeg-static",
|
|
"ffprobe-static",
|
|
"@hyperframes/core",
|
|
"@hyperframes/studio",
|
|
"@hyperframes/producer",
|
|
"@fontsource/archivo-black",
|
|
"@fontsource/eb-garamond",
|
|
"@fontsource/ibm-plex-mono",
|
|
"@fontsource/inter",
|
|
"@fontsource/jetbrains-mono",
|
|
"@fontsource/league-gothic",
|
|
"@fontsource/montserrat",
|
|
"@fontsource/nunito",
|
|
"@fontsource/oswald",
|
|
"@fontsource/outfit",
|
|
"@fontsource/space-mono",
|
|
"@fontsource/lato",
|
|
"@fontsource/noto-sans-jp",
|
|
"@fontsource/open-sans",
|
|
"@fontsource/playfair-display",
|
|
"@fontsource/poppins",
|
|
"@fontsource/roboto",
|
|
"@fontsource/source-code-pro",
|
|
],
|
|
"duplicates": {
|
|
// Raise from the default 5 to 6 lines so trivially short Hono route-handler
|
|
// preambles (resolveProject + 404 + body-parse) are below the threshold.
|
|
// The three 5-line groups in files.ts / render.ts are structural boilerplate
|
|
// that naturally converges and is unlikely to diverge; extraction would
|
|
// require intrusive middleware changes beyond this PR's scope.
|
|
"minLines": 6,
|
|
"ignore": [
|
|
// sourcePatcher.ts: pre-existing internal clones between the inline-style
|
|
// and attribute tag-patchers; only the PatchOperation type gained two
|
|
// optional fields here, but the line shift makes fallow re-flag them.
|
|
"packages/studio/src/utils/sourcePatcher.ts",
|
|
// useGsapSelectionHandlers.ts: pre-existing parallel structure with
|
|
// useDomEditWiring.ts (thin useCallback wrappers guarding on selection);
|
|
// only gained two optional pass-through parameters here, but the line
|
|
// shift makes fallow re-flag the pre-existing clone.
|
|
"packages/studio/src/hooks/useGsapSelectionHandlers.ts",
|
|
// gsapParser.ts: recast/babel GSAP writer — intentional duplication between
|
|
// recast and acorn parallel implementations (pre-existing, moved from core).
|
|
"packages/parsers/src/gsapParser.ts",
|
|
// hfIds.ts: 7-line clone with sdk/engine/mutate.ts — pre-existing duplication
|
|
// from when hfIds lived in packages/core/src/parsers/. Moving the file to the
|
|
// new package makes fallow see it as a fresh finding; the underlying clone
|
|
// predates this refactor.
|
|
"packages/parsers/src/hfIds.ts",
|
|
// Parser test files: parallel arrange/act/assert test cases — pre-existing
|
|
// duplication moved from packages/core/src/parsers/.
|
|
"packages/parsers/src/gsapParser.test.ts",
|
|
"packages/parsers/src/gsapParser.test-helpers.ts",
|
|
"packages/parsers/src/gsapWriter.parity.test.ts",
|
|
"packages/parsers/src/gsapWriterParity.corpus.test.ts",
|
|
"packages/parsers/src/gsapWriterParity.acorn.test.ts",
|
|
"packages/parsers/src/htmlParser.roundtrip.test.ts",
|
|
"packages/parsers/src/htmlParser.test.ts",
|
|
// @hyperframes/studio-server test files: parallel arrange/act/assert test cases
|
|
// (pre-existing structure from when studio-api lived in packages/core/src/studio-api/).
|
|
"packages/studio-server/src/routes/files.test.ts",
|
|
"packages/studio-server/src/routes/render.test.ts",
|
|
"packages/studio-server/src/routes/lint.test.ts",
|
|
"packages/studio-server/src/routes/preview.test.ts",
|
|
"packages/studio-server/src/routes/projects.test.ts",
|
|
"packages/studio-server/src/helpers/backupJournal.test.ts",
|
|
"packages/studio-server/src/helpers/finiteMutation.test.ts",
|
|
"packages/studio-server/src/helpers/hfIdPersist.test.ts",
|
|
"packages/studio-server/src/helpers/manualEditsRenderScript.test.ts",
|
|
"packages/studio-server/src/helpers/mediaValidation.test.ts",
|
|
"packages/studio-server/src/helpers/previewAdapter.test.ts",
|
|
"packages/studio-server/src/helpers/safePath.test.ts",
|
|
"packages/studio-server/src/helpers/sourceMutation.test.ts",
|
|
"packages/studio-server/src/helpers/studioMotionRenderScript.test.ts",
|
|
"packages/studio-server/src/helpers/subComposition.test.ts",
|
|
// @hyperframes/lint rule test files: parallel arrange/act/assert test cases
|
|
// (pre-existing structure from when lint lived in packages/core/src/lint/).
|
|
"packages/lint/src/rules/adapters.test.ts",
|
|
"packages/lint/src/rules/captions.test.ts",
|
|
"packages/lint/src/rules/composition.test.ts",
|
|
"packages/lint/src/rules/core.test.ts",
|
|
"packages/lint/src/rules/fonts.test.ts",
|
|
"packages/lint/src/rules/gsap.test.ts",
|
|
"packages/lint/src/rules/media.test.ts",
|
|
"packages/lint/src/rules/slideshow.test.ts",
|
|
"packages/lint/src/rules/textures.test.ts",
|
|
"packages/lint/src/hyperframeLinter.test.ts",
|
|
// slideshowPanelHelpers.ts: setSlideNotes/addFragment/addHotspot share an
|
|
// intentional parallel shape (signature + mapSlidesIn → exists-check →
|
|
// map/append); the per-slide mutation differs, so a shared abstraction
|
|
// would obscure more than it dedupes.
|
|
"packages/studio/src/components/panels/slideshowPanelHelpers.ts",
|
|
// SlideshowPanel.test.ts: parallel arrange/act/assert test cases — collapsing
|
|
// them would hurt readability of what each case verifies.
|
|
"packages/studio/src/components/panels/SlideshowPanel.test.ts",
|
|
// hyperframes-player.test.ts: parallel arrange/act/assert test cases verifying
|
|
// distinct behaviors (same-origin vs realm media, audio-locked permutations,
|
|
// seek bridge variants). Each case is self-contained for readability;
|
|
// extracting the iframe / mock-audio setup helpers would over-couple
|
|
// unrelated scenarios under a shared fixture.
|
|
"packages/player/src/hyperframes-player.test.ts",
|
|
// present.ts mirrors play.ts's server startup + console-output block. The
|
|
// shared low-level pieces (resolve*/injectRuntime/listenOnFreePort) are in
|
|
// utils/compositionServer.ts; the remaining clone is per-command logging text
|
|
// (different labels/help lines) — extracting it would over-abstract.
|
|
"packages/cli/src/commands/present.ts",
|
|
// skillsManifest.test.ts: parallel arrange/act/assert cases for locateInstall
|
|
// (project vs global scope, per-agent host conventions, claude-code priority).
|
|
// Each case seeds a dir then asserts the resolved location/agent; collapsing
|
|
// the shared seed/assert shape would obscure what each scope/host verifies.
|
|
"packages/cli/src/utils/skillsManifest.test.ts",
|
|
// skills.test.ts: parallel prune cases (removed-in-global vs project, non-slug
|
|
// rejection, --source/--dir plumbing) share a mock-checkSkills → runSkillsUpdate
|
|
// → assert-remove-spawn shape; each verifies a distinct prune behavior, so
|
|
// extracting the shared scaffold would obscure what each case asserts.
|
|
"packages/cli/src/commands/skills.test.ts",
|
|
// figma test files: freeze.test.ts and manifest.test.ts share a common
|
|
// arrange/act/assert setup preamble (file creation + test dir handling) that
|
|
// is minimal boilerplate; collapsing it into a shared fixture would reduce
|
|
// readability of each test's independent setup.
|
|
"packages/core/src/figma/freeze.test.ts",
|
|
"packages/core/src/figma/manifest.test.ts",
|
|
// layout-audit.browser.test.ts: parallel arrange/act/assert cases per audit
|
|
// rule (overflow / overlap / occlusion) that each install their own mocked
|
|
// geometry + computed-style before asserting. The clone groups are this
|
|
// pre-existing per-rule scaffold; adding a clip-path case shifts lines and
|
|
// re-flags it. Collapsing the per-rule installers would obscure each case.
|
|
"packages/cli/src/commands/layout-audit.browser.test.ts",
|
|
// portUtils.ts contains two pre-existing bounded HTTP probe implementations;
|
|
// this PR only teaches the server scan to prefer its reported PID, but that
|
|
// line shift makes fallow re-flag the inherited probe clones.
|
|
"packages/cli/src/server/portUtils.ts",
|
|
// gsapParserAcorn.motionEval.test.ts: parallel arrange/act/assert cases for
|
|
// the staggered-collection honesty pass (.from reveal vs .to landing on the
|
|
// rest pose). Each asserts a distinct keyframe shape; collapsing the shared
|
|
// parse/keyframes-extraction scaffold would obscure what each case verifies.
|
|
"packages/core/src/parsers/gsapParserAcorn.motionEval.test.ts",
|
|
// Studio UX-review sweep (148 findings fixed across ~90 studio files):
|
|
// heavily-edited files re-flag line-shifted inherited complexity, and the
|
|
// new small handlers (a11y keydown/menu/dialog/error-state paths, mostly
|
|
// 5-6 cyclomatic) trip the CRAP threshold absent coverage data. Reviewed
|
|
// individually in the studio-ux PR stack rather than refactored here.
|
|
"packages/studio/src/player/components/TimelineClipDiamonds.test.tsx",
|
|
"packages/studio/src/hooks/useFileManager.ts",
|
|
"packages/studio/src/captions/hooks/useCaptionSync.ts",
|
|
"packages/studio/vite.adapter.ts",
|
|
"packages/studio/src/components/sidebar/AudioRow.tsx",
|
|
"packages/studio/src/components/sidebar/AssetsTab.tsx",
|
|
"packages/studio/src/components/editor/propertyPanelFill.tsx",
|
|
"packages/studio/src/captions/store.ts",
|
|
"packages/studio/src/captions/components/CaptionOverlay.tsx",
|
|
"packages/cli/src/server/studioServer.ts",
|
|
// Sub-composition html/body scoping fix: inlineSubCompositions.ts has a
|
|
// pre-existing head-vs-content script-extraction clone, and the scoping
|
|
// test file has pre-existing parallel arrange/act/assert cases. Adding the
|
|
// scopeRootSelectors handling shifts lines and re-flags both.
|
|
"packages/core/src/compiler/inlineSubCompositions.ts",
|
|
"packages/core/src/compiler/compositionScoping.test.ts",
|
|
// useCanvasZOrderTimelineMirror.test.tsx: independent gesture cases repeat
|
|
// the minimal hook/store harness so rapid and rejected z writes cannot
|
|
// leak state through a shared fixture.
|
|
"packages/studio/src/components/nle/useCanvasZOrderTimelineMirror.test.tsx",
|
|
// timelineTimingSync.test.ts: ownership, rollback, transport, and preview
|
|
// convergence cases deliberately keep their server stubs and assertions
|
|
// local; extracting the repeated arrange/act/assert shape would couple
|
|
// otherwise independent failure-domain regressions.
|
|
"packages/studio/src/hooks/timelineTimingSync.test.ts",
|
|
// useElementLifecycleOps.test.tsx: the reveal and atomic multi-file cases
|
|
// repeat a small render/persist harness to keep each transaction's setup,
|
|
// durable outcome, and rollback assertions visible together.
|
|
"packages/studio/src/hooks/useElementLifecycleOps.test.tsx",
|
|
// timelineClipDragCommit.test.ts: drag permutations are self-contained
|
|
// arrange/act/assert scenarios; the repeated clip/file fixture makes each
|
|
// lane and timing outcome readable without shared mutable setup.
|
|
"packages/studio/src/player/components/timelineClipDragCommit.test.ts",
|
|
// timelineZMirror.test.ts: mirror acceptance/refusal cases repeat their
|
|
// compact lane fixture so each z-to-lane decision remains independently
|
|
// understandable and cannot inherit state from another case.
|
|
"packages/studio/src/player/components/timelineZMirror.test.ts",
|
|
// gsapUndoRestore.test.ts: soft/full restore cases keep the serialized and
|
|
// live DOM snapshots beside their assertions; sharing those short fixtures
|
|
// would obscure the exact script/identity difference under test.
|
|
"packages/studio/src/utils/gsapUndoRestore.test.ts",
|
|
],
|
|
},
|
|
"health": {
|
|
// useGsapTweenCache.ts: pre-existing large React-effect hooks (the populate
|
|
// and runtime-scan effects, the per-element animations memo) whose
|
|
// complexity pre-dates the computed-timeline work. Exempted at file level
|
|
// rather than refactored as scope creep.
|
|
"ignore": [
|
|
// sourcePatcher.ts: resolveSourceFile / splitInlineStyleDeclarations /
|
|
// patch*InTag pre-date this PR; only the PatchOperation type gained two
|
|
// optional fields, but the line-shift fingerprint re-flags the inherited
|
|
// complexity.
|
|
"packages/studio/src/utils/sourcePatcher.ts",
|
|
// timeline.ts: collectRuntimeTimelinePayload (CRITICAL) pre-dates this PR;
|
|
// only an import line changed here (slideshow/sceneId → slideshow/index),
|
|
// but the line-shift fingerprint makes fallow re-flag inherited complexity.
|
|
"packages/core/src/runtime/timeline.ts",
|
|
// sceneId.ts: trivial 5-cyclomatic guard, moved verbatim from
|
|
// packages/core/src/slideshow/ into parsers; flagged only because the move
|
|
// makes fallow treat it as a fresh finding.
|
|
"packages/parsers/src/slideshow/sceneId.ts",
|
|
// assetPaths.ts / rewriteSubCompPaths.ts: pure URL/asset-path helpers moved
|
|
// verbatim from packages/core/src/compiler/ into parsers. The move makes
|
|
// fallow score them as fresh (high CRAP = inherited complexity with no
|
|
// coverage mapping yet); the logic is unchanged.
|
|
"packages/parsers/src/assetPaths.ts",
|
|
"packages/parsers/src/rewriteSubCompPaths.ts",
|
|
// gsapParser.ts: the recast/babel GSAP writer is a 2500-line legacy parser;
|
|
// moved from packages/core/src/parsers/ — same complexity rationale.
|
|
"packages/parsers/src/gsapParser.ts",
|
|
// htmlParser.ts has pre-existing complexity (moved from packages/core).
|
|
"packages/parsers/src/htmlParser.ts",
|
|
// studio-server files: pre-existing complexity (moved from packages/core/src/studio-api/).
|
|
// files.ts: executeGsapMutationRecast/Acorn are CRITICAL; excluded as files.ts
|
|
// was already in health.ignore at the old path (packages/core/src/studio-api/routes/files.ts).
|
|
"packages/studio-server/src/routes/files.ts",
|
|
"packages/studio-server/src/routes/render.ts",
|
|
"packages/studio-server/src/routes/thumbnail.ts",
|
|
"packages/studio-server/src/helpers/manualEditsRenderScript.ts",
|
|
"packages/studio-server/src/helpers/studioMotionRenderScript.ts",
|
|
"packages/studio-server/src/helpers/subComposition.ts",
|
|
// lint rule implementations and project linter: pre-existing complexity
|
|
// (moved from packages/core/src/lint/). File-level exemption avoids the
|
|
// line-shift fingerprint problem for inherited findings.
|
|
"packages/lint/src/rules/media.ts",
|
|
"packages/lint/src/rules/textures.ts",
|
|
"packages/lint/src/rules/gsap.ts",
|
|
"packages/lint/src/project.ts",
|
|
// SlideshowPanel.tsx: top-level editor panel that wires several independent
|
|
// sections (slides/inspector/branches/hotspot). Its cyclomatic count comes
|
|
// from that fan-out; splitting it would scatter shared state without
|
|
// reducing real complexity. File-level exemption (not an inline comment)
|
|
// avoids the line-shift fingerprint problem noted above.
|
|
"packages/studio/src/components/panels/SlideshowPanel.tsx",
|
|
// play.ts / present.ts: CLI command entrypoints whose cyclomatic count is
|
|
// browser/arg validation + server wiring (same shape as preview.ts). The
|
|
// serving logic is factored into utils/compositionServer.ts; the remaining
|
|
// body is linear validation that reads clearly inline.
|
|
"packages/cli/src/commands/play.ts",
|
|
"packages/cli/src/commands/present.ts",
|
|
// sync-agent-dirs.ts: a build-time codegen that regex-parses upstream
|
|
// agents.ts. parseAgents/resolveGlobalExpr are branchy by nature (literal
|
|
// vs base-var args, validation throws) but small and well-tested via the
|
|
// generated table's shape test; this is dev tooling, not shipped runtime.
|
|
"packages/cli/scripts/sync-agent-dirs.ts",
|
|
// Files modified only for import-path updates (one-line changes to switch
|
|
// from @hyperframes/core/* subpaths to the new packages). Their complexity
|
|
// is pre-existing; the line-shift fingerprint problem makes fallow treat
|
|
// the violations as new even though no logic changed.
|
|
"packages/cli/src/server/studioServer.ts",
|
|
// findPortAndServe's existing port-selection flow predates this PR. The
|
|
// preview-lifecycle change only adds PID metadata to the config response,
|
|
// which shifts the inherited complexity fingerprint in portUtils.ts.
|
|
"packages/cli/src/server/portUtils.ts",
|
|
"packages/core/src/core.types.ts",
|
|
"packages/core/src/generators/hyperframes.ts",
|
|
"packages/producer/src/services/htmlCompiler.ts",
|
|
"packages/studio/src/hooks/gsapRuntimeBridge.ts",
|
|
"packages/studio/src/hooks/gsapShared.ts",
|
|
"packages/studio/src/hooks/gsapDragPositionCommit.ts",
|
|
"packages/studio/src/hooks/gsapKeyframeCacheHelpers.ts",
|
|
"packages/studio/vite.config.ts",
|
|
"packages/cli/src/commands/lint.ts",
|
|
"packages/cli/src/commands/preview.ts",
|
|
"packages/cli/src/commands/publish.ts",
|
|
"packages/cli/src/server/studioServer.ts",
|
|
// set-version.ts: compareSemver helper has pre-existing complexity from
|
|
// semver string parsing logic; line-shift fingerprint problem from new
|
|
// packages added to PACKAGES array makes fallow treat it as new.
|
|
"scripts/set-version.ts",
|
|
// gsapRuntimeReaders.ts: pre-existing complexity in readAllAnimatedProperties;
|
|
// line-shift fingerprint from import-path updates triggers the violation.
|
|
"packages/studio/src/hooks/gsapRuntimeReaders.ts",
|
|
// In-page audit scripts: single large browser-side IIFE wrappers
|
|
// (auditLayout/__contrastAudit) with pre-existing CRITICAL helpers
|
|
// (textOverflowFixHint, selectorFor, the WCAG walk). Adding the small
|
|
// clip-path probe helpers shifts every function below it, so the line-shift
|
|
// fingerprint re-flags inherited complexity even though the new helpers are
|
|
// all at the lowest tier (<=5 cyclomatic).
|
|
"packages/cli/src/commands/layout-audit.browser.js",
|
|
"packages/cli/src/commands/contrast-audit.browser.js",
|
|
// lottie.ts: the flagged `seek` handler (lottie-web/dotLottie dual-API
|
|
// dispatch, unchanged by the duration-auto-inference work in this PR)
|
|
// pre-dates this PR's scope. New functions added earlier in the file
|
|
// (getInferredDurationSeconds + helpers) shifted its line numbers,
|
|
// breaking fallow's inherited-detection fingerprint. File-level
|
|
// exemption avoids the line-shift problem for this inherited finding.
|
|
"packages/core/src/runtime/adapters/lottie.ts",
|
|
// info.ts: the flagged `run` command handler pre-dates the keyframes-cli
|
|
// PR; that PR only added the orientation()/durationFromHtml() helpers and
|
|
// swapped a few `maxEnd` reads for the new `duration` variable, without
|
|
// adding branches. The line-shift fingerprint re-flags the inherited
|
|
// complexity even though the logic is unchanged.
|
|
"packages/cli/src/commands/info.ts",
|
|
// gsapParserAcorn.ts: the flagged `sameMemberAccess` (structural equality
|
|
// of two member-access nodes) pre-dates this PR's motion-eval work
|
|
// (added in #1760, unchanged since). The new const-folding / set-seeding /
|
|
// label-position code added earlier in the file shifted its line number,
|
|
// so the line-shift fingerprint re-flags this inherited finding.
|
|
"packages/parsers/src/gsapParserAcorn.ts",
|
|
// isFigmaManifestRecord: type guard with 19 cyclomatic due to chained
|
|
// field validation (id/type/path/source types + value shape guards).
|
|
// This is the correct shape for a discriminating type guard; refactoring
|
|
// into smaller guards would obscure the unified validation contract.
|
|
"packages/core/src/figma/manifest.ts",
|
|
// Studio UX-review sweep (148 findings fixed across ~90 studio files):
|
|
// heavily-edited files re-flag line-shifted inherited complexity, and the
|
|
// new small handlers (a11y keydown/menu/dialog/error-state paths, mostly
|
|
// 5-6 cyclomatic) trip the CRAP threshold absent coverage data. Reviewed
|
|
// individually in the studio-ux PR stack rather than refactored here.
|
|
"packages/studio/src/App.tsx",
|
|
"packages/studio/src/captions/components/CaptionAnimationPanel.tsx",
|
|
"packages/studio/src/captions/components/CaptionOverlay.tsx",
|
|
"packages/studio/src/captions/components/CaptionOverlayUtils.ts",
|
|
"packages/studio/src/captions/components/CaptionPropertyPanel.tsx",
|
|
"packages/studio/src/captions/components/shared.tsx",
|
|
"packages/studio/src/captions/hooks/useCaptionSync.ts",
|
|
"packages/studio/src/components/AskAgentModal.tsx",
|
|
"packages/studio/src/components/editor/BlockParamsPanel.tsx",
|
|
"packages/studio/src/components/editor/DomEditOverlay.tsx",
|
|
"packages/studio/src/components/editor/FileTree.tsx",
|
|
"packages/studio/src/components/editor/FileTreeNodes.tsx",
|
|
"packages/studio/src/components/editor/LayersPanel.tsx",
|
|
"packages/studio/src/components/editor/MotionPathNode.tsx",
|
|
"packages/studio/src/components/editor/PropertyPanel.tsx",
|
|
"packages/studio/src/components/editor/propertyPanelFont.tsx",
|
|
"packages/studio/src/components/editor/propertyPanelMediaSection.tsx",
|
|
"packages/studio/src/components/editor/propertyPanelStyleSections.tsx",
|
|
"packages/studio/src/components/editor/Transform3DCube.tsx",
|
|
"packages/studio/src/components/LintModal.tsx",
|
|
"packages/studio/src/components/MediaPreview.tsx",
|
|
"packages/studio/src/components/nle/NLEPreview.tsx",
|
|
"packages/studio/src/components/sidebar/AudioRow.tsx",
|
|
"packages/studio/src/components/sidebar/BlocksTab.tsx",
|
|
"packages/studio/src/components/sidebar/CompositionsTab.tsx",
|
|
"packages/studio/src/components/sidebar/LeftSidebar.tsx",
|
|
"packages/studio/src/components/storyboard/StoryboardLoaded.tsx",
|
|
"packages/studio/src/components/StudioRightPanel.tsx",
|
|
"packages/studio/src/components/StudioToast.tsx",
|
|
"packages/studio/src/components/ui/Tooltip.tsx",
|
|
"packages/studio/src/components/ui/useDialogBehavior.ts",
|
|
"packages/studio/src/hooks/useAppHotkeys.ts",
|
|
"packages/studio/src/hooks/useCaptionDetection.ts",
|
|
"packages/studio/src/hooks/useFileManager.ts",
|
|
"packages/studio/src/hooks/useFrameCapture.ts",
|
|
"packages/studio/src/hooks/usePanelLayout.ts",
|
|
"packages/studio/src/player/components/menuKeyboardNav.ts",
|
|
"packages/studio/src/player/components/Timeline.tsx",
|
|
"packages/studio/src/player/components/TimelineCanvas.tsx",
|
|
"packages/studio/src/player/components/TimelineClip.tsx",
|
|
"packages/studio/src/player/components/TimelineClipDiamonds.tsx",
|
|
// Sub-composition html/body scoping fix: these files carry pre-existing
|
|
// CRITICAL/HIGH functions (inlineSubCompositions, bundleToSingleHtml,
|
|
// mountCompositionContent/loadExternalCompositions, scopeSelector/
|
|
// replaceAuthoredRootIdSelectors) that pre-date this PR. The change only
|
|
// threads a scopeRootSelectors option through the existing scoping calls;
|
|
// the line-shift fingerprint re-flags the inherited complexity.
|
|
"packages/core/src/compiler/compositionScoping.ts",
|
|
"packages/core/src/compiler/inlineSubCompositions.ts",
|
|
"packages/core/src/compiler/htmlBundler.ts",
|
|
"packages/core/src/runtime/compositionLoader.ts",
|
|
],
|
|
},
|
|
}
|