Skip to content

Commit

Permalink
improve small timeline zoom segments
Browse files Browse the repository at this point in the history
  • Loading branch information
Brendonovich committed Jan 13, 2025
1 parent dcd8b95 commit fec8d86
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 43 deletions.
88 changes: 55 additions & 33 deletions apps/desktop/src/routes/editor/Timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ import { createMemo } from "solid-js";

import { commands, TimelineSegment } from "~/utils/tauri";
import {
SegmentContextProvider,
TimelineContextProvider,
TrackContextProvider,
useEditorContext,
useSegmentContext,
useTimelineContext,
useTrackContext,
} from "./context";
Expand Down Expand Up @@ -459,7 +461,7 @@ export function Timeline() {

return (
<SegmentRoot
class="border-red-300 group"
class="border-red-300 group bg-red-50 hover:bg-opacity-80 transition-colors"
innerClass="ring-red-300"
segment={segment}
onMouseEnter={() => {
Expand All @@ -470,7 +472,7 @@ export function Timeline() {
}}
>
<SegmentHandle
class="bg-red-300 group-hover:bg-opacity-80 transition-colors"
class="bg-red-300 hover:opacity-80 transition-colors"
onMouseDown={(downEvent) => {
const start = segment.start;

Expand Down Expand Up @@ -531,7 +533,7 @@ export function Timeline() {
}}
/>
<SegmentContent
class="bg-red-50 cursor-pointer group-hover:bg-opacity-80 transition-colors flex items-center justify-center"
class="cursor-pointer flex items-center justify-center"
onClick={(e) => {
setState("timelineSelection", {
type: "zoom",
Expand All @@ -540,15 +542,23 @@ export function Timeline() {
e.stopPropagation();
}}
>
<div class="text-xs text-gray-500 whitespace-nowrap flex flex-col justify-center items-center gap-1">
<div class="flex items-center gap-1 text-red-300">
<IconLucideSearch class="size-3" />{" "}
{zoomPercentage()}
</div>
</div>
{(() => {
const ctx = useSegmentContext();

return (
<Show when={ctx.width() > 100}>
<div class="text-xs text-gray-500 whitespace-nowrap flex flex-col justify-center items-center gap-1">
<div class="flex items-center gap-1 text-red-300">
<IconLucideSearch class="size-3" />{" "}
{zoomPercentage()}
</div>
</div>
</Show>
);
})()}
</SegmentContent>
<SegmentHandle
class="bg-red-300 group-hover:bg-opacity-80 transition-colors"
class="bg-red-300 hover:opacity-80 transition-colors"
onMouseDown={(downEvent) => {
const end = segment.end;

Expand Down Expand Up @@ -669,34 +679,38 @@ function SegmentRoot(
return (props.segment.start / duration()) * (trackBounds.width ?? 0);
});

const width = () =>
((trackBounds.width ?? 0) * (props.segment.end - props.segment.start)) /
duration();

return (
<div
{...props}
class={cx(
"border rounded-[calc(0.75rem+1px)] h-[3rem] w-full",
props.class,
isSelected() && "wobble-wrapper",
isFreeForm() && "absolute"
)}
style={{
"--segment-x": `${translateX()}px`,
transform: isFreeForm() ? "translateX(var(--segment-x))" : undefined,
width: `${
(100 * (props.segment.end - props.segment.start)) / duration()
}%`,
}}
onMouseDown={props.onMouseDown}
ref={props.ref}
>
<SegmentContextProvider width={width}>
<div
{...props}
class={cx(
"h-full border border-white ring-1 flex flex-row rounded-xl overflow-hidden group",
props.innerClass
"border rounded-[calc(0.75rem+1px)] h-[3rem] w-full",
props.class,
isSelected() && "wobble-wrapper",
isFreeForm() && "absolute"
)}
style={{
"--segment-x": `${translateX()}px`,
transform: isFreeForm() ? "translateX(var(--segment-x))" : undefined,
width: `${width()}px`,
}}
onMouseDown={props.onMouseDown}
ref={props.ref}
>
{props.children}
<div
class={cx(
"h-full border border-white ring-1 flex flex-row rounded-xl overflow-hidden group",
props.innerClass
)}
>
{props.children}
</div>
</div>
</div>
</SegmentContextProvider>
);
}

Expand All @@ -713,7 +727,15 @@ function SegmentContent(props: ComponentProps<"div">) {
}

function SegmentHandle(props: ComponentProps<"div">) {
const ctx = useSegmentContext();
return (
<div {...props} class={cx("w-[0.5rem] cursor-col-resize", props.class)} />
<div
{...props}
class={cx(
"w-[0.5rem] cursor-col-resize shrink-0 data-[hidden='true']:opacity-0 transition-opacity",
props.class
)}
data-hidden={ctx.width() < 50}
/>
);
}
5 changes: 5 additions & 0 deletions apps/desktop/src/routes/editor/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,8 @@ export const [TrackContextProvider, useTrackContext] = createContextProvider(
},
null!
);

export const [SegmentContextProvider, useSegmentContext] =
createContextProvider((props: { width: Accessor<number> }) => {
return props;
}, null!);
4 changes: 3 additions & 1 deletion crates/export/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ where
MP4Encoder::video_format(),
self.output_size.0,
self.output_size.1,
30,
FPS,
),
audio_info,
cap_media::encoders::Output::File(self.output_path.clone()),
Expand Down Expand Up @@ -310,6 +310,7 @@ where
tx_image_data,
&self.meta,
self.render_segments,
FPS,
)
.then(|f| async { f.map_err(Into::into) });

Expand Down Expand Up @@ -489,6 +490,7 @@ where
tx_image_data,
&self.meta,
self.render_segments,
FPS,
)
.await?;

Expand Down
18 changes: 9 additions & 9 deletions crates/rendering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ pub async fn render_video_to_channel(
sender: mpsc::Sender<RenderedFrame>,
meta: &RecordingMeta,
segments: Vec<RenderSegment>,
fps: u32,
) -> Result<(), RenderingError> {
let constants = RenderVideoConstants::new(options, meta).await?;
let recordings = ProjectRecordings::new(meta);
Expand Down Expand Up @@ -206,7 +207,7 @@ pub async fn render_video_to_channel(
}
};

let total_frames = (30_f64 * duration).ceil() as u32;
let total_frames = (fps as f64 * duration).ceil() as u32;
println!(
"Final export duration: {} seconds ({} frames at 30fps)",
duration, total_frames
Expand Down Expand Up @@ -356,7 +357,6 @@ impl RenderVideoConstants {
depth_or_array_layers: 1,
},
);
println!("Watermark texture created and written to GPU");

let watermark_view = watermark_texture.create_view(&wgpu::TextureViewDescriptor::default());
let watermark_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
Expand Down Expand Up @@ -1091,12 +1091,12 @@ pub async fn produce_frame(
is_upgraded: 0.0,
};

println!(
"Rendering watermark at position: {:?}, size: {:?}, output_size: {:?}",
watermark_uniforms.position,
watermark_uniforms.watermark_size,
watermark_uniforms.output_size
);
// println!(
// "Rendering watermark at position: {:?}, size: {:?}, output_size: {:?}",
// watermark_uniforms.position,
// watermark_uniforms.watermark_size,
// watermark_uniforms.output_size
// );

let watermark_buffer =
constants
Expand Down Expand Up @@ -1170,7 +1170,7 @@ pub async fn produce_frame(
render_pass.set_pipeline(&constants.watermark_pipeline.render_pipeline);
render_pass.set_bind_group(0, &watermark_bind_group, &[]);
render_pass.draw(0..6, 0..1); // Using 6 vertices for two triangles
println!("Drew watermark with 6 vertices");
// println!("Drew watermark with 6 vertices");
}

constants.queue.submit(Some(watermark_encoder.finish()));
Expand Down

1 comment on commit fec8d86

@vercel
Copy link

@vercel vercel bot commented on fec8d86 Jan 13, 2025

Choose a reason for hiding this comment

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

Please sign in to comment.