Skip to content
Open Source

Images as Code.

Write JSX compositions with full CSS support. Export as images. No browser window, no server, no ceremony.

npm install grafex
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>
  );
}
Hello, Grafex!
output.png

Why Grafex?

Full CSS. Real browser engine. Zero configuration. The image composition tool you actually wanted.

Full CSS Support

Flexbox, Grid, gradients, shadows, custom fonts — real CSS rendered by a real browser engine. Not a subset. Not reimplemented. The real thing.

Fast Renders

5-50ms warm renders. Sub-second cold starts. WebKit launches once and stays ready.

AI-Friendly

Compositions are plain JSX functions. Any LLM can write them, modify them, and reason about them.

No Browser Window

WebKit runs headlessly behind the scenes. No Puppeteer scripts. No browser lifecycle management. Just import, render, done.

Compositions Are Just Functions

A composition is a TSX file that exports a function and a config. Accept props, use components, style with CSS — all the patterns you already know.

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>
  );
}
Generated OG card showing 'Building Modern APIs' og-card.png
bash
npx grafex export -f og-card.tsx -o og-card.png

See more examples →

What You Can Build

Open Graph Images

Open Graph Images

Dynamic social previews for every page, generated at build time.

Social Media Cards

Social Media Cards

Branded cards for Twitter, LinkedIn, and Instagram — from one template.

Email & Web Banners

Email & Web Banners

Programmatic banner generation with consistent branding across campaigns.

Certificates

Certificates

Event certificates and awards with dynamic names, dates, and details.

Video Thumbnails

Video Thumbnails

YouTube and podcast covers generated from a single template.

Diagrams & Charts

Diagrams & Charts

Architecture diagrams and data visualizations, version-controlled as code.

Get Started in 3 Steps

1

Install

One package. WebKit is downloaded automatically.

bash
npm install grafex
2

Write a composition

Create a TSX file. Export a component and a config.

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>
  );
}
3

Export

Run one command. Get an image.

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

Start Making Images.

npm install grafex