Skip to content

GPU compositor refactor with masks, effects, and preview fixes#118

Merged
walterlow merged 69 commits intomainfrom
gpu-refactor
Mar 11, 2026
Merged

GPU compositor refactor with masks, effects, and preview fixes#118
walterlow merged 69 commits intomainfrom
gpu-refactor

Conversation

@walterlow
Copy link
Copy Markdown
Owner

Summary

  • move preview, composition, and export onto the GPU compositor and scene runtime, including GPU transitions, scopes, and effect rendering
  • add interactive mask and corner-pin tooling, shape-mask pen editing, and related playback/export fixes
  • include follow-up fixes for clip masks, text export cropping, glitch/chromatic mappings, and mask-pen closing UX

Testing

  • pre-push checks
  • npm run test:run -- src/features/preview/components/mask-editor-overlay.test.tsx

walterlow added 30 commits March 1, 2026 13:13
#98)

* fix(preview): prevent quality dropdown from capturing Space play/pause

Block Space key on the quality SelectTrigger so it doesn't open the
dropdown, and use capture-phase event listener for the play/pause
hotkey to ensure it fires before Radix UI consumes the event.
Also defer blur calls via requestAnimationFrame to avoid focus races
when the dropdown closes.

* fix(preview): apply same Space key and blur fixes to zoom dropdown

Rename handler to handleSelectTriggerKeyDown and reuse it on the zoom
SelectTrigger. Defer zoom blur calls via requestAnimationFrame and add
onCloseAutoFocus to the zoom SelectContent to match the quality
dropdown fixes.
…#99)

* fix(export): align IO trim conversion with preview timing

* fix(export): route source frame conversion through deps adapter
…heels (#102)

* feat(text): add italic and underline style support

* feat(effects): add color grading system with LUT, curves, and wheels

Introduce a color-grading effect type with three variants:
- LUT: built-in preset looks (cinematic, teal-orange, film stocks, etc.)
  with intensity control
- Curves: per-channel tone curves with interactive control points and
  slider-based shadows/midtones/highlights/contrast adjustments
- Wheels: 3-way color wheels (shadows/midtones/highlights) with
  temperature, tint, and saturation global controls

Also adds a color scopes panel toggle in the preview area and upgrades
the frame capture pipeline to support scopes and thumbnail workflows.

* feat(effects): add custom .cube LUT import with OPFS library and canvas rendering

Support importing, saving, and applying custom .cube LUT files in the
color grading pipeline. LUTs are persisted in OPFS via a library manager,
parsed with a dedicated .cube parser, and rendered through both GPU
(WebGL) and CPU fallback paths during export. The preview pipeline forces
the fast-scrub overlay when custom cube LUTs are active to ensure
accurate per-frame color grading.

* fix(effects): route media-library access through deps seam

* fix: address PR review findings across color grading and effects UI

- Add aria-label and aria-pressed to text style toggle buttons
- Guard loadSavedCubeLuts with try/catch to prevent unhandled rejections
- Fix curves add-point using true geometric midpoint instead of endpoint
- Add fallback for unknown LUT preset IDs from persisted data
- Add native disabled, aria-disabled, and touchAction to color wheel
- Move vectorscope graticule drawing after putImageData so it renders
- Serialize color scopes interval to prevent overlapping async captures
- Align WHEELS_CONFIG amount ranges to 0..1 matching the interface
…xt clipping (#104)

* fix(preview): keep gizmo transforms live during fast-scrub LUT overlay

Pass live gizmo preview transforms into the fast-scrub composition
renderer so dragged items reflect transform changes with LUT preview
applied instead of freezing at committed values. Subscribe to gizmo
store changes to pump the render loop during forced custom-CUBE
overlays. Preserve the viewed frame when clearing preview mode to
avoid one-frame render source jumps during gizmo interactions.

* fix(preview): sync gizmo transforms with fast-scrub output and fix text clipping

Route gizmo drag interactions through the fast-scrub render path so
transform previews stay consistent with the displayed canvas output.
Add `displayedFrame` to playback state so UI components (gizmo overlay,
keyframe transforms) resolve against the frame actually rendered on
screen rather than a stale preview/current frame.

Lift transform computation out of SelectableItem into GizmoOverlay via
useVisualTransforms, which merges keyframe animations with gizmo and
property-panel preview overrides. Apply text layout expansion for
preview so text items aren't hard-clipped to their bounding box during
editing, matching the live DOM preview behavior.

Update fast-scrub overlay guard to allow the overlay during gizmo
interactions when the rendered frame matches the current frame, removing
the blanket gizmo-interaction bail-out that caused frame jumps.

* refactor(preview): clean up transform gizmo deps and extract text expansion helper

Remove redundant item.id from TransformGizmo useMemo dependency array
since item is already tracked. Extract applyTextExpansion helper in
useVisualTransforms to centralize the three inline text preview
expansion call sites. Add comment documenting default values in
getTextRequiredHeight that mirror TextItem type defaults.

* fix(preview): break overlong first word in text wrap layout

The word-wrapping logic skipped character-breaking when the first word
in a paragraph exceeded maxWidth because the condition was guarded by
`&& currentLine`. Remove the guard so overlong words are broken via
breakWord regardless of their position in the line.
* Lock preview to full resolution and remove quality selectors

* Remove unused preview quality state from video preview
…109)

* feat(export): support masks inside pre-compositions and fix source frame math

Add mask collection and application for sub-composition items in both
preview (composition-content) and canvas export (canvas-item-renderer)
paths. Replace manual Math.round(duration * speed) calculations in
canvas-audio with proper timelineToSourceFrames/sourceToTimelineFrames
conversions for correct mixed-FPS handling.

* refactor(preview): move color scopes from preview overlay to editor panel tab (#107)

Relocate the color scopes panel from a floating overlay in the preview
area to a dedicated tab in the bottom editor panel alongside keyframes.
Add a raw ImageData capture path (captureFrameImageData) to avoid the
encode/decode overhead of the data URL path used for thumbnails. Extract
the scopes view into a shared component for reuse across both locations.

* fix: prevent vectorscope Uint16 overflow and fix conditional hook calls

Change vectorscope density buffer from Uint16Array to Uint32Array to
handle paused sample sizes (384x216 = 82,944 pixels) that can overflow
a single bin. Move visibleTrackIds and activeMaskInfos useMemo hooks
before the early return in CompositionContent so hooks run
unconditionally.
* fix(precomp): apply nested keyframes during live playback

* test(precomp): remove unused React binding in keyframes regression test
Run boundary checks, deps contracts, legacy lib imports, deps wrapper
health, edge budgets, and lint before every push to catch CI failures
locally.
…shaders

Replace Canvas 2D scope rendering with WebGPU compute+render pipeline for
histogram, waveform, vectorscope, and RGB parade. Adds phosphor bloom,
Gaussian trace spread, bilinear sampling, anti-aliased graticule with color
targets and skin tone line. Near-zero-copy frame capture via
copyExternalImageToTexture bypasses getImageData CPU readback. Falls back
to Canvas 2D when WebGPU is unavailable. Adds RGB/R/G/B/Y view mode
toggles for waveform and histogram scopes.
Port GPU effects system from MasterSelects with standalone EffectsPipeline
that manages its own GPUDevice. Includes 30 WGSL fragment shader effects
across 5 categories: color (9), blur (5), distort (7), stylize (8), and
keying (1). Pipeline supports both canvas output (preview) and ImageData
readback (export) via ping-pong rendering with blit passthrough.

Also wires up canvas source capture in video-preview for GPU effect
integration and adds @webgpu/types for TypeScript support.
…eview

Add GpuEffect type to VisualEffect union and wire GPU shader effects
through all three rendering paths:

- UI: GPU effect categories in Add Effect dropdown with generic
  GpuEffectPanel supporting number/boolean/select params
- Export: lazy EffectsPipeline init in client-render-engine with async
  GPU readback via applyAllEffectsAsync for both item and transition
  rendering
- Preview: WebGPU overlay canvas driven by useGpuEffectsOverlay hook
  that captures frames via captureCanvasSource and processes at ~20fps
Wire the standalone WebGPU effects pipeline into the editor:
- Add GpuEffect type to VisualEffect union with per-effect params
- Add GpuEffectPanel component and GPU effect categories in Add Effect dropdown
- Add WebGPU overlay canvas for event-driven GPU effects preview during scrubbing
- Integrate applyAllEffectsAsync with lazy EffectsPipeline in export renderer
- Fix TypeScript narrowing for color-grading effects after union expansion
Integrate GPU shader effects into the editor UI, preview overlay, and
export pipeline. Effects run through a WebGPU EffectsPipeline with
ping-pong textures, cached uniforms, and GPU backpressure. Preview uses
a dedicated overlay canvas with rAF loop for scrubbing/playback; export
uses async applyEffectsToImageData path with proper GPU readback.
…nders

Adopt the masterselects WebGPU approach: capture directly from <video>
elements via copyExternalImageToTexture (near-zero-copy GPU DMA) instead
of running full CPU composition renders through captureCanvasSource.

- EffectsPipeline.applyEffects now accepts HTMLVideoElement as source
- Hook finds <video> in Player DOM and reads every rAF frame on GPU
- Eliminates captureCanvasSource async chain for seeking/playback
- Add cached uniform buffers, texture views, and GPU backpressure
- Scrubbing still uses offscreen canvas dirty flag (already rendered)
Filter collectGpuEffects by item time range so effects from one clip
don't bleed onto other clips. Clear the overlay with a transparent
render pass when no effects are active at the current frame.
…r preview

- Parallelize video decoding across items via Promise.all in preview mode,
  cutting multi-video render time roughly in half
- Add GPU effects pipeline pool mode (beginBatch/endBatch) with per-item
  output canvases for deferred compositing, allowing GPU work pipelining
- Add rendered frame ImageBitmap cache (120 frames LRU) for instant
  backward scrubbing without mediabunny stream restarts
- Add forward jump restart threshold (>3s) to avoid reading through
  hundreds of samples on large forward seeks
- Update canvas-effects to return deferred GPU canvas in pool mode
  for z-order-correct deferred compositing
- Clean up batch pool resources in EffectsPipeline.destroy()
…layback

During playback, use the Remotion Player's DOM <video> elements instead
of mediabunny decode, and feed them directly to the GPU via
importExternalTexture for zero-copy effect processing.

- Add domVideoElementProvider to ItemRenderContext for querying Player
  video elements by item ID during playback
- Add IMPORT_EXTERNAL_SHADER with texture_external binding and destRect
  uniform for positioned video-to-GPU blit
- Add applyEffectsToVideo() to EffectsPipeline: imports video as
  GPUExternalTexture, blits with positioning to ping texture, runs
  effect chain, outputs to canvas — zero pixel copies
- Direct video→GPU path in renderItemWithEffects when video has
  GPU-only effects, simple transform, and DOM video is available
- Export getGpuEffectInstances for use by render engine
- Graceful fallback to standard canvas 2D path when importExternalTexture
  is unsupported or fails
Use full renderFrame for prewarm instead of lightweight prewarmFrame so
prewarmed frames populate the frame cache as ImageBitmaps. Subsequent
scrubs to those frames are instant cache hits (~0.1ms vs 5-80ms).

- Prewarm uses renderFrame to fill frame cache ahead of scrub position
- Forward prewarm steps increased from 1 to 3 frames
- Frame cache increased from 120 to 240 frames (8s at 30fps)
- 16ms time budget caps prewarm work per cycle to keep scrubbing responsive
…in cache to 300

- Add 60-frame ImageBitmap LRU cache to StrictDecodedVideoFrame for
  instant revisits during drag direction reversal in 2-up/4-up overlays
- Increase main composition renderer frame cache from 240 to 300 frames
- Cache keyed by quantized source time (~1/60s resolution)
- Properly clean up ImageBitmaps on source change and unmount
Export with GPU effects was slow due to 4 pixel copies per item per frame
(getImageData → writeTexture → GPU → readback → putImageData). Now uses
the same zero-copy path as preview (copyExternalImageToTexture → GPU →
canvas output → drawImage).

Also enables parallel video decode and GPU batch/pool mode during export,
matching the preview optimizations for multi-clip compositions.
Overlap JPEG encoding of frame N with video decode of frame N+1.
Previously, the worker blocked on convertToBlob before starting the
next decode. Now: snapshot canvas to ImageBitmap immediately (frees
canvas pool slot), flush previous encode, kick off new encode async,
then resume the decode generator.
Filmstrip thumbnails now appear instantly during extraction by
transferring ImageBitmaps from the worker (zero-copy) instead of
waiting for JPEG encode + blob URL creation.

Two parallel pipelines per decoded frame:
1. FAST: createImageBitmap → transfer to main thread → canvas render
2. SLOW: JPEG encode → OPFS save (persistence, runs in background)

The FilmstripTile component renders from bitmap via canvas when
available, falling back to <img> for OPFS-loaded frames. When the
JPEG blob arrives later, it upgrades the frame with a proper URL
and the bitmap is closed.
Remove all legacy effect systems (CSS filters, glitch, halftone,
vignette, LUT, color grading) and consolidate to GPU shader effects.
Add v6 migration to convert existing projects. Restore specialized
UI panels for curves (interactive SVG tone curve editor) and color
wheels (circular hue/amount pickers) adapted for GPU effect params,
with batch param updates for atomic multi-param changes.
…tter

WASM decode prewarm renders (40-80ms each) were blocking the fast scrub
render loop from processing priority frames during playback, causing the
GPU effects overlay to fall ~30 frames behind and show stale content.
…w, and thumbnails

Implement 5 GPU rendering subsystems and integrate blend modes into
preview/export paths:

- GPU compositor pipeline with 25 Photoshop-compatible blend modes (WGSL)
- Bezier mask renderer (CPU path → GPU texture upload)
- Corner pin perspective warp via 16×16 subdivided mesh
- Optical flow analyzer with 3-level Gaussian pyramid (Lucas-Kanade)
- Scene detection service and frame sampling strategies
- GPU thumbnail renderer with low-power device context

Integration:
- Blend mode dropdown in Fill section (grouped by category)
- CSS mix-blend-mode on preview items via item-visual-wrapper
- Canvas2D globalCompositeOperation for export compositing
- GPU effects overlay detection extended for non-normal blend modes
- Occlusion culling updated to skip items with blend modes
- Schema v7 migration for blendMode, masks, cornerPin fields
walterlow added 23 commits March 8, 2026 11:41
GPU/canvas transitions fully handle all transition rendering now.
The CSS-based TransitionOverlay, NativeTransitionVideo, and
OptimizedEffectsBasedTransitionsLayer are no longer needed.
copyExternalImageToTexture requires BOTH COPY_DST and RENDER_ATTACHMENT
usage flags on destination textures (WebGPU spec). Input textures were
missing RENDER_ATTACHMENT, causing Dawn validation errors and black output
for all GPU transitions (dissolve, glitch, light leak).

Also refactors pipeline to two-pass architecture (transition→rgba8unorm→
blit→canvas) matching EffectsPipeline, rewrites glitch shader with
multi-scale displacement and proper smoothstep args, and fixes writeBuffer
to pass typed array directly instead of underlying ArrayBuffer.
…le-pass GPU render

- Replace hard-seek RVFC drift correction with rate-based correction (±2-5%
  playbackRate adjustment) to eliminate visible "drift then jump" jitter
- Pre-mount shadow video elements ~0.5s before transition start so pool
  elements are loaded when the overlap begins (avoids mediabunny fallback)
- Simplify GPU transition pipeline to single-pass (remove blit shader and
  intermediate rgba8unorm texture)
- Fix writeBuffer TypeScript signature for typed arrays
- Align render engine drift threshold (200ms) with RVFC correction
- Remove per-frame diagnostic logging from transition hot path
- Deduplicate getAdjustmentLayerEffects call in transition renderer
- Lower play gate from readyState >= 3 to >= 2 (saves 100-300ms waiting
  for HAVE_FUTURE_DATA when HAVE_CURRENT_DATA is sufficient)
- Seek and play immediately on mount when playback is active instead of
  pausing and waiting for sync effect next frame (~16-50ms savings)
- Skip redundant seeks when element is already at target position (avoids
  readyState drop that delays play start)
- Pre-resume shared AudioContext on playback start to eliminate 50-100ms
  audio delay from suspended context on cold resume
- Skip force-render timeout during playback to prevent play→pause race
Replace flat 300-frame ImageBitmap LRU cache with a 3-tier architecture:
T1 (VRAM GPUTexture, 300 frames), T2 (per-video last-frame), T3 (RAM
ImageBitmap, 900 frames/8GB). Skip cache writes during sequential forward
scrubbing where mediabunny decode (~1ms) is faster than write overhead
(~2-5ms createImageBitmap + GPU upload).
…r GPU transitions

Three new WebGPU shader transitions: pixelate (mosaic dissolve with
CPU-side block computation), chromatic (directional RGB split with
radial lens distortion), and radial blur (zoom + spin blur with
vignette). All include CSS and Canvas 2D fallbacks.
Replace NumberInput with SliderInput across properties panel for bounded-range
controls (volume, fades, speed, opacity, rotation, mask params, effects).
SliderInput features spring-animated click-to-snap, rubber-band overflow,
handle dodge, hash marks, and inline click-to-edit value input.

Add searchable full-width effect picker replacing the DropdownMenu, with
real-time filtering of effects and presets. Add scroll wheel support to
NumberInput. Move SliderInput to shared/ui for cross-feature reuse.
…ider drag

Replace SVG feGaussianBlur (CPU-rendered, laggy) with Canvas2D blur via Skia
(GPU-accelerated) at reduced resolution for clip mask feather. Add preview
store pattern (like corner pin) so feather/opacity sliders write directly to
a lightweight Zustand store that ItemVisualWrapper subscribes to, bypassing
the slow React prop chain through tracks → composition → StableVideoSequence.

Also fix mask gizmo pointer capture, hide transform gizmo during mask editing,
and add masks to StableVideoSequence's areGroupPropsEqual whitelist.
…ayback

Canvas data URL masks caused Chrome to re-decode PNG each paint cycle,
forcing software compositing and audio jitter during playback. Switch to
SVG-only approach: clip-path for simple masks (GPU geometry), SVG mask
for complex cases (feather/opacity/modes). Add preview store integration
for live slider drag feedback.
… animation

Add 'path' shape type with bezier vertices drawn via pen tool in the
preview overlay. Refactor mask rendering from global SVG mask approach
to per-item resolution via useActiveMasks hook, enabling keyframe
animation on shape masks in both preview and export pipelines.
Create GPU and analysis facade modules in src/infrastructure/ to
eliminate 21 direct @/lib/* imports flagged by the legacy-lib-imports
check. Whitelist facade files in the check script.
* refactor: unify composition render scene planning

* refactor: tighten preview and timeline rendering

* Add editable shape and mask pen paths

* Fix timeline navigator drag behavior

* Address PR feedback and CI budgets
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
freecut Ready Ready Preview, Comment Mar 11, 2026 4:02pm

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 11, 2026

Too many files changed for review. (220 files found, 100 file limit)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 11, 2026

Important

Review skipped

Too many files!

This PR contains 219 files, which is 69 over the limit of 150.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2e9e81b2-adf9-49ce-8552-5b065f4e7914

📥 Commits

Reviewing files that changed from the base of the PR and between 33ba56d and 99c533a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (219)
  • .husky/pre-push
  • package.json
  • scripts/check-bundle-budgets.mjs
  • scripts/check-feature-edge-budgets.mjs
  • scripts/check-legacy-lib-imports.mjs
  • src/components/ui/select.tsx
  • src/domain/projects/migrations/migrations.ts
  • src/domain/projects/migrations/types.ts
  • src/domain/timeline/transitions/register-builtins.ts
  • src/domain/timeline/transitions/registry.ts
  • src/domain/timeline/transitions/renderers/gpu.ts
  • src/domain/timeline/transitions/renderers/index.ts
  • src/features/composition-runtime/components/composition-content.keyframes.test.tsx
  • src/features/composition-runtime/components/composition-content.masks.test.tsx
  • src/features/composition-runtime/components/composition-content.tsx
  • src/features/composition-runtime/components/hooks/use-item-visual-state.ts
  • src/features/composition-runtime/components/item-effect-wrapper.tsx
  • src/features/composition-runtime/components/item-visual-wrapper.tsx
  • src/features/composition-runtime/components/item.tsx
  • src/features/composition-runtime/components/shape-content.tsx
  • src/features/composition-runtime/components/stable-video-sequence.tsx
  • src/features/composition-runtime/components/text-content.tsx
  • src/features/composition-runtime/components/transition-renderer.tsx
  • src/features/composition-runtime/components/video-audio-context.ts
  • src/features/composition-runtime/components/video-content.tsx
  • src/features/composition-runtime/compositions/main-composition.tsx
  • src/features/composition-runtime/deps/effects-contract.ts
  • src/features/composition-runtime/deps/effects.ts
  • src/features/composition-runtime/deps/stores-contract.ts
  • src/features/composition-runtime/hooks/use-frame-composition-scene.ts
  • src/features/composition-runtime/utils/audio-scene.test.ts
  • src/features/composition-runtime/utils/audio-scene.ts
  • src/features/composition-runtime/utils/clip-mask-raster.test.ts
  • src/features/composition-runtime/utils/clip-mask-raster.ts
  • src/features/composition-runtime/utils/corner-pin.ts
  • src/features/composition-runtime/utils/dom-video-element-registry.test.ts
  • src/features/composition-runtime/utils/dom-video-element-registry.ts
  • src/features/composition-runtime/utils/frame-scene.test.ts
  • src/features/composition-runtime/utils/frame-scene.ts
  • src/features/composition-runtime/utils/scene-assembly.test.ts
  • src/features/composition-runtime/utils/scene-assembly.ts
  • src/features/composition-runtime/utils/shape-path.ts
  • src/features/composition-runtime/utils/text-layout.ts
  • src/features/composition-runtime/utils/transition-scene.test.ts
  • src/features/composition-runtime/utils/transition-scene.ts
  • src/features/composition-runtime/utils/video-scene.test.ts
  • src/features/composition-runtime/utils/video-scene.ts
  • src/features/editor/components/editor.tsx
  • src/features/editor/components/media-sidebar.tsx
  • src/features/editor/components/preview-area.tsx
  • src/features/editor/components/properties-sidebar/canvas-panel/index.tsx
  • src/features/editor/components/properties-sidebar/clip-panel/audio-section.tsx
  • src/features/editor/components/properties-sidebar/clip-panel/corner-pin-section.tsx
  • src/features/editor/components/properties-sidebar/clip-panel/fill-section.tsx
  • src/features/editor/components/properties-sidebar/clip-panel/index.tsx
  • src/features/editor/components/properties-sidebar/clip-panel/layout-section.tsx
  • src/features/editor/components/properties-sidebar/clip-panel/shape-section.tsx
  • src/features/editor/components/properties-sidebar/clip-panel/text-section.tsx
  • src/features/editor/components/properties-sidebar/clip-panel/video-section.tsx
  • src/features/editor/components/properties-sidebar/components/slider-input.test.tsx
  • src/features/editor/components/properties-sidebar/components/slider-input.tsx
  • src/features/editor/components/properties-sidebar/marker-panel/index.tsx
  • src/features/editor/components/properties-sidebar/transition-panel/index.tsx
  • src/features/editor/components/transitions-panel.tsx
  • src/features/editor/deps/effects-contract.ts
  • src/features/editor/deps/preview-contract.ts
  • src/features/editor/utils/transition-ui-config.test.ts
  • src/features/editor/utils/transition-ui-config.ts
  • src/features/effects/components/effects-section.tsx
  • src/features/effects/components/panels/css-filter-panel.tsx
  • src/features/effects/components/panels/glitch-panel.tsx
  • src/features/effects/components/panels/gpu-curves-panel.tsx
  • src/features/effects/components/panels/gpu-effect-panel.tsx
  • src/features/effects/components/panels/gpu-wheels-panel.tsx
  • src/features/effects/components/panels/halftone-panel.tsx
  • src/features/effects/components/panels/index.ts
  • src/features/effects/components/panels/vignette-panel.tsx
  • src/features/effects/deps/README.md
  • src/features/effects/deps/media-library-contract.ts
  • src/features/effects/hooks/use-effect-previews.ts
  • src/features/effects/index.ts
  • src/features/effects/utils/effect-to-css.ts
  • src/features/effects/utils/glitch-algorithms.ts
  • src/features/export/deps/composition-runtime-contract.ts
  • src/features/export/deps/preview-contract.ts
  • src/features/export/deps/preview.ts
  • src/features/export/deps/timeline-contract.ts
  • src/features/export/utils/canvas-audio.ts
  • src/features/export/utils/canvas-effects.ts
  • src/features/export/utils/canvas-item-renderer.composition-masks.test.ts
  • src/features/export/utils/canvas-item-renderer.ts
  • src/features/export/utils/canvas-keyframes.test.ts
  • src/features/export/utils/canvas-keyframes.ts
  • src/features/export/utils/canvas-masks.test.ts
  • src/features/export/utils/canvas-masks.ts
  • src/features/export/utils/canvas-render-orchestrator.ts
  • src/features/export/utils/canvas-transitions.ts
  • src/features/export/utils/canvas-video-extractor.ts
  • src/features/export/utils/client-render-engine.ts
  • src/features/export/utils/timeline-to-composition.test.ts
  • src/features/export/utils/timeline-to-composition.ts
  • src/features/keyframes/hooks/use-animated-transform.test.tsx
  • src/features/keyframes/hooks/use-animated-transform.ts
  • src/features/preview/components/color-scopes-panel.tsx
  • src/features/preview/components/corner-pin-container.tsx
  • src/features/preview/components/corner-pin-overlay.tsx
  • src/features/preview/components/edit-2up-panels.tsx
  • src/features/preview/components/gizmo-overlay.tsx
  • src/features/preview/components/mask-editor-container.tsx
  • src/features/preview/components/mask-editor-overlay.test.tsx
  • src/features/preview/components/mask-editor-overlay.tsx
  • src/features/preview/components/playback-controls.tsx
  • src/features/preview/components/preview-zoom-controls.tsx
  • src/features/preview/components/selectable-item.tsx
  • src/features/preview/components/transform-gizmo.tsx
  • src/features/preview/components/video-preview.sync.test.tsx
  • src/features/preview/components/video-preview.tsx
  • src/features/preview/deps/composition-runtime-contract.ts
  • src/features/preview/hooks/use-gpu-effects-overlay.test.ts
  • src/features/preview/hooks/use-gpu-effects-overlay.ts
  • src/features/preview/hooks/use-visual-transform.test.tsx
  • src/features/preview/hooks/use-visual-transform.ts
  • src/features/preview/stores/corner-pin-store.ts
  • src/features/preview/stores/mask-editor-store.ts
  • src/features/preview/stores/playback-store.test.ts
  • src/features/preview/utils/fast-scrub-overlay-guard.test.ts
  • src/features/preview/utils/fast-scrub-overlay-guard.ts
  • src/features/preview/utils/mask-path-utils.ts
  • src/features/preview/utils/path-fit.test.ts
  • src/features/preview/utils/path-fit.ts
  • src/features/preview/utils/scrubbing-cache.ts
  • src/features/preview/utils/text-layout.test.ts
  • src/features/preview/utils/text-layout.ts
  • src/features/project-bundle/schemas/project-schema.ts
  • src/features/timeline/components/clip-filmstrip/index.tsx
  • src/features/timeline/components/keyframe-graph-panel.tsx
  • src/features/timeline/components/timeline-content.tsx
  • src/features/timeline/components/timeline-header.tsx
  • src/features/timeline/components/timeline-markers.tsx
  • src/features/timeline/components/timeline-navigator-utils.ts
  • src/features/timeline/components/timeline-navigator.test.tsx
  • src/features/timeline/components/timeline-navigator.tsx
  • src/features/timeline/components/timeline.tsx
  • src/features/timeline/hooks/shortcuts/use-playback-shortcuts.ts
  • src/features/timeline/hooks/use-visible-items.test.ts
  • src/features/timeline/hooks/use-visible-items.ts
  • src/features/timeline/hooks/use-waveform-prefetch.test.ts
  • src/features/timeline/hooks/use-waveform-prefetch.ts
  • src/features/timeline/services/filmstrip-cache.ts
  • src/features/timeline/services/filmstrip-opfs-storage.ts
  • src/features/timeline/stores/compositions-store.ts
  • src/features/timeline/stores/timeline-store-facade.ts
  • src/features/timeline/theme.css
  • src/features/timeline/utils/sub-composition-normalizer.test.ts
  • src/features/timeline/utils/sub-composition-normalizer.ts
  • src/features/timeline/workers/filmstrip-extraction-worker.ts
  • src/infrastructure/analysis/index.ts
  • src/infrastructure/gpu/compositor.ts
  • src/infrastructure/gpu/effects.ts
  • src/infrastructure/gpu/masks.ts
  • src/infrastructure/gpu/scopes.ts
  • src/infrastructure/gpu/transitions.ts
  • src/lib/analysis/index.ts
  • src/lib/analysis/optical-flow-analyzer.ts
  • src/lib/analysis/optical-flow-shaders.ts
  • src/lib/analysis/scene-detection.ts
  • src/lib/gpu-compositor/blend-modes.ts
  • src/lib/gpu-compositor/compositor-pipeline.ts
  • src/lib/gpu-compositor/corner-pin.ts
  • src/lib/gpu-compositor/index.ts
  • src/lib/gpu-compositor/slice-pipeline.ts
  • src/lib/gpu-effects/common.ts
  • src/lib/gpu-effects/effects-pipeline.ts
  • src/lib/gpu-effects/effects/blur.ts
  • src/lib/gpu-effects/effects/color.ts
  • src/lib/gpu-effects/effects/distort.ts
  • src/lib/gpu-effects/effects/keying.ts
  • src/lib/gpu-effects/effects/stylize.ts
  • src/lib/gpu-effects/index.ts
  • src/lib/gpu-effects/types.ts
  • src/lib/gpu-scopes/histogram-scope.ts
  • src/lib/gpu-scopes/index.ts
  • src/lib/gpu-scopes/scope-renderer.ts
  • src/lib/gpu-scopes/vectorscope-scope.ts
  • src/lib/gpu-scopes/waveform-scope.ts
  • src/lib/gpu-transitions/common.ts
  • src/lib/gpu-transitions/index.ts
  • src/lib/gpu-transitions/transition-pipeline.ts
  • src/lib/gpu-transitions/transitions/chromatic.ts
  • src/lib/gpu-transitions/transitions/dissolve.ts
  • src/lib/gpu-transitions/transitions/glitch.ts
  • src/lib/gpu-transitions/transitions/light-leak.ts
  • src/lib/gpu-transitions/transitions/pixelate.ts
  • src/lib/gpu-transitions/transitions/radial-blur.ts
  • src/lib/gpu-transitions/types.ts
  • src/lib/masks/index.ts
  • src/lib/masks/mask-texture-manager.ts
  • src/lib/thumbnails/gpu-thumbnail-renderer.ts
  • src/lib/thumbnails/index.ts
  • src/lib/thumbnails/sample-strategy.ts
  • src/routes/settings.tsx
  • src/shared/components/color-scopes-view.tsx
  • src/shared/state/playback/frame-resolution.test.ts
  • src/shared/state/playback/frame-resolution.ts
  • src/shared/state/playback/store.ts
  • src/shared/state/playback/types.ts
  • src/shared/ui/property-controls/index.ts
  • src/shared/ui/property-controls/number-input.test.tsx
  • src/shared/ui/property-controls/number-input.tsx
  • src/shared/ui/property-controls/slider-input.tsx
  • src/shared/utils/cube-lut.ts
  • src/shared/utils/curve-spline.ts
  • src/types/blend-mode-css.ts
  • src/types/blend-modes.ts
  • src/types/effects.ts
  • src/types/masks.ts
  • src/types/timeline.ts
  • src/types/transition.ts
  • tsconfig.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch gpu-refactor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@walterlow walterlow merged commit 28ff514 into main Mar 11, 2026
5 checks passed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 99c533ae31

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +218 to 220
const visualEffectSchema = z.union([
cssFilterEffectSchema,
glitchEffectSchema,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Accept GPU effects in snapshot validation schema

The migration path now converts effects to type: 'gpu-effect' (migrate in src/domain/projects/migrations/migrations.ts), but visualEffectSchema here still only accepts legacy effect shapes, so validateSnapshotData() rejects snapshots that contain any migrated/new GPU effect and import fails outright. This blocks round-tripping projects once users add or migrate effects under the new GPU-only model.

Useful? React with 👍 / 👎.

Comment thread src/types/timeline.ts
@@ -87,7 +98,7 @@ export type ImageItem = BaseTimelineItem & {
sourceHeight?: number;
};

export type ShapeType = 'rectangle' | 'circle' | 'triangle' | 'ellipse' | 'star' | 'polygon' | 'heart';
export type ShapeType = 'rectangle' | 'circle' | 'triangle' | 'ellipse' | 'star' | 'polygon' | 'heart' | 'path';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add path shape type to snapshot schema

This commit introduces 'path' as a valid ShapeType, but the snapshot validator still uses a shapeTypeSchema enum without 'path', so any project containing a path shape fails schema validation during import (validateSnapshotData) even though the runtime/editor now supports it. That makes newly created path-based shapes non-portable through JSON import/export workflows.

Useful? React with 👍 / 👎.

@walterlow walterlow deleted the gpu-refactor branch April 3, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant