mirror of
https://github.com/vercel-labs/json-render.git
synced 2026-10-30 07:54:05 +08:00
* add rate limits
* fix lint
* better
generate prompt
update examples
* fixes
* fixes
* new api
* update docs
* fixes
* fixes
* generated prompt
* Add tests for catalog validation and prompt generation
- Test generateSystemPrompt with components, actions, custom rules
- Test new defineCatalog API from schema system
- Test catalog.prompt() method with custom rules
- Test catalog.validate() for valid and invalid specs
- Test catalog.zodSchema() for custom validation
- Test catalog.jsonSchema() for structured outputs
- Add tests for nested specs with children
- Add tests for rejecting invalid component types
* Fix lint: pass children as nested elements in renderer
Change from children={...} prop to nested children pattern
to satisfy react/no-children-prop rule.
* Fix lint errors in dashboard and web apps
- Disable react/prop-types in both eslint configs (TypeScript handles this)
- Allow styled-jsx 'jsx' property in dashboard
- Add DATABASE_URL to turbo env allowlist
- Remove unused drizzle-orm imports (and, sql)
- Suppress unused variable warnings where intentional
* Add server entry point for @json-render/remotion
The main package entry includes React components that require
client-side context (React.createContext). This causes build
failures when importing in server-side API routes.
Added `@json-render/remotion/server` entry point that exports
only schema and catalog definitions without React dependencies:
- schema, RemotionSchema, RemotionSpec
- standardComponentDefinitions, standardTransitionDefinitions
- standardEffectDefinitions
- Type exports for catalogs
Updated remotion example to import from /server in catalog.ts
* Make dashboard database connection lazy-initialized
The database connection threw an error at module load time if
DATABASE_URL was not set, causing builds to fail in CI where
the database is not available.
Changed to lazy initialization using a Proxy so the error only
occurs when the database is actually used at runtime, not at
build time.
* Fix previousSpec property name and lazy rate limiting
- Fix property name mismatch: playground now passes previousSpec
instead of previousTree to match what useUIStream hook expects
- Make rate limiting lazy-initialized to avoid runtime errors when
Redis env vars (KV_REST_API_URL, KV_REST_API_TOKEN) are not set
- Rate limiting gracefully becomes a no-op when Redis is unavailable
6.8 KiB
6.8 KiB
@json-render/remotion
Remotion video renderer for json-render. Turn JSON timeline specs into video compositions.
Installation
npm install @json-render/remotion @json-render/core remotion @remotion/player zod
Quick Start
1. Create a Catalog
import { defineCatalog } from "@json-render/core";
import {
schema,
standardComponentDefinitions,
standardTransitionDefinitions,
standardEffectDefinitions,
} from "@json-render/remotion";
// Use standard definitions or add your own
export const videoCatalog = defineCatalog(schema, {
components: {
...standardComponentDefinitions,
// Add custom components here
},
transitions: standardTransitionDefinitions,
effects: standardEffectDefinitions,
});
2. Render with the Player
import { Player } from "@remotion/player";
import { Renderer } from "@json-render/remotion";
function VideoPlayer({ spec }) {
return (
<Player
component={Renderer}
inputProps={{ spec }}
durationInFrames={spec.composition.durationInFrames}
fps={spec.composition.fps}
compositionWidth={spec.composition.width}
compositionHeight={spec.composition.height}
controls
/>
);
}
Timeline Spec Format
interface TimelineSpec {
composition: {
id: string;
fps: number;
width: number;
height: number;
durationInFrames: number;
};
tracks: Array<{
id: string;
name: string;
type: "video" | "overlay" | "audio";
enabled: boolean;
}>;
clips: Array<{
id: string;
trackId: string;
component: string; // Component name from catalog
props: object; // Component-specific props
from: number; // Start frame
durationInFrames: number;
transitionIn?: {
type: string;
durationInFrames: number;
};
transitionOut?: {
type: string;
durationInFrames: number;
};
}>;
audio: {
tracks: Array<{
id: string;
src: string;
from: number;
durationInFrames: number;
volume?: number;
}>;
};
}
Example spec:
{
"composition": {
"id": "intro-video",
"fps": 30,
"width": 1920,
"height": 1080,
"durationInFrames": 300
},
"tracks": [
{ "id": "main", "name": "Main Video", "type": "video", "enabled": true },
{ "id": "overlay", "name": "Overlays", "type": "overlay", "enabled": true }
],
"clips": [
{
"id": "clip-1",
"trackId": "main",
"component": "TitleCard",
"props": {
"title": "Welcome",
"subtitle": "To the future",
"backgroundColor": "#1a1a1a",
"textColor": "#ffffff"
},
"from": 0,
"durationInFrames": 90,
"transitionIn": { "type": "fade", "durationInFrames": 15 },
"transitionOut": { "type": "fade", "durationInFrames": 15 }
}
],
"audio": { "tracks": [] }
}
Standard Components
The package includes pre-built video components:
| Component | Description | Key Props |
|---|---|---|
TitleCard |
Full-screen title with subtitle | title, subtitle, backgroundColor, textColor |
ImageSlide |
Full-screen image display | src, alt, fit |
SplitScreen |
Two-column layout | leftTitle, rightTitle, leftContent, rightContent |
QuoteCard |
Quote with attribution | quote, author, role |
StatCard |
Large statistic display | value, label, trend |
LowerThird |
Name/title overlay | name, title |
TextOverlay |
Centered text | text, fontSize, fontFamily |
TypingText |
Terminal typing effect | text, charsPerSecond, showCursor |
LogoBug |
Corner logo overlay | src, position, size |
VideoClip |
Video playback | src |
Standard Transitions
| Transition | Description |
|---|---|
fade |
Opacity fade in/out |
slideLeft |
Slide from right |
slideRight |
Slide from left |
slideUp |
Slide from bottom |
slideDown |
Slide from top |
zoom |
Scale zoom in/out |
wipe |
Horizontal wipe |
Custom Components
Add custom components to the Renderer:
import { Renderer, standardComponents, ClipWrapper } from "@json-render/remotion";
import type { Clip } from "@json-render/remotion";
// Define a custom component
function CustomOverlay({ clip }: { clip: Clip }) {
return (
<ClipWrapper clip={clip}>
<div style={{ backgroundColor: clip.props.color }}>
{clip.props.message}
</div>
</ClipWrapper>
);
}
// Merge with standard components
const customComponents = {
...standardComponents,
CustomOverlay,
};
// Pass to Renderer
<Player
component={Renderer}
inputProps={{ spec, components: customComponents }}
// ...
/>
Hooks and Utilities
useTransition
Calculate transition styles for a clip:
import { useTransition } from "@json-render/remotion";
import { useCurrentFrame } from "remotion";
function MyComponent({ clip }: { clip: Clip }) {
const frame = useCurrentFrame();
const transition = useTransition(clip, frame);
return (
<div style={{ opacity: transition.opacity }}>
Content
</div>
);
}
ClipWrapper
Apply transitions automatically:
import { ClipWrapper } from "@json-render/remotion";
function MyComponent({ clip }: { clip: Clip }) {
return (
<ClipWrapper clip={clip}>
{/* Content gets transition styles applied */}
<div>My content</div>
</ClipWrapper>
);
}
Generate AI Prompts
const systemPrompt = videoCatalog.prompt();
// Returns detailed prompt with:
// - Component descriptions and props
// - Transition types
// - Effect definitions
// - Timeline spec format requirements
Exports
Components
import {
// Main renderer
Renderer,
standardComponents,
// Standard components
TitleCard,
ImageSlide,
SplitScreen,
QuoteCard,
StatCard,
LowerThird,
TextOverlay,
TypingText,
LogoBug,
VideoClip,
// Utilities
ClipWrapper,
useTransition,
} from "@json-render/remotion";
Types
import type {
Clip,
TimelineSpec,
AudioTrack,
TransitionStyles,
ClipComponent,
ComponentRegistry,
} from "@json-render/remotion";
Schema and Catalog Definitions
import {
schema,
standardComponentDefinitions,
standardTransitionDefinitions,
standardEffectDefinitions,
} from "@json-render/remotion";
Why Different from React?
| Feature | @json-render/react | @json-render/remotion |
|---|---|---|
| Spec Format | Element tree (nested components) | Timeline (tracks + clips) |
| Components | UI components (Button, Card) | Video components (scenes, overlays) |
| Timing | User interactions | Frame-based animations |
| Output | React DOM | Remotion video |
json-render is "JSON to render" - the spec format and components are completely flexible per renderer.