Skip to content
Grafex
GitHub

Getting Started

Go from zero to a rendered PNG in under 5 minutes.

Install

bash
npm install grafex

Grafex uses WebKit for rendering. The browser binary is downloaded automatically during npm install via a postinstall script — no extra steps needed.

Tip: If the postinstall download fails (corporate firewalls, restricted CI environments), see Browser Setup for manual installation.

Requirements: Node.js >= 20.0.0

Write a composition

Create a file called card.tsx:

card.tsx
import type { CompositionConfig } from 'grafex';

export const config: CompositionConfig = {
  width: 1200,
  height: 630,
};

export default function Card() {
  return (
    <div
      style={{
        width: '100%',
        height: '100%',
        background: 'linear-gradient(135deg, #667eea, #764ba2)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        color: 'white',
        fontSize: '64px',
        fontWeight: 'bold',
        fontFamily: 'system-ui, sans-serif',
      }}
    >
      Hello, Grafex!
    </div>
  );
}

A composition has two parts:

  1. Default export — a function that returns JSX. This is your image layout.
  2. Named config export — a CompositionConfig object that sets the output dimensions and optionally loads custom fonts.

Export

bash
npx grafex export -f card.tsx -o card.png

Grafex bundles your composition with esbuild, renders it in a headless WebKit instance, and saves the screenshot as a PNG. The output is a 1200×630 image with your gradient background and centered text.

See it in action

This is the kind of image Grafex can generate. Code on the left, rendered PNG on the right — no browser window, no server, just one CLI command.

og-card.tsx
export const config = {
  width: 600,
  height: 400,
};

export default function OgCard() {
  return (
    <div style={{
      width: '100%',
      height: '100%',
      background: 'linear-gradient(145deg, #0f172a 0%, #1e293b 100%)',
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'space-between',
      padding: '52px',
      fontFamily: 'system-ui, -apple-system, sans-serif',
      position: 'relative',
      overflow: 'hidden',
    }}>
      {/* Top accent glow */}
      <div style={{
        position: 'absolute',
        top: '-60px',
        right: '-60px',
        width: '300px',
        height: '300px',
        background: 'radial-gradient(circle, rgba(244,114,182,0.2) 0%, transparent 70%)',
      }} />

      {/* Top: tag */}
      <div style={{ display: 'flex', alignItems: 'center', gap: '12px', zIndex: 1 }}>
        <div style={{
          background: 'rgba(163,230,53,0.15)',
          border: '1px solid rgba(163,230,53,0.3)',
          borderRadius: '6px',
          padding: '4px 12px',
          color: '#A3E635',
          fontSize: '12px',
          fontWeight: '600',
          letterSpacing: '0.08em',
          textTransform: 'uppercase',
        }}>
          Tutorial
        </div>
        <span style={{ color: '#475569', fontSize: '13px' }}>5 min read</span>
      </div>

      {/* Middle: title */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', zIndex: 1 }}>
        <div style={{
          color: '#F1F5F9',
          fontSize: '36px',
          fontWeight: '700',
          lineHeight: '1.2',
          letterSpacing: '-0.5px',
        }}>
          Building Modern APIs
        </div>
        <div style={{ color: '#94A3B8', fontSize: '16px', lineHeight: '1.5' }}>
          Best practices for REST and GraphQL in 2026
        </div>
      </div>

      {/* Bottom: author + meta */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', zIndex: 1 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
          <div style={{
            width: '36px',
            height: '36px',
            borderRadius: '50%',
            background: 'linear-gradient(135deg, #F472B6, #38BDF8)',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            color: 'white',
            fontSize: '14px',
            fontWeight: '700',
            flexShrink: 0,
          }}>
            JS
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: '2px' }}>
            <span style={{ color: '#E2E8F0', fontSize: '14px', fontWeight: '600' }}>Jane Smith</span>
            <span style={{ color: '#64748B', fontSize: '12px' }}>March 15, 2026</span>
          </div>
        </div>
        <div style={{
          color: '#475569',
          fontSize: '13px',
          fontWeight: '600',
          letterSpacing: '0.05em',
        }}>
          dev.blog
        </div>
      </div>

      {/* Bottom-left accent stripe */}
      <div style={{
        position: 'absolute',
        bottom: '0',
        left: '0',
        right: '0',
        height: '3px',
        background: 'linear-gradient(90deg, #F472B6, #38BDF8, #A3E635)',
      }} />
    </div>
  );
}
Rendered OG card composition output og-card.png
$ npx grafex export -f og-card.tsx -o og-card.png

Next steps