# How to Generate SVG Logos from Post Titles Deterministically: A Technical Deep Dive

> Learn to generate deterministic SVG logos from post titles using SHA-256 hashing, pi digits, and harmonic contours. A technical guide for developers.

- Repository: [Ege Chelebi/blog](https://github.com/woosal1337/blog)
- Tags: deep-dive
- Published: 2026-08-06

---

**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`](https://github.com/woosal1337/blog/blob/main/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.

```typescript
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`](https://github.com/woosal1337/blog/blob/main/lib/contour.ts) and await the SVG string:

```typescript
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:

```typescript
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:

```tsx
// 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:

```tsx
// 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`](https://github.com/woosal1337/blog/blob/main/lib/contour.ts) – Core deterministic SVG generator containing `generateContour`, `sha256Bytes`, and `makePiStream`.
- `app/blog-og/[slug]/route.tsx` – Next.js route handler that generates Open Graph images using the contour logos.
- [`components/ds/post-glyph.tsx`](https://github.com/woosal1337/blog/blob/main/components/ds/post-glyph.tsx) – Example component that renders the generated SVG as a post glyph.
- [`components/blocks/sticker-stamp.tsx`](https://github.com/woosal1337/blog/blob/main/components/blocks/sticker-stamp.tsx) – Consumer that uses contour logos for sticker graphics.
- [`components/blocks/stamps.tsx`](https://github.com/woosal1337/blog/blob/main/components/blocks/stamps.tsx) – Display component showcasing contour logos in preset SVG blocks.

## Summary

- **Deterministic output:** The `generateContour` function in [`lib/contour.ts`](https://github.com/woosal1337/blog/blob/main/lib/contour.ts) produces 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`](https://github.com/woosal1337/blog/blob/main/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.