@ogify/core 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +350 -0
- package/dist/index.d.mts +400 -0
- package/dist/index.d.ts +400 -0
- package/dist/index.js +492 -0
- package/dist/index.mjs +481 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 RevoLabs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# OGify - Beautiful Dynamic OG Images in Seconds
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/%40ogify%2Fcore)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
|
|
7
|
+
Generate stunning Open Graph images in seconds, not hours. OGify eliminates the complexity of OG image generation with zero-config font loading, automatic caching, and production-ready templates.
|
|
8
|
+
|
|
9
|
+
## ⚡ Why OGify?
|
|
10
|
+
|
|
11
|
+
- 🔌 **Zero-config**: Works out of the box with Next.js, Remix, Astro, etc.
|
|
12
|
+
- 🎨 **No font management**: Just specify a Google Font name - no downloads, no font files, no hassle.
|
|
13
|
+
- 📦 **No asset pipeline**: Emojis load dynamically from CDNs.
|
|
14
|
+
- 🖼️ **Rich templates**: OGify provides a set of production-ready templates with zero configuration.
|
|
15
|
+
- ⚡ **Smart caching**: OGify automatically caches fonts, emojis, and generated images - no configuration required.
|
|
16
|
+
- 🛡️ **Type-safe**: Full TypeScript support catches errors before runtime.
|
|
17
|
+
|
|
18
|
+
## 📦 Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add @ogify/core
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 🚀 Quick Start
|
|
25
|
+
|
|
26
|
+
### 1. Define a Template
|
|
27
|
+
|
|
28
|
+
Create a template using `defineTemplate` with an HTML renderer function:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { defineTemplate, OgTemplateOptions } from '@ogify/core';
|
|
32
|
+
|
|
33
|
+
const blogTemplate = defineTemplate({
|
|
34
|
+
id: 'blog-post',
|
|
35
|
+
name: 'Blog Post',
|
|
36
|
+
description: 'Template for blog post OG images',
|
|
37
|
+
fonts: [
|
|
38
|
+
{ name: 'Inter', weight: 700 },
|
|
39
|
+
{ name: 'Inter', weight: 400 }
|
|
40
|
+
],
|
|
41
|
+
renderer: ({ params }: OgTemplateOptions) => {
|
|
42
|
+
return `
|
|
43
|
+
<div style="display: flex; flex-direction: column; width: 100%; height: 100%; background: white; padding: 40px;">
|
|
44
|
+
<h1 style="font-size: 60px; font-weight: 700; color: #000;">
|
|
45
|
+
${params.title}
|
|
46
|
+
</h1>
|
|
47
|
+
<p style="font-size: 30px; color: #666;">
|
|
48
|
+
${params.description}
|
|
49
|
+
</p>
|
|
50
|
+
</div>
|
|
51
|
+
`;
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. Create a Renderer
|
|
57
|
+
|
|
58
|
+
Create a renderer instance and register your templates:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { createTemplateRenderer } from '@ogify/core';
|
|
62
|
+
|
|
63
|
+
const renderer = createTemplateRenderer({
|
|
64
|
+
templates: [blogTemplate],
|
|
65
|
+
defaultParams: {
|
|
66
|
+
brand: 'My Company'
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 3. Generate an Image
|
|
72
|
+
|
|
73
|
+
Render a template to a PNG buffer:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Basic usage (1200x630)
|
|
77
|
+
const imageBuffer = await renderer.renderToImage('blog-post', {
|
|
78
|
+
title: 'Hello World',
|
|
79
|
+
description: 'My first OG image'
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Custom dimensions for Twitter (1200x675)
|
|
83
|
+
const twitterImage = await renderer.renderToImage('blog-post', {
|
|
84
|
+
title: 'Hello World'
|
|
85
|
+
}, {
|
|
86
|
+
width: 1200,
|
|
87
|
+
height: 675
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**That's it!** You're ready for production. No font files to download, no build configuration, no asset pipeline.
|
|
92
|
+
|
|
93
|
+
## 🚀 Time-Saving Features
|
|
94
|
+
|
|
95
|
+
### **Zero-Config Google Fonts**
|
|
96
|
+
|
|
97
|
+
Traditional approach (manual setup):
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// ❌ Manual: Download fonts, manage files, configure paths
|
|
101
|
+
import fs from 'fs';
|
|
102
|
+
const fontData = fs.readFileSync('./fonts/Inter-Bold.ttf');
|
|
103
|
+
const font2Data = fs.readFileSync('./fonts/Inter-Regular.ttf');
|
|
104
|
+
|
|
105
|
+
const fonts = [
|
|
106
|
+
{ name: 'Inter', data: fontData, weight: 700 },
|
|
107
|
+
{ name: 'Inter', data: font2Data, weight: 400 }
|
|
108
|
+
];
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
OGify approach (zero config):
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// ✅ OGify: Just specify the font name - we handle the rest
|
|
115
|
+
const template = defineTemplate({
|
|
116
|
+
fonts: [
|
|
117
|
+
{ name: 'Inter', weight: 700 }, // Automatically loaded from Google Fonts
|
|
118
|
+
{ name: 'Inter', weight: 400 }
|
|
119
|
+
],
|
|
120
|
+
// ...
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Time saved**: ~15 minutes per font family
|
|
125
|
+
|
|
126
|
+
### **Automatic Caching**
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
// First render: Downloads fonts from Google (~500ms)
|
|
130
|
+
await renderer.renderToImage('blog-post', { title: 'Post 1' });
|
|
131
|
+
|
|
132
|
+
// Second render: Uses cached fonts (~50ms) - 10x faster! ⚡
|
|
133
|
+
await renderer.renderToImage('blog-post', { title: 'Post 2' });
|
|
134
|
+
|
|
135
|
+
// All subsequent renders: Lightning fast
|
|
136
|
+
await renderer.renderToImage('blog-post', { title: 'Post 3' });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Performance**: 10x faster after first render, no configuration needed
|
|
140
|
+
|
|
141
|
+
### **Dynamic Emoji Loading**
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// ✅ Emojis just work - loaded dynamically from CDN
|
|
145
|
+
renderer: ({ params }) => `
|
|
146
|
+
<div>
|
|
147
|
+
<h1>${params.title}</h1>
|
|
148
|
+
<div>👋 😄 🎉 🚀</div> <!-- Automatically rendered -->
|
|
149
|
+
</div>
|
|
150
|
+
`
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Time saved**: No emoji sprite sheets, no asset management, no build step
|
|
154
|
+
|
|
155
|
+
## 📚 Advanced Usage
|
|
156
|
+
|
|
157
|
+
### Custom Fonts
|
|
158
|
+
|
|
159
|
+
Load fonts from Google Fonts, custom URLs, or embedded data:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
const template = defineTemplate({
|
|
163
|
+
id: 'custom-fonts',
|
|
164
|
+
name: 'Custom Fonts Template',
|
|
165
|
+
description: 'Template with custom fonts',
|
|
166
|
+
fonts: [
|
|
167
|
+
// Google Fonts (automatic)
|
|
168
|
+
{ name: 'Roboto', weight: 400 },
|
|
169
|
+
|
|
170
|
+
// Custom URL
|
|
171
|
+
{ name: 'MyFont', url: 'https://example.com/font.woff2', weight: 700 },
|
|
172
|
+
|
|
173
|
+
// Embedded data
|
|
174
|
+
{ name: 'EmbeddedFont', data: fontBuffer, weight: 400 }
|
|
175
|
+
],
|
|
176
|
+
renderer: ({ params }) => `<div>${params.title}</div>`
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Emoji Support
|
|
181
|
+
|
|
182
|
+
Choose from multiple emoji providers:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const template = defineTemplate({
|
|
186
|
+
id: 'emoji-template',
|
|
187
|
+
name: 'Emoji Template',
|
|
188
|
+
description: 'Template with emoji support',
|
|
189
|
+
fonts: [{ name: 'Inter', weight: 400 }],
|
|
190
|
+
emojiProvider: 'twemoji', // or 'fluent', 'noto', 'openmoji', etc.
|
|
191
|
+
renderer: ({ params }) => `
|
|
192
|
+
<div>
|
|
193
|
+
<h1>${params.title}</h1>
|
|
194
|
+
<div>👋 😄 🎉</div>
|
|
195
|
+
</div>
|
|
196
|
+
`
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Lifecycle Hooks
|
|
201
|
+
|
|
202
|
+
Add custom logic before and after rendering:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const renderer = createTemplateRenderer({
|
|
206
|
+
templates: [blogTemplate],
|
|
207
|
+
beforeRender: async (templateId, params) => {
|
|
208
|
+
console.log(`Rendering ${templateId}`, params);
|
|
209
|
+
// Log analytics, validate params, etc.
|
|
210
|
+
},
|
|
211
|
+
afterRender: async (templateId, params, imageBuffer) => {
|
|
212
|
+
console.log(`Rendered ${templateId} successfully`);
|
|
213
|
+
// Cache image, send notifications, etc.
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Platform-Specific Dimensions
|
|
219
|
+
|
|
220
|
+
Generate images for different platforms:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// Facebook/LinkedIn (1200x630)
|
|
224
|
+
const facebookImage = await renderer.renderToImage('blog-post', params);
|
|
225
|
+
|
|
226
|
+
// Twitter (1200x675)
|
|
227
|
+
const twitterImage = await renderer.renderToImage('blog-post', params, {
|
|
228
|
+
width: 1200,
|
|
229
|
+
height: 675
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## 🎨 Template Features
|
|
234
|
+
|
|
235
|
+
### Supported CSS Properties
|
|
236
|
+
|
|
237
|
+
Templates support a subset of CSS properties via Satori:
|
|
238
|
+
|
|
239
|
+
- **Layout**: `display: flex`, `flexDirection`, `alignItems`, `justifyContent`
|
|
240
|
+
- **Spacing**: `padding`, `margin`, `gap`
|
|
241
|
+
- **Typography**: `fontSize`, `fontWeight`, `color`, `lineHeight`, `textAlign`
|
|
242
|
+
- **Background**: `backgroundColor`, `backgroundImage`
|
|
243
|
+
- **Border**: `border`, `borderRadius`
|
|
244
|
+
- **Size**: `width`, `height`, `maxWidth`, `maxHeight`
|
|
245
|
+
|
|
246
|
+
### Tailwind-like Utilities
|
|
247
|
+
|
|
248
|
+
You can use Tailwind-like class names:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
renderer: ({ params }) => `
|
|
252
|
+
<div class="flex flex-col items-center justify-center w-full h-full bg-white p-4">
|
|
253
|
+
<h1 class="text-[60px] font-bold text-black">${params.title}</h1>
|
|
254
|
+
<p class="text-[30px] text-gray-600">${params.description}</p>
|
|
255
|
+
</div>
|
|
256
|
+
`
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## 📖 API Reference
|
|
260
|
+
|
|
261
|
+
### `defineTemplate(config)`
|
|
262
|
+
|
|
263
|
+
Defines a new OG template.
|
|
264
|
+
|
|
265
|
+
**Parameters:**
|
|
266
|
+
|
|
267
|
+
- `id` (string): Unique identifier
|
|
268
|
+
- `name` (string): Human-readable name
|
|
269
|
+
- `description` (string): Template description
|
|
270
|
+
- `renderer` (function): Function that returns HTML string
|
|
271
|
+
- `fonts` (array): Array of font configurations
|
|
272
|
+
- `emojiProvider` (optional): Emoji provider to use
|
|
273
|
+
|
|
274
|
+
**Returns:** `OgTemplate`
|
|
275
|
+
|
|
276
|
+
### `createTemplateRenderer(config)`
|
|
277
|
+
|
|
278
|
+
Creates a new template renderer instance.
|
|
279
|
+
|
|
280
|
+
**Parameters:**
|
|
281
|
+
|
|
282
|
+
- `templates` (array): Array of template definitions
|
|
283
|
+
- `defaultParams` (optional): Default parameters for all templates
|
|
284
|
+
- `beforeRender` (optional): Hook called before rendering
|
|
285
|
+
- `afterRender` (optional): Hook called after rendering
|
|
286
|
+
|
|
287
|
+
**Returns:** `TemplateRenderer`
|
|
288
|
+
|
|
289
|
+
### `renderer.renderToImage(templateId, params, options?)`
|
|
290
|
+
|
|
291
|
+
Renders a template to a PNG buffer.
|
|
292
|
+
|
|
293
|
+
**Parameters:**
|
|
294
|
+
|
|
295
|
+
- `templateId` (string): ID of the template to render
|
|
296
|
+
- `params` (object): Parameters to pass to the template
|
|
297
|
+
- `options` (optional): Rendering options
|
|
298
|
+
- `width` (number): Image width (default: 1200)
|
|
299
|
+
- `height` (number): Image height (default: 630)
|
|
300
|
+
|
|
301
|
+
**Returns:** `Promise<Buffer>`
|
|
302
|
+
|
|
303
|
+
### `renderer.getTemplate(id)`
|
|
304
|
+
|
|
305
|
+
Retrieves a template by ID.
|
|
306
|
+
|
|
307
|
+
**Returns:** `OgTemplate | undefined`
|
|
308
|
+
|
|
309
|
+
### `renderer.getTemplateIds()`
|
|
310
|
+
|
|
311
|
+
Gets all registered template IDs.
|
|
312
|
+
|
|
313
|
+
**Returns:** `string[]`
|
|
314
|
+
|
|
315
|
+
## ⚡ Performance & Production
|
|
316
|
+
|
|
317
|
+
### **Automatic Caching (Zero Config)**
|
|
318
|
+
|
|
319
|
+
OGify automatically caches fonts and emojis in memory - no configuration required:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
// First render: Downloads fonts from Google Fonts (~500ms)
|
|
323
|
+
await renderer.renderToImage('blog-post', { title: 'Post 1' });
|
|
324
|
+
|
|
325
|
+
// Second render: Uses cached fonts (~50ms) - 10x faster! ⚡
|
|
326
|
+
await renderer.renderToImage('blog-post', { title: 'Post 2' });
|
|
327
|
+
|
|
328
|
+
// Third+ renders: Lightning fast from cache
|
|
329
|
+
await renderer.renderToImage('blog-post', { title: 'Post 3' });
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## 📋 Changelog
|
|
333
|
+
|
|
334
|
+
See [CHANGELOG.md](CHANGELOG.md) for a complete history of changes and releases.
|
|
335
|
+
|
|
336
|
+
## 🤝 Contributing
|
|
337
|
+
|
|
338
|
+
We welcome contributions! Please see our contributing guidelines.
|
|
339
|
+
|
|
340
|
+
## 📄 License
|
|
341
|
+
|
|
342
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
343
|
+
|
|
344
|
+
## 🙏 Credits
|
|
345
|
+
|
|
346
|
+
Built on top of:
|
|
347
|
+
|
|
348
|
+
- [satori](https://github.com/vercel/satori) - SVG generation
|
|
349
|
+
- [satori-html](https://github.com/vercel/satori-html) - HTML to VDOM conversion
|
|
350
|
+
- [resvg-js](https://github.com/thx/resvg-js) - PNG conversion
|