How to Use @openmaic/renderer to Render OpenMAIC Slides: A Complete Guide
@openmaic/renderer is a read-only React component library that transforms PPTist-style Slide JSON objects into responsive canvas renderings using the <SlideCanvas> component and a pluggable element architecture.
The @openmaic/renderer package, located in the THU-MAIC/OpenMAIC monorepo, provides the definitive rendering engine for OpenMAIC presentation slides. It consumes structured slide data and outputs faithful visual representations without allowing direct editing, making it ideal for slide previewing, presentation mode, or static export scenarios.
Core Architecture and File Structure
The library is organized around a central canvas component with specialized dispatchers and effect overlays. Understanding these modules helps you customize rendering behavior effectively.
SlideCanvas(src/SlideCanvas.tsx): The main entry point that receives aSlideobject and renders all slide elements inside an auto-fitting container.SlideElement(src/SlideElement.tsx): A wrapper dispatcher that routes each element to its specific renderer, such asBaseTextElementorBaseImageElement.- Effect Overlays (
src/effects/*): Optional visual layers includingLaserOverlay,SpotlightOverlay,HighlightOverlay, andZoomWrapperthat animate on top of rendered content. - Context API (
src/context.tsx): Provides<SlideRendererProvider>for sharing slide data across the component tree anduseSlideContext()for consuming that data. - Utility Hooks (
src/hooks/*): ContainsuseViewportSizefor auto-fit calculations anduseSlideBackgroundStylefor generating background CSS. - Type Definitions (
src/types/*): Central TypeScript interfaces includingSlide,PPTElement,SlideBackground, andSlideEffects.
Installation and Prerequisites
Before integrating the renderer, ensure your project meets the peer dependency requirements. The package expects React ≥18, Tailwind CSS ≥4, and Motion ≥11.
npm install @openmaic/renderer
Import the optional CJK font stylesheet if your slides contain Chinese, Japanese, or Korean characters.
import '@openmaic/renderer/fonts.css';
The Rendering Pipeline
The @openmaic/renderer follows a strict five-step flow to convert JSON data into visual output:
- Data Ingestion: A
Slideobject (conforming to theSlidetype) is passed to<SlideCanvas>or supplied via<SlideRendererProvider>. - Viewport Calculation:
SlideCanvasinvokesuseViewportSizeto auto-fit the canvas to its parent container, unless a fixedscaleprop overrides this behavior. - Element Dispatching: For each item in
slide.elements,SlideCanvasrenders a<SlideElement>which delegates to the appropriate base component based on the element type. - Effect Application: Optional
effectsprops trigger overlay components that animate on top of specific elements. - Custom Slot Injection: Props like
renderImageandrenderVideoallow you to inject custom media handling while preserving the default layout pipeline.
Basic Usage: Rendering a Single Slide
Pass a valid Slide JSON object to the slide prop of SlideCanvas. The component handles layout, background styling, and element positioning automatically.
import { SlideCanvas, type Slide } from '@openmaic/renderer';
import '@openmaic/renderer/fonts.css';
const slide: Slide = {
id: 'demo-1',
viewportSize: 1000,
viewportRatio: 0.5625, // 16:9
theme: {
backgroundColor: '#fff',
themeColors: ['#5b8def'],
fontColor: '#222',
fontName: 'sans-serif',
},
elements: [
{
type: 'text',
id: 't1',
left: 100,
top: 80,
width: 800,
height: 60,
rotate: 0,
content: '<p>Hello, Slide</p>',
defaultFontName: 'sans-serif',
defaultColor: '#222',
},
],
background: { type: 'solid', color: '#fff' },
};
export default function Demo() {
return (
<div style={{ width: 800, height: 450 }}>
<SlideCanvas
slide={slide}
effects={{
laser: { elementId: 't1', color: '#ff3b30', duration: 1500 },
}}
/>
</div>
);
}
Auto-Fitting and Viewport Handling
By default, SlideCanvas uses the useViewportSize hook to compute dimensions that maintain the slide's aspect ratio within the parent container. To disable responsive scaling and use a fixed size, provide the scale prop with a numeric value between 0 and 1.
Advanced Patterns
Using SlideRendererProvider for Context
When multiple components need access to the same slide data—such as annotation layers, navigation controls, or thumbnail strips—wrap them in <SlideRendererProvider> instead of passing props manually.
import {
SlideRendererProvider,
SlideCanvas,
useSlideContext,
} from '@openmaic/renderer';
function AnnotationLayer() {
const { slide } = useSlideContext();
return <div className="annotation">Annotations for {slide.id}</div>;
}
export default function Presentation() {
return (
<SlideRendererProvider slide={slide} scale={0.9}>
<SlideCanvas />
<AnnotationLayer />
</SlideRendererProvider>
);
}
This pattern, implemented in src/context.tsx, ensures all descendants share consistent slide state and rendering options.
Customizing Media with Render Slots
Inject custom rendering logic for specific media types without modifying the core library. The renderImage, renderVideo, and renderText props accept functions that receive the element config, source URL, and default React node.
<SlideCanvas
slide={slide}
renderImage={(element, src, defaultContent) =>
src.startsWith('placeholder:')
? <MyPlaceholder src={src} />
: defaultContent
}
/>
Granular Element Composition
For scenarios requiring fine-grained control over individual elements, import base components directly from the elements barrel. This allows you to wrap or extend specific renderers while maintaining type safety.
import { BaseImageElement } from '@openmaic/renderer/elements';
function CustomImage({ el }: { el: PPTImageElement }) {
return (
<BaseImageElement
elementInfo={el}
renderImage={(element, src, defaultNode) => (
<MyLazyImage src={src} fallback={defaultNode} />
)}
/>
);
}
Working with Effect Overlays
The effects prop accepts an object defining visual animations that render above the slide content. Configure laser pointers, spotlights, or highlight regions by referencing element IDs from your slide JSON.
<SlideCanvas
slide={slide}
effects={{
laser: { elementId: 't1', color: '#ff3b30', duration: 1500 },
spotlight: { x: 500, y: 300, radius: 100, opacity: 0.5 },
}}
/>
These overlays are implemented in src/effects/LaserOverlay.tsx and related files, using the Motion library for smooth animations.
Summary
- @openmaic/renderer provides a read-only canvas for OpenMAIC slide data via the
<SlideCanvas>component defined insrc/SlideCanvas.tsx. - The rendering pipeline auto-fits viewports using
useViewportSize, delegates elements throughSlideElement.tsx, and supports visual effect overlays. - Use
<SlideRendererProvider>fromsrc/context.tsxto share slide data across component trees, accessing it viauseSlideContext(). - Custom rendering logic can be injected through slots like
renderImageandrenderVideowithout disrupting the layout engine. - The library requires React 18+, Tailwind CSS 4+, and Motion 11+ as peer dependencies.
Frequently Asked Questions
How do I install @openmaic/renderer and its dependencies?
Install the package via npm or yarn, ensuring your project includes React 18 or higher, Tailwind CSS 4 or higher, and Motion 11 or higher as peer dependencies. For CJK language support, import the optional fonts.css stylesheet provided by the package.
Can I customize how images or videos render without forking the library?
Yes. Pass custom render functions to the renderImage, renderVideo, or renderText props on SlideCanvas. These slots receive the element data, source URL, and default content node, allowing you to implement lazy-loading, placeholders, or custom video players while preserving the layout calculations.
What is the difference between SlideCanvas and SlideRendererProvider?
SlideCanvas is a presentational component that accepts a slide prop directly and renders the content immediately. SlideRendererProvider is a context wrapper from src/context.tsx that supplies slide data to any descendant via React context. Use the provider when multiple components—such as annotation layers or navigation controls—need simultaneous access to the same slide object.
How does the auto-fit scaling work?
The component uses the useViewportSize hook located in src/hooks/useViewportSize.ts to calculate dimensions that fit the parent container while preserving the slide's aspect ratio defined by viewportRatio in the slide data. You can override this behavior by providing a fixed scale prop to either SlideCanvas or SlideRendererProvider.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →