npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@openmaic/renderer

v0.0.2

Published

React component for rendering PPTist-style Slide JSON, extracted from OpenMAIC.

Readme

@openmaic/renderer

React component for rendering PPTist-style Slide JSON. Extracted from OpenMAIC.

v1 = read-only canvas. Editing (selection, drag/resize, ProseMirror inline editor) is planned for v2.

Install

pnpm add @openmaic/renderer
# or
npm install @openmaic/renderer

Required peers:

  • react >= 18
  • react-dom >= 18
  • motion >= 11
  • tailwindcss >= 4the 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

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.

interface SlideCanvasProps {
  slide?: Slide;                       // required unless via <SlideRendererProvider>
  scale?: number;                      // omit = auto-fit container
  background?: SlideBackground;        // overrides slide.background
  effects?: SlideEffects;              // laser / spotlight / highlight / zoom, all default off
  renderImage?: (el, src) => ReactNode;
  renderVideo?: (el) => ReactNode;
  onElementClick?: (el, event) => void;
  className?: string;
  style?: CSSProperties;
}

Play-time effects

All effects are off by default. Pass any combination via effects:

<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:

<SlideCanvas
  slide={slide}
  renderImage={(el, src) => (
    src.startsWith('placeholder:')
      ? <MyPlaceholder taskId={src} />
      : <img src={resolveCdnUrl(src)} alt="" style={{ width: '100%', height: '100%' }} />
  )}
/>

<SlideRendererProvider> + useSlideContext()

Optional high-order pattern when sibling overlays need the same slide data:

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:

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

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:

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:

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 for the face list and their licenses.

Companion package

@openmaic/importer converts .pptx files to the same Slide[] shape, so you can do .pptx → @openmaic/renderer end-to-end.

See also

  • DESIGN.md — package design decisions and scope
  • v2 will add editing (<SlideEditor editable onChange />); the read-only <SlideCanvas> API will remain stable

License

MIT