Output Formats
All exports derive from the internal Vec<Polyline> representation.
Each serializer is a pure function in the mujou-export crate (core layer, no I/O).
For a device-compatibility view of which tables accept which formats, see File Formats by Device.
Theta-Rho (.thr)
For Sisyphus tables, Oasis Mini, and DIY polar sand tables.
Format Specification
- Plain text, one
theta rhopair per line (space-separated) - Theta: continuous radians (accumulating, does NOT wrap at 2pi)
- Rho: 0.0 (center) to 1.0 (edge), normalized
- Lines beginning with
#are comments, ignored by table firmware
Example
# mujou
# Source: cherry-blossoms.jpg
# blur=1.4, canny=15/40, simplify=2, tracer=BorderFollowing, joiner=Mst, mask=75%, res=256
# Exported: 2026-02-14_12-30-45
# Config: {"blur_sigma":1.4,"canny_low":15.0,...}
0.00000 0.00000
0.10000 0.15000
0.20000 0.30000
0.50000 0.45000
1.00000 0.60000
Metadata
Metadata is embedded as #-prefixed comment lines at the top of the file.
This mirrors the SVG exporter’s <title>, <desc>, and <metadata> approach
and follows the convention established by Sandify,
which uses # comments for file name, type, and section markers.
| Line prefix | Content | Purpose |
|---|---|---|
# mujou | Fixed identifier | Identifies the file as mujou-generated |
# Source: | Source image filename | Provenance |
# (free-form) | Pipeline parameters summary | Human-readable settings (blur, canny, simplify, etc.) |
# Exported: | Timestamp | When the file was exported |
# Config: | Full PipelineConfig JSON | Machine-parseable settings for reproducibility |
All metadata lines are optional. Parsers should skip any line beginning with #.
Each metadata value must occupy a single line. Producers must not embed newline characters within a # comment value — continuation text after a newline would lack the # prefix and be misinterpreted as theta-rho data by table firmware.
The # Config: line contains the complete serialized PipelineConfig as a
single JSON object, matching the content of the SVG exporter’s
<mujou:pipeline> element. This allows re-importing settings to reproduce
the exact same output.
XY-to-Polar Conversion
This is the most complex export step.
- Center: Image center = polar origin
- Axes: Cartesian +X points right, +Y points up (the pipeline’s normalized space is already +Y up)
- Rho:
rho = sqrt(x^2 + y^2) / max_radius, normalized to [0.0, 1.0] - Theta:
theta = atan2(x, y), with continuous accumulation
The Sisyphus ecosystem uses atan2(x, y) – not the standard math atan2(y, x).
This means theta=0 points up (along +Y), and the Cartesian-to-polar / polar-to-Cartesian conversions are:
theta = atan2(x, y)x = rho * sin(theta),y = rho * cos(theta)
This is confirmed by both Sandify (geometry.js, toThetaRho) and jsisyphus (Point.java: “The zero radial is coincident with the positive y axis”).
Continuous theta unwinding is critical. Theta must accumulate across the full path – if the path spirals clockwise, theta decreases past 0, -pi, -2pi, etc. If it spirals counterclockwise, theta increases past 2pi, 4pi, etc.
Algorithm:
#![allow(unused)]
fn main() {
for each point after the first:
raw_theta = atan2(x, y)
// Choose the equivalent angle closest to previous theta
delta = raw_theta - prev_theta
while delta > PI:
delta -= 2 * PI
while delta < -PI:
delta += 2 * PI
theta = prev_theta + delta
prev_theta = theta
}
Path Start/End Requirements
The path must start and end with rho at 0 (center) or 1 (edge). If the contours don’t naturally start/end there, add a spiral-in or spiral-out segment.
G-code (.gcode)
For XY/Cartesian sand tables (ZenXY, GRBL/Marlin machines).
Format Specification
- Standard G-code text
G0 X... Y...– rapid move (travel between contours)G1 X... Y... F...– linear move (drawing)- Coordinates scaled to configurable bed size
Example
G28 ; Home
G90 ; Absolute positioning
G0 X10.00 Y15.00
G1 X12.50 Y18.30 F3000
G1 X14.00 Y20.10 F3000
G0 X30.00 Y5.00
G1 X32.50 Y7.80 F3000
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
bed_width | f64 | 200.0 | Bed width in mm |
bed_height | f64 | 200.0 | Bed height in mm |
feed_rate | f64 | 3000.0 | Feed rate (mm/min) |
SVG (.svg)
The most versatile output format. Also accepted by the Oasis Mini app (upload at app.grounded.so), though THR is preferred for Oasis because SVG sizing and centering can be incorrect in certain cases (see Oasis SVG sizing). Useful for plotters, laser cutters, vinyl cutters, or viewing in a browser.
Format Specification
- Standard SVG XML
- Optional
<title>element with the source image name (for accessibility and file manager identification) - Optional
<desc>element with pipeline parameters and export timestamp - Optional
<metadata>element containing the fullPipelineConfigas JSON, wrapped in a namespaced<mujou:pipeline>element for machine-parseable reproducibility - Each polyline becomes a
<path>element with adattribute containingM(move to) andL(line to) commands - Disconnected contours are separate
<path>elements viewBoxset to the image dimensions
Example
<?xml version="1.0" encoding="UTF-8"?>
<svg height="600" viewBox="0 0 800 600" width="800" xmlns="http://www.w3.org/2000/svg">
<title>cherry-blossoms</title>
<desc>blur=1.4, canny=15/40, simplify=2, tracer=BorderFollowing, joiner=Mst, mask=75%, res=256
Exported: 2026-02-14_12-30-45</desc>
<metadata>
<mujou:pipeline xmlns:mujou="https://mujou.app/ns/1">{"blur_sigma":1.4,"canny_low":15.0,...}</mujou:pipeline>
</metadata>
<path d="M10,15 L12.5,18.3 L14,20.1" fill="none" stroke="black" stroke-width="1"/>
<path d="M30,5 L32.5,7.8 L35,10.2" fill="none" stroke="black" stroke-width="1"/>
</svg>
Note: SVG output is generated by the
svgcrate. Attribute ordering is determined by the library (typically alphabetical). Path coordinates use the library’s defaultf32precision formatting. The JSON inside<mujou:pipeline>is XML-escaped —<becomes<,&becomes&, etc. Parsers should XML-unescape the text content before JSON-parsing it.
DXF (.dxf)
CAD interchange format for OnShape, Fusion 360, etc.
Format Specification
- Minimal DXF using
LINEentities in theENTITIESsection - Each segment of each polyline becomes a
LINEentity - ASCII DXF format (not binary)
Example
0
SECTION
2
ENTITIES
0
LINE
8
0
10
10.0
20
15.0
11
12.5
21
18.3
0
LINE
8
0
10
12.5
20
18.3
11
14.0
21
20.1
0
ENDSEC
0
EOF
PNG Preview
Rasterized render of the traced paths for quick sharing and thumbnailing.
Specification
- Render polylines onto a pixel buffer using the
imagecrate - White background, black strokes (or configurable colors)
- Output as PNG-encoded bytes
- Resolution matches the input image dimensions
Live SVG Preview (UI)
In the browser UI, traced paths are rendered as inline SVG elements directly in the Dioxus DOM. This provides crisp vector rendering at any zoom level without requiring canvas or JS interop.
The preview uses a simplified version of the paths (higher RDP tolerance) to keep the DOM lightweight when the full path set is very large.
Preview Modes
| Mode | Description |
|---|---|
| Original | Source image displayed as-is |
| Edges | Binary edge map (Canny output) |
| Paths | Traced polylines overlaid on original |
| Paths only | Traced polylines on blank background |