Use when creating SVG shapes, paths, or generators for charts. Invoke for line/area/arc generators, curves, symbols, pie/donut charts, stacks, ribbons, or path manipulation operations.
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
npx agent-skills-cli listSkill Instructions
name: d3-shapes-paths description: Use when creating SVG shapes, paths, or generators for charts. Invoke for line/area/arc generators, curves, symbols, pie/donut charts, stacks, ribbons, or path manipulation operations. allowed-tools: Read, Grep, Glob
D3 Shapes & Paths Expert
Purpose
Expert knowledge of D3's shape generators and path manipulation. Covers line, area, arc, pie, symbol, stack, ribbon generators, curve interpolation, and SVG path construction.
When to Use
Invoke this skill when:
- Creating line or area charts
- Building pie or donut charts
- Generating arc segments (gauges, progress indicators)
- Creating stacked charts (bar, area)
- Working with curve interpolation
- Drawing symbols (circles, squares, diamonds)
- Building chord diagrams
- Generating contour plots
- Manipulating SVG paths
- Debugging shape rendering issues
Documentation Available
Location: /Users/zach/Documents/cc-skills/docs/d3/
Coverage (203 files):
-
Shapes (146 files):
- Lines: line generator, curve interpolation
- Areas: area generator, radial areas
- Arcs: arc generator, pie layout
- Symbols: symbol types and custom symbols
- Stacks: stack layout, stack order
- Links: link generators (orthogonal, radial)
- Curves: 15+ interpolation types
-
Paths (12 files):
- Path construction and serialization
- Path data parsing
- Geometric operations
-
Contours (17 files):
- Contour generation
- Density estimation
- Marching squares algorithm
-
Chords (22 files):
- Chord layout
- Ribbon generator
- Chord diagrams
-
Polygons (6 files):
- Polygon operations
- Hull, centroid, area calculations
Related Skills
- d3-core-data: For scales used with shapes
- d3-geo: For geographic path generators
- d3-interaction-animation: For animating shapes
- d3-layouts-hierarchies: For tree/network shapes
Best Practices
- Define accessors consistently - Use x/y accessors for data binding
- Use curve interpolators - Choose appropriate curve type for data
- Handle null data - Set .defined() to skip gaps in lines
- Use radial variants - For circular/polar charts
- Optimize path rendering - Simplify paths for large datasets
- Set arc padding - Add spacing in pie charts
- Use stack keys - Define series for stacked charts
- Apply proper transforms - Translate arcs to center
Examples
Example 1: Line Chart with Multiple Series
Question: "How do I create a multi-series line chart?"
Response:
import * as d3 from 'd3';
// Sample data
const data = [
{ date: new Date('2024-01-01'), series1: 30, series2: 20 },
{ date: new Date('2024-01-02'), series1: 45, series2: 35 },
{ date: new Date('2024-01-03'), series1: 40, series2: 30 },
{ date: new Date('2024-01-04'), series1: null, series2: 40 }, // Gap in series1
{ date: new Date('2024-01-05'), series1: 60, series2: 50 },
];
// Create scales
const xScale = d3.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, 800]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => Math.max(d.series1 || 0, d.series2))])
.range([400, 0])
.nice();
// Create line generator
const line = d3.line()
.x(d => xScale(d.date))
.y(d => yScale(d.value))
.curve(d3.curveMonotoneX) // Smooth curve
.defined(d => d.value != null); // Skip null values
// Transform data for each series
const series1Data = data.map(d => ({ date: d.date, value: d.series1 }));
const series2Data = data.map(d => ({ date: d.date, value: d.series2 }));
// Generate path data
const path1 = line(series1Data);
const path2 = line(series2Data);
// Create SVG
const svg = d3.create('svg')
.attr('width', 800)
.attr('height', 400);
// Add lines
svg.append('path')
.attr('d', path1)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 2);
svg.append('path')
.attr('d', path2)
.attr('fill', 'none')
.attr('stroke', 'orange')
.attr('stroke-width', 2);
// Add axes
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);
svg.append('g')
.attr('transform', 'translate(0, 400)')
.call(xAxis);
svg.append('g')
.call(yAxis);
Curve Types:
curveLinear- Straight lines (default)curveMonotoneX- Smooth, no overshootcurveCatmullRom- Smooth, passes through pointscurveBasis- Smooth B-splinecurveStep- Step function
References:
- See:
docs/d3/shape/line.md - See:
docs/d3/shape/curve.md
Example 2: Area Chart with Gradient
Question: "How do I create an area chart with gradient fill?"
Response:
import * as d3 from 'd3';
const data = [
{ x: 0, y0: 0, y1: 30 },
{ x: 1, y0: 0, y1: 45 },
{ x: 2, y0: 0, y1: 40 },
{ x: 3, y0: 0, y1: 60 },
{ x: 4, y0: 0, y1: 50 },
];
// Create scales
const xScale = d3.scaleLinear()
.domain([0, 4])
.range([0, 800]);
const yScale = d3.scaleLinear()
.domain([0, 60])
.range([400, 0]);
// Create area generator
const area = d3.area()
.x(d => xScale(d.x))
.y0(d => yScale(d.y0)) // Baseline
.y1(d => yScale(d.y1)) // Top line
.curve(d3.curveMonotoneX);
// Create SVG
const svg = d3.create('svg')
.attr('width', 800)
.attr('height', 400);
// Define gradient
const gradient = svg.append('defs')
.append('linearGradient')
.attr('id', 'area-gradient')
.attr('x1', '0%')
.attr('y1', '0%')
.attr('x2', '0%')
.attr('y2', '100%');
gradient.append('stop')
.attr('offset', '0%')
.attr('stop-color', 'steelblue')
.attr('stop-opacity', 0.8);
gradient.append('stop')
.attr('offset', '100%')
.attr('stop-color', 'steelblue')
.attr('stop-opacity', 0.1);
// Add area
svg.append('path')
.datum(data)
.attr('d', area)
.attr('fill', 'url(#area-gradient)');
// Add top line
const line = d3.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y1))
.curve(d3.curveMonotoneX);
svg.append('path')
.datum(data)
.attr('d', line)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 2);
Radial Area (for circular charts):
const radialArea = d3.areaRadial()
.angle(d => angleScale(d.angle))
.innerRadius(d => radiusScale(d.inner))
.outerRadius(d => radiusScale(d.outer));
References:
- See:
docs/d3/shape/area.md - See:
docs/d3/shape/radial.md
Example 3: Pie and Donut Charts
Question: "How do I create a pie chart with labels?"
Response:
import * as d3 from 'd3';
const data = [
{ category: 'A', value: 30 },
{ category: 'B', value: 80 },
{ category: 'C', value: 45 },
{ category: 'D', value: 60 },
];
// Create pie layout
const pie = d3.pie()
.value(d => d.value)
.sort(null) // Keep original order
.padAngle(0.02); // Spacing between slices
// Create arc generator
const arc = d3.arc()
.innerRadius(0) // Use innerRadius > 0 for donut
.outerRadius(150);
// Arc for labels (slightly outside)
const labelArc = d3.arc()
.innerRadius(170)
.outerRadius(170);
// Color scale
const color = d3.scaleOrdinal()
.domain(data.map(d => d.category))
.range(d3.schemeCategory10);
// Create SVG
const svg = d3.create('svg')
.attr('width', 400)
.attr('height', 400);
const g = svg.append('g')
.attr('transform', 'translate(200, 200)'); // Center
// Generate pie data
const pieData = pie(data);
// Add arcs
g.selectAll('path')
.data(pieData)
.join('path')
.attr('d', arc)
.attr('fill', d => color(d.data.category))
.attr('stroke', 'white')
.attr('stroke-width', 2);
// Add labels
g.selectAll('text')
.data(pieData)
.join('text')
.attr('transform', d => `translate(${labelArc.centroid(d)})`)
.attr('text-anchor', 'middle')
.text(d => d.data.category);
// Add percentage labels
g.selectAll('.percentage')
.data(pieData)
.join('text')
.attr('class', 'percentage')
.attr('transform', d => `translate(${arc.centroid(d)})`)
.attr('text-anchor', 'middle')
.attr('fill', 'white')
.attr('font-weight', 'bold')
.text(d => {
const percent = ((d.endAngle - d.startAngle) / (2 * Math.PI) * 100).toFixed(1);
return `${percent}%`;
});
Donut Chart (add inner radius):
const arc = d3.arc()
.innerRadius(80) // Creates donut hole
.outerRadius(150);
Corner Radius (rounded corners):
const arc = d3.arc()
.innerRadius(80)
.outerRadius(150)
.cornerRadius(5);
References:
- See:
docs/d3/shape/pie.md - See:
docs/d3/shape/arc.md
Example 4: Stacked Area Chart
Question: "How do I create a stacked area chart?"
Response:
import * as d3 from 'd3';
const data = [
{ date: new Date('2024-01-01'), apples: 30, bananas: 20, oranges: 10 },
{ date: new Date('2024-01-02'), apples: 45, bananas: 35, oranges: 15 },
{ date: new Date('2024-01-03'), apples: 40, bananas: 30, oranges: 20 },
{ date: new Date('2024-01-04'), apples: 60, bananas: 40, oranges: 25 },
];
// Define stack keys (series)
const keys = ['apples', 'bananas', 'oranges'];
// Create stack layout
const stack = d3.stack()
.keys(keys)
.order(d3.stackOrderNone) // Keep original order
.offset(d3.stackOffsetNone); // Start from zero
// Generate stack data
const stackedData = stack(data);
// [
// [[0, 30], [0, 45], ...], // apples layer
// [[30, 50], [45, 80], ...], // bananas layer
// [[50, 60], [80, 95], ...], // oranges layer
// ]
// Create scales
const xScale = d3.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, 800]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(stackedData[stackedData.length - 1], d => d[1])])
.range([400, 0])
.nice();
// Create area generator
const area = d3.area()
.x(d => xScale(d.data.date))
.y0(d => yScale(d[0])) // Bottom of stack
.y1(d => yScale(d[1])) // Top of stack
.curve(d3.curveMonotoneX);
// Color scale
const color = d3.scaleOrdinal()
.domain(keys)
.range(d3.schemeCategory10);
// Create SVG
const svg = d3.create('svg')
.attr('width', 800)
.attr('height', 400);
// Add layers
svg.selectAll('path')
.data(stackedData)
.join('path')
.attr('d', area)
.attr('fill', d => color(d.key))
.attr('stroke', 'white')
.attr('stroke-width', 1);
// Add legend
const legend = svg.append('g')
.attr('transform', 'translate(700, 20)');
legend.selectAll('rect')
.data(keys)
.join('rect')
.attr('y', (d, i) => i * 25)
.attr('width', 20)
.attr('height', 20)
.attr('fill', d => color(d));
legend.selectAll('text')
.data(keys)
.join('text')
.attr('x', 25)
.attr('y', (d, i) => i * 25 + 15)
.text(d => d);
Stack Orders:
stackOrderNone- Original orderstackOrderAscending- Smallest on topstackOrderDescending- Largest on topstackOrderInsideOut- Largest in middle
Stack Offsets:
stackOffsetNone- Zero baselinestackOffsetExpand- Normalize to [0, 1]stackOffsetSilhouette- Center around zerostackOffsetWiggle- Minimize changes in slope
References:
- See:
docs/d3/shape/stack.md
Example 5: Symbols and Custom Shapes
Question: "How do I use D3 symbols for scatter plots?"
Response:
import * as d3 from 'd3';
const data = [
{ x: 30, y: 20, type: 'A' },
{ x: 50, y: 80, type: 'B' },
{ x: 80, y: 50, type: 'A' },
{ x: 120, y: 90, type: 'C' },
];
// Create scales
const xScale = d3.scaleLinear()
.domain([0, 150])
.range([0, 800]);
const yScale = d3.scaleLinear()
.domain([0, 100])
.range([400, 0]);
// Symbol types
const symbolTypes = [
d3.symbolCircle,
d3.symbolSquare,
d3.symbolTriangle,
d3.symbolStar,
d3.symbolDiamond,
d3.symbolCross,
];
// Symbol scale
const symbolScale = d3.scaleOrdinal()
.domain(['A', 'B', 'C'])
.range([d3.symbolCircle, d3.symbolSquare, d3.symbolTriangle]);
// Create symbol generator
const symbol = d3.symbol()
.size(200); // Area in square pixels
// Create SVG
const svg = d3.create('svg')
.attr('width', 800)
.attr('height', 400);
// Add symbols
svg.selectAll('path')
.data(data)
.join('path')
.attr('d', d => {
symbol.type(symbolScale(d.type));
return symbol();
})
.attr('transform', d => `translate(${xScale(d.x)}, ${yScale(d.y)})`)
.attr('fill', 'steelblue')
.attr('stroke', 'white')
.attr('stroke-width', 2);
Available Symbol Types:
symbolCircle- CirclesymbolSquare- SquaresymbolTriangle- Upward trianglesymbolStar- Five-pointed starsymbolDiamond- DiamondsymbolCross- Plus signsymbolWye- Y shape
Custom Symbol:
const customSymbol = {
draw(context, size) {
const r = Math.sqrt(size / 5) / 2;
context.moveTo(-3 * r, -r);
context.lineTo(-r, -r);
context.lineTo(-r, -3 * r);
context.lineTo(r, -3 * r);
context.lineTo(r, -r);
context.lineTo(3 * r, -r);
context.lineTo(3 * r, r);
context.lineTo(r, r);
context.lineTo(r, 3 * r);
context.lineTo(-r, 3 * r);
context.lineTo(-r, r);
context.lineTo(-3 * r, r);
context.closePath();
},
};
const symbol = d3.symbol()
.type(customSymbol)
.size(200);
References:
- See:
docs/d3/shape/symbol.md
Common Patterns
Responsive Line Chart
const line = d3.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y))
.curve(d3.curveMonotoneX);
svg.append('path')
.datum(data)
.attr('d', line)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 2);
Arc with Hover Effect
const arc = d3.arc()
.innerRadius(80)
.outerRadius(150);
const arcHover = d3.arc()
.innerRadius(80)
.outerRadius(160); // Larger
svg.selectAll('path')
.on('mouseenter', function() {
d3.select(this).transition()
.attr('d', arcHover);
})
.on('mouseleave', function() {
d3.select(this).transition()
.attr('d', arc);
});
Link Generators (for node diagrams)
const link = d3.linkHorizontal()
.x(d => d.x)
.y(d => d.y);
const linkData = {
source: { x: 0, y: 100 },
target: { x: 200, y: 150 },
};
svg.append('path')
.attr('d', link(linkData))
.attr('fill', 'none')
.attr('stroke', 'black');
Search Helpers
# Find line/area docs
grep -r "line\|area\|curve" /Users/zach/Documents/cc-skills/docs/d3/shape/
# Find pie/arc docs
grep -r "pie\|arc\|donut" /Users/zach/Documents/cc-skills/docs/d3/shape/
# Find stack docs
grep -r "stack\|layer" /Users/zach/Documents/cc-skills/docs/d3/shape/
# Find symbol docs
grep -r "symbol\|scatter" /Users/zach/Documents/cc-skills/docs/d3/shape/
# Find path operations
grep -r "path\|serialize" /Users/zach/Documents/cc-skills/docs/d3/path/
# List shape generators
ls /Users/zach/Documents/cc-skills/docs/d3/shape/
Common Errors
-
Path not rendering: Check scale domains match data range
- Solution: Use d3.extent() to compute correct domain
-
Area chart inverted: Y scale range is backwards
- Solution: Set range as [height, 0] (SVG y grows downward)
-
Pie chart off-center: Missing transform translate
- Solution: Add
transform="translate(cx, cy)"to group
- Solution: Add
-
Gaps in line: Null/undefined values in data
- Solution: Set
.defined(d => d.value != null)
- Solution: Set
-
Stack negative values: stackOffsetNone doesn't handle negatives
- Solution: Use stackOffsetDiverging for +/- values
Performance Tips
- Use .curve(d3.curveLinear) - Fastest rendering
- Simplify paths - Use fewer data points for large datasets
- Avoid recomputing generators - Create once, reuse
- Use context rendering - For Canvas instead of SVG
- Batch path updates - Use .datum() instead of .data() when possible
- Optimize arc rendering - Use fewer padAngle for large datasets
Notes
- Documentation covers D3 v7 (latest version)
- All generators support both SVG and Canvas contexts
- Curve interpolators are interchangeable across line/area generators
- Pie layout computes startAngle and endAngle for each datum
- Stack layout adds [y0, y1] arrays to each data point
- Symbol size is in square pixels (area, not radius)
- Path generators are immutable - methods return new generators
- File paths reference local documentation cache
- For latest updates, check https://d3js.org/d3-shape
More by zacharyr0th
View allUse when building marketplace platforms, multi-party payments, or managing connected accounts. Invoke for account onboarding, platform payments, charge flows (direct/destination/separate), transfers, payouts, or commission/fee splits.
Use when getting started with Shelby Protocol for the first time. Guides through initial setup, token acquisition, account funding, first upload, and choosing between CLI/SDK/media player. Invoke when user is new to Shelby, needs onboarding, or asks "how to start with Shelby", "Shelby setup", or "get started with Shelby".
Use when working with the Shelby Protocol CLI for uploading files, downloading blobs, managing accounts, or configuring contexts. Helps with initialization, funding accounts with ShelbyUSD/Aptos tokens, file operations, and troubleshooting Shelby CLI issues. Invoke for Shelby storage, decentralized blob storage, or video streaming uploads.
Use when working with Next.js App Router (app/ directory). Invoke for Server Components, layouts, route handlers, parallel routes, intercepting routes, Server Actions, streaming, loading states, or error handling in the app directory.
