A modern TypeScript library for creating hand-drawn style charts inspired by comics and sketches. Built with D3.js and designed with type safety and excellent developer experience in mind.
Here’s some example of a graph generated with this library:
- 🖌️ Real watercolor washes - Per-shape layered pigment with edge darkening, interior pooling, and feathered edges (
fillStyle: 'watercolor') - 🖍️ Pastel/chalk fills - Soft chalky texture over paper tooth (
fillStyle: 'pastel') - 📜 Paper ground - Cream sheet with grain and a soft vignette behind every chart
- ✍️ Hand-guided strokes - Smooth-noise wobble, gentle bowing, and multi-pass pencil sketching instead of digital jitter
- 🎨 Curated pigment palette - Watercolor-set default colors (ultramarine, burnt sienna, sap green, …)
- 🌱 Deterministic rendering - Seeded randomness: the same chart drawn twice is the same drawing (
seedoption) - ⚡ Fast, DOM-free geometry - All hand-drawn paths are computed numerically; no layout thrashing while rendering
- 📊 Multiple chart types - Line graphs, bar charts, and pie charts
- 🔧 TypeScript support - Full type definitions and IntelliSense
- 🎯 Multi-series support - Handle complex datasets with ease
- 🎭 Interactive tooltips - Hover effects with detailed information
- 🎪 Directional scribble fills - Artistic fill patterns for charts
- 🎨 Oil paint textures - Rich painterly tile fills
- ⚙️ Highly configurable - Extensive customization options
- 🧩 Modern architecture - Clean OOP design with proper separation of concerns
npm install handwritten-graphOr via CDN:
<script src="https://unpkg.com/handwritten-graph@latest/dist/handwritten-graph.js"></script>import { LineChart, BarChart, PieChart } from 'handwritten-graph';
// Sample data that can be reused across chart types
const chartData = {
labels: ["Q1", "Q2", "Q3", "Q4"],
datasets: [
{
label: "Revenue",
data: [65, 59, 80, 81],
lineColor: "rgb(75, 192, 192)", // For LineChart
barColor: "#36A2EB" // For BarChart
}
]
};
// Line Chart with Area Fill
const lineChart = new LineChart("#line-chart-container", chartData, {
showArea: true,
useScribbleFill: true
});
// Bar Chart (Vertical)
const barChart = new BarChart("#bar-chart-container", chartData, {
orientation: 'vertical',
showValues: true
});
// Horizontal Bar Chart
const horizontalBarChart = new BarChart("#horizontal-bar-container", chartData, {
orientation: 'horizontal'
});
// Pie Chart
const pieData = [
{ label: "Marketing", value: 30, color: "#FF6384" },
{ label: "Development", value: 45, color: "#36A2EB" },
{ label: "Research", value: 15, color: "#FFCE56" },
{ label: "Administration", value: 10, color: "#4BC0C0" }
];
const pieChart = new PieChart("#pie-chart-container", pieData, {
useScribbleFill: true,
fillStyle: 'directional'
});// Using factory functions for backward compatibility
const lineCleanup = HandwrittenGraph.createGraph("#graph-container", chartData);
const barCleanup = HandwrittenGraph.createBarChart("#bar-container", chartData);
const pieCleanup = HandwrittenGraph.createPieChart("#pie-container", pieData);
// Clean up when done
lineCleanup();
barCleanup();
pieCleanup();// Line Chart
new LineChart(selector: string, data: LineChartData, config?: Partial)
// Bar Chart
new BarChart(selector: string, data: BarChartData, config?: Partial)
// Pie Chart
new PieChart(selector: string, data: PieChartData, config?: Partial)interface BaseChartConfig {
width?: number;
height?: number;
handDrawnEffect?: boolean;
useScribbleFill?: boolean; // Enable artistic fills (always on for pie charts)
fillStyle?: 'watercolor' | 'pastel' | 'directional' | 'oilpaint';
// Painting controls
seed?: number; // Deterministic wobble; same seed = identical drawing
roughness?: number; // 0 = ruler-straight … ~2 = very loose (default 1)
sketchPasses?: number; // Pencil passes per stroke, 1-3 (default 2)
paper?: boolean; // Paper sheet behind the chart (default true)
paperColor?: string; // Sheet tint (default warm cream)
inkColor?: string; // Axis/outline/text ink (default warm near-black)
}
// LineChart specific
interface LineChartConfig extends BaseChartConfig {
showArea?: boolean; // Enable area fill under lines
pointRadius?: number;
lineColor?: string;
}
// BarChart specific
interface BarChartConfig extends BaseChartConfig {
orientation?: 'vertical' | 'horizontal'; // Chart orientation
showValues?: boolean; // Show value labels on bars
barSpacing?: number;
groupSpacing?: number;
}
// PieChart specific
interface PieChartConfig extends BaseChartConfig {
innerRadius?: number; // For donut charts
legendBorder?: boolean;
}- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Modern mobile browsers
# Install dependencies
npm install
# Development build with watch
npm run dev
# Production build
npm run build
# Testing
npm run testThe library follows modern TypeScript patterns:
- Object-Oriented Design: Charts are classes with proper encapsulation
- Type Safety: Full TypeScript definitions with strict typing
- Composition: Modular utilities and components
- Inheritance: Base chart class with shared functionality
- Factory Pattern: Backward-compatible factory functions
- Strategy Pattern: Pluggable fill styles and effects
MIT License - see LICENSE file for details.
The default look is now a true painted wash, not a texture tile. Every shape (pie slice, bar, area) gets its own pigment: a wet base polygon, several translucent deposits that multiply where they overlap, interior pooling, and a darker rim where the wash "dries". One shared SVG filter feathers all edges.
// Watercolor is the default fill style — a pie chart needs no config at all
new PieChart('#pie', pieData);
// Watercolor area chart
new LineChart('#line', lineData, {
showArea: true,
useScribbleFill: true,
fillStyle: 'watercolor'
});
// Chalky pastel bars on custom paper
new BarChart('#bars', barData, {
useScribbleFill: true,
fillStyle: 'pastel',
paperColor: '#f6f1e5',
seed: 7 // pick a different hand
});
// Prefer the old transparent background?
new PieChart('#pie', pieData, { paper: false });Colors omitted from your datasets are assigned from WATERCOLOR_PALETTE
(exported, along with PASTEL_PALETTE, INK_COLOR and PAPER_COLOR).
fillStyledefaults to'watercolor'(was'directional'); the legacy'directional'and'oilpaint'tile styles are still available.- Charts render on a paper background by default — set
paper: falsefor the previous transparent look. - Default colors moved from
d3.schemeCategory10to the watercolor palette; explicitlineColor/barColor/colorvalues are respected as before. - Rendering is deterministic: re-creating a chart with the same data no longer
reshuffles the wobble. Pass a different
seedto vary it.
- NEW: Per-shape watercolor washes (
fillStyle: 'watercolor', now the default) with layered translucent deposits, edge darkening, and interior pooling - NEW: Pastel/chalk fill style (
fillStyle: 'pastel') - NEW: Paper background with grain and vignette (
paper,paperColor) - NEW: Seeded deterministic rendering (
seed), stroke roughness control (roughness), and multi-pass sketching (sketchPasses) - NEW: Curated watercolor pigment palette used for default series colors; palettes exported
- ENHANCED: Hand-drawn strokes use smooth value noise + bowing (reads as a hand, not a tremor); axes, dots, and legend chips are drawn, not filtered
- PERFORMANCE: All stroke/slice geometry is computed numerically — no more temporary SVG nodes appended to
<body>forgetPointAtLengthmeasurement - PERFORMANCE: Color adjustments are pure math (previously one DOM element +
getComputedStyleper tweak) - PERFORMANCE: One shared grain/edge filter set per chart instead of a filter pipeline per pattern; displacement filters applied per group, not per element
- PERFORMANCE: Tooltip pointer tracking caches the chart's bounding rect per hover instead of measuring layout on every mousemove
- ENHANCED: Blob shapes improved to have better borders, and soft boundaries
- ENHANCED: Improve pastel/pencil color conversion for hand-drawn aesthetics
- OPTIMIZED: Improve rendering performance with reduced filter complexity
- OPTIMIZED: Pattern caching system reduce memory footprint
- FIXED: Improved scribble lines to cover fill areas properly
- NEW: BarChart support with vertical and horizontal orientations
- NEW: Area fill support for LineCharts with
showAreaoption - NEW: Multi-series support for BarCharts
- NEW: Value labels on bar charts with
showValuesoption - ENHANCED: Improved scribble fill patterns for all chart types
- ENHANCED: Better responsive design and styling
- ENHANCED: Seamless pie chart borders matching slice colors
- Update test suite
- Add test coverage
- Type check scripts
- Type definition publish support
- Comprehensive test suite
- Test Setup with D3 mocks
- Example html to preview built lib
- Text elements with proper SVG property handling
- Axes and grid styling
- Line chart elements
- Pie chart elements
- Legend and Tooltip styling
- Hand-drawn effects
- Responsive design
- Print styles
- Enhanced type definitions
- Improved performance
- Better error handling
- Complete TypeScript rewrite from handwritten-graph
- Modern class-based architecture


