Clip composition tool with client-side recording, multi-clip grid, and media playback for Hiyve video conferencing.
npm install @hiyve/react-clips
Peer dependencies:
npm install @hiyve/react @hiyve/utilities @mui/material @mui/icons-material @emotion/react @emotion/styled react
Optional peer dependencies:
@hiyve/react-collaboration — enables session management (ClipsSession component)@hiyve/react-media-player — enhanced clip playback with waveforms, regions, and volume controls (falls back to native <audio> / <video> elements)import { HiyveProvider } from '@hiyve/react';
import { ClipComposition } from '@hiyve/react-clips';
function App() {
return (
<HiyveProvider apiKey="your-api-key" roomName="my-room">
<ClipComposition
enableRecording
enableDragReorder
maxClips={10}
onClipAdded={(clip) => console.log('Added:', clip.name)}
onError={(err) => console.error(err)}
/>
</HiyveProvider>
);
}
| Component | Description |
|---|---|
ClipComposition |
Main composition component with recording, multi-clip grid, and auto-save |
ClipsSession |
Session wrapper with file management (requires @hiyve/react-collaboration) |
CreateCompositionDialog |
MUI dialog for naming a new composition before creation |
ClipRecorder |
Recording panel for capturing audio and video clips |
ClipPlayer |
Single clip playback (wraps @hiyve/react-media-player or falls back to native elements) |
ClipGrid |
Responsive grid layout with drag-and-drop reorder |
ClipToolbar |
Composition controls (lock, play all, collaboration mode, recorder toggle) |
| Hook | Description |
|---|---|
useClipRecorder |
Client-side recording via the MediaRecorder API. Manages device selection, recording lifecycle, and clip upload. |
useClipPersistence |
Auto-save composition data with configurable interval, manual save, and unsaved change tracking. |
| Function | Description |
|---|---|
generateCompositionId() |
Generate a unique composition ID |
generateClipId() |
Generate a unique clip ID |
getSupportedMimeType(mediaType) |
Get the first browser-supported MIME type for recording |
formatRecordingDuration(seconds) |
Format seconds as mm:ss string |
getFileExtensionFromMime(mimeType) |
Get file extension (.webm, .ogg, .mp4) from a MIME type |
createCompositionFile(client, options) |
Create and upload a new composition JSON file |
| Prop | Type | Default | Description |
|---|---|---|---|
initialComposition |
ClipCompositionFile |
— | Initial composition data to load |
title |
string |
— | Composition title |
fileId |
string |
— | Existing file ID for updates |
fileLocation |
string |
'/Clips' |
Storage location for composition files |
enableAutoSave |
boolean |
true |
Auto-save composition changes |
enableRecording |
boolean |
true |
Show recording controls |
enableRegions |
boolean |
false |
Enable named regions on clip players |
enableAudioPassthrough |
boolean |
false |
Enable audio passthrough mode |
enableDragReorder |
boolean |
true |
Enable drag-and-drop clip reordering |
maxClips |
number |
20 |
Maximum number of clips in the composition |
maxRecordingDuration |
number |
300 |
Maximum recording duration in seconds |
autoSaveInterval |
number |
5000 |
Auto-save interval in milliseconds |
showHeader |
boolean |
true |
Show header with title and save status |
showToolbar |
boolean |
true |
Show toolbar with controls |
readOnly |
boolean |
false |
Disable editing |
labels |
Partial<ClipCompositionLabels> |
— | Custom text labels |
icons |
Partial<ClipCompositionIcons> |
— | Custom icons (ReactNode) |
colors |
Partial<ClipCompositionColors> |
— | Custom color values |
styles |
Partial<ClipCompositionStyles> |
— | Custom style values |
onAutoSave |
(fileId: string) => void |
— | Called after auto-save completes |
onSaveError |
(error: Error) => void |
— | Called when a save error occurs |
onChange |
(composition: ClipCompositionFile) => void |
— | Called when the composition changes |
onClipAdded |
(clip: ClipItem) => void |
— | Called when a clip is added |
onClipRemoved |
(clipId: string) => void |
— | Called when a clip is removed |
onError |
(error: Error) => void |
— | General error callback |
maxHeight |
string | number |
— | Maximum container height |
sx |
SxProps<Theme> |
— | MUI sx styling prop |
ClipComposition exposes a ref with the following methods:
import { useRef } from 'react';
import { ClipComposition, type ClipCompositionRef } from '@hiyve/react-clips';
function MyEditor() {
const ref = useRef<ClipCompositionRef>(null);
return (
<>
<ClipComposition ref={ref} />
<button onClick={() => ref.current?.save()}>Save Now</button>
</>
);
}
| Method / Property | Type | Description |
|---|---|---|
save() |
() => Promise<string | null> |
Trigger a manual save, returns file ID |
isSaving |
boolean |
Whether currently saving |
hasUnsavedChanges |
boolean |
Whether there are unsaved changes |
lastSaved |
Date | null |
Timestamp of the last save |
fileId |
string | null |
Current file ID |
addClip(clip) |
(clip: ClipItem) => void |
Add a clip programmatically |
removeClip(clipId) |
(clipId: string) => void |
Remove a clip by ID |
getComposition() |
() => ClipCompositionFile |
Get the current composition data |
Record audio or video clips with device selection and max duration enforcement:
import { useClipRecorder } from '@hiyve/react-clips';
function MyRecorder() {
const recorder = useClipRecorder({
maxDuration: 120, // 2 minutes
onError: (err) => console.error(err),
});
return (
<div>
<p>State: {recorder.state}</p>
{recorder.state === 'idle' && (
<button onClick={recorder.initialize}>Initialize</button>
)}
{recorder.state === 'ready' && (
<button onClick={recorder.start}>Record</button>
)}
{recorder.state === 'recording' && (
<>
<span>{recorder.duration}s</span>
<button onClick={recorder.pause}>Pause</button>
<button onClick={recorder.stop}>Stop</button>
</>
)}
{recorder.state === 'paused' && (
<>
<button onClick={recorder.resume}>Resume</button>
<button onClick={recorder.stop}>Stop</button>
</>
)}
{recorder.state === 'stopped' && recorder.previewUrl && (
<>
<audio src={recorder.previewUrl} controls />
<button onClick={recorder.discard}>Discard</button>
</>
)}
</div>
);
}
Recorder state machine: idle → requesting → ready → recording ⇄ paused → stopped → saving → ready
Auto-save composition data with retry logic:
import { useClipPersistence } from '@hiyve/react-clips';
const persistence = useClipPersistence({
client,
clips,
title: 'My Composition',
lockMode: 'unlocked',
collaborationMode: 'public',
enabled: true,
userId: 'user-123',
autoSaveInterval: 5000,
onSaved: (fileId) => console.log('Saved:', fileId),
onError: (err) => console.error(err),
});
// persistence.save() — trigger manual save
// persistence.isSaving — currently saving?
// persistence.hasUnsavedChanges — pending changes?
// persistence.lastSaved — last save timestamp
// persistence.fileId — current file ID
// persistence.markUnsaved() — mark as changed
ClipsSession integrates with @hiyve/react-collaboration for file management:
import { ClipsSession } from '@hiyve/react-clips';
<ClipsSession
labels={{
emptyState: { title: 'My Clips', createButton: 'New' },
}}
clipCompositionProps={{
enableRecording: true,
maxClips: 10,
}}
onError={(err) => console.error(err)}
sx={{ height: '100%' }}
/>
The session provides an empty state with a file list and create button. Clicking "New Composition" opens a CreateCompositionDialog to name the composition before creation. When a composition is opened or created, it renders ClipComposition with a session header for save/close controls.
All visual aspects are customizable through four prop objects. Only override the keys you want to change — defaults are applied for the rest.
~40 text strings covering header, save status, toolbar, recorder, player, grid, collaboration, and error messages. Includes two functions: lastSaved(date) and clipCount(count).
<ClipComposition
labels={{
title: 'Sound Clips',
startRecording: 'Record',
noClips: 'No clips yet — start recording!',
lastSaved: (date) => `Saved at ${date.toLocaleTimeString()}`,
}}
/>
19 icon slots, each accepting a ReactNode. Defaults use @mui/icons-material.
import { MicNone, FiberManualRecord } from '@mui/icons-material';
<ClipComposition
icons={{
recordAudio: <MicNone />,
startRecording: <FiberManualRecord color="error" />,
}}
/>
24 color values for container, header, toolbar, recorder, grid, clip cards, save status, and collaboration mode indicators.
<ClipComposition
colors={{
containerBackground: '#2d2d2d',
recordingIndicator: '#e53935',
clipCardBackground: '#383838',
}}
/>
12 numeric/string values for border radius, padding, grid layout, and component dimensions.
<ClipComposition
styles={{
borderRadius: 12,
gridGap: 16,
gridMinColumnWidth: 320,
playerHeight: 150,
}}
/>
| Default Object | Merge Function |
|---|---|
defaultClipCompositionLabels |
mergeClipCompositionLabels(overrides?) |
defaultClipCompositionIcons |
mergeClipCompositionIcons(overrides?) |
defaultClipCompositionColors |
mergeClipCompositionColors(overrides?) |
defaultClipCompositionStyles |
mergeClipCompositionStyles(overrides?) |
defaultClipsSessionLabels |
mergeClipsSessionLabels(overrides?) |
defaultCreateCompositionDialogLabels |
mergeCreateCompositionDialogLabels(overrides?) |
@hiyve/react-media-player is installed)<audio> / <video> fallback when media player is not available@hiyve/react-collaboration is installed)HiyveProvider| Constant | Value | Description |
|---|---|---|
DEFAULT_FILE_LOCATION |
'/Clips' |
Default storage location |
CLIP_COMPOSITION_FILE_EXTENSION |
'.json' |
Composition file extension |
CLIP_COMPOSITION_FILE_MIME_TYPE |
'application/json' |
Composition MIME type |
CLIP_RESOURCE_TYPE |
'clip-composition' |
Resource type identifier for composition files |
CLIP_VIDEO_RESOURCE_TYPE |
'clip' |
Resource type identifier for individual video clip files |
CLIP_AUDIO_RESOURCE_TYPE |
'clip-audio' |
Resource type identifier for individual audio clip files |
DEFAULT_AUTO_SAVE_INTERVAL |
5000 |
Auto-save interval (ms) |
DEFAULT_MAX_RECORDING_DURATION |
300 |
Default max recording (seconds) |
MAX_RECORDING_DURATION_HARD |
1800 |
Hard limit on recording (seconds) |
RECORDING_TIMESLICE |
1000 |
MediaRecorder timeslice (ms) |
DEFAULT_MAX_CLIPS |
20 |
Default max clips per composition |
DEFAULT_GRID_COLUMNS |
2 |
Default grid columns |
PREFERRED_AUDIO_MIME_TYPES |
string[] |
Audio MIME type preference order |
PREFERRED_VIDEO_MIME_TYPES |
string[] |
Video MIME type preference order |
COLLABORATION_MODES |
['private', 'public'] |
Available collaboration modes |
LOCK_MODES |
['locked', 'unlocked'] |
Available lock modes |
| Type | Description |
|---|---|
ClipItem |
A single clip with media type, file reference, duration, regions, and metadata |
ClipCompositionFile |
Full composition data: title, clips array, lock/collaboration modes, author info |
ClipMediaType |
'audio' | 'video' |
CompositionLockMode |
'locked' | 'unlocked' |
CollaborationMode |
'private' | 'public' |
RecorderState |
'idle' | 'requesting' | 'ready' | 'recording' | 'paused' | 'stopped' | 'saving' |
RegionData |
Named region for clip playback (id, start, end, content) |
GridLayoutItem |
Custom grid position for a clip |
ClipFileClient |
File client interface for upload and URL resolution |
ClipCompositionRef |
Imperative handle exposed by ClipComposition |
CreateCompositionDialogLabels |
Customizable labels for the create composition dialog |
CreateCompositionDialogProps |
Props for CreateCompositionDialog |
Seven style-generating functions for building custom layouts:
| Function | Description |
|---|---|
getContainerStyles(colors, styles) |
Main container styles |
getHeaderStyles(colors, styles) |
Header bar styles |
getToolbarStyles(colors, styles) |
Toolbar styles |
getRecorderStyles(colors, styles) |
Recorder panel styles |
getGridStyles(colors, styles) |
CSS Grid layout styles |
getClipCardStyles(colors, styles, isDragging?) |
Individual clip card styles |
getEmptyStateStyles(colors) |
Empty state placeholder styles |
@mui/material, @mui/icons-material, @emotion/react, @emotion/styled)@hiyve/react — provides HiyveProvider context (components work outside the provider with limited functionality)@hiyve/utilities — debug logging and retry utilities
@hiyve/react-clips — Clip composition tool with client-side recording, multi-clip grid, and media playback for Hiyve video conferencing.