HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
1import { MARK_DARK, MarkImg } from './mark';23/**4 * Shared chrome for Open Graph images (ImageResponse cannot read CSS variables → dark-theme token hex values inlined).5 * `Frame` = header lockup + content + footer; `Wallpaper` = the dark atlas plate with a faint coordinate grid and the mark6 * large at left — used by the root OG image and by the per-type OG images (D1–D3) through `Wallpaper` + `Counters`.7 */8export const INK = '#e9ebf0';9export const INK2 = '#a3a9b8';10export const INK3 = '#6f7688';11export const ACCENT = '#6d95ff';12export const ACCENT2 = '#f2b04a';13export const CANVAS = '#0b0d11';14export const SURFACE = '#12151b';15export const RULE = 'rgba(190,200,225,0.14)';1617export function Mark({ px = 56 }: { px?: number }) {18 return <MarkImg px={px} colors={{ ...MARK_DARK, plate: SURFACE }} />;19}2021/** Faint coordinate grid covering the whole image (absolute, behind content). */22export function Grid({ step = 60, opacity = 1 }: { step?: number; opacity?: number }) {23 return (24 <div25 style={{26 position: 'absolute',27 inset: 0,28 display: 'flex',29 opacity,30 backgroundImage: `linear-gradient(to right, ${RULE} 1px, transparent 1px), linear-gradient(to bottom, ${RULE} 1px, transparent 1px)`,31 backgroundSize: `${step}px ${step}px`,32 }}33 />34 );35}3637export function Lockup({ px = 56, fontSize = 32 }: { px?: number; fontSize?: number }) {38 return (39 <div style={{ display: 'flex', alignItems: 'center', gap: Math.round(px * 0.3) }}>40 <Mark px={px} />41 <div style={{ display: 'flex', fontSize, letterSpacing: -1, alignItems: 'baseline' }}>42 <span style={{ fontWeight: 700 }}>AI</span>43 <span style={{ color: INK2, marginLeft: Math.round(fontSize * 0.28), fontWeight: 500 }}>Atlas</span>44 </div>45 </div>46 );47}4849export function Frame({ children, footer }: { children: React.ReactNode; footer: string }) {50 return (51 <div style={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', padding: '56px 72px', background: CANVAS, color: INK, fontFamily: 'sans-serif', position: 'relative' }}>52 <Grid />53 <div style={{ position: 'absolute', right: -160, top: -200, width: 720, height: 720, borderRadius: 999, background: 'radial-gradient(circle at 40% 40%, rgba(109,149,255,0.16), rgba(11,13,17,0) 70%)', display: 'flex' }} />54 <div style={{ display: 'flex', position: 'relative' }}>55 <Lockup />56 </div>57 <div style={{ display: 'flex', flexDirection: 'column', position: 'relative' }}>{children}</div>58 <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', color: INK3, fontSize: 21, position: 'relative' }}>59 <span>{footer}</span>60 <span>who said it · when · where · how it was extracted</span>61 </div>62 </div>63 );64}6566export function Eyebrow({ children, color = ACCENT }: { children: string; color?: string }) {67 return <div style={{ display: 'flex', fontSize: 18, letterSpacing: 3, textTransform: 'uppercase', color, fontWeight: 600 }}>{children}</div>;68}6970export function Title({ children }: { children: string }) {71 const long = children.length > 26;72 return (73 <div style={{ display: 'flex', fontSize: long ? 58 : 74, fontWeight: 600, lineHeight: 1.04, letterSpacing: -2.2, maxWidth: 1040, overflow: 'hidden', maxHeight: long ? 128 : 160 }}>74 <span style={{ display: 'block', overflow: 'hidden', textOverflow: 'ellipsis' }}>{children}</span>75 </div>76 );77}7879export function Facts({ items }: { items: [string, string][] }) {80 if (!items.length) return null;81 return (82 <div style={{ display: 'flex', gap: 52, marginTop: 10 }}>83 {items.map(([label, value]) => (84 <div key={label} style={{ display: 'flex', flexDirection: 'column' }}>85 <span style={{ fontSize: 15, letterSpacing: 2.5, textTransform: 'uppercase', color: INK3, fontWeight: 600 }}>{label}</span>86 <span style={{ fontSize: 34, fontWeight: 600, color: INK, letterSpacing: -1, marginTop: 6 }}>{value}</span>87 </div>88 ))}89 </div>90 );91}9293/** Live counter strip (label above value, hairline separators). Empty array → renders nothing (graceful fallback). */94export function Counters({ items, size = 'md' }: { items: [string, string][]; size?: 'sm' | 'md' }) {95 if (!items.length) return null;96 const vs = size === 'sm' ? 30 : 38;97 return (98 <div style={{ display: 'flex', borderTop: `1px solid ${RULE}`, paddingTop: 18, gap: 0 }}>99 {items.map(([label, value], i) => (100 <div key={label} style={{ display: 'flex', flexDirection: 'column', paddingRight: 36, paddingLeft: i === 0 ? 0 : 36, borderLeft: i === 0 ? 'none' : `1px solid ${RULE}` }}>101 <span style={{ fontSize: 14, letterSpacing: 2.5, textTransform: 'uppercase', color: INK3, fontWeight: 600 }}>{label}</span>102 <span style={{ fontSize: vs, fontWeight: 600, color: INK, letterSpacing: -1, marginTop: 4, fontVariantNumeric: 'tabular-nums' }}>{value}</span>103 </div>104 ))}105 </div>106 );107}108109/**110 * The "wallpaper": dark plate, faint grid, the mark large at left, title + tagline at right and a counter strip at the bottom.111 * `eyebrow` defaults to the site tagline; `title` to "AI Atlas". Per-type OG images pass their own eyebrow/title/counters.112 */113export function Wallpaper({ eyebrow, title = 'AI Atlas', subtitle, counters = [], footer = 'www.ai-atlas.co', markPx = 300 }: { eyebrow?: string; title?: string; subtitle?: string; counters?: [string, string][]; footer?: string; markPx?: number }) {114 return (115 <div style={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', padding: '56px 72px 48px', background: CANVAS, color: INK, fontFamily: 'sans-serif', position: 'relative' }}>116 <Grid step={50} />117 <div style={{ position: 'absolute', left: -120, bottom: -260, width: 760, height: 760, borderRadius: 999, background: 'radial-gradient(circle at 50% 50%, rgba(109,149,255,0.14), rgba(11,13,17,0) 68%)', display: 'flex' }} />118 <div style={{ display: 'flex', alignItems: 'center', gap: 56, position: 'relative', flex: 1 }}>119 <div style={{ display: 'flex', flexShrink: 0 }}>120 <MarkImg px={markPx} colors={{ ...MARK_DARK, plate: SURFACE }} />121 </div>122 <div style={{ display: 'flex', flexDirection: 'column', gap: 14, minWidth: 0 }}>123 {eyebrow && <Eyebrow>{eyebrow}</Eyebrow>}124 <div style={{ display: 'flex', fontSize: title.length > 22 ? 56 : 84, fontWeight: 700, lineHeight: 1, letterSpacing: -3, maxHeight: 180, overflow: 'hidden' }}>125 {title === 'AI Atlas' ? (126 <>127 <span>AI</span>128 <span style={{ color: INK2, marginLeft: 22, fontWeight: 500 }}>Atlas</span>129 </>130 ) : (131 <span style={{ display: 'block', overflow: 'hidden', textOverflow: 'ellipsis' }}>{title}</span>132 )}133 </div>134 {subtitle && <div style={{ display: 'flex', fontSize: 27, color: INK2, lineHeight: 1.3, maxWidth: 720 }}>{subtitle}</div>}135 </div>136 </div>137 <div style={{ display: 'flex', flexDirection: 'column', gap: 16, position: 'relative' }}>138 <Counters items={counters} />139 <div style={{ display: 'flex', justifyContent: 'space-between', color: INK3, fontSize: 19 }}>140 <span>{footer}</span>141 <span>who said it · when · where · how it was extracted</span>142 </div>143 </div>144 </div>145 );146}147148export function Fallback({ label }: { label: string }) {149 return (150 <Frame footer="www.ai-atlas.co">151 <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>152 <Eyebrow>{label}</Eyebrow>153 <Title>Explore the AI ecosystem.</Title>154 <div style={{ fontSize: 24, color: INK2, display: 'flex' }}>Models · organizations · research · providers & pricing · benchmarks · hardware</div>155 </div>156 </Frame>157 );158}159