@json-render/image

Image renderer. Turn JSON specs into SVG and PNG images using Satori.

Install

npm install @json-render/core @json-render/image

For PNG output, also install the optional peer dependency:

npm install @resvg/resvg-js

See the Image example for a full working example.

schema

The image element schema for image specs. Use with defineCatalog from core.

import { defineCatalog } from '@json-render/core';
import { schema, standardComponentDefinitions } from '@json-render/image';

const catalog = defineCatalog(schema, {
  components: standardComponentDefinitions,
});

Render Functions

Server-side functions for producing image output. Both accept a spec and optional RenderOptions.

import { renderToSvg, renderToPng } from '@json-render/image/render';

const svg = await renderToSvg(spec, { fonts });

const png = await renderToPng(spec, { fonts });
await writeFile('output.png', png);

RenderOptions

interface RenderOptions {
  registry?: ComponentRegistry;
  includeStandard?: boolean;  // default: true
  state?: Record<string, unknown>;
  fonts?: SatoriOptions['fonts'];
  width?: number;
  height?: number;
}
OptionTypeDefaultDescription
fontsSatoriOptions['fonts'][]Font data for text rendering (required for meaningful output)
widthnumberFrame propOverride the output image width
heightnumberFrame propOverride the output image height
registryRecord<string, ComponentRenderer>{}Custom component map (merged with standard components)
includeStandardbooleantrueInclude built-in standard components
stateRecord<string, unknown>{}Initial state for $state / $cond dynamic prop resolution

Standard Components

Root

Frame

Root image container. Defines the output image dimensions and background. Must be the root element.

{
  width: number;
  height: number;
  backgroundColor: string | null;
  padding: number | null;
  display: "flex" | "none" | null;
  flexDirection: "row" | "column" | null;
  alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
}

Layout

Box

Generic container with padding, margin, background, border, and flex alignment. Supports absolute positioning.

{
  padding: number | null;
  paddingTop: number | null;
  paddingBottom: number | null;
  paddingLeft: number | null;
  paddingRight: number | null;
  margin: number | null;
  backgroundColor: string | null;
  borderWidth: number | null;
  borderColor: string | null;
  borderRadius: number | null;
  flex: number | null;
  width: number | string | null;
  height: number | string | null;
  alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
  flexDirection: "row" | "column" | null;
  position: "relative" | "absolute" | null;
  top: number | null;
  left: number | null;
  right: number | null;
  bottom: number | null;
  overflow: "visible" | "hidden" | null;
}

Row

Horizontal flex layout with optional wrapping.

{
  gap: number | null;
  alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
  padding: number | null;
  flex: number | null;
  wrap: boolean | null;
}

Column

Vertical flex layout.

{
  gap: number | null;
  alignItems: "flex-start" | "center" | "flex-end" | "stretch" | null;
  justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | null;
  padding: number | null;
  flex: number | null;
}

Content

Heading

Heading text at various levels. h1 is largest, h4 is smallest.

{
  text: string;
  level: "h1" | "h2" | "h3" | "h4" | null;
  color: string | null;
  align: "left" | "center" | "right" | null;
  letterSpacing: number | string | null;
  lineHeight: number | null;
}

Text

Body text with configurable size, color, weight, and alignment.

{
  text: string;
  fontSize: number | null;
  color: string | null;
  align: "left" | "center" | "right" | null;
  fontWeight: "normal" | "bold" | null;
  fontStyle: "normal" | "italic" | null;
  lineHeight: number | null;
  letterSpacing: number | string | null;
  textDecoration: "none" | "underline" | "line-through" | null;
}

Image

Image from a URL with optional dimensions and fit.

{
  src: string;
  width: number | null;
  height: number | null;
  borderRadius: number | null;
  objectFit: "contain" | "cover" | "fill" | "none" | null;
}

Decorative

Divider

Horizontal line separator.

{
  color: string | null;
  thickness: number | null;
  marginTop: number | null;
  marginBottom: number | null;
}

Spacer

Empty vertical space.

{
  height: number | null;
}

Catalog Definitions

Pre-built definitions for creating image catalogs:

import { standardComponentDefinitions } from '@json-render/image/catalog';
import { defineCatalog } from '@json-render/core';
import { schema } from '@json-render/image';

const catalog = defineCatalog(schema, {
  components: {
    ...standardComponentDefinitions,
    // Add custom components
  },
});

Server-Safe Import

Import schema and catalog definitions without pulling in React or Satori:

import { schema, standardComponentDefinitions } from '@json-render/image/server';

Sub-path Exports

ExportDescription
@json-render/imageFull package: schema, renderer, components, render functions
@json-render/image/serverSchema and catalog definitions only (no React or Satori)
@json-render/image/catalogStandard component definitions and types
@json-render/image/renderServer-side render functions only

Types

ExportDescription
ImageSchemaSchema type for image specs
ImageSpecSpec type for image output
RenderOptionsOptions for render functions
ComponentRenderPropsProps passed to component render functions
ComponentRendererComponent render function type
ComponentRegistryMap of component names to render functions
StandardComponentDefinitionsType of the standard component definitions object
StandardComponentProps<K>Inferred props type for a standard component by name