Skip to content
| Marketplace
Sign in
Visual Studio Code>Visualization>3D Files PreviewNew to Visual Studio Code? Get it now.
3D Files Preview

3D Files Preview

Nir Adler

|
64 installs
| (0) | Free
CAD-style 3D preview for mesh files and OpenSCAD
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

3D Files Preview

VS Code Marketplace

VS Code extension for CAD-style 3D preview of mesh files and OpenSCAD.

Install from the VS Code Marketplace: niradler.3d-files-preview.

Install the companion agent skill:

npx skills add niradler/vscode-3d-preview --skill vscode-3d-preview

Open stl / obj / fbx / dae / 3ds / 3mf and you get a Z-up viewer with an XY print-bed grid. Open .scad and it stays a text editor; a side panel tessellates through the OpenSCAD CLI when you hit Render.

Not a fork of vscode-3dviewer. Same problem, CAD-oriented UI.

Features

  • Mesh files open in an editable 3D editor with dirty tracking, Save, Save As, revert, and recovery backups (Text Editor still available via Open With).
  • Restore Earlier Version… puts back any of the last 10 saves. Every save copies the bytes it is about to overwrite into VS Code's global storage for this extension, outside your workspace, so nothing appears next to the model and nothing reaches git. Available from the Command Palette and the explorer and editor context menus; the file must have no unsaved edits. The store keeps 10 versions per file and 200 MB overall, dropping the oldest first.
  • Edit ▾ and the part context menu offer duplicate, copy/paste, remove, split, plane/frame cut, merge, boolean operations, import, and STL/3MF export, plus Undo/Redo. Ctrl/Cmd/Shift-click selects multiple parts.
  • Numbers sets exact position, size, scale, and rotation. Move/Rotate/Scale gizmos use the selection's anchor; Base movement stays on the bed plane.
  • Save/Export STL flattens the model. Save/Export 3MF writes a minimal single-plate model; imported slicer settings and multi-plate metadata are not retained.
  • .scad stays text; Render Preview runs OpenSCAD once (no save/live rebuild)
  • OpenSCAD mouse: LMB orbit, RMB drag pan, scroll zoom
  • Click a part to select it; Fit, Front/Back, Left/Right, Top/Bottom and Iso use its bounds. Show bed returns to the current bed.
  • Bambu-style 3MF projects: named Bed selector, first bed by default, optional All beds overview. Explicit object/instance assignments are preserved; other slicer metadata dialects and painted filament colors are not yet supported.
  • Shading: Shaded / Edges / Wireframe; 3MF file colors on by default
  • Hover inspect: name, size (tooltip only while hovering)
  • Move / Rotate a part, then Drop to bed to sit it on Z = 0 (keeps XY)
  • Refresh re-tessellates .scad or reloads a mesh file. It stays in Actions ▾ unless the source is newer than the last tessellation, when it appears on the toolbar as Refresh (modified). Mesh previews still auto-reload when the file changes on disk.
  • Actions ▾ also includes Open with Bambu Lab and Open with Orca Slicer. Mesh previews open the current file; OpenSCAD previews open the last rendered STL. Explorer and editor context menus offer the same commands for mesh files.
  • Slice & Report slices the open model headlessly with Bambu Studio or OrcaSlicer and reports print time, filament weight and length, supports, per-plate and per-filament detail beside the 3D view. The source file is never touched and the output 3MF goes to a fresh temp path. Available from Actions ▾, the Command Palette, and the explorer and editor context menus.
    • Exit code is not the success condition: the result is accepted only when the output opens as a ZIP holding Metadata/slice_info.config and a non-empty Metadata/plate_<N>.gcode. A failed run reports the slicer's own log line, never an estimate.
    • An open slicer window is fine by default: both slicers ship with single instance off, and the extension reads that preference out of BambuStudio.conf / OrcaSlicer.conf instead of assuming. Only when a running slicer has single instance enabled would it take over the command line and write nothing, so that slicer is skipped up front. With cadPreview.slicer on auto the other installed slicer runs instead and the report says which one produced the numbers; when a slicer is pinned, or both are blocked this way, the run is refused with "close the slicer window and retry, or turn off single instance in its preferences".
    • A Bambu Studio run also shows Time by feature - outer wall, sparse infill, travel and the rest with their share of the print - taken from the result.json Bambu writes beside the archive. OrcaSlicer does not write one, so an Orca run leaves that section out instead of estimating it.
    • Estimates are labelled as slicer estimates and always carry the slicer, its version, the profile and every --key=value override that was passed.
  • Use Hide toolbar to collapse the top controls to one small Show toolbar button. The top Actions ▾ dropdown contains Add marker…, Copy dimensions…, Copy point…, Copy for chat…, Insert in SCAD…, Go to SCAD, Refresh, Open with Bambu Lab, Open with Orca Slicer, and Clear all markers and comments…. Refresh moves to the toolbar when the source is modified. SCAD actions appear when a linked source exists. Each picked location becomes a numbered Review marker. Clearing requires confirmation and applies across every bed, cancelling pending review questions.
  • Choose an action, then click a part or face. Copy dimensions… copies W × D × H. Arrow keys and Home/End navigate the menu; Esc closes it and Tab moves to the next toolbar control.
  • Go to SCAD jumps to // @id, module, or // @cad-pick (QuickPick when the mesh has no names)
  • Add marker… (Actions): click a face and save; comment text is optional. Every marker stores part, bed, local point and surface normal. Review docks beside the model, lists markers from all beds, and offers Show part, Edit, Move and Remove. Human and agent pointers share the same fixed screen-size marker system.
  • Agents can inspect parts, add markers, and ask a location-and-task question through the collaboration API. You confirm, pick another area, or cancel in the viewer.
  • The distributable vscode-3d-preview agent skill teaches this review flow and uses the optional VSCode Internals bridge when installed.
  • Comments are scoped to the open preview session. Reloading keeps earlier notes as stale; closing the preview ends the session.

Requirements

  • VS Code 1.85+
  • Node 22+ (to build)
  • OpenSCAD on PATH, or set cadPreview.openscadPath (default: C:\Program Files\OpenSCAD\openscad.exe)

[!NOTE] OpenSCAD 2021 writes STL. STL has no part names and no color, so a .scad preview is gray and Go to SCAD falls back to QuickPick. Named jump and file colors work on examples/colors.3mf (same basename as examples/colors.scad). Mark modules with // @id name so a click can land on the right line.

Run from source

npm ci
npm test
npm run typecheck
npm run compile

Press F5 (Run Extension). In the Extension Development Host:

  1. Open examples/colors.3mf - red / green / blue parts, file materials on
  2. Choose Actions ▾ → Go to SCAD, then click a colored part to jump to examples/colors.scad
  3. Choose Actions ▾ → Copy dimensions…, then click a part to copy W × D × H mm. Actions ▾ → Copy for chat… → crosshair → click a face
  4. Open examples/colors.scad → right-click Render Preview (or the title-bar preview icon)

Command Palette: CAD Preview: Render Current File. Explorer and editor context menus also have Render Preview.

Settings

Setting Default Purpose
cadPreview.openscadPath C:\Program Files\OpenSCAD\openscad.exe OpenSCAD executable used to tessellate .scad files
cadPreview.bambuStudioPath C:\Program Files\Bambu Studio\bambu-studio.exe Bambu Studio executable used by Open with Bambu Lab and Slice & Report
cadPreview.orcaSlicerPath C:\Program Files\OrcaSlicer\orca-slicer.exe Orca Slicer executable. Leave unset to use Program Files, LocalAppData, or a Microsoft Store install
cadPreview.slicer auto Which slicer Slice & Report uses: auto (first one installed), bambu, or orca
cadPreview.sliceTimeoutSeconds 180 How long to wait for the slice. Raise it for large or dense models; the report says when it was hit
cadPreview.slicePlate 0 Plate to slice. 0 slices every plate
cadPreview.slicePrinter "" Printer preset name as the slicer shows it, e.g. Bambu Lab P1S 0.4 nozzle. Empty uses the slicer's last used printer
cadPreview.sliceProcess "" Process preset name, e.g. 0.20mm Standard @BBL X1C. Empty picks a compatible one and names it in the report
cadPreview.sliceFilament "" Filament preset name, e.g. Bambu PLA Basic @BBL X1C. Empty picks a compatible one and names it in the report
cadPreview.sliceSettingsPresets [] Flattened printer and process preset JSON files passed with --load-settings. Set only to override the three names above
cadPreview.sliceFilamentPresets [] Filament preset JSON files passed with --load-filaments
cadPreview.sliceOverrides {} Settings passed as --key=value. Every one is listed in the report
cadPreview.sliceOutputDirectory "" Where the sliced 3MF is written. Empty uses a fresh temp folder; never the model's own folder
cadPreview.defaultShading edges Shading a preview opens with: shaded, edges or wireframe
cadPreview.autoReloadMesh true Reload a mesh preview when the file changes. Off shows a Refresh (modified) button instead

Spawn is always argv (never a shell string). Working directory is the model file’s folder, or the output folder for a headless slice.

[!NOTE] A slicer CLI needs a complete profile, and its defaults are not one. Slice & Report builds one for you: it reads the slicer's own installed system presets, resolves the inherits chain into standalone JSON ("from": "system", a process preset whose compatible_printers names the printer), and writes the pair to a temp folder. Every preset it picked is named in the report, so nothing changes silently. Set cadPreview.slicePrinter / sliceProcess / sliceFilament to pin the choice, or cadPreview.sliceSettingsPresets / sliceFilamentPresets to supply your own flattened files. A .3mf that carries Metadata/project_settings.config is sliced with its own settings and gets no injected preset. cadPreview.sliceOverrides only works for options the slicer registers as command line options - OrcaSlicer 2.4 rejects print settings passed this way (Invalid option --enable_support), so set those in a preset instead.

Examples

File What it shows
examples/cube.stl / examples/cube.scad Centered 20 mm cube
examples/colors.3mf / examples/colors.scad Named colored parts + SCAD jump
examples/bad.scad OpenSCAD error overlay

Development

Node 22+ is the only prerequisite for building and testing. OpenSCAD and a slicer are needed to exercise those features, not to compile or to get a green test run.

npm ci
npm run typecheck    # tsc --noEmit
npm test             # vitest run
npm run lint         # eslint src
npm run check:layers # import-layer guard
npm run check:ids    # webview element id guard
npm run compile      # vite build && node esbuild.mjs

Press F5 (Run Extension) to launch an Extension Development Host with the built bundles. npm run watch rebuilds the extension bundle; npm run watch:webview rebuilds the webview bundle. Both are needed while changing both halves.

Repo layout

src/ is layered, and each layer may import only from itself and the ones above it. npm run check:layers enforces this.

Path Contents
src/core/ Pure data and math. No three, no vscode, no node: specifiers. Holds the message protocol and the PreviewHost type
src/ops/ Stateless geometry over three: transform, boolean, cut, merge, shells, contact, export
src/scene/ The stateful three scene: graph, lights, grid, shading, picking, loaders, markers
src/app/ Controllers holding session state: edit session and undo, edit panel, review, slice panel
src/ui/ React 19 components, and the vendored shadcn/ui primitives under components/ui/
src/webview/ viewer.ts and viewer.css, the glue that owns the canvas and the message loop
src/platform/node/ Child processes and the filesystem: OpenSCAD, the slicers, preset stores
src/hosts/vscode/ The only layer that may import vscode, and the only place postMessage lives

Tests sit next to the code as *.test.ts (node environment) and *.test.tsx (jsdom). Relative imports of TypeScript files carry a .js suffix; the wrong suffix typechecks and fails at runtime.

docs/architecture.md explains the layers, the PreviewHost seam and the two-bundler build. Agent notes and locked product decisions live in AGENTS.md.

Coverage

npm run coverage measures with @vitest/coverage-v8. There is no threshold gate. As of this writing, 49 test files and 472 tests give 58.9% statement coverage overall, concentrated where a gap would be silent:

Layer Statements
ops/ 94.5%
core/ 87.5%
ui/ 81.8%
webview/ 65.9%
platform/node/ 60.9%
app/ 38.9%
hosts/vscode/ 35.4%
scene/ 31.7%

The low layers are the ones that need a live VS Code or a WebGL context to mean anything, so their number is not the interesting one. A gate, if one is ever added, belongs on core/ and ops/ only.

Third-party licences

This extension is MIT. The webview dependency tree added for the React UI:

Package Version Licence
react 19.3.0 MIT
react-dom 19.3.0 MIT
tailwindcss, @tailwindcss/vite 4.3.3 MIT
@radix-ui/react-* 1.x / 2.x MIT
lucide-react 0.544.0 ISC
vite 8.3.0 MIT
@vitejs/plugin-react 6.1.1 MIT
class-variance-authority 0.7.1 Apache-2.0
clsx 2.1.1 MIT
tailwind-merge 3.7.0 MIT

The shadcn/ui components under src/ui/components/ui/ are vendored source, not a dependency. They are MIT and carry their provenance in-repo, which is how the shadcn model is meant to work.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft