Skip to content

Commit 81723f7

Browse files
feat: add dynamically generated og for landing
1 parent 60bb942 commit 81723f7

File tree

2 files changed

+311
-13
lines changed

2 files changed

+311
-13
lines changed

apps/sim/app/opengraph-image.tsx

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
import fs from 'fs/promises'
2+
import path from 'path'
3+
import { ImageResponse } from 'next/og'
4+
5+
export const alt = 'Sim — Build AI Agents & Run Your Agentic Workforce'
6+
export const size = { width: 1200, height: 630 }
7+
export const contentType = 'image/png'
8+
9+
const COLORS = ['#2ABBF8', '#FA4EDF', '#FFCC02', '#00F701'] as const
10+
11+
async function loadFonts() {
12+
const fontsDirPrimary = path.join(process.cwd(), 'app', '_styles', 'fonts', 'season')
13+
const fontsDirFallback = path.join(
14+
process.cwd(),
15+
'apps',
16+
'sim',
17+
'app',
18+
'_styles',
19+
'fonts',
20+
'season'
21+
)
22+
23+
let fontsDir = fontsDirPrimary
24+
try {
25+
await fs.access(fontsDirPrimary)
26+
} catch {
27+
fontsDir = fontsDirFallback
28+
}
29+
30+
const [fontMedium, fontBold] = await Promise.all([
31+
fs.readFile(path.join(fontsDir, 'SeasonSans-Medium.woff')),
32+
fs.readFile(path.join(fontsDir, 'SeasonSans-Bold.woff')),
33+
])
34+
35+
return { fontMedium, fontBold }
36+
}
37+
38+
export default async function OgImage() {
39+
let fontMedium: Buffer
40+
let fontBold: Buffer
41+
try {
42+
const fonts = await loadFonts()
43+
fontMedium = fonts.fontMedium
44+
fontBold = fonts.fontBold
45+
} catch {
46+
return new Response('Font assets not found', { status: 500 })
47+
}
48+
49+
return new ImageResponse(
50+
<div
51+
style={{
52+
height: '100%',
53+
width: '100%',
54+
display: 'flex',
55+
flexDirection: 'column',
56+
justifyContent: 'center',
57+
alignItems: 'center',
58+
padding: '64px 80px',
59+
background: '#1C1C1C',
60+
fontFamily: 'Season Sans',
61+
position: 'relative',
62+
overflow: 'hidden',
63+
}}
64+
>
65+
<div
66+
style={{
67+
position: 'absolute',
68+
top: 0,
69+
left: 0,
70+
right: 0,
71+
bottom: 0,
72+
backgroundImage:
73+
'radial-gradient(circle at 2px 2px, rgba(255, 255, 255, 0.03) 1px, transparent 0)',
74+
backgroundSize: '32px 32px',
75+
}}
76+
/>
77+
<div
78+
style={{
79+
position: 'absolute',
80+
top: 0,
81+
left: 0,
82+
right: 0,
83+
bottom: 0,
84+
border: '1px solid #2A2A2A',
85+
}}
86+
/>
87+
<div
88+
style={{
89+
display: 'flex',
90+
flexDirection: 'column',
91+
position: 'absolute',
92+
top: 0,
93+
left: 0,
94+
}}
95+
>
96+
<div style={{ display: 'flex' }}>
97+
{COLORS.map((color) => (
98+
<div key={color} style={{ width: 20, height: 20, backgroundColor: color }} />
99+
))}
100+
</div>
101+
<div style={{ display: 'flex', flexDirection: 'column' }}>
102+
{COLORS.slice(0, 3).map((color) => (
103+
<div key={`v-${color}`} style={{ width: 20, height: 20, backgroundColor: color }} />
104+
))}
105+
</div>
106+
</div>
107+
108+
{/* Bottom-right colored blocks */}
109+
<div
110+
style={{
111+
display: 'flex',
112+
flexDirection: 'column',
113+
position: 'absolute',
114+
bottom: 0,
115+
right: 0,
116+
alignItems: 'flex-end',
117+
}}
118+
>
119+
<div style={{ display: 'flex', flexDirection: 'column' }}>
120+
{COLORS.slice(0, 3)
121+
.reverse()
122+
.map((color) => (
123+
<div key={`vb-${color}`} style={{ width: 20, height: 20, backgroundColor: color }} />
124+
))}
125+
</div>
126+
<div style={{ display: 'flex' }}>
127+
{[...COLORS].reverse().map((color) => (
128+
<div key={`b-${color}`} style={{ width: 20, height: 20, backgroundColor: color }} />
129+
))}
130+
</div>
131+
</div>
132+
133+
{/* Top-right accent blocks */}
134+
<div
135+
style={{
136+
display: 'flex',
137+
position: 'absolute',
138+
top: 0,
139+
right: 80,
140+
gap: 0,
141+
}}
142+
>
143+
<div style={{ width: 20, height: 20, backgroundColor: '#2ABBF8', opacity: 0.6 }} />
144+
<div style={{ width: 20, height: 20, backgroundColor: '#FA4EDF' }} />
145+
<div style={{ width: 20, height: 20, backgroundColor: '#00F701', opacity: 0.6 }} />
146+
</div>
147+
148+
{/* Bottom-left accent blocks */}
149+
<div
150+
style={{
151+
display: 'flex',
152+
position: 'absolute',
153+
bottom: 0,
154+
left: 80,
155+
gap: 0,
156+
}}
157+
>
158+
<div style={{ width: 20, height: 20, backgroundColor: '#00F701', opacity: 0.6 }} />
159+
<div style={{ width: 20, height: 20, backgroundColor: '#FFCC02' }} />
160+
<div style={{ width: 20, height: 20, backgroundColor: '#2ABBF8', opacity: 0.6 }} />
161+
</div>
162+
163+
{/* Logo mark (green Sim icon) */}
164+
<div
165+
style={{
166+
display: 'flex',
167+
alignItems: 'center',
168+
justifyContent: 'center',
169+
marginBottom: 32,
170+
zIndex: 1,
171+
}}
172+
>
173+
<svg width='48' height='48' viewBox='0 0 294 294' fill='none'>
174+
<path
175+
fillRule='evenodd'
176+
clipRule='evenodd'
177+
d='M142.793 124.175C142.793 128.925 140.913 133.487 137.577 136.846L137.099 137.327C133.765 140.696 129.236 142.579 124.519 142.579H17.8063C7.97854 142.579 0 150.605 0 160.503V275.91C0 285.808 7.97854 293.834 17.8063 293.834H132.383C142.211 293.834 150.179 285.808 150.179 275.91V167.858C150.179 163.453 151.914 159.226 155.009 156.109C158.095 153.001 162.292 151.253 166.666 151.253H275.166C284.994 151.253 292.962 143.229 292.962 133.33V17.9231C292.962 8.02512 284.994 0 275.166 0H160.588C150.761 0 142.793 8.02512 142.793 17.9231V124.175ZM177.564 24.5671H258.181C263.925 24.5671 268.57 29.2545 268.57 35.0301V116.224C268.57 121.998 263.925 126.687 258.181 126.687H177.564C171.83 126.687 167.175 121.998 167.175 116.224V35.0301C167.175 29.2545 171.83 24.5671 177.564 24.5671Z'
178+
fill='#33C482'
179+
/>
180+
<path
181+
d='M275.293 171.578H190.106C179.779 171.578 171.406 180.01 171.406 190.412V275.162C171.406 285.564 179.779 293.996 190.106 293.996H275.293C285.621 293.996 293.994 285.564 293.994 275.162V190.412C293.994 180.01 285.621 171.578 275.293 171.578Z'
182+
fill='#33C482'
183+
/>
184+
<path
185+
d='M275.293 171.18H190.106C179.779 171.18 171.406 179.612 171.406 190.014V274.763C171.406 285.165 179.779 293.596 190.106 293.596H275.293C285.621 293.596 293.994 285.165 293.994 274.763V190.014C293.994 179.612 285.621 171.18 275.293 171.18Z'
186+
fill='#33C482'
187+
fillOpacity='0.2'
188+
/>
189+
</svg>
190+
</div>
191+
192+
{/* Main heading */}
193+
<div
194+
style={{
195+
display: 'flex',
196+
flexDirection: 'column',
197+
alignItems: 'center',
198+
gap: 16,
199+
zIndex: 1,
200+
}}
201+
>
202+
<div
203+
style={{
204+
fontSize: 64,
205+
fontWeight: 500,
206+
color: '#FFFFFF',
207+
lineHeight: 1,
208+
letterSpacing: '-0.02em',
209+
textAlign: 'center',
210+
}}
211+
>
212+
Build AI Agents
213+
</div>
214+
<div
215+
style={{
216+
fontSize: 22,
217+
fontWeight: 500,
218+
color: 'rgba(246, 246, 246, 0.6)',
219+
lineHeight: 1.3,
220+
letterSpacing: '0.02em',
221+
textAlign: 'center',
222+
}}
223+
>
224+
Sim is the AI Workspace for Agent Builders.
225+
</div>
226+
</div>
227+
<div
228+
style={{
229+
display: 'flex',
230+
alignItems: 'center',
231+
gap: 12,
232+
marginTop: 40,
233+
zIndex: 1,
234+
}}
235+
>
236+
{[
237+
{ label: '1,000+ Integrations', color: '#2ABBF8' },
238+
{ label: 'Open Source', color: '#00F701' },
239+
{ label: 'SOC 2 & HIPAA', color: '#FFCC02' },
240+
{ label: 'Enterprise Ready', color: '#FA4EDF' },
241+
].map((pill) => (
242+
<div
243+
key={pill.label}
244+
style={{
245+
display: 'flex',
246+
alignItems: 'center',
247+
gap: 6,
248+
padding: '6px 14px',
249+
border: '1px solid #2A2A2A',
250+
backgroundColor: '#232323',
251+
fontSize: 13,
252+
fontWeight: 500,
253+
color: '#999999',
254+
letterSpacing: '0.04em',
255+
textTransform: 'uppercase',
256+
}}
257+
>
258+
<div
259+
style={{
260+
width: 8,
261+
height: 8,
262+
backgroundColor: pill.color,
263+
flexShrink: 0,
264+
}}
265+
/>
266+
{pill.label}
267+
</div>
268+
))}
269+
</div>
270+
<div
271+
style={{
272+
display: 'flex',
273+
justifyContent: 'center',
274+
alignItems: 'center',
275+
gap: 24,
276+
position: 'absolute',
277+
bottom: 40,
278+
zIndex: 1,
279+
}}
280+
>
281+
<span
282+
style={{
283+
fontSize: 30,
284+
color: '#666666',
285+
fontWeight: 500,
286+
letterSpacing: '0.05em',
287+
}}
288+
>
289+
sim.ai
290+
</span>
291+
</div>
292+
</div>,
293+
{
294+
...size,
295+
fonts: [
296+
{
297+
name: 'Season Sans',
298+
data: fontMedium,
299+
style: 'normal' as const,
300+
weight: 500 as const,
301+
},
302+
{
303+
name: 'Season Sans',
304+
data: fontBold,
305+
style: 'normal' as const,
306+
weight: 700 as const,
307+
},
308+
],
309+
}
310+
)
311+
}

apps/sim/app/page.tsx

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,6 @@ export const metadata: Metadata = {
2929
url: baseUrl,
3030
siteName: 'Sim',
3131
locale: 'en_US',
32-
images: [
33-
{
34-
url: '/logo/426-240/primary/small.png',
35-
width: 2130,
36-
height: 1200,
37-
alt: 'Sim — Build AI Agents & Run Your Agentic Workforce',
38-
type: 'image/png',
39-
},
40-
],
4132
},
4233
twitter: {
4334
card: 'summary_large_image',
@@ -46,10 +37,6 @@ export const metadata: Metadata = {
4637
title: 'Sim — Build AI Agents & Run Your Agentic Workforce',
4738
description:
4839
'Sim is the open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to orchestrate agentic workflows.',
49-
images: {
50-
url: '/logo/426-240/primary/small.png',
51-
alt: 'Sim — Build AI Agents & Run Your Agentic Workforce',
52-
},
5340
},
5441
alternates: {
5542
canonical: baseUrl,

0 commit comments

Comments
 (0)