# How to Generate Contour SVG Logos Using SHA‑256 and a Seeded RNG

> Learn to generate unique SVG contour logos with SHA-256 and a seeded RNG. This client-side algorithm creates deterministic, reproducible logos from any input string.

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

---

**The `woosal1337/blog` repository provides a client-side algorithm that hashes any input string with SHA‑256, derives a seeded pseudo‑random number generator from π digits, and renders the result as a unique, deterministic SVG contour logo.**

The `generateContour` function transforms arbitrary text—such as project names or UUIDs—into reproducible vector graphics without requiring server-side processing or external graphics libraries. By combining the Web Crypto API’s SHA‑256 implementation with a custom π‑stream randomness generator, the code ensures that identical seeds always produce identical visual outputs.

## The Core Algorithm in [`lib/contour.ts`](https://github.com/woosal1337/blog/blob/main/lib/contour.ts)

The entire generation pipeline lives in **[`lib/contour.ts`](https://github.com/woosal1337/blog/blob/main/lib/contour.ts)** and executes in five distinct phases, from entropy extraction to SVG markup emission.

### Step 1 – Hash the Input Seed with SHA‑256

Lines 21‑25 prefix the input string with `"pi-scribble-logo:"` and digest it using `crypto.subtle.digest('SHA-256', ...)`. The resulting 32‑byte array serves as the entropy source for all subsequent randomness.

### Step 2 – Derive the π‑Stream Randomness Generator

Lines 27‑44 implement a deterministic RNG by mixing the hash bytes with hard‑coded π digits. The **`Next`** function yields floating‑point values in the range `[0,1)` and accepts a `length` argument to provide arbitrary precision when needed.

### Step 3 – Select Geometric Parameters

Lines 47‑53 use helper functions **`pick`** and **`pickInt`** to translate raw random values into bounded parameters. These include stroke width, harmonic frequencies, amplitudes, phases, and radial offsets that define the contour’s irregular shape.

### Step 4 – Build Sinusoidal Contour Paths

Lines 86‑117 generate eight concentric loops. For each loop, a base radius is perturbed by a sum of sinusoidal harmonics calculated as a function of angle. The resulting `(x,y)` coordinate pairs are converted into an SVG path string via a **`polyline`** helper.

### Step 5 – Emit the SVG Markup

Lines 119‑122 wrap the generated paths in an `<svg>` element with a `256×256` viewBox and return the complete markup as a string, ready for embedding or download.

## Generating Logos Programmatically

Import **`generateContour`** to create logos in any TypeScript or JavaScript context. The function returns a Promise that resolves to an SVG string.

```typescript
import { generateContour } from '@/lib/contour';

async function makeLogo(name: string) {
  const svg = await generateContour(name, '#ff6600', {
    strokeWidth: 1.8,
    nonScalingStroke: true,
  });
  console.log(svg); // Embed directly in HTML or save to file
}

makeLogo('OpenAI');

```

## Interactive React Playground

The **`ContourPlayground`** component in **[`components/blocks/contour-playground.tsx`](https://github.com/woosal1337/blog/blob/main/components/blocks/contour-playground.tsx)** provides a live UI. It sanitizes and debounces user input, invokes `generateContour`, and renders the output using `URL.createObjectURL` for instant preview.

```tsx
import { ContourPlayground } from '@/components/blocks/contour-playground';

export default function Demo() {
  return (
    <section className="max-w-xl mx-auto">
      <h2 className="text-xl mb-4">Contour Logo Generator</h2>
      <ContourPlayground />
    </section>
  );
}

```

## Exporting to SVG or PNG

Download the generated vector client-side by constructing a Blob and triggering a download anchor.

```typescript
const svg = await generateContour('my-seed');
const blob = new Blob([svg], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'my-seed-contour.svg';
a.click();
URL.revokeObjectURL(url);

```

## Summary

- **Deterministic output:** The same seed always produces the identical SVG because the algorithm uses SHA‑256 hashing and a seeded π‑stream RNG.
- **Zero dependencies:** All calculations use the native Web Crypto API and standard TypeScript, requiring no external graphics libraries.
- **Configurable styling:** Optional parameters control stroke width (`strokeWidth`), color, and scaling behavior (`nonScalingStroke`).
- **Client-side only:** Generation happens entirely in the browser, making it suitable for offline applications and privacy-sensitive environments.

## Frequently Asked Questions

### What makes the contour generation deterministic?

The algorithm prefixes the input with `"pi-scribble-logo:"`, hashes it with SHA‑256 in [`lib/contour.ts`](https://github.com/woosal1337/blog/blob/main/lib/contour.ts) lines 21‑25, and uses those bytes to seed a custom RNG. Because the hash and the π digit sequence are constant for a given input, the resulting random numbers—and thus the geometry—remain identical across every execution.

### Why use SHA‑256 and π digits for randomness?

SHA‑256 provides cryptographic-grade entropy distribution from arbitrary strings, ensuring that even similar inputs produce wildly different hashes. The π digits serve as a publicly verifiable, infinite source of pseudo‑randomness that remains consistent across platforms, eliminating the need for external randomness or stateful generators.

### Can I customize the stroke width and colors?

Yes. The `generateContour` function accepts an optional configuration object where you can specify `strokeWidth` as a number and the stroke color as a hex string. Passing `nonScalingStroke: true` ensures the stroke width remains constant when the SVG is scaled in the viewport.

### Is the generation truly client-side without external services?

Yes. All processing occurs in the browser using `crypto.subtle.digest` and the custom `Next` RNG implemented in [`lib/contour.ts`](https://github.com/woosal1337/blog/blob/main/lib/contour.ts). No network requests are made after the initial page load, and the `ContourPlayground` component even supports rasterizing to PNG entirely within the client using canvas APIs.