14k

@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