# Mermaid handDrawn Look Option: How to Enable Sketch-Style Diagrams with Deterministic Rendering

> Enable Mermaid handDrawn diagrams for a sketch-like style. Learn how handDrawnSeed ensures consistent randomized rendering for reproducible jitter patterns.

- Repository: [mermaid-js/mermaid](https://github.com/mermaid-js/mermaid)
- Tags: deep-dive
- Published: 2026-02-23

---

**The `handDrawn` look option in Mermaid enables sketch-style diagram rendering via Rough.js, while `handDrawnSeed` supplies a fixed random seed to Rough.js to ensure identical jitter patterns across renders.**

The **mermaid-js/mermaid** repository supports two visual rendering modes for diagrams: the default crisp vector style and an organic, hand-sketched aesthetic. When you enable the **handDrawn look option**, Mermaid utilizes the Rough.js library to perturb lines and fills with randomized jitter, creating an informal, pencil-drawn appearance. To prevent this randomization from causing visual diffs between renders or test runs, the **`handDrawnSeed`** configuration parameter locks the pseudo-random generator to a specific starting value.

## What Is the Mermaid handDrawn Look Option?

Mermaid diagrams render in one of two distinct visual styles controlled by the `look` configuration property defined in [`packages/mermaid/src/schemas/config.schema.yaml`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/schemas/config.schema.yaml) (lines 79-86).

- **classic**: Default SVG rendering with precise geometry and exact paths.
- **handDrawn**: Rough.js-generated shapes featuring randomized line perturbations, sketchy outlines, and hachure fills.

When `look: 'handDrawn'` is active, the rendering pipeline checks `node.look !== 'handDrawn'` within individual shape files (such as [`rectWithTitle.ts`](https://github.com/mermaid-js/mermaid/blob/main/rectWithTitle.ts) and [`waveRectangle.ts`](https://github.com/mermaid-js/mermaid/blob/main/waveRectangle.ts)) to determine whether to apply Rough.js styling. This ensures that only diagrams explicitly requesting the sketch style receive the randomized treatment, leaving classic diagrams unaffected.

## How handDrawnSeed Ensures Consistent Randomized Rendering

By default, Rough.js initializes with a random seed of `0`, which causes it to select a new random value on every render. This results in diagrams that look slightly different each time—problematic for visual regression testing, automated documentation generation, or any workflow requiring deterministic output.

The **`handDrawnSeed`** configuration property (numeric, default `0`) solves this by injecting a fixed seed value into all Rough.js calls throughout the rendering pipeline:

- In [`packages/mermaid/src/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.ts), the `solidStateFill` function (lines 6-15) returns fill styles containing `seed: handDrawnSeed`.
- The `userNodeOverrides` helper (lines 95-108) merges the seed into node style maps.
- Edge rendering modules, such as [`packages/mermaid/src/rendering-util/rendering-elements/edges.js`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/rendering-util/rendering-elements/edges.js) (line 517), retrieve the seed via `getConfig()` and pass it to Rough.js options.

When you provide a specific non-zero integer (e.g., `handDrawnSeed: 12345`), Rough.js receives identical seed values for every element, reproducing the exact same random perturbations on every render while preserving the sketchy visual style.

## Configuration and Usage Examples

### Enabling handDrawn in HTML/JS

Initialize Mermaid with the `look` and `handDrawnSeed` options to enable deterministic sketch-style rendering in browser environments:

```html
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
  mermaid.initialize({
    startOnLoad: true,
    theme: 'default',
    look: 'handDrawn',
    handDrawnSeed: 12345
  });
</script>

<div class="mermaid">
graph TD
    A[Start] --> B{Decision}
    B -->|Yes| C[Result]
    B -->|No| D[Alternative]
</div>

```

Setting `handDrawnSeed` to a fixed integer ensures the diagram renders with identical jitter patterns on every page load.

### Node.js API Implementation

For server-side rendering or build pipelines, configure the seed during initialization to guarantee consistent SVG output across builds:

```javascript
import mermaid from 'mermaid';

mermaid.initialize({
  look: 'handDrawn',
  handDrawnSeed: 42,
});

const definition = `
graph LR
  X --> Y
  Y --> Z
`;

mermaid.render('graphDiv', definition, (svgCode) => {
  console.log(svgCode);
});

```

The generated `svgCode` will contain the same Rough.js seed values on each execution, making the output suitable for snapshot testing.

### Per-Node Style Overrides

Apply the hand-drawn style to specific nodes only using class definitions within the diagram syntax:

```mermaid
graph TD
    A[Classic Style] --> B[Hand Drawn]:::hand
    classDef hand look handDrawn, handDrawnSeed=99;

```

This configuration applies `look: 'handDrawn'` and a deterministic seed (`99`) exclusively to nodes tagged with the `hand` class.

## Source Code Implementation Details

The handDrawn rendering path spans several key files in the mermaid-js/mermaid repository:

| File | Role |
|------|------|
| [`packages/mermaid/src/schemas/config.schema.yaml`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/schemas/config.schema.yaml) | Defines the `look` enum (`classic`, `handDrawn`) and `handDrawnSeed` numeric property. |
| [`packages/mermaid/src/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.ts`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/rendering-util/rendering-elements/shapes/handDrawnShapeStyles.ts) | Central utilities (`solidStateFill`, `userNodeOverrides`) that inject Rough.js options including the seed into node and fill styles. |
| [`packages/mermaid/src/rendering-util/rendering-elements/edges.js`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/rendering-util/rendering-elements/edges.js) | Applies seed-driven Rough.js styling to edge paths when `look: 'handDrawn'` is active. |
| [`packages/mermaid/src/diagram-api/diagramAPI.js`](https://github.com/mermaid-js/mermaid/blob/main/packages/mermaid/src/diagram-api/diagramAPI.js) | Provides `getConfig()` used throughout the rendering pipeline to retrieve the current `handDrawnSeed` value. |

All shape-rendering modules guard Rough.js invocations with conditional checks against `node.look`, ensuring the classic rendering path remains unaffected when the handDrawn look option is disabled.

## Summary

- The **handDrawn look option** activates Rough.js integration to render diagrams with sketch-like, randomized aesthetics instead of crisp vector geometry.
- **`handDrawnSeed`** accepts an integer that seeds Rough.js's random number generator, making the jitter patterns deterministic and reproducible across renders.
- When `handDrawnSeed` is `0` (default), Rough.js selects random values on each render, causing visual variation; any non-zero value locks the randomization.
- The seed propagates through [`handDrawnShapeStyles.ts`](https://github.com/mermaid-js/mermaid/blob/main/handDrawnShapeStyles.ts) and [`edges.js`](https://github.com/mermaid-js/mermaid/blob/main/edges.js) via the global configuration retrieved by `getConfig()`.

## Frequently Asked Questions

### What is the default value of handDrawnSeed?

The default value is `0`. When set to `0`, Rough.js generates a new random seed internally for every render, causing the hand-drawn diagram to appear slightly different each time it is generated.

### Can I use handDrawn with any Mermaid diagram type?

The handDrawn look option is supported across most Mermaid diagram types that utilize the standard rendering pipeline, including flowcharts, sequence diagrams, and class diagrams. However, the implementation requires the specific shape files to check `node.look !== 'handDrawn'` and apply Rough.js styles accordingly, so compatibility depends on whether the individual diagram implementation includes these guards.

### Why does my handDrawn diagram look different on every page load?

This occurs because `handDrawnSeed` defaults to `0`, which instructs Rough.js to randomize its seed on each initialization. To freeze the appearance, set `handDrawnSeed` to any specific non-zero integer in your Mermaid configuration; this ensures Rough.js receives the same seed for every element on every render.

### Does handDrawnSeed affect performance?

No, the `handDrawnSeed` value itself has negligible performance impact. However, the handDrawn look option overall can be slightly slower than classic rendering because Rough.js generates more complex SVG paths with randomized perturbations and hachure fills, increasing the DOM node count and rendering complexity compared to simple geometric shapes.