Skip to content

GridSpace/raster-path

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Raster Path - WebGPU Toolpath Generator

Fast browser-based terrain + tool path generator using WebGPU compute shaders.

Features

  • Dual Mode Rasterization: Planar (traditional XY grid) and Radial (cylindrical unwrap) modes
  • CNC Toolpath Generation: Generate toolpaths by simulating tool movement over terrain
  • GPU Accelerated: 20-100× faster than CPU-based solutions
  • Unified API: Clean three-method interface that works uniformly across both modes
  • ESM Module: Importable package for browser applications

Quick Start

As a Module

import { RasterPath } from '@gridspace/raster-path';

// Initialize for planar mode
const raster = new RasterPath({
    mode: 'planar',
    resolution: 0.1  // 0.1mm grid resolution
});
await raster.init();

// 1. Load tool (from STL triangles)
const toolTriangles = parseSTL(toolSTLBuffer);
const toolData = await raster.loadTool({
    triangles: toolTriangles
});

// 2. Load terrain (rasterizes immediately in planar mode)
const terrainTriangles = parseSTL(terrainSTLBuffer);
const terrainData = await raster.loadTerrain({
    triangles: terrainTriangles,
    zFloor: -100
});

// 3. Generate toolpaths
const toolpathData = await raster.generateToolpaths({
    xStep: 5,    // Sample every 5th point in X
    yStep: 5,    // Sample every 5th point in Y
    zFloor: -100
});

console.log(`Generated ${toolpathData.pathData.length} toolpath points`);

// Cleanup
raster.terminate();

Radial Mode (for cylindrical parts)

// Initialize for radial mode
const raster = new RasterPath({
    mode: 'radial',
    resolution: 0.1,      // Radial resolution (mm)
    rotationStep: 1.0     // 1 degree between rays
});
await raster.init();

// Load tool and terrain (same API!)
await raster.loadTool({ triangles: toolTriangles });
await raster.loadTerrain({
    triangles: terrainTriangles,
    zFloor: 0
});

// Generate toolpaths
const toolpathData = await raster.generateToolpaths({
    xStep: 5,
    yStep: 5,
    zFloor: 0
});

// Output is array of strips (one per rotation angle)
console.log(`Generated ${toolpathData.numStrips} strips, ${toolpathData.totalPoints} points`);

Demo UI

npm install
npm run dev

Open http://localhost:3000 and drag STL files onto the interface.

Algorithm

Planar Mode (XY Grid Rasterization)

  1. Tool Rasterization: Create XY grid at specified resolution and rasterize tool geometry (keeps min Z per grid cell)
  2. Terrain Rasterization: Rasterize terrain geometry on matching XY grid (keeps max Z per grid cell)
  3. Toolpath Generation:
    • Scan tool over terrain in XY grid with configurable step sizes (xStep, yStep)
    • At each position, calculate minimum Z-offset where tool doesn't collide with terrain
    • Output scanline-based toolpath as array of Z-heights

Radial Mode (Cylindrical Rasterization)

  1. Tool Rasterization: Rasterize tool in planar mode (same as above)
  2. Terrain Preparation: Center terrain in YZ plane and store triangles
  3. Toolpath Generation:
    • Cast rays from origin at specified rotation angles (e.g., every 1°)
    • For each ray, rasterize terrain triangles along that angle
    • Use X-bucketing optimization to partition triangles spatially
    • Calculate tool-terrain collisions along each radial strip
    • Output array of strips (one per angle), each containing Z-heights along X-axis

Performance

Example (84×84×28mm model, 6,120 triangles):

Step Size Points WebGPU Time CPU Time (WASM)
0.5mm 48K 0.8s 20-80s
0.1mm 1.2M 2s 280s

Speedup: 20-100× faster with WebGPU

Project Structure

src/
  index.js                    # Main RasterPath API (ESM export)
  web/
    webgpu-worker.js         # WebGPU worker (GPU compute shaders)
    app.js                   # Demo web application
    index.html               # Demo UI entry point
    style.css                # Demo styles
    parse-stl.js             # STL file parser utility
  test/
    planar-test.cjs          # Planar mode regression test
    planar-tiling-test.cjs   # Planar high-resolution test
    radial-test.cjs          # Radial mode regression test
  benchmark/
    fixtures/                # Test STL files (terrain.stl, tool.stl)
build/                        # Built files (generated by npm run build)

API Reference

RasterPath

Constructor: new RasterPath(options)

Options:

  • mode (string): 'planar' or 'radial'
  • resolution (number): Grid resolution in mm (e.g., 0.1)
  • rotationStep (number, radial only): Degrees between rays (e.g., 1.0)

async init()

Initialize WebGPU worker. Must be called before other methods.

Returns: Promise<void>

Example:

const raster = new RasterPath({ mode: 'planar', resolution: 0.1 });
await raster.init();

async loadTool({ triangles, sparseData })

Load tool geometry for toolpath generation.

Parameters (one required):

  • triangles (Float32Array, optional): STL triangle data (9 floats per triangle: v0.xyz, v1.xyz, v2.xyz)
  • sparseData (object, optional): Pre-computed raster data with { bounds, positions, pointCount }

Returns: Promise<object> - Tool raster data with { bounds, positions, pointCount }

Example:

// From STL triangles
const toolData = await raster.loadTool({
    triangles: toolTriangles
});

// From pre-computed sparse data (Kiri:Moto integration)
const toolData = await raster.loadTool({
    sparseData: { bounds, positions, pointCount }
});

async loadTerrain({ triangles, zFloor, boundsOverride, onProgress })

Load terrain geometry. Behavior depends on mode:

  • Planar mode: Rasterizes immediately and returns terrain data
  • Radial mode: Stores triangles for later, returns null

Parameters:

  • triangles (Float32Array): STL triangle data
  • zFloor (number, optional): Z floor value for out-of-bounds areas
  • boundsOverride (object, optional): Override bounding box {min: {x, y, z}, max: {x, y, z}}
  • onProgress (function, optional): Progress callback (progress: number) => void

Returns:

  • Planar mode: Promise<object> - Terrain raster data with { bounds, positions, pointCount }
  • Radial mode: Promise<null>

Example:

// Planar mode - returns terrain data immediately
const terrainData = await raster.loadTerrain({
    triangles: terrainTriangles,
    zFloor: -100
});

// Radial mode - stores for later
await raster.loadTerrain({
    triangles: terrainTriangles,
    zFloor: 0
});

async generateToolpaths({ xStep, yStep, zFloor, onProgress })

Generate toolpaths from loaded tool and terrain. Must call loadTool() and loadTerrain() first.

Parameters:

  • xStep (number): Sample every Nth point in X direction
  • yStep (number): Sample every Nth point in Y direction
  • zFloor (number): Z floor value for out-of-bounds areas
  • onProgress (function, optional): Progress callback (progress: number) => void

Returns:

  • Planar mode: Promise<object> with:

    • pathData (Float32Array): Z-heights in scanline order
    • width (number): Points per scanline
    • height (number): Number of scanlines
  • Radial mode: Promise<object> with:

    • strips (Array): Array of strip objects, each containing:
      • angle (number): Rotation angle in degrees
      • pathData (Float32Array): Z-heights along X-axis
    • numStrips (number): Total number of strips
    • totalPoints (number): Sum of all points across strips

Example:

// Works for both planar and radial modes!
const toolpathData = await raster.generateToolpaths({
    xStep: 5,
    yStep: 5,
    zFloor: -100,
    radiusOffset: 20  // radial mode only
});

terminate()

Terminate WebGPU worker and cleanup resources.

Example:

raster.terminate();

Requirements

  • Modern browser with WebGPU support (Chrome 113+, Edge 113+)
  • For testing: Electron (provides headless WebGPU environment)

Development

# Install dependencies
npm install

# Build (copies web files to build/)
npm run build

# Run demo
npm run serve

# Test
npm test

License

MIT

About

Terrain + Tool Raster Path Generator using WebGPU

Resources

License

Stars

Watchers

Forks

Packages

No packages published