@darshio/vivid
v0.1.1
Published
Production-grade React components for rendering AI-generated presentations with streaming support, PPTX/PDF export, and theming
Downloads
194
Maintainers
Readme
@darshio/vivid
Production-grade React components for rendering AI-generated presentations with real-time streaming support and export capabilities.
✨ Features
- 🎨 Beautiful Rendering - High-fidelity slide rendering with smooth animations
- 🌊 Streaming Support - Real-time slide generation from AI/LLM responses
- 📤 Export Ready - Built-in PPTX, PDF, PNG, and JSON export
- 🎯 Fully Typed - Complete TypeScript definitions
- 🧩 Modular - Tree-shakeable, use only what you need
- 🎭 Themeable - CSS variables for seamless integration with any design system
- ⚡ Performant - Optimized rendering with virtualization support
- 📱 Responsive - Works on all screen sizes
📦 Installation
npm install @darshio/vivid
# or
pnpm add @darshio/vivid
# or
yarn add @darshio/vividPeer Dependencies
This package requires React 18+:
npm install react react-dom🚀 Quick Start
import { VividProvider, SlideViewer, SlideRail, ExportButton } from '@darshio/vivid';
function PresentationApp() {
const presentation = {
metadata: {
title: 'My Presentation',
author: 'Your Name',
},
theme: {
colors: {
primary: '#3b82f6',
background: '#0f172a',
},
},
slides: [
{
id: 'slide-1',
layout: 'title',
elements: [
{
id: 'title-1',
type: 'text',
content: 'Welcome to Vivid',
position: { x: 10, y: 40 },
size: { width: 80, height: 20 },
style: { fontSize: 48, fontWeight: 'bold' },
},
],
},
],
};
return (
<VividProvider presentation={presentation}>
<div style={{ display: 'flex', height: '100vh' }}>
{/* Thumbnail Sidebar */}
<div style={{ width: 200, borderRight: '1px solid #333' }}>
<SlideRail showNumbers />
</div>
{/* Main Viewer */}
<div style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
<header style={{ padding: 16, display: 'flex', justifyContent: 'flex-end' }}>
<ExportButton formats={['pptx', 'pdf', 'png']} />
</header>
<SlideViewer showControls enableKeyboard />
</div>
</div>
</VividProvider>
);
}🌊 Streaming from AI
Render slides in real-time as they're generated by an AI/LLM:
import { VividProvider, SlideViewer, StreamingIndicator, useSlideStream } from '@darshio/vivid';
function AIPresentation({ prompt }: { prompt: string }) {
const { startStream, status, progress } = useSlideStream();
const generatePresentation = async () => {
// Your AI service that yields slides as async generator
const generator = myAIService.streamPresentation(prompt);
await startStream(generator);
};
return (
<VividProvider>
<button onClick={generatePresentation}>Generate</button>
<StreamingIndicator showProgress showCount />
<SlideViewer />
</VividProvider>
);
}Streaming Protocol
The streaming generator should yield objects in this format:
interface StreamChunk {
type: 'metadata' | 'slide' | 'complete' | 'error';
data?: {
metadata?: PresentationMetadata;
theme?: PresentationTheme;
slide?: Slide;
totalSlides?: number;
};
error?: string;
}🎨 Theming
The package uses CSS custom properties for styling, with sensible fallbacks. Components work out-of-the-box and adapt to your application's theme.
CSS Variables Reference
Define these in your app's CSS to customize appearance:
:root {
/* === Primary Colors === */
--vivid-primary: #3b82f6; /* Primary accent color */
--vivid-primary-hover: #2563eb; /* Primary hover state */
/* === Surfaces === */
--vivid-background: #0f172a; /* Main background */
--vivid-surface: #1e293b; /* Cards, panels */
--vivid-surface-hover: #334155; /* Surface hover state */
--vivid-border: #334155; /* Borders, dividers */
/* === Text === */
--vivid-text-primary: #f8fafc; /* Primary text */
--vivid-text-secondary: #94a3b8; /* Secondary text */
--vivid-text-muted: #64748b; /* Muted/disabled text */
/* === Typography === */
--vivid-font-body: system-ui, -apple-system, sans-serif;
--vivid-font-heading: system-ui, -apple-system, sans-serif;
/* === Spacing & Radius === */
--vivid-radius-sm: 4px;
--vivid-radius-md: 8px;
--vivid-radius-lg: 12px;
}Light Theme
:root {
--vivid-primary: #3b82f6;
--vivid-background: #ffffff;
--vivid-surface: #f1f5f9;
--vivid-surface-hover: #e2e8f0;
--vivid-border: #e2e8f0;
--vivid-text-primary: #0f172a;
--vivid-text-secondary: #475569;
--vivid-text-muted: #94a3b8;
}Tailwind CSS Integration
:root {
--vivid-primary: theme('colors.blue.500');
--vivid-background: theme('colors.slate.900');
--vivid-surface: theme('colors.slate.800');
--vivid-border: theme('colors.slate.700');
--vivid-text-primary: theme('colors.slate.50');
--vivid-text-secondary: theme('colors.slate.400');
}📚 API Reference
Components
<VividProvider>
Root context provider. Wrap your app with this component.
<VividProvider
presentation={presentation} // Initial presentation data
theme="dark" // "dark" | "light" | DesignSystem
aspectRatio="16:9" // "16:9" | "4:3" | "16:10" | "1:1"
animations={true} // Enable/disable animations
onSlideChange={(index) => {}} // Slide change callback
onError={(error) => {}} // Error callback
>
{children}
</VividProvider><SlideViewer>
Main slide rendering component with navigation.
<SlideViewer
width="100%" // Container width
height="100%" // Container height
showControls={true} // Show prev/next buttons
showCounter={true} // Show slide counter
enableKeyboard={true} // Arrow key navigation
enableTransitions={true} // Animate slide changes
fitMode="contain" // "contain" | "cover" | "none"
/><SlideRail>
Thumbnail navigation sidebar.
<SlideRail
thumbnailWidth={160} // Thumbnail width in pixels
orientation="vertical" // "vertical" | "horizontal"
showNumbers={true} // Show slide numbers
onSlideClick={(index) => {}} // Click callback
/><ExportButton>
Export dropdown with multiple format options.
<ExportButton
formats={['pptx', 'pdf', 'png', 'json']} // Available formats
variant="dropdown" // "dropdown" | "buttons"
label="Export" // Button label
onExportStart={(format) => {}} // Export started
onExportComplete={(format, blob) => {}} // Export completed
onExportError={(format, error) => {}} // Export failed
/><StreamingIndicator>
Shows streaming generation progress.
<StreamingIndicator
showProgress={true} // Show progress text
showCount={true} // Show slide count
/>Hooks
useVividContext()
Access the main context for programmatic control.
const {
// State
slides,
currentSlideIndex,
streamingStatus, // 'idle' | 'streaming' | 'complete' | 'error'
streamingProgress, // { current: number, total: number }
// Navigation
goToSlide,
nextSlide,
prevSlide,
// Data
setPresentation,
setSlides,
addSlide,
// Streaming
setStreamingStatus,
setStreamingProgress,
} = useVividContext();useSlideStream()
Handle streaming slide generation.
const {
startStream, // Start streaming from async generator
stopStream, // Stop current stream
status, // Current streaming status
progress, // { current, total }
error, // Error if any
} = useSlideStream();
// Usage
await startStream(async function* () {
yield { type: 'metadata', data: { metadata, theme, totalSlides: 5 } };
yield { type: 'slide', data: { slide: slide1 } };
yield { type: 'slide', data: { slide: slide2 } };
yield { type: 'complete' };
});useKeyboardNavigation()
Keyboard navigation controls.
useKeyboardNavigation({
enabled: true,
onEscape: () => {},
onFullscreen: () => {},
});Types
Slide Schema
interface Slide {
id: string;
layout: 'title' | 'content' | 'twoColumn' | 'comparison' | 'blank';
background?: {
type: 'solid' | 'gradient' | 'image';
value: string;
};
elements: SlideElement[];
}
interface SlideElement {
id: string;
type: 'text' | 'image' | 'shape' | 'chart' | 'table' | 'list' | 'code' | 'metric' | 'progress' | 'callout' | 'divider' | 'icon';
content: string | object;
position: { x: number; y: number }; // Percentage (0-100)
size: { width: number; height: number }; // Percentage (0-100)
style?: ElementStyle;
}Presentation Schema
interface Presentation {
metadata: {
title: string;
subtitle?: string;
author?: string;
createdAt?: string;
};
theme: {
colors: {
primary: string;
secondary?: string;
background: string;
text: string;
};
fonts?: {
heading?: string;
body?: string;
};
};
slides: Slide[];
}📤 Export Formats
| Format | Description | Library Used | |--------|-------------|--------------| | PPTX | Native PowerPoint files | pptxgenjs | | PDF | High-quality PDF documents | jspdf + modern-screenshot | | PNG | Individual slide images | modern-screenshot | | JSON | Raw presentation data | Native |
🔧 Advanced Usage
Custom Element Renderers
For advanced use cases, you can import individual element components:
import {
TextElement,
ImageElement,
ChartElement,
TableElement,
ListElement,
MetricElement,
CodeElement,
CalloutElement,
ProgressElement,
DividerElement,
IconElement,
ShapeElement,
} from '@darshio/vivid';Slide Dimensions
The package uses a fixed coordinate system for positioning:
import { SLIDE_WIDTH, SLIDE_HEIGHT } from '@darshio/vivid';
// SLIDE_WIDTH = 1920
// SLIDE_HEIGHT = 1080
// Element positions use percentages (0-100)
// position: { x: 10, y: 20 } = 10% from left, 20% from top🚢 Publishing to npm
Prerequisites
- Create an npm account at npmjs.com
- Login to npm CLI:
npm login
Publishing Steps
Update version in package.json:
npm version patch # or minor, majorBuild the package:
pnpm buildPublish:
# For scoped packages (@darshio/vivid) npm publish --access public
Publish Checklist
- [ ] Update version number
- [ ] Update CHANGELOG.md
- [ ] Run tests:
pnpm test - [ ] Build:
pnpm build - [ ] Check package contents:
npm pack --dry-run - [ ] Publish:
npm publish --access public - [ ] Create GitHub release with tag
🤝 Contributing
Contributions are welcome! Please read our contributing guidelines.
- Fork the repository
- Create your feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
📄 License
MIT © Adarsh Satpute
Made with ❤️ by Adarsh Satpute for the AI Developers community
