@ewanc26/og 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/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # @ewanc26/og
2
+
3
+ Dynamic OpenGraph image generator with noise backgrounds, bold typography, and Satori-based rendering. Works in SvelteKit endpoints, edge runtimes, and build scripts.
4
+
5
+ ## Features
6
+
7
+ - **Bold, identifiably personal design** — massive typography, ALL CAPS site names, unique per-page noise
8
+ - **@ewanc26/noise integration** — deterministic noise backgrounds seeded by title
9
+ - **Zero native dependencies** — works in Node.js, edge runtimes, and browsers
10
+ - **SvelteKit helpers** — drop-in endpoint creation
11
+ - **Customisable** — colours, fonts, templates
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ pnpm add @ewanc26/og
17
+ ```
18
+
19
+ ### SvelteKit Endpoint
20
+
21
+ ```ts
22
+ // src/routes/og/[...path]/+server.ts
23
+ import { createOgEndpoint } from '@ewanc26/og';
24
+
25
+ export const GET = createOgEndpoint({
26
+ siteName: 'ewancroft.uk',
27
+ defaultTemplate: 'blog',
28
+ cacheMaxAge: 86400, // 24 hours
29
+ });
30
+ ```
31
+
32
+ Use in your page:
33
+
34
+ ```svelte
35
+ <script>
36
+ import { createOgImageUrl } from '@ewanc26/og';
37
+ </script>
38
+
39
+ <svelte:head>
40
+ <meta property="og:image" content={createOgImageUrl('/og', {
41
+ title: data.post.title,
42
+ description: data.post.excerpt,
43
+ })} />
44
+ </svelte:head>
45
+ ```
46
+
47
+ ### Direct Generation
48
+
49
+ ```ts
50
+ import { generateOgImage } from '@ewanc26/og';
51
+ import { writeFileSync } from 'fs';
52
+
53
+ const png = await generateOgImage({
54
+ title: 'My Blog Post',
55
+ description: 'A compelling description',
56
+ siteName: 'ewancroft.uk',
57
+ template: 'blog', // 'blog' | 'profile' | 'default'
58
+ });
59
+
60
+ writeFileSync('./og-image.png', png);
61
+ ```
62
+
63
+ ## Templates
64
+
65
+ ### `blog` (default)
66
+
67
+ Massive title (72px), ALL CAPS site name, noise background, accent bar. Optimised for blog posts and articles.
68
+
69
+ ### `profile`
70
+
71
+ Centered layout with prominent avatar. Works well for user pages, about pages.
72
+
73
+ ### `default`
74
+
75
+ Bold but minimal. Good for generic pages.
76
+
77
+ ## Customisation
78
+
79
+ ### Colours
80
+
81
+ ```ts
82
+ await generateOgImage({
83
+ title: 'My Page',
84
+ siteName: 'mysite.com',
85
+ colors: {
86
+ background: '#1a1a2e',
87
+ text: '#ffffff',
88
+ accent: '#00d4ff',
89
+ },
90
+ });
91
+ ```
92
+
93
+ ### Fonts
94
+
95
+ Package bundles Inter. Override with custom fonts:
96
+
97
+ ```ts
98
+ await generateOgImage({
99
+ title: 'My Page',
100
+ siteName: 'mysite.com',
101
+ fonts: {
102
+ heading: './static/fonts/CustomFont-Bold.ttf',
103
+ body: './static/fonts/CustomFont-Regular.ttf',
104
+ },
105
+ });
106
+ ```
107
+
108
+ ### Noise
109
+
110
+ Disable or customise noise:
111
+
112
+ ```ts
113
+ await generateOgImage({
114
+ title: 'My Page',
115
+ siteName: 'mysite.com',
116
+ noise: {
117
+ enabled: true,
118
+ opacity: 0.3,
119
+ colorMode: 'grayscale',
120
+ },
121
+ noiseSeed: 'custom-seed', // optional, defaults to title
122
+ });
123
+ ```
124
+
125
+ ## API
126
+
127
+ ### `generateOgImage(options): Promise<Buffer>`
128
+
129
+ Generate PNG buffer.
130
+
131
+ ### `generateOgImageDataUrl(options): Promise<string>`
132
+
133
+ Generate base64 data URL.
134
+
135
+ ### `createOgEndpoint(options): RequestHandler`
136
+
137
+ Create SvelteKit GET handler.
138
+
139
+ ### `createOgImageUrl(baseUrl, params): string`
140
+
141
+ Build OG image URL with query parameters.
142
+
143
+ ## License
144
+
145
+ AGPL-3.0-only
@@ -0,0 +1,258 @@
1
+ // src/templates/blog.ts
2
+ function blogTemplate({
3
+ title,
4
+ description,
5
+ siteName,
6
+ colors,
7
+ width,
8
+ height
9
+ }) {
10
+ return {
11
+ type: "div",
12
+ props: {
13
+ style: {
14
+ display: "flex",
15
+ flexDirection: "column",
16
+ alignItems: "center",
17
+ justifyContent: "center",
18
+ width,
19
+ height,
20
+ backgroundColor: colors.background
21
+ },
22
+ children: [
23
+ {
24
+ type: "h1",
25
+ props: {
26
+ style: {
27
+ fontSize: 64,
28
+ fontWeight: 700,
29
+ color: colors.text,
30
+ letterSpacing: "-0.02em",
31
+ margin: 0,
32
+ textAlign: "center",
33
+ lineHeight: 1.1,
34
+ maxWidth: 1e3
35
+ },
36
+ children: title
37
+ }
38
+ },
39
+ description ? {
40
+ type: "p",
41
+ props: {
42
+ style: {
43
+ fontSize: 28,
44
+ fontWeight: 400,
45
+ color: colors.accent,
46
+ marginTop: 28,
47
+ marginBottom: 0,
48
+ textAlign: "center",
49
+ lineHeight: 1.4,
50
+ maxWidth: 900
51
+ },
52
+ children: description
53
+ }
54
+ } : null,
55
+ {
56
+ type: "p",
57
+ props: {
58
+ style: {
59
+ fontSize: 24,
60
+ fontWeight: 400,
61
+ color: colors.accent,
62
+ marginTop: 56,
63
+ marginBottom: 0,
64
+ textAlign: "center",
65
+ opacity: 0.7
66
+ },
67
+ children: siteName
68
+ }
69
+ }
70
+ ].filter(Boolean)
71
+ }
72
+ };
73
+ }
74
+
75
+ // src/templates/profile.ts
76
+ function profileTemplate({
77
+ title,
78
+ description,
79
+ siteName,
80
+ image,
81
+ colors,
82
+ width,
83
+ height
84
+ }) {
85
+ const children = [];
86
+ if (image) {
87
+ children.push({
88
+ type: "img",
89
+ props: {
90
+ src: image,
91
+ width: 120,
92
+ height: 120,
93
+ style: {
94
+ borderRadius: "50%",
95
+ marginBottom: 32,
96
+ objectFit: "cover"
97
+ }
98
+ }
99
+ });
100
+ }
101
+ children.push({
102
+ type: "h1",
103
+ props: {
104
+ style: {
105
+ fontSize: 56,
106
+ fontWeight: 700,
107
+ color: colors.text,
108
+ letterSpacing: "-0.02em",
109
+ margin: 0,
110
+ textAlign: "center",
111
+ lineHeight: 1.1,
112
+ maxWidth: 900
113
+ },
114
+ children: title
115
+ }
116
+ });
117
+ if (description) {
118
+ children.push({
119
+ type: "p",
120
+ props: {
121
+ style: {
122
+ fontSize: 26,
123
+ fontWeight: 400,
124
+ color: colors.accent,
125
+ marginTop: 20,
126
+ marginBottom: 0,
127
+ textAlign: "center",
128
+ lineHeight: 1.4,
129
+ maxWidth: 700
130
+ },
131
+ children: description
132
+ }
133
+ });
134
+ }
135
+ children.push({
136
+ type: "p",
137
+ props: {
138
+ style: {
139
+ fontSize: 24,
140
+ fontWeight: 400,
141
+ color: colors.accent,
142
+ marginTop: 48,
143
+ marginBottom: 0,
144
+ textAlign: "center",
145
+ opacity: 0.7
146
+ },
147
+ children: siteName
148
+ }
149
+ });
150
+ return {
151
+ type: "div",
152
+ props: {
153
+ style: {
154
+ display: "flex",
155
+ flexDirection: "column",
156
+ alignItems: "center",
157
+ justifyContent: "center",
158
+ width,
159
+ height,
160
+ backgroundColor: colors.background
161
+ },
162
+ children
163
+ }
164
+ };
165
+ }
166
+
167
+ // src/templates/default.ts
168
+ function defaultTemplate({
169
+ title,
170
+ description,
171
+ siteName,
172
+ colors,
173
+ width,
174
+ height
175
+ }) {
176
+ return {
177
+ type: "div",
178
+ props: {
179
+ style: {
180
+ display: "flex",
181
+ flexDirection: "column",
182
+ alignItems: "center",
183
+ justifyContent: "center",
184
+ width,
185
+ height,
186
+ backgroundColor: colors.background
187
+ },
188
+ children: [
189
+ {
190
+ type: "h1",
191
+ props: {
192
+ style: {
193
+ fontSize: 72,
194
+ fontWeight: 700,
195
+ color: colors.text,
196
+ letterSpacing: "-0.02em",
197
+ margin: 0,
198
+ textAlign: "center"
199
+ },
200
+ children: title
201
+ }
202
+ },
203
+ description ? {
204
+ type: "p",
205
+ props: {
206
+ style: {
207
+ fontSize: 32,
208
+ fontWeight: 400,
209
+ color: colors.accent,
210
+ marginTop: 24,
211
+ marginBottom: 0,
212
+ textAlign: "center",
213
+ maxWidth: 900
214
+ },
215
+ children: description
216
+ }
217
+ } : null,
218
+ {
219
+ type: "p",
220
+ props: {
221
+ style: {
222
+ fontSize: 28,
223
+ fontWeight: 400,
224
+ color: colors.accent,
225
+ marginTop: 64,
226
+ marginBottom: 0,
227
+ textAlign: "center",
228
+ opacity: 0.7
229
+ },
230
+ children: siteName
231
+ }
232
+ }
233
+ ].filter(Boolean)
234
+ }
235
+ };
236
+ }
237
+
238
+ // src/templates/index.ts
239
+ var templates = {
240
+ blog: blogTemplate,
241
+ profile: profileTemplate,
242
+ default: defaultTemplate
243
+ };
244
+ function getTemplate(name) {
245
+ if (typeof name === "function") {
246
+ return name;
247
+ }
248
+ return templates[name];
249
+ }
250
+
251
+ export {
252
+ blogTemplate,
253
+ profileTemplate,
254
+ defaultTemplate,
255
+ templates,
256
+ getTemplate
257
+ };
258
+ //# sourceMappingURL=chunk-EPPJ2HBS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/templates/blog.ts","../src/templates/profile.ts","../src/templates/default.ts","../src/templates/index.ts"],"sourcesContent":["/**\n * Blog OG template.\n * Clean centered layout.\n */\n\nimport type { OgTemplateProps } from '../types.js'\n\nexport function blogTemplate({\n\ttitle,\n\tdescription,\n\tsiteName,\n\tcolors,\n\twidth,\n\theight,\n}: OgTemplateProps) {\n\treturn {\n\t\ttype: 'div',\n\t\tprops: {\n\t\t\tstyle: {\n\t\t\t\tdisplay: 'flex',\n\t\t\t\tflexDirection: 'column',\n\t\t\t\talignItems: 'center',\n\t\t\t\tjustifyContent: 'center',\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\tbackgroundColor: colors.background,\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'h1',\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tfontSize: 64,\n\t\t\t\t\t\t\tfontWeight: 700,\n\t\t\t\t\t\t\tcolor: colors.text,\n\t\t\t\t\t\t\tletterSpacing: '-0.02em',\n\t\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\t\tlineHeight: 1.1,\n\t\t\t\t\t\t\tmaxWidth: 1000,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tchildren: title,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tdescription ? {\n\t\t\t\t\ttype: 'p',\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tfontSize: 28,\n\t\t\t\t\t\t\tfontWeight: 400,\n\t\t\t\t\t\t\tcolor: colors.accent,\n\t\t\t\t\t\t\tmarginTop: 28,\n\t\t\t\t\t\t\tmarginBottom: 0,\n\t\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\t\tlineHeight: 1.4,\n\t\t\t\t\t\t\tmaxWidth: 900,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tchildren: description,\n\t\t\t\t\t},\n\t\t\t\t} : null,\n\t\t\t\t{\n\t\t\t\t\ttype: 'p',\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tfontSize: 24,\n\t\t\t\t\t\t\tfontWeight: 400,\n\t\t\t\t\t\t\tcolor: colors.accent,\n\t\t\t\t\t\t\tmarginTop: 56,\n\t\t\t\t\t\t\tmarginBottom: 0,\n\t\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\t\topacity: 0.7,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tchildren: siteName,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t].filter(Boolean),\n\t\t},\n\t}\n}\n","/**\n * Profile OG template.\n * Centered layout.\n */\n\nimport type { OgTemplateProps } from '../types.js'\n\nexport function profileTemplate({\n\ttitle,\n\tdescription,\n\tsiteName,\n\timage,\n\tcolors,\n\twidth,\n\theight,\n}: OgTemplateProps) {\n\tconst children: unknown[] = []\n\n\tif (image) {\n\t\tchildren.push({\n\t\t\ttype: 'img',\n\t\t\tprops: {\n\t\t\t\tsrc: image,\n\t\t\t\twidth: 120,\n\t\t\t\theight: 120,\n\t\t\t\tstyle: {\n\t\t\t\t\tborderRadius: '50%',\n\t\t\t\t\tmarginBottom: 32,\n\t\t\t\t\tobjectFit: 'cover',\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\n\tchildren.push({\n\t\ttype: 'h1',\n\t\tprops: {\n\t\t\tstyle: {\n\t\t\t\tfontSize: 56,\n\t\t\t\tfontWeight: 700,\n\t\t\t\tcolor: colors.text,\n\t\t\t\tletterSpacing: '-0.02em',\n\t\t\t\tmargin: 0,\n\t\t\t\ttextAlign: 'center',\n\t\t\t\tlineHeight: 1.1,\n\t\t\t\tmaxWidth: 900,\n\t\t\t},\n\t\t\tchildren: title,\n\t\t},\n\t})\n\n\tif (description) {\n\t\tchildren.push({\n\t\t\ttype: 'p',\n\t\t\tprops: {\n\t\t\t\tstyle: {\n\t\t\t\t\tfontSize: 26,\n\t\t\t\t\tfontWeight: 400,\n\t\t\t\t\tcolor: colors.accent,\n\t\t\t\t\tmarginTop: 20,\n\t\t\t\t\tmarginBottom: 0,\n\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\tlineHeight: 1.4,\n\t\t\t\t\tmaxWidth: 700,\n\t\t\t\t},\n\t\t\t\tchildren: description,\n\t\t\t},\n\t\t})\n\t}\n\n\tchildren.push({\n\t\ttype: 'p',\n\t\tprops: {\n\t\t\tstyle: {\n\t\t\t\tfontSize: 24,\n\t\t\t\tfontWeight: 400,\n\t\t\t\tcolor: colors.accent,\n\t\t\t\tmarginTop: 48,\n\t\t\t\tmarginBottom: 0,\n\t\t\t\ttextAlign: 'center',\n\t\t\t\topacity: 0.7,\n\t\t\t},\n\t\t\tchildren: siteName,\n\t\t},\n\t})\n\n\treturn {\n\t\ttype: 'div',\n\t\tprops: {\n\t\t\tstyle: {\n\t\t\t\tdisplay: 'flex',\n\t\t\t\tflexDirection: 'column',\n\t\t\t\talignItems: 'center',\n\t\t\t\tjustifyContent: 'center',\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\tbackgroundColor: colors.background,\n\t\t\t},\n\t\t\tchildren,\n\t\t},\n\t}\n}\n","/**\n * Default OG template.\n * Clean, centered layout.\n */\n\nimport type { OgTemplateProps } from '../types.js'\n\nexport function defaultTemplate({\n\ttitle,\n\tdescription,\n\tsiteName,\n\tcolors,\n\twidth,\n\theight,\n}: OgTemplateProps) {\n\treturn {\n\t\ttype: 'div',\n\t\tprops: {\n\t\t\tstyle: {\n\t\t\t\tdisplay: 'flex',\n\t\t\t\tflexDirection: 'column',\n\t\t\t\talignItems: 'center',\n\t\t\t\tjustifyContent: 'center',\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\tbackgroundColor: colors.background,\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttype: 'h1',\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tfontSize: 72,\n\t\t\t\t\t\t\tfontWeight: 700,\n\t\t\t\t\t\t\tcolor: colors.text,\n\t\t\t\t\t\t\tletterSpacing: '-0.02em',\n\t\t\t\t\t\t\tmargin: 0,\n\t\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tchildren: title,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tdescription ? {\n\t\t\t\t\ttype: 'p',\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tfontSize: 32,\n\t\t\t\t\t\t\tfontWeight: 400,\n\t\t\t\t\t\t\tcolor: colors.accent,\n\t\t\t\t\t\t\tmarginTop: 24,\n\t\t\t\t\t\t\tmarginBottom: 0,\n\t\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\t\tmaxWidth: 900,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tchildren: description,\n\t\t\t\t\t},\n\t\t\t\t} : null,\n\t\t\t\t{\n\t\t\t\t\ttype: 'p',\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tstyle: {\n\t\t\t\t\t\t\tfontSize: 28,\n\t\t\t\t\t\t\tfontWeight: 400,\n\t\t\t\t\t\t\tcolor: colors.accent,\n\t\t\t\t\t\t\tmarginTop: 64,\n\t\t\t\t\t\t\tmarginBottom: 0,\n\t\t\t\t\t\t\ttextAlign: 'center',\n\t\t\t\t\t\t\topacity: 0.7,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tchildren: siteName,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t].filter(Boolean),\n\t\t},\n\t}\n}\n","/**\n * Built-in OG templates.\n */\n\nexport { blogTemplate } from './blog.js'\nexport { profileTemplate } from './profile.js'\nexport { defaultTemplate } from './default.js'\n\nimport { blogTemplate } from './blog.js'\nimport { profileTemplate } from './profile.js'\nimport { defaultTemplate } from './default.js'\nimport type { OgTemplate } from '../types.js'\n\nexport const templates = {\n\tblog: blogTemplate,\n\tprofile: profileTemplate,\n\tdefault: defaultTemplate,\n} as const\n\nexport type TemplateName = keyof typeof templates\n\nexport function getTemplate(name: TemplateName | OgTemplate): OgTemplate {\n\tif (typeof name === 'function') {\n\t\treturn name\n\t}\n\treturn templates[name]\n}\n"],"mappings":"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","names":[]}
Binary file
Binary file