@trilogy-innovations/video-applets-player
v0.0.4
Published
A React video player component that renders interactive videos from JSON schemas with timeline controls
Readme
@trilogy-innovations/video-applets-player
A powerful React video player component that renders interactive videos from JSON schemas with timeline controls, animations, and educational elements.
✨ Features
- 🎬 Interactive Video Player - Render videos from declarative JSON schemas
- ⏱️ Timeline Controls - Play, pause, seek, reset, fullscreen controls
- 🎭 Rich Elements - Text, shapes, images, videos, clocks, arrows, line plots
- 🎨 Smooth Animations - Keyframe-based interpolation with 60fps rendering
- 📐 Flexible Layouts - Vertical, horizontal, absolute, and grid positioning
- 🎯 Educational Focus - Purpose-built for interactive learning content
- 📱 Responsive Design - Works across desktop, tablet, and mobile
- ⌨️ Keyboard Support - Full keyboard navigation and shortcuts
- 🔧 TypeScript Ready - Complete type definitions included
📦 Installation
npm install @trilogy-innovations/video-applets-playeryarn add @trilogy-innovations/video-applets-playerpnpm add @trilogy-innovations/video-applets-player🚀 Quick Start
Basic Usage
import React from 'react';
import { VideoPlayer, CompactTimeline, useVideoPlayer } from '@trilogy-innovations/video-applets-player';
import '@trilogy-innovations/video-applets-player/dist/styles.css';
function MyVideoApp() {
const schema = {
meta: {
width: 1920,
height: 1080,
duration: 10,
fps: 30
},
nodes: [
{
kind: 'container',
id: 'root',
layout: { type: 'vertical', splits: [1] },
children: ['welcome-text']
},
{
kind: 'element',
id: 'welcome-text',
type: 'text',
text: 'Welcome to Video Applets!',
fontSize: 48,
fontWeight: 'bold',
color: '#2c3e50',
timeline: { in: 0, out: 10 },
keyframes: [
{ time: 0, opacity: 0, scaleX: 0.5, scaleY: 0.5 },
{ time: 1, opacity: 1, scaleX: 1, scaleY: 1 },
{ time: 9, opacity: 1 },
{ time: 10, opacity: 0 }
],
layoutRef: 'root'
}
]
};
const videoPlayer = useVideoPlayer(schema);
return (
<div style={{ width: '100%', maxWidth: '800px', margin: '0 auto' }}>
<VideoPlayer
schema={schema}
{...videoPlayer}
style={{ width: '100%', aspectRatio: '16/9' }}
/>
<CompactTimeline {...videoPlayer} />
</div>
);
}
export default MyVideoApp;Advanced Example with Multiple Elements
import { VideoPlayer, CompactTimeline, useVideoPlayer } from '@trilogy-innovations/video-applets-player';
import '@trilogy-innovations/video-applets-player/dist/styles.css';
function EducationalContent() {
const mathLessonSchema = {
meta: { width: 1920, height: 1080, duration: 15 },
nodes: [
// Root container with 2x2 grid
{
kind: 'container',
id: 'root',
layout: {
type: 'grid',
rows: 2,
cols: 2,
gaps: { row: 20, col: 20 }
},
children: ['title', 'clock', 'plot', 'arrow']
},
// Animated title
{
kind: 'element',
id: 'title',
type: 'title',
text: 'Time and Data Visualization',
fontSize: 36,
timeline: { in: 0, out: 15 },
keyframes: [
{ time: 0, y: -50, opacity: 0 },
{ time: 1, y: 0, opacity: 1 }
],
layoutRef: 'root'
},
// Interactive clock
{
kind: 'element',
id: 'clock',
type: 'clock',
clockConfig: {
hours: 3,
minutes: 15,
size: 200,
showNumbers: true,
highlightMinuteHand: { type: 'glow', color: '#e74c3c' }
},
timeline: { in: 2, out: 15 },
layoutRef: 'root'
},
// Data visualization
{
kind: 'element',
id: 'plot',
type: 'lineplot',
linePlotConfig: {
title: 'Student Heights',
data: [
{ value: 48, color: '#3498db' },
{ value: 52, color: '#3498db' },
{ value: 47, color: '#3498db' },
{ value: 50, color: '#3498db' }
],
plotType: 'frequency',
pointShape: 'circle',
pointSize: 20,
xAxis: { title: 'Height (inches)', min: 45, max: 55 }
},
timeline: { in: 5, out: 15 },
layoutRef: 'root'
},
// Pointing arrow
{
kind: 'element',
id: 'arrow',
type: 'arrow',
arrowConfig: {
startPoint: { x: 0.1, y: 0.1 },
endPoint: { x: 0.9, y: 0.9 },
strokeColor: '#f39c12',
strokeWidth: 4,
arrowHeadType: 'triangle'
},
timeline: { in: 8, out: 12 },
keyframes: [
{ time: 8, opacity: 0 },
{ time: 9, opacity: 1 }
],
layoutRef: 'root'
}
]
};
const videoPlayer = useVideoPlayer(mathLessonSchema);
return (
<div className="educational-video">
<VideoPlayer schema={mathLessonSchema} {...videoPlayer} />
<CompactTimeline {...videoPlayer} />
</div>
);
}📚 API Reference
Components
VideoPlayer
Main video player component that renders the schema.
interface VideoPlayerProps {
schema: VideoSchema;
currentTime: number;
style?: React.CSSProperties;
className?: string;
}CompactTimeline
Timeline controls component with play/pause, seek, and fullscreen.
interface TimelineControlsProps {
currentTime: number;
duration: number;
isPlaying: boolean;
onSeek: (time: number) => void;
onTogglePlay: () => void;
onReset?: () => void;
onFullscreen?: () => void;
className?: string;
}Hooks
useVideoPlayer(schema: VideoSchema)
Main hook that manages video player state.
const videoPlayer = useVideoPlayer(schema);
// Returns: {
// currentTime: number;
// isPlaying: boolean;
// duration: number;
// onTogglePlay: () => void;
// onSeek: (time: number) => void;
// onReset: () => void;
// onFullscreen: () => void;
// }useSchema(initialSchema: VideoSchema)
Hook for schema management and validation.
const { schema, validationErrors, isValid, updateSchema } = useSchema(initialSchema);useAnimation()
Hook for animation state management.
const { currentTime, isPlaying, play, pause, seek, reset } = useAnimation();useFullscreen()
Hook for fullscreen functionality.
const { isFullscreen, toggleFullscreen, exitFullscreen } = useFullscreen();Services
SchemaService
Validates and processes video schemas.
import { SchemaService } from '@trilogy-innovations/video-applets-player';
const errors = SchemaService.validateSchema(schema);
const isValid = errors.length === 0;AssetManager
Manages loading and caching of media assets.
import { AssetManager } from '@trilogy-innovations/video-applets-player';
AssetManager.preloadAsset('image', 'https://example.com/image.jpg');🎨 Schema Structure
Meta Configuration
interface VideoMeta {
width: number; // Canvas width in pixels
height: number; // Canvas height in pixels
duration: number; // Total duration in seconds
fps?: number; // Frame rate (default: 30)
backgroundColor?: string; // Background color
}Container Nodes
interface ContainerNode {
kind: 'container';
id: string;
layout: {
type: 'vertical' | 'horizontal' | 'absolute' | 'grid';
splits?: number[]; // For vertical/horizontal
rows?: number; // For grid
cols?: number; // For grid
gaps?: { row: number; col: number }; // For grid
};
children: string[]; // Child node IDs
style?: React.CSSProperties;
}Element Nodes
interface ElementNode {
kind: 'element';
id: string;
type: 'text' | 'shape' | 'image' | 'video' | 'html' | 'title' | 'box' | 'clock' | 'arrow' | 'lineplot';
layoutRef: string; // Parent container ID
timeline: {
in: number; // Start time in seconds
out: number; // End time in seconds
};
keyframes?: Keyframe[]; // Animation keyframes
stateChanges?: StateChange[]; // State change events
// Element-specific properties...
}Keyframes
interface Keyframe {
time: number; // Time in seconds
x?: number; // X position offset
y?: number; // Y position offset
scaleX?: number; // X scale factor
scaleY?: number; // Y scale factor
rotate?: number; // Rotation in degrees
opacity?: number; // Opacity (0-1)
// Custom properties for specific elements
}🎭 Element Types
Text Element
{
type: 'text',
text: 'Hello World',
fontSize: 24,
fontFamily: 'Arial',
fontWeight: 'bold',
color: '#333',
textAlign: 'center'
}Image Element
{
type: 'image',
src: 'https://example.com/image.jpg',
alt: 'Description',
objectFit: 'cover'
}Video Element
{
type: 'video',
src: 'https://example.com/video.mp4',
autoplay: true,
muted: true,
loop: false
}Clock Element
{
type: 'clock',
clockConfig: {
hours: 3,
minutes: 15,
seconds: 30,
size: 200,
showNumbers: true,
showSecondHand: true,
highlightHourHand: { type: 'glow', color: '#e74c3c' },
highlightMinuteHand: { type: 'pulse', color: '#3498db' }
}
}Line Plot Element
{
type: 'lineplot',
linePlotConfig: {
title: 'Data Visualization',
data: [
{ value: 10, color: '#3498db', label: 'Point 1' },
{ value: 15, color: '#e74c3c', label: 'Point 2' }
],
plotType: 'frequency' | 'scatter' | 'line',
pointShape: 'circle' | 'square' | 'triangle' | 'x' | 'diamond',
pointSize: 20,
showFrequencyLabels: true,
xAxis: {
title: 'X Axis',
min: 0,
max: 20,
step: 5
},
yAxis: {
title: 'Y Axis',
min: 0,
max: 10
}
}
}Arrow Element
{
type: 'arrow',
arrowConfig: {
startPoint: { x: 0.2, y: 0.3 }, // Relative coordinates (0-1)
endPoint: { x: 0.8, y: 0.7 },
strokeColor: '#2c3e50',
strokeWidth: 3,
arrowHeadType: 'triangle' | 'circle' | 'square'
}
}🎨 Advanced Features
State Changes and Highlighting
Add dynamic highlighting and state changes during playback:
{
kind: 'element',
id: 'highlighted-text',
type: 'text',
text: 'This text will glow!',
stateChanges: [
{
timestamp: 3,
state: 'highlighted',
highlightConfig: {
type: 'glow',
color: '#f39c12',
intensity: 0.8
}
},
{
timestamp: 6,
state: 'normal'
}
]
}Complex Animations
Chain multiple keyframes for complex animations:
{
keyframes: [
{ time: 0, x: -100, opacity: 0, scaleX: 0.5 },
{ time: 1, x: 0, opacity: 1, scaleX: 1 },
{ time: 3, rotate: 180 },
{ time: 5, x: 100, rotate: 360 },
{ time: 6, opacity: 0 }
]
}Custom Layouts
Create complex layouts with nested containers:
{
kind: 'container',
id: 'main',
layout: { type: 'vertical', splits: [0.3, 0.7] },
children: ['header', 'content'],
style: { padding: '20px', backgroundColor: '#f8f9fa' }
}Educational Interactions
Perfect for educational content with step-by-step reveals:
// Show mathematical concepts progressively
{
type: 'lineplot',
linePlotConfig: {
data: [
{ value: 2, color: '#3498db' },
{ value: 4, color: '#e74c3c' },
{ value: 3, color: '#2ecc71' }
],
revealAnimation: {
type: 'sequential',
delay: 1, // 1 second between each point
startTime: 2 // Start revealing at 2 seconds
}
}
}⌨️ Keyboard Shortcuts
- Space - Play/Pause
- Left Arrow - Seek backward 5 seconds
- Right Arrow - Seek forward 5 seconds
- Home - Reset to beginning
- F - Toggle fullscreen
- Escape - Exit fullscreen
🔧 TypeScript Support
Full TypeScript support with comprehensive type definitions:
import type {
VideoSchema,
VideoPlayerProps,
ElementNode,
ContainerNode,
ValidationError
} from '@trilogy-innovations/video-applets-player';
const schema: VideoSchema = {
meta: { width: 1920, height: 1080, duration: 10 },
nodes: [/* ... */]
};🎨 Styling and Customization
CSS Custom Properties
Override default styles using CSS custom properties:
.video-player {
--primary-color: #3498db;
--secondary-color: #2c3e50;
--background-color: #ecf0f1;
--text-color: #2c3e50;
--border-radius: 8px;
}Custom CSS Classes
<VideoPlayer
schema={schema}
className="my-custom-player"
style={{ borderRadius: '12px', overflow: 'hidden' }}
/>Timeline Customization
.compact-timeline {
background: linear-gradient(45deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
padding: 16px;
}
.timeline-progress {
background: #fff;
border-radius: 6px;
}🔧 Performance Tips
Schema Optimization
- Keep keyframe arrays reasonably sized (< 100 keyframes per element)
- Use relative positioning when possible
- Optimize image and video assets
- Consider using
React.memo()for wrapper components
Asset Loading
import { AssetManager } from '@trilogy-innovations/video-applets-player';
// Preload assets for better performance
useEffect(() => {
AssetManager.preloadAsset('image', '/path/to/image.jpg');
AssetManager.preloadAsset('video', '/path/to/video.mp4');
}, []);Memory Management
// Clean up when component unmounts
useEffect(() => {
return () => {
AssetManager.clearCache();
};
}, []);📱 Responsive Design
Make your video player responsive:
function ResponsiveVideoPlayer({ schema }) {
return (
<div style={{
width: '100%',
maxWidth: '1200px',
aspectRatio: `${schema.meta.width}/${schema.meta.height}`,
margin: '0 auto'
}}>
<VideoPlayer
schema={schema}
style={{
width: '100%',
height: '100%'
}}
/>
</div>
);
}🐛 Troubleshooting
Common Issues
Schema Validation Errors
import { SchemaService } from '@trilogy-innovations/video-applets-player';
const errors = SchemaService.validateSchema(schema);
console.log('Validation errors:', errors);Asset Loading Issues
// Check asset loading status
AssetManager.getLoadingStatus('my-image').then(status => {
console.log('Asset status:', status);
});Performance Issues
- Reduce keyframe density
- Optimize media assets
- Use
React.memo()for parent components - Enable hardware acceleration in CSS
Debug Mode
Enable debug information:
<VideoPlayer
schema={schema}
debug={true} // Shows performance metrics
/>🔗 Examples and Demos
Educational Math Lesson
const mathLesson = {
meta: { width: 1920, height: 1080, duration: 30 },
nodes: [
// Problem statement
{
kind: 'element',
id: 'problem',
type: 'text',
text: 'What is 5 + 3?',
fontSize: 48,
timeline: { in: 0, out: 10 }
},
// Visual representation
{
kind: 'element',
id: 'visual',
type: 'image',
src: '/counting-blocks.png',
timeline: { in: 3, out: 20 }
},
// Answer reveal
{
kind: 'element',
id: 'answer',
type: 'text',
text: '8',
fontSize: 72,
color: '#27ae60',
timeline: { in: 15, out: 30 },
keyframes: [
{ time: 15, opacity: 0, scaleX: 2, scaleY: 2 },
{ time: 16, opacity: 1, scaleX: 1, scaleY: 1 }
]
}
]
};Data Visualization Story
const dataStory = {
meta: { width: 1920, height: 1080, duration: 25 },
nodes: [
{
kind: 'element',
id: 'chart',
type: 'lineplot',
linePlotConfig: {
title: 'Sales Growth Over Time',
data: [
{ value: 100, color: '#3498db', label: 'Q1' },
{ value: 150, color: '#e74c3c', label: 'Q2' },
{ value: 200, color: '#2ecc71', label: 'Q3' },
{ value: 180, color: '#f39c12', label: 'Q4' }
],
plotType: 'line',
pointShape: 'circle',
revealAnimation: { type: 'sequential', delay: 2 }
},
timeline: { in: 0, out: 25 }
}
]
};🤝 Contributing
We welcome contributions! See our Contributing Guide for details.
📞 Support
Made with ❤️ by Trilogy Innovations
Perfect for educational content, data visualization, interactive presentations, and engaging user experiences.
