Files
openmaic/OpenMAIC/packages/@openmaic/renderer/README.md
2026-08-16 14:58:47 +08:00

239 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# @openmaic/renderer
React component for rendering PPTist-style `Slide` JSON. Extracted from [OpenMAIC](https://github.com/THU-MAIC/OpenMAIC).
> `@openmaic/renderer` is the read-only canvas package. Editing lives in the
> separate `@openmaic/editor` package, which depends on this renderer.
## Migrating from 0.0.x
Version `0.1.0` removes the experimental `@openmaic/renderer/editing` subpath.
Install `@openmaic/editor` and migrate editing imports to its explicit layers:
```ts
import { EditableSlideCanvas } from '@openmaic/editor/react';
import { EditableSlideCanvasWithUI } from '@openmaic/editor/ui';
```
Read-only rendering imports from `@openmaic/renderer` are unchanged.
## Install
```bash
pnpm add @openmaic/renderer
# or
npm install @openmaic/renderer
```
Required peers:
- `react >= 18`
- `react-dom >= 18`
- `motion >= 11`
- `tailwindcss >= 4`**the package emits Tailwind 4 arbitrary-value classes, consumers must use Tailwind 4**
Optional peers (install only if your slides use the corresponding element type):
- `echarts >= 5` — for chart elements
- `shiki >= 1` — for code elements
## Quickstart
```tsx
import { SlideCanvas, type Slide } from '@openmaic/renderer';
const slide: Slide = {
id: 'demo-1',
viewportSize: 1000,
viewportRatio: 0.5625,
theme: {
backgroundColor: '#ffffff',
themeColors: ['#5b8def'],
fontColor: '#222222',
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: '#ffffff' },
};
export default function Demo() {
return (
<div style={{ width: 800, height: 450 }}>
<SlideCanvas slide={slide} />
</div>
);
}
```
The canvas auto-fits its parent container. The parent must have a defined `width × height`.
## API
### `<SlideCanvas slide effects? renderImage? renderVideo? onElementClick? scale? background? />`
The main read-only entry. Reads everything from props; zero global state.
```ts
interface SlideCanvasProps {
slide?: Slide; // required unless via <SlideRendererProvider>
scale?: number; // omit = auto-fit container
canvasPercentage?: number; // percent of the parent used by auto-fit
onScaleChange?: (scale) => void; // computed auto-fit scale
background?: SlideBackground; // overrides slide.background
effects?: SlideEffects; // laser / spotlight / highlight / zoom, all default off
renderImage?: (el, src, defaultContent) => ReactNode;
renderVideo?: (el) => ReactNode;
videoInteractive?: boolean; // defaults true; set false to disable video pointer interaction
onElementClick?: (el, event) => void;
elementIdPrefix?: string;
className?: string;
style?: CSSProperties;
}
```
### Play-time effects
All effects are off by default. Pass any combination via `effects`:
```tsx
<SlideCanvas
slide={slide}
effects={{
laser: { elementId: 't1', color: '#ff3b30' },
spotlight: { elementId: 't1' },
highlight: { elementId: 't1', color: '#ff6b6b', animated: true },
zoom: { elementId: 't1', scale: 1.5 },
}}
/>
```
### Media injection slots
The package's `BaseImageElement` and `BaseVideoElement` render plain `<img>` / `<video>` and know nothing about your media pipeline. Inject business behaviour via the `renderImage` / `renderVideo` slots:
```tsx
<SlideCanvas
slide={slide}
renderImage={(el, src, defaultContent) => (
src.startsWith('placeholder:')
? <MyPlaceholder taskId={src} />
: defaultContent
)}
/>
```
`defaultContent` is the renderer-prepared image, including clipping, filters,
soft edges, and `colorMask`. The slot return value is authoritative: return
`null` to intentionally hide the image.
### `<SlideRendererProvider>` + `useSlideContext()`
Optional high-order pattern when sibling overlays need the same slide data:
```tsx
import { SlideRendererProvider, SlideCanvas, useSlideContext } from '@openmaic/renderer';
function MyAnnotationLayer() {
const { slide } = useSlideContext();
return <div>Annotations for {slide.id}</div>;
}
<SlideRendererProvider slide={slide} scale={0.9}>
<SlideCanvas /> {/* reads slide/scale from context */}
<MyAnnotationLayer />
</SlideRendererProvider>
```
### Granular components — `@openmaic/renderer/elements`
If you want to compose your own layout instead of using `SlideCanvas`, the 9 base elements are exported individually:
```ts
import {
BaseTextElement, BaseShapeElement, BaseImageElement,
BaseLineElement, BaseChartElement, BaseLatexElement,
BaseTableElement, BaseVideoElement, BaseCodeElement,
ElementOutline,
} from '@openmaic/renderer/elements';
```
Each accepts `{ elementInfo: PPTXxxElement }`. Image/Video also take a render slot.
### Types — `@openmaic/renderer/types`
```ts
import type {
Slide, PPTElement, SlideBackground, SlideTheme,
PPTTextElement, PPTShapeElement, PPTImageElement,
PPTLineElement, PPTChartElement, PPTLatexElement,
PPTTableElement, PPTVideoElement, PPTCodeElement,
ImageElementClip, ImageElementFilters,
Gradient, GradientType, PPTElementOutline, PPTElementShadow,
SlideEffects, LaserEffectOptions, SpotlightEffectOptions,
HighlightEffectOptions, ZoomEffectOptions,
} from '@openmaic/renderer/types';
```
## Tailwind 4 setup
Ensure your `tailwind.config.{ts,js}` includes the package source:
```js
export default {
content: [
'./src/**/*.{ts,tsx}',
'./node_modules/@openmaic/renderer/dist/**/*.{js,cjs}',
],
};
```
## Fonts (optional, CDN-hosted)
Slides imported from PowerPoint often reference Chinese faces that aren't
installed on the viewer's machine. The package ships a `fonts.css` with
`@font-face` rules for a small whitelist of self-hosted CJK faces — import it
once at your app shell to make those faces available:
```ts
import '@openmaic/renderer/fonts.css';
```
> **Runtime dependency — read this.** The `@font-face` `src` URLs point at an
> external font host (`https://file.maic.chat/fonts/<name>.woff2`); the woff2
> files are **not** bundled in the package. So this is a hard runtime dependency:
> the host must be **reachable and CORS-enabled** from the consumer's app, or the
> browser will **silently fall back to system fonts** (no error, just different
> glyphs/metrics). If you need a different origin (self-hosting, air-gapped, a
> private CDN), change `FONT_CDN_BASE_URL` in `fonts.config.mjs` and regenerate
> with `pnpm run genfonts`.
>
> The import is **optional** — slides render fine without it, using whatever
> fonts the system provides. See [FONTS.md](./FONTS.md) for the face list and
> their licenses.
## Companion package
[`@openmaic/importer`](../importer) converts `.pptx` files to the same `Slide[]` shape, so you can do `.pptx → @openmaic/renderer` end-to-end.
## See also
- [DESIGN.md](./DESIGN.md) — package design decisions and scope
- v2 will add editing (`<SlideEditor editable onChange />`); the read-only `<SlideCanvas>` API will remain stable
## License
MIT