# Kerf

Modular raster-to-vector conversion engine paired with a 2D sign and patch design canvas. Upload a raster image (PNG, JPEG, BMP), trace it into clean vector paths using Potrace or VTracer, and export as SVG or DXF — ready for CNC routers, vinyl cutters, laser engravers, and embroidery machines.

## Quick Start

```bash
docker compose up -d
```

Once both services are healthy:

- **Web App** → [http://localhost:3000](http://localhost:3000)
- **Engine API** → [http://localhost:8000/engine/health](http://localhost:8000/engine/health)
- **Interactive API Docs** → [http://localhost:8000/docs](http://localhost:8000/docs)

Check service health:

```bash
docker compose ps
```

Tear down:

```bash
docker compose down
```

## Repository Structure

```
engine/              Kerf Engine — standalone Python/FastAPI vectorization API
  api/               API route definitions
  pipeline/          Preprocessing, vectorization, and post-processing stages
  output/            SVG, DXF, and JSON output generators
  presets/           Built-in preset configurations (JSON)
  tests/             Engine test suite (pytest)
app/                 Kerf App — React/TypeScript design canvas (Vite + Konva)
  src/               Application source code
  public/            Static assets including bundled fonts
docker/              Dockerfiles and nginx configuration
  Dockerfile.engine  Multi-stage build for the engine (Python 3.11)
  Dockerfile.app     Multi-stage build for the app (Node 22 → nginx 1.27)
  nginx.conf         SPA routing + /engine reverse-proxy
docker-compose.yml   Full-stack orchestration with healthchecks
```

## Engine API Reference

The engine exposes four endpoints under the `/engine` prefix. All endpoints accept and return JSON unless otherwise noted.

### `GET /engine/health`

Healthcheck endpoint for container orchestration.

**Response:**

```json
{ "status": "ok" }
```

### `GET /engine/presets`

List all available presets and their parameter values.

**Response:**

```json
{
  "presets": {
    "sign": { "name": "sign", "description": "Metal signage, bold text cutouts", "..." : "..." },
    "patch": { "name": "patch", "description": "Embroidered patches, fabric cutting", "..." : "..." }
  }
}
```

### `POST /engine/trace`

Convert a raster image to vector output through the full preprocessing → vectorization → post-processing pipeline.

**Content-Type:** `multipart/form-data`

| Field           | Type   | Default    | Description |
|-----------------|--------|------------|-------------|
| `file`          | file   | (required) | Raster image (PNG, JPEG, BMP) |
| `mode`          | string | from preset | Vectorization engine: `potrace` or `vtracer` |
| `output_format` | string | `svg`      | Output format: `svg`, `dxf`, or `json` |
| `preset`        | string | `sign`     | Preset name (see [Presets](#presets)) |
| `params`        | string | `{}`       | JSON string of parameter overrides |

**Example — trace with the sign preset:**

```bash
curl -X POST http://localhost:8000/engine/trace \
  -F file=@logo.png \
  -F preset=sign \
  -F output_format=svg
```

**Example — trace with custom parameters:**

```bash
curl -X POST http://localhost:8000/engine/trace \
  -F file=@photo.jpg \
  -F preset=detailed \
  -F mode=vtracer \
  -F 'params={"filter_speckle": 4, "epsilon": 0.3}'
```

**Response (SVG/JSON formats):**

```json
{
  "output": "<svg ...>...</svg>",
  "format": "svg",
  "metadata": {
    "format": "svg",
    "path_count": 12,
    "node_count_total": 483,
    "open_paths": 0,
    "island_count": 2,
    "warnings": [],
    "processing_ms": 142.57
  }
}
```

**Response (DXF format):** Raw DXF bytes with `Content-Type: application/dxf` and metadata in the `X-Kerf-Metadata` response header.

### `POST /engine/simplify`

Simplify an existing SVG using Ramer–Douglas–Peucker path simplification. Optionally export to DXF with unit and scale control.

**Content-Type:** `multipart/form-data`

| Field           | Type   | Default    | Description |
|-----------------|--------|------------|-------------|
| `file`          | file   | (required) | SVG file to simplify |
| `epsilon`       | float  | `1.0`      | RDP simplification tolerance (higher = fewer points) |
| `output_format` | string | `svg`      | Output format: `svg`, `dxf`, or `json` |
| `units`         | string | none       | DXF unit metadata: `inches` or `mm` |
| `scale_factor`  | float  | `1.0`      | DXF coordinate scale factor |

**Example — simplify and export to DXF in millimeters:**

```bash
curl -X POST http://localhost:8000/engine/simplify \
  -F file=@drawing.svg \
  -F epsilon=2.0 \
  -F output_format=dxf \
  -F units=mm \
  -F scale_factor=25.4
```

## Presets

Presets bundle tuned parameter sets for each pipeline stage — preprocessing, vectorization, and post-processing — optimized for specific use cases.

| Preset     | Description                        | Mode     | Epsilon | Notes |
|------------|------------------------------------|----------|---------|-------|
| `sign`     | Metal signage, bold text cutouts   | potrace  | 2.5     | Aggressive denoising, auto-close enabled |
| `patch`    | Embroidered patches, fabric cutting| potrace  | 1.0     | Moderate smoothing, fine detail retention |
| `stencil`  | Physical stencil cutting           | potrace  | 3.0     | Heavy simplification, fixed threshold at 128 |
| `detailed` | High-fidelity illustration work    | potrace  | 0.5     | Minimal smoothing, preserves fine curves |
| `custom`   | All params exposed, no defaults    | potrace  | —       | Pass all parameters explicitly via `params` |

Use the `params` field on `/engine/trace` to override any preset value. For example, to use the `sign` preset but switch to VTracer mode:

```bash
curl -X POST http://localhost:8000/engine/trace \
  -F file=@image.png \
  -F preset=sign \
  -F 'params={"mode": "vtracer"}'
```

## Font System

The web app bundles three fonts for text-to-path conversion, enabling text elements to be converted to SVG outlines for cutting/engraving:

| Font       | File                    |
|------------|-------------------------|
| Roboto     | `Roboto-Regular.ttf`    |
| Open Sans  | `OpenSans-Regular.ttf`  |
| Lato       | `Lato-Regular.ttf`      |

Fonts are parsed client-side using [opentype.js](https://opentype.js.org/) and converted to SVG path data with configurable font size and letter spacing. The conversion handles glyph positioning, coordinate system flipping, and path assembly — no server round-trip required.

## Engine Standalone Usage

The engine runs independently of the web app. Use it as a standalone API service or build just the engine Docker image:

**Docker (standalone):**

```bash
docker build -f docker/Dockerfile.engine -t kerf-engine .
docker run -p 8000:8000 kerf-engine
```

**Local development (Python):**

```bash
cd engine
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
uvicorn main:app --host 0.0.0.0 --port 8000 --reload
```

API docs are available at [http://localhost:8000/docs](http://localhost:8000/docs) (Swagger UI) and [http://localhost:8000/redoc](http://localhost:8000/redoc) (ReDoc).

## Development

### Engine (Python)

```bash
cd engine
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

# Run the API server with auto-reload
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

# Run tests
pytest
```

System dependencies for pypotrace: `libpotrace-dev`, `libpotrace0`, `libagg-dev` (Debian/Ubuntu).

### App (React/TypeScript)

```bash
npm install
npm run dev --workspace=app
```

The Vite dev server proxies `/engine/*` requests to `http://localhost:8000` — start the engine first for full functionality.

### Full Stack (Docker Compose)

```bash
docker compose up --build
```

The app is served on port 3000 with nginx reverse-proxying `/engine/*` to the engine container.

## Known Limitations

- **Single-image processing** — the engine processes one image per request; batch endpoints are not yet available.
- **Binary vectorization only** — both Potrace and VTracer operate in binary (black/white) mode; color/multi-layer tracing is not supported.
- **No authentication** — the API is open; add a reverse proxy with auth for production deployments.
- **Font selection** — the app ships with three bundled fonts; custom font upload is not yet supported.
- **DXF fidelity** — DXF export covers basic polyline geometry; advanced CAD features (layers, blocks, hatches) are not included.
