npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openskp

v1.1.0

Published

Open-source SketchUp (.skp) binary file parser and writer — extract geometry, metadata, layers, and materials; create and edit .skp files; export to GLB, OBJ, STL, PLY, DXF, and IFC4. Works in browser and Node.js.

Readme

OpenSKP

The open-source SketchUp (.skp) file parser — TypeScript / JavaScript edition.

Parse .skp files without SketchUp. No SDK. No license. Zero native dependencies — fflate handles ZIP extraction and a ported earcut handles triangulation, so it runs anywhere JavaScript does: Node.js or the browser.

License: MIT npm Node

🏠 openskp.com · 🌐 Try the Live Web Viewer · 📖 Docs · Changelog

[!IMPORTANT] This project was built by reverse engineering a proprietary binary format. It is not affiliated with or endorsed by Trimble Inc. or SketchUp.

What is OpenSKP?

OpenSKP is the first and only open-source, cross-platform parser for SketchUp binary files — reverse-engineered from both the modern VFF container (SketchUp 2021+) and the classic MFC CArchive container (SketchUp 2013–2020). It gives you full programmatic access to geometry, materials, components, layers, and metadata, with no SketchUp installation and no proprietary SDK required. The same parser and export API also ship as first-class packages for Python, .NET, Dart, and C++ — see the project README for the full cross-language picture.

This package can also write new .skp files from scratch, and edit existing ones, validated feature-by-feature against the real SketchUp SDK (see Writing below).

Features

  • Full-fidelity parsing — vertices, edges, faces, normals, UV coordinates, nested component hierarchies, layers/tags, materials, textures, styles, and dynamic-component attributes.
  • Both SketchUp file generations — modern VFF (2021+) and legacy MFC (2013–2020) containers, transparently, behind one parseSkp()/.parse() call.
  • Scene baking — an opt-in buildScene() pass resolves the full placed scene graph to world-space, triangulated, export-ready geometry.
  • Native multi-format export — glTF (GLB), Wavefront OBJ/MTL, STL, PLY, AutoCAD DXF (3DFACE and Polyface Mesh), IFC4 (BIM/ISO 10303-21 STEP), and JSON — all written from scratch, no third-party CAD/BIM SDK involved. The DXF writer is verified against real desktop AutoCAD, not just lenient DXF readers.
  • Runs anywhere JavaScript does — zero native dependencies, works in Node.js and directly in the browser from a File/Blob.
  • Structured observability — opt-in progress reporting and structured, location-carrying parse errors.
  • Write support — build new legacy-format .skp files from scratch: geometry (including true, editable circular/arc curves, freeform polylines, faces with holes cut out, and non-planar auto-triangulation), materials (solid + PNG/JPEG textures), layers, nested component definitions and groups, instance rotation/visibility, and custom attribute dictionaries — or load and extend an existing file with openExisting(). No SDK involved; every feature validated against the real SketchUp SDK. See Writing below.

Installation

npm install openskp

Quick Start

import { SkpFile } from 'openskp';

// Node.js
const skp = SkpFile.open('model.skp');
const model = skp.parse();

// Browser: parse from a File/Blob's ArrayBuffer
import { parseSkp } from 'openskp';
const buffer = await file.arrayBuffer();
const model2 = parseSkp(buffer);

console.log(model.version, model.layers.length, 'layers');

// Inspect definitions (component geometry) - model.definitions is a Map
for (const [id, defn] of model.definitions) {
  console.log(`${defn.name}: ${defn.faces.length} faces, ${defn.vertices.length} vertices`);
}

// model.root holds whatever is placed directly in the model, not inside
// any component/group
console.log(model.root.instances.length, 'root-level instances');

// Opt-in: full placed scene graph, triangulated, world-space, GLB-ready
const scene = skp.buildScene();
console.log(scene.glbPrimitives.length, 'renderable mesh primitives');

Exporting

import { toGLB, toOBJ, toMTL, exportOBJ, toSTLAscii, toSTLBinary, exportSTL, toPLYAscii, toPLYBinary, exportPLY, toDXF, exportDXF, toIFC, exportIFC, toJSON } from 'openskp';

// Serialize a built scene straight to .glb bytes (in-memory, no disk I/O)
const glbBytes = toGLB(scene);

// Export to Wavefront OBJ string, plus a companion .mtl material library
const objText = toOBJ(scene, 'output.mtl');
const mtlText = toMTL(scene);

// Node.js only: writes both output.obj and output.mtl together
exportOBJ(scene, 'output.obj');

// Export to STL ASCII or Binary string/buffer
const stlText = toSTLAscii(scene);
const stlBytes = toSTLBinary(scene);

// Export to PLY ASCII or Binary string/buffer
const plyText = toPLYAscii(scene);
const plyBytes = toPLYBinary(scene);

// Export to AutoCAD 3D DXF text format (R2000 / AC1015 compliant)
const dxfText = toDXF(scene);

// Node.js only: export directly to a .dxf file
exportDXF(scene, 'output.dxf');

// Export to IFC4 / BIM (ISO 10303-21 STEP format string / file)
const ifcText = toIFC(scene);
exportIFC(scene, 'output.ifc');

// Full metadata as a JSON-compatible object
const meta = toJSON(model, scene);

Writing

OpenSKP can also create new .skp files from scratch — a genuine, from-scratch binary writer for the legacy MFC CArchive format (SketchUp 2013–2020), with no SketchUp SDK involved at any point. Ports the same feature set as the Python package's writer, verified byte-identical to Python's own output on the same input: geometry, materials (solid + PNG/JPEG textures), layers (with color and default visibility), component definitions with multiple instances, groups, nested definitions and nested group instances, per-instance rotation and visibility, explicit per-side texture positioning, custom key/value attribute dictionaries, circular faces and partial arcs, freeform polyline curves, faces with holes cut out, and non-planar auto-triangulation. openExisting() loads an existing legacy-format file and rebuilds it as a new builder, so more geometry can be added before saving. See src/create.ts for the full scope notes.

import { create } from 'openskp';

const builder = create();

// Materials and layers
const red = builder.addMaterial('Red', [255, 0, 0]);
const brick = builder.addTextureMaterial('Brick', brickPngBytes);
const roofLayer = builder.addLayer('Roof', { color: [180, 60, 40] });

// All addComponentDefinition/addGroup calls must come before any
// addInstance/addFace call - placing anything locks in the file's
// internal slot numbering for everything after it
const chair = builder.addComponentDefinition('Chair', (def) => {
  def.addFace([[0, 0, 0], [20, 0, 0], [20, 20, 0], [0, 20, 0]]);
});
builder.addInstance(chair, { translation: [50, 0, 0] });
builder.addInstance(chair, { translation: [100, 0, 0], hidden: true });

builder.addFace(
  [[0, 0, 0], [100, 0, 0], [100, 100, 0], [0, 100, 0]],
  { material: red, layer: roofLayer }
);

builder.save('output.skp');   // Node.js only; use builder.toBytes() in the browser

Editing an existing file

import { openExisting } from 'openskp';

const { builder, warnings, definitions } = openExisting('building.skp');
for (const w of warnings) console.log('not fully reproduced:', w);

builder.addCircle([0, 0, 100], [0, 0, 1], 50);
builder.save('building_edited.skp');

warnings is the honest account of what couldn't be faithfully reproduced from that specific source file. Every material/layer the source had is reachable on builder.materialsByName/builder.layersByName without a separate lookup, and definitions maps each replayed component definition's own name to its builder for placing more instances of something the source already defined.

Observability

parse()/buildScene() accept an optional options object for progress reporting and structured errors — silent by default:

const model = skp.parse({
  onProgress: (info) => console.log(`${info.stage}: ${info.current}/${info.total}`),
  onLog: (level, message) => console.log(`[${level}] ${message}`),
});

Parse failures throw SkpParseError, carrying stage, recordIndex, totalRecords, tag, and definitionId context, with the original error preserved as .cause. See docs/OBSERVABILITY.md for the full cross-language reference.

Known limitation: large files

Memory use scales worse than the other four ports on very large files — a 113 MB file needs 8–16 GB of Node heap, and files beyond ~150-200 MB may not parse in a browser tab at all (a typical tab's heap ceiling is ~4 GB). Root cause: V8's per-object overhead on millions of small geometry objects. See docs/DEVELOPER_GUIDE.md for verified numbers before parsing very large files in this package.

Package Structure

| Module | Purpose | |---|---| | parser.ts | TLV binary parser for SketchUp's internal format | | model.ts | Interfaces for geometry, layers, materials, scenes | | legacy.ts | Legacy MFC container support (SketchUp 2013–2020) | | vff.ts | VFF/ZIP container handling (fflate-based) | | triangulator.ts | Planar polygon triangulation (ported earcut) | | transforms.ts | 3D matrix transforms and coordinate conversions | | observability.ts | Progress/log callback types | | errors.ts | SkpParseError and structured failure context | | index.ts | Public entry point — SkpFile, parseSkp, buildScene, toGLB, toJSON |

Requirements

Node.js ≥ 16, or any modern browser. No native dependencies.

Used in Production

OpenSKP powers the SketchUp import pipeline for FrameSmart (a 3D collaboration platform with nearly 200 active users) and IngeTrazo (a SketchUp-alternative 3D modeler with a BIM → IFC bridge). Using OpenSKP in your own project? Open an issue or a PR to get added here.

Contributing

The Python package in ../python/ and this package are both full, independent implementations at parity — neither is a stub for the other. See CONTRIBUTING.md for guidelines.

License

MIT — see LICENSE