Skip to content

Vector Networks vs Paths

Comparing traditional path-based vector graphics with Figma-style vector networks.

Definitions

Path (Traditional)

A path is an ordered sequence of segments forming a chain:

A ──-> B ──-> C ──-> D
  • Each point has at most 2 connections (previous, next)
  • May be open (A to D) or closed (D connects back to A)
  • No branching allowed
rust
struct Path {
    segments: Vec<Segment>,  // ordered
    closed: bool,
}

Vector Network (Figma)

A vector network is a graph of anchors and edges:

    A ───── B
   /│\      │
  / │ \     │
 D  │  E    │
  \ │ /     │
   \│/      │
    C ───── F
  • Points can have any number of connections
  • Edges connect any two anchors
  • Regions (faces) are implicit from the topology
  • More like a 2D mesh than a path
rust
struct VectorNetwork {
    anchors: Vec<Anchor>,
    edges: Vec<Edge>,
    // faces derived from edges
}

struct Anchor {
    position: Vec2,
    // possibly: handle style, etc.
}

struct Edge {
    start: AnchorId,
    end: AnchorId,
    curve: CurveType,  // line, bezier, etc.
}

Visual Comparison

Simple shape: both work fine

Path:                    Network:
┌───────────┐            ┌───────────┐
│           │            │           │
│           │            │           │
└───────────┘            └───────────┘
(4 segments, closed)     (4 anchors, 4 edges)

2D projection of cube: network required

Paths (need 3 separate paths):     Network (single structure):
    ╱╲                                  A
   ╱  ╲                                ╱│╲
  ╱    ╲       Path 1: outer hex      B │ C
 │      │      Path 2: line A->D       │╲│╱│
 │      │      Path 3: line B->E        D─E
  ╲    ╱       (or draw as strokes)    │╱│╲
   ╲  ╱                                F │ G
    ╲╱                                  ╲│╱
                                        H

With network: single unified structure
Interior lines are edges, not separate paths

Letter 'A': network might help

Path approach:              Network approach:
Outer path + inner path     Single network with hole
(compound path)             (hole is a face property)
    ╱╲                          ╱╲
   ╱  ╲                        ╱  ╲
  ╱────╲                      A────B
 ╱ ╱╲   ╲                    ╱│    │╲
╱ ╱  ╲   ╲                  C─D    E─F

2 paths                     6 anchors, multiple edges

Trade-offs

Paths

Pros:

  • Simpler mental model
  • Easier to iterate (just walk the array)
  • Clear ordering (start -> end)
  • Maps directly to SVG, PostScript, PDF
  • Boolean operations well-understood
  • Most algorithms assume path input

Cons:

  • Can't represent branching structures natively
  • Cube projection needs multiple paths or stroke hacks
  • Compound paths (holes) are separate concept
  • Shared anchors are duplicated

Vector Networks

Pros:

  • More general (paths are a subset)
  • Natural for branching structures
  • Shared anchors are actually shared
  • Closer to mesh topology (2D mesh, essentially)
  • Regions/fills are topological, not winding-rule based
  • Edit any anchor/edge independently

Cons:

  • More complex implementation
  • Need to derive regions from edges (face finding algorithm)
  • Fill rules become topology, not just math
  • Most file formats don't support (SVG needs conversion)
  • Most renderers expect paths
  • Boolean ops more complex

When Networks Win

  1. Technical drawings: circuit diagrams, floor plans, graphs
  2. Geometric constructions: projections, wireframes
  3. Connected structures: flowcharts, node diagrams
  4. Shared anchors: when you need "move this point, all connected edges follow"

When Paths Win

  1. Artistic illustration: most art is non-branching curves
  2. Text/fonts: glyphs are paths
  3. Interoperability: SVG, PDF, fonts all use paths
  4. Simple shapes: rectangles, circles, hand-drawn curves

Implementation Complexity

OperationPathNetwork
Iterate pointsO(n) trivialO(n) trivial
Find neighborsindex ± 1graph traversal
Boolean unionwell-studiedresearch territory
Render/filldirectfind regions first
Export to SVGdirectconvert to paths
Offset/strokewell-studiedper-region?

Conversion

Network -> Paths

Always possible by tracing each region boundary:

rust
fn network_to_paths(net: &VectorNetwork) -> Vec<Path> {
    let regions = find_regions(net);  // face-finding algorithm
    regions.iter().map(|r| trace_boundary(net, r)).collect()
}

Loses the "shared anchor" property - anchors get duplicated.

Paths -> Network

Possible but may not capture intent:

rust
fn paths_to_network(paths: &[Path]) -> VectorNetwork {
    // Add all anchors and edges
    // Optionally: merge coincident anchors
}

Multiple paths through same point become shared anchor.

Hybrid Approach?

Could support both:

rust
enum VectorGeometry {
    Path(Path),
    Network(VectorNetwork),
}

// Convert on demand
impl VectorGeometry {
    fn as_paths(&self) -> Vec<Path> { /* ... */ }
    fn as_network(&self) -> VectorNetwork { /* ... */ }
}

Or: use network internally, present path-like API for common cases.

Prior Art

ToolModelNotes
SVGPathsIndustry standard
PostScript/PDFPaths
FigmaNetworksPrimary innovation
IllustratorPaths
InkscapePaths
Paper.jsPaths
OpenType/TrueTypePathsFonts

Figma is the only major tool using networks natively.

Recommendation

Network internally, both APIs as equals.

Key insight: paths are just networks with a constraint (degree ≤ 2). No need to choose - use network as the internal representation, offer both API surfaces.

rust
// Internal: always a network
struct VectorNetwork {
    anchors: Vec<Anchor>,
    edges: Vec<Edge>,
}

// Path is a constrained view/wrapper
struct Path(VectorNetwork);  // newtype enforcing degree ≤ 2

impl Path {
    fn line_to(&mut self, p: Vec2) -> &mut Self { ... }
    fn point_at(&self, t: f32) -> Vec2 { ... }  // global parameterization
}

impl VectorNetwork {
    fn as_path(&self) -> Option<Path> { ... }  // None if branching
    fn add_edge(&mut self, a: AnchorId, b: AnchorId) { ... }
}

Different APIs for different mental models:

Path API (constrained)Network API (general)
point_at(t) globalpoint_at(edge, t) per-edge
iter_segments() orderediter_edges() unordered
reverse() flip directionedges directed or not
append(other) concatenatemerge(other) union graphs

Interoperability is just conversion at boundaries:

  • Import SVG -> parse as paths -> store as network
  • Export -> decompose to paths -> write SVG

Open Questions

  1. Is Figma's network model documented anywhere? (Seems proprietary)
  2. Are there academic papers on vector network algorithms?
  3. What's the actual use case frequency for branching structures?
  4. Could we get 80% of the benefit with "paths + shared anchor references"?
rust
// Lighter-weight alternative to full networks?
struct PathWithSharedAnchors {
    anchors: Vec<Anchor>,
    paths: Vec<Vec<AnchorId>>,  // paths reference shared anchors
}

This gets shared-anchor editing without full graph topology.