Repository navigation
Releases
Skpwright 0.6.0
Skpwright 0.6.0 reads and writes every and all SketchUp releases from 3 to 2027!
The project was called OpenSKP up to 0.5.0.
Releases and formats
- Files of releases 3 to 8, 2013 to 2016 and 2018 to 2020 read whole through one grammar and write back byte for byte.
Model::write_aswrites a model as any release 3 to 2020, and returns notes on what the target release cannot hold. - Releases 2021 to 2025 are supported through the 2026 container, which gates on its model revision. Files written at revision 17 or 18 open in current SketchUp.
- Post-2017 features read into
Model.features: hatch patterns, layer folders, line styles, physically based materials, environments, the coordinate reference system, snaps and procedures. - A 2017 radial dimension that names no edge reads whole instead of falling back to the byte scan.
Renamed
- The crates are
skpwright,skpwright-cliandskpwright-capi. The command isskpwright, and the C library islibskpwright, with its headerinclude/skpwright.hand theskpwright_function prefix. The 0.5.0 and earlier versions stay on crates.io as theopenskpcrates.
Upgrading from 0.5
Document17isStreamDocumentand takes a release.Model::write_2017iswrite_as(path, Release::R2017).Container::Carchive2017isContainer::Stream, and the JSON reports"stream".Model,RenderingOptions,RadialDimensionandDiagnosticgain fields and variants, so struct literals that name every field and exhaustive matches must add them.
See the changelog for the full list.
skpwright = "0.6"OpenSKP 0.5.0
OpenSKP 0.5.0 writes SketchUp files: 2026 and 2017, authored from a model or edited in place.
Writing
Model::writeandModel::write_2017author either container from any model. SketchUp Make 2017 and SketchUp for Web open the results.Document(2026) andDocument17(2017) reproduce an unedited file byte for byte, and edit vertices, transforms, visibility and material colors in place.WriteEnvfixes the save time and seed, so the same input writes the same bytes, including on WebAssembly.
Reading
- 2017 files are read by a whole-file grammar. Every 2017 corpus file reproduces byte for byte from it.
- New on both containers: radial dimensions, 3D polylines, placed images, matched photos, sketchy edges, thumbnails, classifications, and attribute dictionaries on every object.
- A 2017 file with tens of thousands of entity lists no longer spends over a minute resolving them.
CLI and C ABI
openskpgainsconvert,verifyandcopy, with exit status 0, 1 for a file error, and 2 for a usage error. Install it withcargo install openskp-cli.- The C ABI gains
openskp_writeandopenskp_write_2017.
Upgrading from 0.4
Materialopacityis now one minus the stored transparency. 0.4 returned the stored value, so translucent materials read differently.- Public structs,
Materialvariants andDiagnosticgain fields and variants. Struct literals and exhaustive matches must add them; most types now implementDefault. - Guide, texture-size and attribute values are no longer rounded to five decimals.
- The CLI rejects unknown options and extra arguments.
openskp = "0.5"OpenSKP 0.4.1
A model can cut on a section plane without any scene recording it: each entity list keeps track of the plane currently cutting it. OpenSKP 0.4.1 reads that plane on both containers, so a consumer can tell the cutting plane from planes merely placed.
The active section plane
GeometryRun::active_sectionis the persistent id of the plane currently cutting that run's entity list, orNonewhen no plane is active. It names one of the run's ownsections. Seedocs/SDK.md.- 2026 container: every entity container records it (
0x1394, present only while a plane is active), so definitions report their own active plane. - 2017 format: the root tail's first pointer, null in every file without a cut, is a back-reference to the active plane's store-map slot (
docs/SKP_FORMAT.md§4). It is read for the root run; a definition's own active plane is not decoded on 2017 and readsNone. - The 2017 marker was isolated with a new minimal pair,
corpus/2017/section-plane-deactivated.skp: two planes whose records are byte-identical, the second one active. A section plane record carries no active flag.
Compatibility
GeometryRungains the public fieldactive_section. Code that only readsGeometryRunis unaffected; code that constructs it with a struct literal or destructures it exhaustively must add the field.- No other API, format, or dependency changes.
OpenSKP 0.4.0
OpenSKP reads the SketchUp 2026 container, the format every current SketchUp release saves, and treats it as the primary target. The 2017 format stays fully supported, and both readers produce the same Model.
SketchUp 2026 files
Model::parseopens 2026 files: a ZIP container whosemodel.datis a tree ofu16 tag | u32 length | payloadrecords, with XML materials beside their textures.docs/SKP_FORMAT.md§16 specifies it, decoded clean-room against 72 pairs of 2017 files and their 2026 saves.- Every 2017 corpus file has a 2026 twin, and each twin reads equivalent to its original in geometry, materials, layers, UVs, scenes, guides and document settings. The third-party benchmark meets its COLLADA oracle in both containers.
- A damaged record no longer fails the file. The reader keeps everything before the damage and records the loss as
Diagnostic::Skipped; record tags it does not know are reported instead of dropped. Buffers are reserved fallibly, so an oversized model returns an error instead of aborting. - One runtime dependency,
miniz_oxide, for DEFLATE.
Typed document settings
Camera, rendering options, shadows, units, styles and watermarks, fonts, texts, dimensions, axes, text and dimension defaults, animation and geo-location are typed fields on Model on both paths. Scenes carry their saved parts instead of names only. See docs/SDK.md.
The 2017 walk
- Production-scale models, up to a 464 MB furnished house, read on the continuous walk. A store-map slot shrank from 256 to 64 bytes, and map growth is fallible. An opt-in test (
OPENSKP_EXTERNAL_MODELS) checks local third-party files. - A mis-sized construction point or section plane could silently drop every root entity after it. Both bodies are now sized exactly, and the walk requires the root tail where the root list ends.
Breaking changes
ContainergainsZip, andModel::parsereturns a model for 2026 files instead of an error.Model::format_guidisModel::model_guid: Option<String>(JSON keymodel_guid);header_inforeturns an optional GUID.Model::scenesisVec<Scene>.- New public fields:
InstanceandPlacedInstancecarrypidandslot,GeometryRungainssections,Scenegainshidden_layers,Guidegainsdef_index.