How to Generate SVG Logos from Post Titles Deterministically: A Technical Deep Dive
You can generate deterministic SVG logos from post titles by hashing the title with SHA-256, mixing the result with pi digits to create a pseudo-random stream, and rendering harmonic contours using the generateContour utility in lib/contour.ts.
The woosal1337/blog repository implements a unique visual identity system where every blog post receives a deterministic SVG logo derived from its title. This approach uses the generateContour function to transform any string seed into a reproducible 256×256 SVG graphic, ensuring identical titles always produce identical visual marks without requiring external assets.
How Deterministic SVG Generation Works
The algorithm follows a pure-functional pipeline that converts text entropy into geometric paths. Because the process relies entirely on deterministic hashing and mathematical constants, the same input always yields the same output.
Seed Hashing with SHA-256
The process begins by creating a unique entropy source from the post title. The code prefixes the seed with pi-scribble-logo: and computes a SHA-256 hash using the sha256Bytes function.
const bytes = await sha256Bytes(`pi-scribble-logo:${seed}`);
Source: lib/contour.ts:27-31
These hash bytes serve as the foundation for all subsequent random selections, guaranteeing that changing a single character in the title produces a completely different visual output.
Pi-Digit Random Stream
Rather than using a standard random number generator, the implementation employs makePiStream to create a deterministic pseudo-random sequence. This function mixes the SHA-256 bytes with a long static string of π digits, returning a Next function that yields floats in the range [0, 1).
Source: lib/contour.ts:34-44
This technique ensures cross-platform reproducibility while providing high-quality entropy for the harmonic calculations.
Parameter Selection and Path Construction
Using the Next function, the algorithm selects parameters for eight concentric loops including stroke width, harmonic frequencies, amplitudes, phases, and offsets. The code samples 200 points around a circle for each loop, perturbing the radius with the generated harmonics to create organic contour lines.
The points are converted to polylines and emitted as SVG <path> elements.
Source: lib/contour.ts:81-95 (parameters), lib/contour.ts:99-117 (path construction)
SVG Assembly
All paths are wrapped in a <g> element inside an <svg> with a fixed 256×256 viewBox. The function accepts optional arguments to control stroke width and scaling behavior.
Source: lib/contour.ts:119-122
Implementation Examples
Basic Logo Generation
To generate a logo for any title, import the generateContour function from lib/contour.ts and await the SVG string:
import { generateContour } from '@/lib/contour';
async function makeLogo(title: string) {
// Produce a 256×256 SVG with the default background colour.
const svg = await generateContour(title, '#f5f5f5');
console.log(svg); // ← raw SVG markup
}
makeLogo('How to generate SVG logos from post titles deterministically');
The function returns a complete <svg> element as a string, ready for rendering or storage.
Customizing Stroke Properties
You can override the auto-generated stroke width and prevent stroke scaling using the options parameter:
const svg = await generateContour(
'My Blog Post',
'#ffcc00',
{ strokeWidth: 2.4, nonScalingStroke: true }
);
Setting nonScalingStroke: true adds vector-effect="non-scaling-stroke" to maintain consistent line thickness when the SVG resizes.
Integration in Open Graph Images
The repository uses this utility in its OG image pipeline at app/blog-og/[slug]/route.tsx. The generated SVG is base64-encoded and embedded as an image source:
// Inside a Next.js OG route
const logoSvg = await generateContour(post.title, '#f5f5f5');
const logoDataUri = `data:image/svg+xml;base64,${Buffer.from(logoSvg).toString('base64')}`;
// Later in the JSX:
<img src={logoDataUri} width={430} height={430} alt="" />
Source: app/blog-og/[slug]/route.tsx:24-26
Component Integration
You can reuse the utility in React components for dynamic rendering:
// components/ds/post-glyph.tsx
import { generateContour } from '@/lib/contour';
import { useEffect, useState } from 'react';
export function PostGlyph({ title }: { title: string }) {
const [svg, setSvg] = useState<string>('');
useEffect(() => {
generateContour(title).then(setSvg);
}, [title]);
return <div dangerouslySetInnerHTML={{ __html: svg }} />;
}
Key Files in the Repository
Understanding the file structure helps navigate the implementation:
lib/contour.ts– Core deterministic SVG generator containinggenerateContour,sha256Bytes, andmakePiStream.app/blog-og/[slug]/route.tsx– Next.js route handler that generates Open Graph images using the contour logos.components/ds/post-glyph.tsx– Example component that renders the generated SVG as a post glyph.components/blocks/sticker-stamp.tsx– Consumer that uses contour logos for sticker graphics.components/blocks/stamps.tsx– Display component showcasing contour logos in preset SVG blocks.
Summary
- Deterministic output: The
generateContourfunction inlib/contour.tsproduces identical SVGs for identical titles by using SHA-256 hashing and pi-based pseudo-randomness. - Pure functional design: No external randomness or mutable state ensures reproducibility across environments.
- Flexible integration: The utility supports custom stroke widths, non-scaling strokes, and seamless embedding in OG images via base64 encoding.
- Multi-layered contours: The algorithm generates eight concentric harmonic loops with 200 sampled points each, creating complex organic shapes from simple string inputs.
Frequently Asked Questions
Why use pi digits instead of a standard random number generator?
The makePiStream function uses pi digits as a deterministic entropy source that is identical across all platforms and runtime environments. Standard random number generators may produce different sequences depending on the JavaScript engine or seeding method, whereas pi provides a universally constant, infinite stream of digits that, when mixed with the SHA-256 hash, guarantees identical visual output everywhere.
Can I use this with titles containing non-ASCII characters?
Yes. The generateContour function processes the seed string through SHA-256 hashing, which handles Unicode characters correctly. Since the hash operates on bytes rather than specific character encodings, titles in any language or containing emojis will produce valid, deterministic SVG outputs.
How do I change the size of the generated SVG?
The viewBox is fixed at 256×256 pixels in lib/contour.ts. To resize the output, wrap the returned SVG in a container with CSS scaling or transform the coordinates mathematically before calling the function. The nonScalingStroke option helps maintain stroke clarity when scaling the SVG via CSS.
Is the generation process performant for server-side rendering?
Yes. The algorithm is computationally lightweight, involving only cryptographic hashing and mathematical operations on 200 points per loop. According to the implementation in app/blog-og/[slug]/route.tsx, the function executes synchronously after the initial async hash computation, making it suitable for real-time OG image generation in Next.js edge functions without noticeable latency.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →