OpenSCAD in the browser - React component for 3D CAD modeling
npm install openscad-playgroundOpenSCAD in the browser - A React component for 3D CAD modeling with WebAssembly.
- Full OpenSCAD in the browser - No installation required
- Monaco Editor - VSCode-like editing experience with syntax highlighting
- 3D Viewer - Real-time rendering with Google's model-viewer
- 20+ Libraries - BOSL2, MCAD, NopSCADlib, and more pre-bundled
- Multiple Export Formats - STL, 3MF, GLB, SVG, DXF, and more
- Customizer - Interactive parameter controls
- React Component - Easy integration into your React apps
``bash`
npm install openscad-playground
`tsx
import { OpenSCADPlayground } from 'openscad-playground';
import 'openscad-playground/styles';
function App() {
return (
'main.scad': 'cube([10, 10, 10]);'
}}
layout="multi"
/>
);
}
`
`tsx
import { OpenSCADPlayground } from 'openscad-playground';
import 'openscad-playground/styles';
function MyCADApp() {
return (
}}
layout="multi"
onRender={(output) => {
console.log('Rendered:', output);
}}
/>
$3
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
initialFiles | Record | - | Initial file contents |
| initialState | Partial | - | Full initial state |
| layout | 'single' \| 'multi' | 'multi' | Layout mode |
| defaultFocus | 'editor' \| 'viewer' \| 'customizer' | 'editor' | Default focused panel |
| libraries | LibraryConfig[] | - | Custom library configurations |
| onStateChange | (state: State) => void | - | State change callback |
| onRender | (output: any) => void | - | Render complete callback |
| onError | (error: Error) => void | - | Error callback |
| statePersister | StatePersister | - | Custom state persistence |
| className | string | - | CSS class for container |
| style | React.CSSProperties | - | Inline styles for container |
| customizerValues | CustomizerValuesInput | - | Override customizer parameter values |
| onCustomizerValuesChange | (values: CustomizerValues) => void | - | Callback when values change |
| onParametersChange | (parameters: Parameter[]) => void | - | Callback when parameter schema changes |$3
You need to host these files publicly (available in the
public/ folder):1. OpenSCAD WASM (~10MB)
-
public/wasm/openscad.js
- public/wasm/openscad.wasm2. External Libraries
-
public/browserfs.min.js - Virtual filesystem
- public/model-viewer.min.js - 3D viewer3. OpenSCAD Libraries (optional)
-
public/libraries/*.zip - 20+ OpenSCAD libraries4. Other Assets
-
public/fonts/ - Font files
- public/axes.glb - 3D axes model
- public/skybox-lights.jpg - Environment lightingDevelopment
$3
`
openscad-component/
├── src/ # Source code
├── demo/ # Demo app (npm run dev)
├── test-app/ # Test consumer app
├── public/ # Static assets
└── dist/ # Built package
`$3
`bash
Development (runs demo app)
npm run devBuild the component
npm run buildBuild with watch mode
npm run build:watch
`$3
`bash
Build and setup test app
bash scripts/build-and-test.shRun test app
cd test-app
npm run dev # Opens on port 3001
`Advanced Usage
$3
Build your own customizer UI by using the
customizerValues, onCustomizerValuesChange, and onParametersChange props. This allows you to create a completely custom parameter interface while the playground handles rendering.#### Types
`typescript
// Simple input format for setting values
type CustomizerValuesInput = Record;// Rich output format with full metadata
type CustomizerValues = Record value: number | string | boolean | number[];
type: 'number' | 'string' | 'boolean';
initial: number | string | boolean | number[];
group: string; // From OpenSCAD / [Group Name] / syntax
caption?: string;
min?: number;
max?: number;
step?: number;
options?: { name: string; value: number | string }[];
}>;
// Parameter schema from OpenSCAD file
type Parameter = {
name: string;
type: 'number' | 'string' | 'boolean';
initial: number | string | boolean | number[];
group: string;
caption?: string;
min?: number;
max?: number;
step?: number;
options?: { name: string; value: number | string }[];
};
`#### Example
onParametersChange Payload`json
[
{ "name": "width", "type": "number", "initial": 20, "group": "Dimensions", "min": 1, "max": 100 },
{ "name": "height", "type": "number", "initial": 10, "group": "Dimensions" },
{ "name": "rounded", "type": "boolean", "initial": true, "group": "Options" },
{ "name": "style", "type": "string", "initial": "modern", "group": "Options",
"options": [{ "name": "Modern", "value": "modern" }, { "name": "Classic", "value": "classic" }] }
]
`#### Example
`tsx
import { OpenSCADPlayground } from 'openscad-playground';
import type { CustomizerValues, CustomizerValuesInput, Parameter } from 'openscad-playground';
import { useState, useCallback } from 'react';function CustomCustomizerApp() {
// Parameter schema from the OpenSCAD file
const [parameters, setParameters] = useState([]);
// Current values with full metadata
const [values, setValues] = useState({});
// Your overrides to send back to the playground
const [overrides, setOverrides] = useState({});
const handleChange = useCallback((name: string, value: number | string | boolean) => {
setOverrides(prev => ({ ...prev, [name]: value }));
}, []);
// Group parameters by their / [Group] / annotations
const grouped = parameters.reduce((acc, param) => {
(acc[param.group] ??= []).push(param);
return acc;
}, {} as Record);
return (
{/ Your custom UI /}
{/ Playground with bindings /}
initialFiles={{
'main.scad':
/ [Dimensions] /
width = 20;
height = 10;
/ [Options] /
rounded = true;
cube([width, width, height], center=true);
}}
customizerValues={overrides}
onCustomizerValuesChange={setValues}
onParametersChange={setParameters}
initialState={{
view: {
layout: { mode: 'multi', editor: true, viewer: true, customizer: false }
}
}}
/>
);
}
`#### How It Works
1.
onParametersChange fires when the OpenSCAD file is parsed, providing the parameter schema with types, groups, and constraints
2. onCustomizerValuesChange fires whenever values change, providing the current state with full metadata
3. customizerValues accepts simple key-value pairs to override parameter values - changes trigger instant re-rendersThe OpenSCAD
/ [Group Name] / syntax is used to organize parameters into groups in your custom UI.$3
`tsx
import { OpenSCADPlayground, State } from 'openscad-playground';
import { useState } from 'react';function App() {
const [state, setState] = useState>({
params: {
activePath: 'main.scad',
sources: [
{ path: 'main.scad', content: 'cube([10,10,10]);' }
]
}
});
return (
initialState={state}
onStateChange={(newState) => {
setState(newState);
// Save to localStorage, database, etc.
}}
/>
);
}
`$3
`tsx
import { useOpenSCAD } from 'openscad-playground';function MyComponent() {
const { model, fs, isReady, error } = useOpenSCAD({
initialState: getInitialState()
});
if (!isReady) return
Loading...;
if (error) return Error: {error.message}; return
OpenSCAD is ready!;
}
``- Original OpenSCAD Playground by Olivier Chafik
- OpenSCAD project: openscad.org
- BOSL2 and other bundled libraries by their respective authors