@zyrab/domo-og
Version:
An OG (Open Graph) image generator config based SVG templates and WASM engine.
242 lines (176 loc) • 9.97 kB
Markdown
<div align="center">
<h1>@zyrab/domo-og</h1>
<p>A blazing-fast, cross-platform, config-driven Open Graph (OG) image generator for Node.js.</p>
</div>
## Introduction
`@zyrab/domo-og` is a modern utility to dynamically generate high-quality Open Graph images for your websites, blogs, and applications.
## Why use Domo-OG?
Historically, generating SVGs and converting them to PNGs required OS-specific binaries or heavy headless browsers like Puppeteer. `@zyrab/domo-og` solves this by utilizing WebAssembly (`@resvg/resvg-wasm`). It runs perfectly across Windows, macOS, and Linux without complex native dependencies.
Furthermore, instead of wrestling with messy raw SVG strings, you design your images using clean, readable JSON configuration objects.
## Key Features
- **WASM Powered Engine**: Cross-platform compatibility out of the box. No OS-specific binary downloads.
- **Config-Driven Templates**: Define layouts, backgrounds, text, and images via simple JavaScript objects.
- **Dynamic Data Injection**: Easily swap variables like `{{title}}` or `{{author}}` at build time.
- **Smart Text Wrapping**: Automatically calculates text line-breaks and multi-line positioning.
- **Built-in Caching**: Prevents redundant generation with an internal `og-cache.json` manifest, drastically speeding up static site generation (SSG) builds.
- **Remote Image Fetching**: Safely fetches and caches remote background/element images with built-in size limits (20MB) to prevent memory issues.
## Performance & Benchmarks
When it comes to automated Open Graph image generation, speed matters—especially for static site generators that might need to build thousands of pages.
### Why is Domo-OG so fast?
Other popular generation tools rely on heavy stacks:
- **Puppeteer / Playwright**: They spin up an entire headless Chromium browser just to take a screenshot. This is infamously slow (often taking **1-3 seconds per image**), highly resource-intensive, and prone to memory leaks.
- **Satori**: While much faster than Puppeteer, it relies on a custom React/HTML/CSS parsing engine (Yoga) in JavaScript to convert layouts into SVGs. This is heavily CPU-bound.
`@zyrab/domo-og` uses a completely different approach. By taking a simple JSON config, we completely bypass HTML/CSS layout engines and DOM parsing. The JSON is instantly mapped onto a flat SVG canvas and immediately handed off to the high-performance `@resvg/resvg-wasm` Rust engine to render the PNG.
### Benchmark Results
Tested on an Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz (8 Cores, Node v22.19.0):
| Test Condition | Iterations | Avg Time per Image | Total Time |
| --- | --- | --- | --- |
| **Simple Template** (Cold) | 200 | **~33 ms** | 6.7s |
| **Complex Template** (Remote Image) | 50 | **~43 ms** | 2.1s |
| **Simple Template** (Cache Hit) | 200 | **~29 ms** | 5.8s |
*(Note: Cache hits skip rendering entirely, safely fetching from disk).*
## Installation
```bash
npm install @zyrab/domo-og
# or
yarn add @zyrab/domo-og
# or
pnpm add @zyrab/domo-og
```
## Quick Start
Here is a basic example of generating an OG image for a blog post. By default, the generator uses a built-in template and handles relative project paths automatically.
```javascript
import { generateOgImage } from "@zyrab/domo-og";
async function build() {
const imagePath = await generateOgImage({
slug: "my-first-post", // Used for caching and file naming
ogOutputPath: "public", // Where the assets/og-images folder will be created
title: "My Awesome First Post!", // Injects into {{title}} in the template
type: "Blog Article" // Injects into {{type}} if defined in template
});
console.log(`Generated successfully at: ${imagePath}`);
}
build();
```
---
## Configuration API (Templates)
Templates in Domo-OG are just JavaScript objects. This eliminates the need to manually manipulate SVG tags.
### Root Configuration
| Property | Type | Default | Description |
|---|---|---|---|
| `width` | `number` | `1200` | The width of the generated image. |
| `height` | `number` | `630` | The height of the generated image. |
| `fontPath` | `string` | `null` | Path or URL to a custom `.ttf`, `.otf`, or `.woff` font. |
| `background` | `object` | `null` | The background layer configuration. |
| `elements` | `array` | `[]` | An array of element objects (text or images) to render on top. |
### Background Object
| Property | Type | Description |
|---|---|---|
| `type` | `"color"` \| `"image"` | Defines the type of background. |
| `value` | `string` | The hex/rgb color code (Required if `type` is `"color"`). |
| `src` | `string` | Path or URL to the background image (Required if `type` is `"image"`). |
### Elements Array Objects
Elements render sequentially (the last element in the array renders on top).
#### Text Element
| Property | Type | Description |
|---|---|---|
| `type` | `"text"` | Identifies the element type. |
| `content` | `string` | The text to display. Supports variables e.g., `{{title}}`. |
| `width` | `number` | The width of the text element. |
| `maxLength` | `number` | The maximum length of the text element. |
| `horizontalAlign` | `"left"`\|`"center"`\|`"right"` | Horizontal alignment based on padding/width. |
| `verticalAlign` | `"top"`\|`"middle"`\|`"bottom"` | Vertical alignment based on padding/height. |
| `fontSize` | `number` | Font size in pixels (Default: `32`). |
| `color` | `string` | Hex/rgb text color. |
| `backgroundColor` | `string` | Adds a highlighted background box behind the text. |
| `borderRadius` | `number` | Border radius for the text background box. |
| `padding` | `number` | Distance from the edges of the canvas. |
| `bgPadding` | `number` | Padding between the text and its own `backgroundColor` box. |
#### Image Element
| Property | Type | Description |
|---|---|---|
| `type` | `"image"` | Identifies the element type. |
| `src` | `string` | Local path or remote URL (`http/https`) to the image. |
| `width` | `number` | Width of the image (Default: `100`). |
| `height` | `number` | Height of the image (Default: `100`). |
| `horizontalAlign` | `"left"`\|`"center"`\|`"right"` | Horizontal alignment on the canvas. |
| `verticalAlign` | `"top"`\|`"middle"`\|`"bottom"` | Vertical alignment on the canvas. |
| `padding` | `number` | Distance from the edges of the canvas. |
### Advanced Template Example
Here is an advanced template showcasing dynamic data, remote images, and custom styling.
```javascript
const advancedTemplate = {
width: 1200,
height: 630,
background: {
type: "color",
value: "#1a1a1a",
},
elements: [
{
type: "image",
src: "https://example.com/mock-logo.png", // Mock remote image
horizontalAlign: "left",
verticalAlign: "top",
padding: 40,
width: 80,
height: 80,
},
{
type: "text",
content: "{{category}}", // Dynamic variable
horizontalAlign: "left",
verticalAlign: "top",
padding: 140, // Pushed down below the logo
fontSize: 24,
color: "#000000",
backgroundColor: "#E9FA00",
bgPadding: 8,
borderRadius: 4,
},
{
type: "text",
content: "{{title}}", // Dynamic variable
horizontalAlign: "center",
verticalAlign: "middle",
fontSize: 64,
color: "#FFFFFF",
maxLength: 20 // Forces line breaks after ~20 characters
}
]
};
```
---
## Core API Reference
### `generateOgImage(options)`
The primary workhorse of the package. It builds the SVG, renders it to PNG, and manages the cache.
**Options:**
- `slug` (**String, Required**): A unique identifier for the image (often the URL slug).
- `ogOutputPath` (**String, Required**): The relative or absolute path to your output directory (e.g., `"public"`). Images are saved into `${ogOutputPath}/assets/og-images/`.
- `template` (**Object, Optional**): Your config template. Falls back to the built-in default config if omitted.
- `routeKey` (**String, Optional**): An alternative key to use for hashing/caching instead of slug.
- `...flatParams`: Any other key passed in this object will be injected into the template (e.g., passing `title: "Hello"` replaces `{{title}}` in the template).
**Returns:**
- `Promise<String>`: The relative path to the generated PNG (e.g., `assets/og-images/my-post-1a2b3c4d.png`).
### `getDefaultConfig()`
Returns a clean, modern, dark-themed default configuration object if you don't want to design one from scratch.
### `flushManifestImmediately()`
(`og-cache.json` is debounced by default)
Forces the caching manifest (`og-cache.json`) to write to the disk immediately. Useful for build scripts that might exit before the standard 500ms debounce timer finishes.
---
## Fonts & Fallbacks
The WASM rendering engine requires a valid `.ttf`, `.otf`, or `.woff` font file to render text. `@zyrab/domo-og` handles this intelligently:
1. **Explicit URL/Path**: If you provide `fontPath` in your config, it will fetch/load it.
2. **Local Assets**: It will automatically scan `${ogOutputPath}/assets/fonts/` for any valid font file.
3. **Internal Fallback**: If neither are found, it safely falls back to a default font bundled within the package (`fonts/default.ttf`).
---
## Remote Image Security & Limits
To protect your build processes from memory leaks and hang-ups:
- Remote images have a strict **20MB size limit**.
- The package uses a custom User-Agent: `Domo-OG-Builder/1.0`.
_(Note: If your server blocks unknown User-Agents, ensure you whitelist `Domo-OG-Builder/1.0` to allow image fetching)._
---
## License & Acknowledgements
`@zyrab/domo-og` is licensed under the MIT License.
### Engine Acknowledgment
This package relies on the fantastic `@resvg/resvg-wasm` for rendering SVGs to PNGs via WebAssembly. Please refer to the Resvg repository or the `@resvg/resvg-wasm` package for detailed licensing information regarding the underlying rendering engine.