grain.social is a photo sharing platform built on atproto. grain.social
atproto photography appview
57
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: use Syne brand font for "grain" wordmark in OG images

Load Syne ExtraBold TTF for the brand wordmark in gallery and story
OpenGraph images, matching the app logo font.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+25 -4
server/og/Syne-ExtraBold.ttf

This is a binary file and will not be displayed.

+17
server/og/fonts.ts
··· 1 + import { readFileSync } from "node:fs"; 2 + import { resolve } from "node:path"; 3 + 4 + let syneFontData: ArrayBuffer | null = null; 5 + 6 + export function syneBrandFont() { 7 + if (!syneFontData) { 8 + const path = resolve(import.meta.dirname, "Syne-ExtraBold.ttf"); 9 + syneFontData = readFileSync(path).buffer; 10 + } 11 + return { 12 + name: "Syne", 13 + data: syneFontData, 14 + weight: 800 as const, 15 + style: "normal" as const, 16 + }; 17 + }
+4 -2
server/og/gallery.ts
··· 1 1 import { defineOG } from "$hatk"; 2 2 import type { GrainActorProfile, Photo } from "$hatk"; 3 + import { syneBrandFont } from "./fonts.ts"; 3 4 4 5 export default defineOG("/og/profile/:did/gallery/:rkey", async (ctx) => { 5 6 const { db, params, fetchImage, lookup, blobUrl } = ctx; ··· 227 228 { 228 229 type: "div", 229 230 props: { 230 - children: "Grain", 231 - style: { fontSize: 32, color: "#171717" }, 231 + children: "grain", 232 + style: { fontSize: 32, fontFamily: "Syne", fontWeight: 800, color: "#171717", letterSpacing: "-0.02em" }, 232 233 }, 233 234 }, 234 235 ], ··· 240 241 ], 241 242 }, 242 243 }, 244 + options: { fonts: [syneBrandFont()] }, 243 245 meta: { 244 246 title: `${gallery.title} by @${author?.handle || did.slice(0, 24)} — Grain`, 245 247 description: gallery.description || `Photo gallery on Grain`,
+4 -2
server/og/story.ts
··· 1 1 import { defineOG } from "$hatk"; 2 2 import type { GrainActorProfile } from "$hatk"; 3 + import { syneBrandFont } from "./fonts.ts"; 3 4 4 5 export default defineOG("/og/profile/:did/story/:rkey", async (ctx) => { 5 6 const { db, params, fetchImage, lookup, blobUrl } = ctx; ··· 124 125 { 125 126 type: "div", 126 127 props: { 127 - children: "Grain", 128 - style: { fontSize: 16, color: "rgba(255,255,255,0.7)" }, 128 + children: "grain", 129 + style: { fontSize: 16, fontFamily: "Syne", fontWeight: 800, color: "rgba(255,255,255,0.7)", letterSpacing: "-0.02em" }, 129 130 }, 130 131 }, 131 132 ], ··· 137 138 ], 138 139 }, 139 140 }, 141 + options: { fonts: [syneBrandFont()] }, 140 142 meta: { 141 143 title: `Story by @${author?.handle || did.slice(0, 24)} — Grain`, 142 144 description: "Photo story on Grain",