Building My Own SVG Path Editor featured image

Building My Own SVG Path Editor

June 02, 2025

From “Why Is This So Hard?” to “Okay, This Slaps”

Somewhere between my third ad popup and the seventh “premium feature” paywall, I hit that classic developer breaking point: if every SVG tool only does one thing I need, I’m going to end up doing all the things myself anyway. So I made a cup of coffee, opened a fresh repo, and said the words that have launched many side projects and a few regrettable weekends: I’ll just build my own.

What followed started as a tiny utility for editing paths and turned into a fast, shareable, developer‑friendly SVG path editor I actually use daily. Here’s how (and why) it came together.

The Problem: Tool Fragmentation

My workflow got silly. One tab for path editing, another for optimization, a third for measurements—and still jumping into my editor to hand‑tweak curves. Each tool had strengths, but the rough edges (ads, feature gates, imprecision) slowed actual making. The moment I needed to quickly iterate on icons while understanding the underlying path structure, I realized I was spending more time switching tools than drawing.

Technical Architecture Decisions

Framework Choice: Next.js + React

I picked Next.js 14 with the App Router because it let me move fast without fighting the stack:

  • Server-side rendering for solid SEO and quick first paint.
  • Built-in optimization for images, fonts, and static assets.
  • Flexible deployment (hello, Vercel) without yak shaving.
  • TypeScript-first DX so geometry math doesn’t bite later.

The component architecture stays clean and layered:

- Canvas layer: Pure SVG manipulation and rendering
- UI layer: shadcn/ui components built on Radix primitives
- State layer: React Context for global state management
- Utility layer: Pure functions for path calculations and transformations

State Management Strategy

Instead of pulling in Redux/Zustand out of habit, I used focused React contexts to keep concerns tight and renders cheap:

  • EditorContext: Modes, zoom, pan, selection.
  • PathsContext: Path data, styles, metadata.
  • HistoryContext: Undo/redo with efficient snapshots.
  • CanvasEventsContext: Mouse interactions and keyboard shortcuts.

This split kept performance predictable and the codebase understandable. Each context owns a domain; components only subscribe to what they need.

The SVG Path Challenge

SVG paths look simple—M 10,10 L 20,20 C 30,30 40,40 50,50—until you start manipulating them programmatically. Then it’s coordinate transforms, curve math, winding rules, and many, many edge cases.

I built lib/path-utils.ts to handle the heavy lifting:

  • Parsing: Convert path strings into structured data.
  • Serialization: Output valid SVG path syntax.
  • Transformations: Rotate, scale, translate points precisely.
  • Optimization: Remove redundant points and simplify curves.
  • Measurements: Bounds, area, perimeter, and complexity metrics.

Evolution: From Personal Tool to Feature-Rich Editor

The first feature that unlocked everything was shareable, state‑encoded URLs:

// Compress and encode state for sharing
const compressedData = LZString.compressToEncodedURIComponent(
  JSON.stringify(pathsData)
);
const shareUrl = `${baseUrl}?share=${compressedData}`;

I could send someone a link and they’d see exactly what I saw—no uploads, accounts, or servers. Then it clicked: generate OpenGraph images from the actual SVG in the URL. Now links show a real preview of the work. It feels like magic the first time.

Adding Developer-Focused Features

As I used it, I kept smoothing the places I personally felt friction:

  • Path operation breakdown to understand how shapes are built.
  • Optimization tools to clean up bloated exports from design apps.
  • Measurement and analysis for quick, precise dimension checks.
  • Transform controls for scaling and nudging with real accuracy.

The AI Experiment: “What If I Could Just Describe It?”

For fun (and because prototyping should be fast), I tried generating paths from text using Grok via Vercel’s AI SDK:

// AI generates SVG path from text description
const result = await generateObject({
  model: xai('grok-beta'),
  prompt: `Generate an SVG path for: ${description}`,
  schema: pathSchema,
});

It’s not a silver bullet, but for simple icons it’s a surprisingly good head start. “A simple house icon” becomes something you can tweak, instead of a blank canvas.

Performance Optimizations

Canvas Rendering Strategy

SVG manipulation can bog down fast, so I optimized early:

  • Selective re-rendering: Update only changed paths.
  • Debounced interactions: Batch drag events and cursor thrash.
  • Efficient hit detection: Lean on elementFromPoint where it shines.
  • Transform caching: Avoid repeating expensive matrix math.

Memory Management

Undo/redo can balloon memory if you’re careless. The history system uses:

  • Structural sharing to store diffs.
  • Configurable limits to cap depth.
  • Lazy serialization so sharing work doesn’t tax editing.

User Experience Decisions

Keyboard-First Workflow

Good tools respect momentum. Shortcuts make it feel fast:

  • Mode switching: 1–4 or Q–R.
  • Canvas navigation: F for fit-to-view, +/- for zoom.
  • Path operations: Ctrl/Cmd+Z and Y for undo/redo.
  • UI toggles: G for grid, S for snap, Tab for sidebar.

Progressive Disclosure

Start simple, reveal power as needed:

  • Clean start: A calm canvas with essentials.
  • Advanced tools appear when context calls for them.
  • Expert mode: Full keyboard control and deep path ops.

Mobile Considerations

It’s desktop‑first, but it holds up on tablets:

  • Touch-friendly point targets.
  • Gestures for pinch‑to‑zoom and pan.
  • Responsive sidebar with collapsible panels.

Deployment and Infrastructure

Deploys to Vercel with minimal ceremony:

  • Edge runtime for snappy global performance.
  • Automatic optimization for assets.
  • Privacy‑respecting analytics to understand usage.
  • Custom domain for clean links and SEO.

Lessons Learned

Build for Your Own Needs First

The best features came from fixing my actual day‑to‑day annoyances. Needed complexity metrics? Built measurement. Wanted frictionless sharing? Encoded state in the URL. Scratching your own itch keeps scope honest.

TypeScript Is Non‑Negotiable

Geometry and transforms without types is pain. Type safety caught bugs early and made refactors calm instead of scary.

Innovation Loves the Gaps

State‑encoded URLs and dynamic OG images weren’t “net new” tech—just smart combinations. Great UX often comes from connecting existing pieces in a new way.

Optimize Early Enough

SVG performance debt compounds. A little care up front saved a lot of retrofits later.

What’s Next

Roadmap items I’m excited about:

  • Format export to PNG, JSX, and React Native components.
  • Path grouping for complex illustrations.
  • Animation preview to test motion before export.

From Personal Tool to Public App

This started as a weekend fix and became a tool I reach for constantly. It replaces a whole stack of single‑purpose apps and makes sharing dead simple. I’ve made it publicly available and free to use so other developers and designers can benefit in their own workflows—whether that’s the state management approach, the URL‑based sharing, or the dynamic OG image generation.

The source isn’t open right now. I may open‑source select parts in the future if there’s interest; in the meantime, feedback and feature requests are very welcome.

And yes, I use it regularly. There’s a special kind of satisfaction in shipping something that removes your own friction—and then discovering other people like it too.


Try it here: svg-editor.griffen.codes. It’s free to use. If you’ve been juggling three tools to get one SVG right, give it a spin—it might save you a few tabs (and maybe a few choice words).