How to Manage Clip Trimming with Millisecond-Accurate Timing Precision in Clypra

Clypra stores clip timing as IEEE-754 floating-point seconds and enforces millisecond precision through the trimIn and trimOut fields, normalized by normalizeClipTiming in timelineClip.ts and ripple-edited via rippleTrimClip in timelineStore.ts.

Clypra is an open-source video editing framework that treats time as a continuous floating-point value, enabling frame-level and millisecond-level precision when managing clip trimming. Unlike editors that round to nearest frames, Clypra's architecture allows you to trim clips to exact millisecond boundaries using the trimIn and trimOut properties stored in the timeline state. This approach ensures that every trim operation maintains the invariant duration === trimOut - trimIn regardless of zoom level or playback resolution.

Understanding Millisecond-Accurate Timing Storage

Clypra represents all temporal values as number types (JavaScript's IEEE-754 double-precision floating-point), where one second equals 1.0 and one millisecond equals 0.001. This storage method provides sub-second precision out of the box without requiring specialized integer scaling or rational number libraries.

The trimIn and trimOut Fields

According to the type definitions in src/types/index.ts, every clip contains two critical fields that drive trimming:

  • trimIn: The offset in seconds from the start of the source media to the first visible frame
  • trimOut: The offset in seconds from the start of the source media to the last visible frame

These values are stored as raw numbers and can accept fractional values down to the millisecond level (e.g., 0.125 for 125 milliseconds).

Core Trimming Implementation

The mathematical integrity of trim operations is maintained in src/lib/timeline/timelineClip.ts, which provides utility functions that enforce Clypra's timing invariants.

Normalizing Clip Timing

When a clip is created or modified, the normalizeClipTiming function (lines 21-40 in timelineClip.ts) clamps trimIn and trimOut to valid ranges and recomputes the clip's duration:

// Pseudocode representation of the normalization logic
const normalizeClipTiming = (clip, sourceDuration) => {
  clip.trimIn = Math.max(0, Math.min(clip.trimIn, sourceDuration));
  clip.trimOut = Math.max(clip.trimIn, Math.min(clip.trimOut, sourceDuration));
  clip.duration = clip.trimOut - clip.trimIn; // Enforces millisecond precision
};

This guarantees that duration always equals trimOut - trimIn, even when the source media length is unknown or when users drag trim handles by fractional amounts.

Calculating Visible Duration

To retrieve the actual playable length of a trimmed clip, use the getClipVisibleDuration helper (lines 15-19 in timelineClip.ts). This function returns the difference between trimOut and trimIn, ensuring that any code consuming clip data receives the precise millisecond-accurate duration.

Performing Ripple Trims

For professional editing workflows, Clypra implements ripple editing through the rippleTrimClip method in src/store/timelineStore.ts (lines 857-910). This function adjusts a clip's trim points while automatically shifting downstream clips to preserve timeline gaps or eliminate overlaps.

Left-Side vs Right-Side Trimming

The rippleTrimClip method accepts three parameters:

  1. clipId: The unique identifier of the target clip
  2. side: Either "left" or "right" indicating which edge to trim
  3. deltaTime: The time change in seconds (positive to extend, negative to shorten)

The implementation follows this sequence:

  1. Computes the desired new duration as clip.duration + deltaTime
  2. Adjusts trimIn (for left-side) or trimOut (for right-side) by the specified delta
  3. Updates the clip's duration to trimOut - trimIn
  4. Propagates the deltaTime value to every subsequent clip on the same track

Because deltaTime accepts floating-point values like 0.030 (30 milliseconds), you can perform ripple edits with millisecond accuracy.

Practical Code Examples

Setting Trim Points Manually

To programmatically set a clip's trim points to exact millisecond values:

import { useTimelineStore } from '@/store/timelineStore';

const clipId = 'c123';
const newTrimIn = 0.125;   // 125 milliseconds
const newTrimOut = 5.000;  // 5 seconds

useTimelineStore.getState().updateClip(clipId, {
  trimIn: newTrimIn,
  trimOut: newTrimOut,
});

Performing a Ripple Trim

To extend a clip's right edge by 30 milliseconds while shifting subsequent clips:

import { useTimelineStore } from '@/store/timelineStore';

// Extend clip "c123" by 30ms at the right edge
useTimelineStore.getState().rippleTrimClip('c123', 'right', 0.030);

To shorten a clip from the left side by 15 milliseconds:

useTimelineStore.getState().rippleTrimClip('c123', 'left', -0.015);

Verifying Visible Duration

To confirm the precise duration after trimming:

import { getClipVisibleDuration } from '@/lib/timeline/timelineClip';

const clip = useTimelineStore.getState().clips.find(c => c.id === 'c123')!;
console.log('Visible duration:', getClipVisibleDuration(clip)); // Returns seconds with millisecond precision

Configuring Snap Behavior

To enable snapping to whole-millisecond intervals during UI interactions:

import { useTimelineStore } from '@/store/timelineStore';

// Toggle snap to 0.001s (1ms) grid
useTimelineStore.getState().toggleSnapEnabled();

UI Precision and Zoom Handling

The visual representation of millisecond-level changes depends on the timeline's zoom level, calculated in src/lib/timeline/timelineZoom.ts. The pixelsPerSecond value determines how many pixels represent one second of time. When zoomed in sufficiently, a single millisecond change (0.001 seconds) becomes visually apparent as a one-pixel shift or greater.

For display purposes, src/lib/utils/timeFormatting.ts (lines 52-53) provides utilities that format timestamps with millisecond precision, ensuring that the user interface reflects the exact values stored in the trimIn and trimOut fields.

Summary

  • Storage Format: Clypra uses floating-point seconds (0.001 = 1ms) for all timing values, defined in src/types/index.ts
  • Core Helpers: normalizeClipTiming and getClipVisibleDuration in timelineClip.ts enforce the invariant that duration === trimOut - trimIn
  • Ripple Editing: The rippleTrimClip method in timelineStore.ts (lines 857-910) maintains millisecond accuracy when shifting downstream clips
  • Manual Updates: Use updateClip from the timeline store to programmatically set trimIn and trimOut to exact millisecond values
  • Visual Feedback: pixelsPerSecond zoom ratios and snapGuides enable precise UI interaction at the millisecond level

Frequently Asked Questions

What data type does Clypra use for millisecond-accurate timing?

Clypra stores all timing values as JavaScript number types (IEEE-754 double-precision floating-point), representing time in seconds. This allows millisecond precision by using values like 0.001 for one millisecond, providing sufficient accuracy for sub-frame editing without requiring specialized rational number libraries.

How does Clypra prevent trim values from exceeding the source media duration?

The normalizeClipTiming function in src/lib/timeline/timelineClip.ts clamps both trimIn and trimOut using Math.max(0, Math.min(trim, sourceDuration)). This ensures trim points never fall below zero or exceed the actual source length, maintaining valid clip boundaries even when users drag trim handles aggressively or programmatic updates provide invalid values.

What is the difference between a standard trim and a ripple trim in Clypra?

A standard trim modifies only the target clip's trimIn or trimOut values without affecting other clips. A ripple trim, implemented via rippleTrimClip in src/store/timelineStore.ts, adjusts the trim point and then propagates the time change (deltaTime) to all subsequent clips on the same track. This shifts downstream content to prevent gaps or overlaps while maintaining the exact millisecond duration change specified.

How does the timeline UI handle millisecond-precision trimming when zoomed out?

The UI relies on the pixelsPerSecond zoom ratio defined in src/lib/timeline/timelineZoom.ts. At low zoom levels, milliseconds may occupy less than one pixel, making them visually imperceptible but still stored accurately. When users enable snapping via toggleSnapEnabled(), the UI constrains drag operations to whole-millisecond intervals (0.001s), ensuring precise edits regardless of the current zoom level.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →