The vcad IR (Intermediate Representation) is the serializable format for CAD documents. Both Rust (vcad-ir) and TypeScript (@vcad/ir) provide equivalent types.
Document
The root container for a vcad file.
Documentinterface Document {
version: "0.1";
nodes: Record<string, Node>;
materials: Record<string, MaterialDef>;
roots: SceneEntry[];
}
versionstringrequiredFormat version. Currently always "0.1".
nodesRecord<string, Node>requiredAll nodes in the document, keyed by ID as string.
materialsRecord<string, MaterialDef>requiredMaterial definitions, keyed by material name.
rootsSceneEntry[]requiredWhich nodes to render and their materials.
Node
A single operation in the CSG graph.
Nodeinterface Node {
id: number;
name: string | null;
op: CsgOp;
}
idnumberrequiredUnique identifier for this node. Used for references.
namestring | nullrequiredOptional display name. null for anonymous intermediate nodes.
opCsgOprequiredThe operation this node represents.
CsgOp
Tagged union of all CSG operations.
Primitives
Cube{ type: "Cube", size: Vec3 }
Box with corner at origin, extending to size.
Cylinder{ type: "Cylinder", radius: number, height: number, segments: number }
Cylinder along Z axis, base at origin.
Sphere{ type: "Sphere", radius: number, segments: number }
Sphere centered at origin.
Cone{
type: "Cone",
radiusBottom: number,
radiusTop: number,
height: number,
segments: number
}
Cone or frustum along Z axis, base at origin.
Boolean Operations
Union{ type: "Union", left: NodeId, right: NodeId }
Combines two shapes.
Difference{ type: "Difference", left: NodeId, right: NodeId }
Subtracts right from left.
Intersection{ type: "Intersection", left: NodeId, right: NodeId }
Keeps only overlapping region.
Transforms
Translate{ type: "Translate", child: NodeId, offset: Vec3 }
Moves a shape by offset.
Rotate{ type: "Rotate", child: NodeId, angles: Vec3 }
Rotates a shape. Angles in degrees.
Scale{ type: "Scale", child: NodeId, factor: Vec3 }
Scales a shape non-uniformly.
Patterns
LinearPattern{
type: "LinearPattern",
child: NodeId,
direction: Vec3,
count: number,
spacing: number
}
Creates copies along a line.
CircularPattern{
type: "CircularPattern",
child: NodeId,
axis: Vec3,
count: number,
angle: number
}
Creates copies around an axis.
Vec3
3D vector used for positions, sizes, and directions.
Vec3interface Vec3 {
x: number;
y: number;
z: number;
}
NodeId
Reference to another node by its ID.
NodeIdtype NodeId = number;
MaterialDef
PBR material definition.
MaterialDefinterface MaterialDef {
name: string;
color: [number, number, number];
metallic: number;
roughness: number;
density?: number;
description?: string;
}
namestringrequiredDisplay name for the material.
color[number, number, number]requiredRGB color values, 0.0-1.0.
metallicnumberrequiredMetallic factor, 0.0-1.0.
roughnessnumberrequiredRoughness factor, 0.0-1.0.
densitynumberoptionalMaterial density in kg/m³. For physics simulation.
descriptionstringoptionalHuman-readable description.
SceneEntry
Connects a root node to a material for rendering.
SceneEntryinterface SceneEntry {
root: NodeId;
material: string;
}
rootNodeIdrequiredID of the node to render.
materialstringrequiredKey into the materials dictionary.
Complete Example
const document: Document = {
version: "0.1",
nodes: {
"1": {
id: 1,
name: "plate",
op: { type: "Cube", size: { x: 100, y: 60, z: 5 } }
},
"2": {
id: 2,
name: null,
op: {
type: "Translate",
child: 1,
offset: { x: -50, y: -30, z: -2.5 }
}
},
"3": {
id: 3,
name: "hole",
op: { type: "Cylinder", radius: 3, height: 10, segments: 32 }
},
"4": {
id: 4,
name: "result",
op: { type: "Difference", left: 2, right: 3 }
}
},
materials: {
aluminum: {
name: "Aluminum",
color: [0.9, 0.9, 0.92],
metallic: 0.95,
roughness: 0.3
}
},
roots: [
{ root: 4, material: "aluminum" }
]
};
TypeScript Import
import type {
Document,
Node,
CsgOp,
Vec3,
MaterialDef,
SceneEntry,
} from "@vcad/ir";
Rust Import
use vcad_ir::{
Document,
Node,
CsgOp,
Vec3,
MaterialDef,
SceneEntry,
};
Serialization
Both implementations use JSON with the same schema:
// Rust
let json = serde_json::to_string_pretty(&document)?;
let doc: Document = serde_json::from_str(&json)?;
// TypeScript
const json = JSON.stringify(document, null, 2);
const doc: Document = JSON.parse(json);