summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/panels/properties/index.tsx
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-02-28 18:41:22 +0100
committerMaze Winther <mazewinther@gmail.com>2026-02-28 18:41:22 +0100
commit216e3e0c397be3719a94e1a22bc1c2ce2de3856c (patch)
tree883bdda1539f11ccf5d6fe50a994e4e6dbee0d75 /apps/web/src/components/editor/panels/properties/index.tsx
parenta9e93471a74a3d1978278f09f35632d4f6588a76 (diff)
downloadopencut-216e3e0c397be3719a94e1a22bc1c2ce2de3856c.tar.gz
feat: introduce WebGL effects system and Blur effect
This implements the foundational architecture for video effects, starting with a multi-pass WebGL rendering pipeline and a customizable Gaussian Blur effect. Key changes: - WebGL Engine: Added `raw-loader` for `.glsl` shaders, multi-pass framebuffer rendering, and live offscreen canvas previews. - Node Architecture: Replaced hardcoded background blur with `CompositeEffectNode` and added `EffectLayerNode` to apply effects to specific visual elements. - Timeline & DND: Added a new `effect` track type. Upgraded drag-and-drop to support dropping effects directly onto the timeline. Consolidated track constants into a cleaner `TRACK_CONFIG`. - UI/UX: Added an Effects tab in the assets panel with live previews. Added an Effect Properties panel with sliders and inputs for fine-tuning parameters. - Data Model: Added `sourceDuration` to video and audio elements, and wrote a v8 storage migration to update existing projects to the new schema. - Docs: Added `CHANGELOG.md` tracking v0.1.0 and v0.2.0, plus `docs/effects-renderer.md` to document the new WebGL pipeline.
Diffstat (limited to 'apps/web/src/components/editor/panels/properties/index.tsx')
-rw-r--r--apps/web/src/components/editor/panels/properties/index.tsx65
1 files changed, 39 insertions, 26 deletions
diff --git a/apps/web/src/components/editor/panels/properties/index.tsx b/apps/web/src/components/editor/panels/properties/index.tsx
index 4f285f84..75dd81a9 100644
--- a/apps/web/src/components/editor/panels/properties/index.tsx
+++ b/apps/web/src/components/editor/panels/properties/index.tsx
@@ -4,9 +4,37 @@ import { ScrollArea } from "@/components/ui/scroll-area";
import { AudioProperties } from "./audio-properties";
import { VideoProperties } from "./video-properties";
import { TextProperties } from "./text-properties";
+import { EffectProperties } from "./effect-properties";
import { EmptyView } from "./empty-view";
import { useEditor } from "@/hooks/use-editor";
import { useElementSelection } from "@/hooks/timeline/element/use-element-selection";
+import type { TimelineElement, TimelineTrack } from "@/types/timeline";
+
+function ElementProperties({
+ track,
+ element,
+}: {
+ track: TimelineTrack;
+ element: TimelineElement;
+}) {
+ if (element.type === "text") {
+ return <TextProperties element={element} trackId={track.id} />;
+ }
+ if (element.type === "audio") {
+ return <AudioProperties _element={element} />;
+ }
+ if (
+ element.type === "video" ||
+ element.type === "image" ||
+ element.type === "sticker"
+ ) {
+ return <VideoProperties element={element} trackId={track.id} />;
+ }
+ if (element.type === "effect") {
+ return <EffectProperties element={element} trackId={track.id} />;
+ }
+ return null;
+}
export function PropertiesPanel() {
const editor = useEditor();
@@ -16,34 +44,19 @@ export function PropertiesPanel() {
elements: selectedElements,
});
+ const hasSelection = selectedElements.length > 0;
+
return (
- <div className="panel bg-background h-full rounded-sm border border-t-0 overflow-hidden">
- {selectedElements.length > 0 ? (
+ <div className="panel bg-background h-full rounded-sm border overflow-hidden">
+ {hasSelection ? (
<ScrollArea className="h-full scrollbar-hidden">
- {elementsWithTracks.map(({ track, element }) => {
- if (element.type === "text") {
- return (
- <div key={element.id}>
- <TextProperties element={element} trackId={track.id} />
- </div>
- );
- }
- if (element.type === "audio") {
- return <AudioProperties key={element.id} _element={element} />;
- }
- if (
- element.type === "video" ||
- element.type === "image" ||
- element.type === "sticker"
- ) {
- return (
- <div key={element.id}>
- <VideoProperties element={element} trackId={track.id} />
- </div>
- );
- }
- return null;
- })}
+ {elementsWithTracks.map(({ track, element }) => (
+ <ElementProperties
+ key={element.id}
+ track={track}
+ element={element}
+ />
+ ))}
</ScrollArea>
) : (
<EmptyView />