Advanced Guides
Cut Block (Blade Tool)
Slice and split timeline action blocks at precise time positions using the CutOverlay component.
The CutOverlay provides a visual "blade" that lets users split action blocks at any time position. It operates as a standalone overlay component mounted next to the timeline.
Live Preview
Turn on blade mode to cut blocks.
How it Works
CutOverlaysits on top of<Timeline>inside aposition: relativewrapper- When the user hovers over an action block, a precision blade line appears
- When they click,
onCutfires with the exact row ID, action ID, and cut time - Use the included
splitActionInRowutility to perform the immutable data update
Basic Usage
import React, { useState } from "react";
import {
Timeline,
TimelineRow,
CutOverlay,
splitActionInRow,
} from "@keplar-404/react-timeline-editor";
const mockData: TimelineRow[] = [
{
id: "0",
actions: [{ id: "action00", start: 0, end: 10, effectId: "effect0" }],
},
];
export const EditorCutBlock = () => {
const [data, setData] = useState(mockData);
const [isCutMode, setIsCutMode] = useState(false);
// Geometry must match between Timeline and CutOverlay
const scale = 5;
const scaleSplitCount = 10;
const scaleWidth = 160;
const startLeft = 20;
const rowHeight = 32;
const editAreaTopOffset = 32; // Height of the time ruler
const handleCut = (rowId: string, actionId: string, cutTime: number) => {
// splitActionInRow returns a new immutable data array
const newData = splitActionInRow(data, rowId, actionId, cutTime);
setData(newData);
};
return (
<div
style={{
position: "relative",
width: "100%",
height: "400px",
display: "flex",
flexDirection: "column",
}}
>
<div style={{ flexShrink: 0, paddingBottom: "8px" }}>
<button
className="bg-blue-600 text-white px-4 py-2 rounded"
onClick={() => setIsCutMode(!isCutMode)}
>
{isCutMode ? "Disable Cut Blade" : "Enable Cut Blade (Hold C)"}
</button>
</div>
<div style={{ flex: 1, position: "relative" }}>
<Timeline
editorData={data}
effects={{}}
onChange={setData}
scale={scale}
scaleWidth={scaleWidth}
startLeft={startLeft}
rowHeight={rowHeight}
disableDrag={isCutMode} // Disable regular dragging while in cut mode
style={{ width: "100%", height: "100%" }}
/>
<CutOverlay
data={data}
scale={scale}
scaleSplitCount={scaleSplitCount}
scaleWidth={scaleWidth}
startLeft={startLeft}
rowHeight={rowHeight}
editAreaTopOffset={editAreaTopOffset}
gridSnap={false}
config={{ keyboardModifier: "c" }} // Activate with 'C' key
onModifierChange={setIsCutMode}
onCut={handleCut}
/>
</div>
</div>
);
};Key constraint: Every geometry prop (scale, scaleWidth, startLeft, rowHeight) must be
identical in both <Timeline> and <CutOverlay>, otherwise the blade and block positions won't align.
Visual Configuration
Customize the blade's appearance via the config prop:
<CutOverlay
{/* ...required geometry props... */}
config={{
bladeColor: '#ef4444', // Vertical blade line color
showPill: true, // Show floating time label
formatPillLabel: (time) => `✂ ${time.toFixed(2)}s`, // Custom label format
pillColor: '#ef4444', // Label background
pillTextColor: '#ffffff', // Label text color
showBlockHighlight: true, // Highlight hovered block
blockHighlightColor: 'rgba(239,68,68,0.08)', // Block highlight fill
blockHighlightBorderColor: 'rgba(239,68,68,0.3)', // Block highlight border
cursor: 'col-resize', // Custom CSS cursor
keyboardModifier: 'c', // Hold 'c' key to activate
}}
onCut={handleCut}
/>splitActionInRow Utility
import { splitActionInRow } from "@keplar-404/react-timeline-editor";
const newData = splitActionInRow(
data, // Current TimelineRow[]
"row-1", // Row ID
"action-1", // Action ID to split
5, // Cut time in seconds
);
// Result: the action [0, 10] becomes two: [0, 5] and [5, 10]The original action's effectId and data are inherited by both resulting pieces.