{"_id":"openskp","_rev":"8-7533d6059d168c926551dd70cbaaf32d","name":"openskp","dist-tags":{"latest":"1.3.0"},"versions":{"0.1.0":{"name":"openskp","version":"0.1.0","keywords":["sketchup","skp","3d","parser","glb","gltf","bim","cad","geometry","three.js","webgl"],"author":{"name":"Ahsan Mehmood"},"license":"MIT","_id":"openskp@0.1.0","maintainers":[{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"}],"homepage":"https://github.com/iamahsanmehmood/openskp","bugs":{"url":"https://github.com/iamahsanmehmood/openskp/issues"},"dist":{"shasum":"4ec320aa8241dfefba53945a74f4122bad7dc610","tarball":"https://registry.npmjs.org/openskp/-/openskp-0.1.0.tgz","fileCount":6,"integrity":"sha512-zw5UGTRu9z+RtJIiHzKhn+J+MR6qqFU+I92nd+WcTTMx5sLLnvNZNrUgMy9qe6j1QSvmd/Az//icfGK1edktrA==","signatures":[{"sig":"MEYCIQDcbT557uCREtg4+0TupnvYCoH4Lu/lGKyU5/cy1zP+ZAIhAMFgukUuIzKqbHOipCSwbB8XvkSclnIv/8r4o3s6XSj3","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":87790},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"c9fe27d96247d9d45f716591fa1849503610159f","scripts":{"lint":"eslint src/","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","copy-dist":"node copy-dist.js","typecheck":"tsc --noEmit"},"_npmUser":{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"},"repository":{"url":"git+https://github.com/iamahsanmehmood/openskp.git","type":"git","directory":"packages/typescript"},"_npmVersion":"10.8.2","description":"Open-source SketchUp (.skp) binary file parser — extract geometry, metadata, layers, and materials. Works in browser and Node.js.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"earcut":"^3.0.0","fflate":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^1.0.0","typescript":"^5.3.0","@types/earcut":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/openskp_0.1.0_1781767481245_0.5815315597342883","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"openskp","version":"0.2.0","keywords":["sketchup","skp","3d","parser","glb","gltf","bim","cad","geometry","three.js","webgl"],"author":{"name":"Ahsan Mehmood"},"license":"MIT","_id":"openskp@0.2.0","maintainers":[{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"}],"homepage":"https://github.com/iamahsanmehmood/openskp","bugs":{"url":"https://github.com/iamahsanmehmood/openskp/issues"},"dist":{"shasum":"7728b8ec243962fa8b8b7a855b565757d90bcf16","tarball":"https://registry.npmjs.org/openskp/-/openskp-0.2.0.tgz","fileCount":6,"integrity":"sha512-y5zOXAQRt4kSSgDXbftsg8lLhEhMqdHTz3eXjZxhskV/jTRkA1GlT5ZY5d04HLzd8xbZXVGbPFcjnkLjlGgeZg==","signatures":[{"sig":"MEUCIQCJiqPgHXPg90Mhsy9GEaFUe8dSmyP7XtDbJXf8iU0KDQIgDo1m+kbpPLs07po/HIUJwykOpEzaYWaQpxCSsiIfCVQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":94986},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"b09497d2c8698ecb4cd4d2b6224cab992c33080a","scripts":{"lint":"eslint src/","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","copy-dist":"node copy-dist.js","typecheck":"tsc --noEmit"},"_npmUser":{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"},"repository":{"url":"git+https://github.com/iamahsanmehmood/openskp.git","type":"git","directory":"packages/typescript"},"_npmVersion":"10.8.2","description":"Open-source SketchUp (.skp) binary file parser — extract geometry, metadata, layers, and materials. Works in browser and Node.js.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"earcut":"^3.0.0","fflate":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^1.0.0","typescript":"^5.3.0","@types/earcut":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/openskp_0.2.0_1781779089475_0.43732027536807005","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"openskp","version":"0.3.0","keywords":["sketchup","skp","3d","parser","glb","gltf","bim","cad","geometry","three.js","webgl"],"author":{"name":"Ahsan Mehmood"},"license":"MIT","_id":"openskp@0.3.0","maintainers":[{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"}],"homepage":"https://github.com/iamahsanmehmood/openskp","bugs":{"url":"https://github.com/iamahsanmehmood/openskp/issues"},"dist":{"shasum":"e5c9321448076623dba0e43cb23c1f388760b8df","tarball":"https://registry.npmjs.org/openskp/-/openskp-0.3.0.tgz","fileCount":6,"integrity":"sha512-H3no/Tp//urrwL59rgBC4GGl/jT9AwxTyW7IfuycZ0v9DUKecfpREwIJaYdE5coMGFICLDp82vxRMlnoqjjpYQ==","signatures":[{"sig":"MEUCIQCfC9xguL0FgYpqRVNCb/LtKlfgg+KGx0BfVW2fx/demAIgVVInOgv3TfDlWnqTRrLH52EfcP+uE57WO5dFa1DAznA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":209626},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"3b3228e23f14838f4ba905761f7efbd9a9812487","scripts":{"lint":"eslint src/","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","copy-dist":"node copy-dist.js","typecheck":"tsc --noEmit"},"_npmUser":{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"},"repository":{"url":"git+https://github.com/iamahsanmehmood/openskp.git","type":"git","directory":"packages/typescript"},"_npmVersion":"10.8.2","description":"Open-source SketchUp (.skp) binary file parser — extract geometry, metadata, layers, and materials. Works in browser and Node.js.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"earcut":"^3.0.0","fflate":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^1.0.0","typescript":"^5.3.0","@types/earcut":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/openskp_0.3.0_1785385866359_0.40067096571966876","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"openskp","version":"0.3.1","keywords":["sketchup","skp","3d","parser","glb","gltf","bim","cad","geometry","three.js","webgl"],"author":{"name":"Ahsan Mehmood"},"license":"MIT","_id":"openskp@0.3.1","maintainers":[{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"}],"homepage":"https://github.com/iamahsanmehmood/openskp","bugs":{"url":"https://github.com/iamahsanmehmood/openskp/issues"},"dist":{"shasum":"fc264477f4975d29a2a07da6b0f8ab7144eea107","tarball":"https://registry.npmjs.org/openskp/-/openskp-0.3.1.tgz","fileCount":6,"integrity":"sha512-dA/pAfJrm7l6pw93paxiPN7bzTp91eX9WXBUtaF782byCUUL3QZmFxcC5OJuur6I0CE4iL35d89SCNxoGKmdcg==","signatures":[{"sig":"MEYCIQCSfKRslUOHc3XMMs0JRKhFwYKHHGRNbePiGtPIgoxygQIhAOluIB3PK4JfLoKv+C/R/TQZQMANrCStX4YTGRlyFWhP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":212294},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"c3f91b66f613a59a60027b261d62ab6f67bf0ffb","scripts":{"lint":"eslint src/","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","copy-dist":"node copy-dist.js","typecheck":"tsc --noEmit"},"_npmUser":{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"},"repository":{"url":"git+https://github.com/iamahsanmehmood/openskp.git","type":"git","directory":"packages/typescript"},"_npmVersion":"10.8.2","description":"Open-source SketchUp (.skp) binary file parser — extract geometry, metadata, layers, and materials. Works in browser and Node.js.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"earcut":"^3.0.0","fflate":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","vitest":"^1.0.0","typescript":"^5.3.0","@types/earcut":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/openskp_0.3.1_1785386987747_0.14619107677396337","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"openskp","version":"1.0.0","keywords":["sketchup","skp","3d","parser","glb","gltf","bim","cad","geometry","three.js","webgl","dxf","autocad","ifc","obj","stl","ply"],"author":{"name":"Ahsan Mehmood"},"license":"MIT","_id":"openskp@1.0.0","maintainers":[{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"}],"homepage":"https://openskp.com","bugs":{"url":"https://github.com/iamahsanmehmood/openskp/issues"},"dist":{"shasum":"15ebc5d8a30a04be5c829051fecf970d2b37fcc4","tarball":"https://registry.npmjs.org/openskp/-/openskp-1.0.0.tgz","fileCount":6,"integrity":"sha512-aTKJ1M9AUXrC5B1SPwDXMEepVWlsDIPd5eU+R+sqgAa2cyEOd2E00ytdip6zj9N4NI6ipwprEvMVS2ru8q0PEA==","signatures":[{"sig":"MEUCIFHjT8HwDe/Th1DGD3fjQKZuJYmyoAbLdYwWX3NL04qXAiEAqFJtZHSGOtcH9TEm/GYyt0uH7cgrA3e+VO7OIfOxxKU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":390238},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"318eb474096ea3dd02bb16cc6c2cb3f56e597fc0","scripts":{"lint":"eslint src/","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","copy-dist":"node copy-dist.js","typecheck":"tsc --noEmit"},"_npmUser":{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"},"repository":{"url":"git+https://github.com/iamahsanmehmood/openskp.git","type":"git","directory":"packages/typescript"},"_npmVersion":"10.8.2","description":"Open-source SketchUp (.skp) binary file parser — extract geometry, metadata, layers, and materials; export to GLB, OBJ, STL, PLY, DXF, and IFC4. Works in browser and Node.js.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"earcut":"^3.0.0","fflate":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"9.39.5","vitest":"^1.0.0","@eslint/js":"9.39.5","typescript":"^5.3.0","@types/earcut":"^2.1.0","typescript-eslint":"8.67.0"},"_npmOperationalInternal":{"tmp":"tmp/openskp_1.0.0_1786595256110_0.2911917970703559","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"openskp","version":"1.1.0","keywords":["sketchup","skp","3d","parser","glb","gltf","bim","cad","geometry","three.js","webgl","dxf","autocad","ifc","obj","stl","ply"],"author":{"name":"Ahsan Mehmood"},"license":"MIT","_id":"openskp@1.1.0","maintainers":[{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"}],"homepage":"https://openskp.com","bugs":{"url":"https://github.com/iamahsanmehmood/openskp/issues"},"dist":{"shasum":"ee7b785eeb5435ee649619e52257f796a66507ff","tarball":"https://registry.npmjs.org/openskp/-/openskp-1.1.0.tgz","fileCount":6,"integrity":"sha512-eOgyv8m199T1hgK36UeCfwEfRFjsEfrZ6fp2HV5mgyqMZGeNhhE800q8skP4l5RFnQPBd0xEaZcmB3ipDowo+g==","signatures":[{"sig":"MEYCIQCbZhQWJ8PFSvvtlcH4sQAXXO2YHIV1cnjgv0/cCRozZwIhAJV/likd66CaTvmKJx7NR8jsJGsC0wIw3Abqx6D6znXW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":610507},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"b8da666cb875ad9123457666bf6f1b1883da2bb3","scripts":{"lint":"eslint src/","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","copy-dist":"node copy-dist.js","typecheck":"tsc --noEmit"},"_npmUser":{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"},"overrides":{"postcss":"8.5.23"},"repository":{"url":"git+https://github.com/iamahsanmehmood/openskp.git","type":"git","directory":"packages/typescript"},"_npmVersion":"10.8.2","description":"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.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"earcut":"^3.0.0","fflate":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"10.8.1","vitest":"^1.0.0","@eslint/js":"10.0.1","typescript":"^5.3.0","@types/earcut":"^3.0.0","typescript-eslint":"8.67.0"},"_npmOperationalInternal":{"tmp":"tmp/openskp_1.1.0_1787208549387_0.03026795959320583","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"openskp","version":"1.2.0","keywords":["sketchup","skp","3d","parser","writer","converter","conversion","glb","gltf","bim","cad","geometry","three.js","webgl","dxf","autocad","ifc","obj","stl","ply"],"author":{"name":"Ahsan Mehmood"},"license":"MIT","_id":"openskp@1.2.0","maintainers":[{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"}],"homepage":"https://openskp.com","bugs":{"url":"https://github.com/iamahsanmehmood/openskp/issues"},"dist":{"shasum":"63580cd5cb815733270c71709216da6d1b2c5456","tarball":"https://registry.npmjs.org/openskp/-/openskp-1.2.0.tgz","fileCount":6,"integrity":"sha512-TrmpVvYrTrqySxitW4XVx13ij17z2k6ppwk7Fk1Z8RdEOU8TsfOWTPBuz/1C3t3LKLVKl9hnJqhw8GCpnEjG8A==","signatures":[{"sig":"MEYCIQDrXjJq2nSBuT9rjlVHS0HT152+eLbUPlS4TelRjCbiagIhAJrBLY4YBH1UURQCev224egYTet29aJERcDgVcIH1YeZ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIASn7fDhOjXBL/5JApgzcjm9Rr9VpAUhhH2E53wzl2Z0AiEA9AbyDjVqCPqZwaSd5z9B1A6CxPo1Jh099NmhdHnv1Vs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":826257},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"42044f3afb4e1c6ab31c2ea9a14d8ecd709b81d9","scripts":{"lint":"eslint src/","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","copy-dist":"node copy-dist.js","typecheck":"tsc --noEmit","bench:instanced":"vite-node tests/bench/instanced-bench.ts","bench:vertex-store":"node --expose-gc ./node_modules/vite-node/dist/cli.mjs tests/bench/vertex-store-bench.ts"},"_npmUser":{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"},"overrides":{"postcss":"8.5.23"},"repository":{"url":"git+https://github.com/iamahsanmehmood/openskp.git","type":"git","directory":"packages/typescript"},"_npmVersion":"10.8.2","description":"Open-source SketchUp (.skp) binary file parser, writer, and converter — extract geometry, metadata, layers, and materials; create and edit .skp files; convert to GLB, OBJ, STL, PLY, DXF, and IFC4. Works in browser and Node.js.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"earcut":"^3.0.0","fflate":"^0.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","eslint":"10.9.1","vitest":"^3.2.7","vite-node":"^6.0.0","@eslint/js":"10.0.1","typescript":"^5.3.0","@types/earcut":"^3.0.0","typescript-eslint":"8.68.0"},"_npmOperationalInternal":{"tmp":"tmp/openskp_1.2.0_1788517997151_0.885370239657566","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"_id":"openskp@1.3.0","bugs":{"url":"https://github.com/iamahsanmehmood/openskp/issues"},"dist":{"shasum":"1111b7481ab86941cb350086208790ae4f8553f4","tarball":"https://registry.npmjs.org/openskp/-/openskp-1.3.0.tgz","fileCount":6,"integrity":"sha512-YSQPGVzBOSEbAgIWA+oOUMyKzcuUCLoDzRis8sF7VPa2SM9PcZyt11YyRH84VDOSSL8TPtqJaEAF12wFNkxAWw==","signatures":[{"sig":"MEUCIQC3ueoN78YzFtERMOmJ3OoQFhXONZ3JoG6AEhAM5mOnaQIgZMfgHQ5dAtuhiz5dl3uTU+X1vwb2PaRG1WG4xO9S7NM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDpiEp/tzQwOeo6F38whUgbjdWTqDfJLYkY5H1iXZVurgIgWXb8Q8PSPXl5jnoXPyWdoLbS1b4cNvUHv9lhTJlGz40="}],"unpackedSize":1069326},"main":"dist/index.js","name":"openskp","types":"dist/index.d.ts","author":{"name":"Ahsan Mehmood"},"module":"dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"e8b5af690e9759bf5569aca6ad2fd2296933c0a6","license":"MIT","scripts":{"lint":"eslint src/","test":"vitest run","build":"tsup src/index.ts --format cjs,esm --dts","copy-dist":"node copy-dist.js","typecheck":"tsc --noEmit","bench:instanced":"vite-node tests/bench/instanced-bench.ts","bench:vertex-store":"node --expose-gc ./node_modules/vite-node/dist/cli.mjs tests/bench/vertex-store-bench.ts"},"version":"1.3.0","_npmUser":{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"},"homepage":"https://openskp.com","keywords":["sketchup","skp","3d","parser","writer","converter","conversion","glb","gltf","bim","cad","geometry","three.js","webgl","dxf","autocad","ifc","obj","stl","ply"],"overrides":{"esbuild":"^0.28.1","postcss":"8.5.23"},"repository":{"url":"git+https://github.com/iamahsanmehmood/openskp.git","type":"git","directory":"packages/typescript"},"_npmVersion":"10.8.2","description":"Open-source SketchUp (.skp) binary file parser, writer, and converter — extract geometry, metadata, layers, and materials; create and edit .skp files; convert to GLB, OBJ, STL, PLY, DXF, and IFC4. Works in browser and Node.js.","directories":{},"maintainers":[{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"}],"_nodeVersion":"20.20.2","dependencies":{"earcut":"^3.0.0","fflate":"^0.8.0","flatbuffers":"^25.9.23"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.0","three":"^0.186.0","eslint":"10.10.0","vitest":"^4.1.11","web-ifc":"^0.0.77","vite-node":"^6.0.0","@eslint/js":"10.0.1","typescript":"^5.3.0","@types/earcut":"^3.0.0","typescript-eslint":"8.70.0","@thatopen/fragments":"^3.4.7"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/openskp_1.3.0_1789710535033_0.08891446763481503"}}},"time":{"created":"2026-06-18T07:24:41.177Z","modified":"2026-09-18T05:48:55.321Z","0.1.0":"2026-06-18T07:24:41.391Z","0.2.0":"2026-06-18T10:38:09.610Z","0.3.0":"2026-07-30T04:31:06.493Z","0.3.1":"2026-07-30T04:49:47.915Z","1.0.0":"2026-08-13T04:27:36.262Z","1.1.0":"2026-08-20T06:49:09.538Z","1.2.0":"2026-09-04T10:33:17.235Z","1.3.0":"2026-09-18T05:48:55.168Z"},"bugs":{"url":"https://github.com/iamahsanmehmood/openskp/issues"},"author":{"name":"Ahsan Mehmood"},"license":"MIT","homepage":"https://openskp.com","keywords":["sketchup","skp","3d","parser","writer","converter","conversion","glb","gltf","bim","cad","geometry","three.js","webgl","dxf","autocad","ifc","obj","stl","ply"],"repository":{"url":"git+https://github.com/iamahsanmehmood/openskp.git","type":"git","directory":"packages/typescript"},"description":"Open-source SketchUp (.skp) binary file parser, writer, and converter — extract geometry, metadata, layers, and materials; create and edit .skp files; convert to GLB, OBJ, STL, PLY, DXF, and IFC4. Works in browser and Node.js.","maintainers":[{"name":"iamahsanmehmood","email":"mail.ahsanmehmood@gmail.com"}],"readme":"# OpenSKP\n\n**The open-source SketchUp (`.skp`) file parser, writer, and converter — TypeScript / JavaScript edition.**\n\nParse, write, and convert `.skp` files without SketchUp. No SDK. No\nlicense. Zero native dependencies — `fflate` handles ZIP extraction and a\nported `earcut` handles triangulation, so it runs anywhere JavaScript\ndoes: Node.js or the browser.\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![npm](https://img.shields.io/npm/v/openskp.svg?logo=npm&logoColor=white)](https://www.npmjs.com/package/openskp)\n[![Node](https://img.shields.io/node/v/openskp.svg?logo=node.js&logoColor=white)](https://www.npmjs.com/package/openskp)\n\n🏠 [openskp.com](https://openskp.com) · 🌐 [Try the Live Web Viewer](https://iamahsanmehmood.github.io/openskp/) · 📖 [Docs](https://iamahsanmehmood.github.io/openskp/docs/) · [Changelog](https://github.com/iamahsanmehmood/openskp/blob/main/CHANGELOG.md)\n\n> [!IMPORTANT]\n> This project was built by reverse engineering a proprietary binary format. It is not affiliated with or endorsed by Trimble Inc. or SketchUp.\n\n## What is OpenSKP?\n\nOpenSKP is the first and only open-source, cross-platform parser for\nSketchUp binary files — reverse-engineered from both the modern **VFF\ncontainer** (SketchUp 2021+) and the classic **MFC `CArchive`** container\n(SketchUp 2013–2020). It gives you full programmatic access to geometry,\nmaterials, components, layers, and metadata, with no SketchUp installation\nand no proprietary SDK required. The same parser and export API also ship\nas first-class packages for Python, .NET, Dart, and C++ — see the\n[project README](https://github.com/iamahsanmehmood/openskp) for the full\ncross-language picture.\n\nThis package can also *write* new `.skp` files from scratch, and edit\nexisting ones, validated feature-by-feature against the real SketchUp\nSDK (see [Writing](#writing) below).\n\n## Features\n\n- **Full-fidelity parsing** — vertices, edges, faces, normals, UV\n  coordinates, nested component hierarchies, layers/tags, materials,\n  textures, styles, and dynamic-component attributes.\n- **Both SketchUp file generations** — modern VFF (2021+) and legacy MFC\n  (2013–2020) containers, transparently, behind one `parseSkp()`/`.parse()`\n  call.\n- **Scene baking** — an opt-in `buildScene()` pass resolves the full placed\n  scene graph to world-space, triangulated, export-ready geometry.\n- **Instancing preserved** — `buildInstancedScene()` keeps SketchUp's own\n  instancing instead of baking it out: unique geometry once, plus one\n  transform per placement, so a component placed 1,000 times costs one copy\n  of its buffers. Losslessly — no decimation or quantisation. See\n  [Choosing an API](#choosing-an-api).\n- **Native multi-format conversion** — glTF (GLB), Wavefront OBJ/MTL, STL,\n  PLY, AutoCAD DXF (3DFACE and Polyface Mesh), IFC4 (BIM/ISO 10303-21 STEP),\n  ThatOpen Fragments (.frag binary for high-speed Web BIM streaming), and\n  JSON — all written from scratch, no third-party CAD/BIM SDK involved.\n  The DXF writer is verified against real desktop AutoCAD, not just lenient\n  DXF readers.\n- **Runs anywhere JavaScript does** — zero native dependencies, works in\n  Node.js and directly in the browser from a `File`/`Blob`.\n- **Structured observability** — opt-in progress reporting and\n  structured, location-carrying parse errors.\n- **Write support** — build new legacy-format `.skp` files from scratch:\n  geometry (including true, editable circular/arc curves, freeform\n  polylines, faces with holes cut out, and non-planar auto-triangulation),\n  materials (solid + PNG/JPEG textures), layers, nested component\n  definitions and groups, instance rotation/visibility, and custom\n  attribute dictionaries — or load and extend an existing file with\n  `openExisting()`. No SDK involved; every feature validated against the\n  real SketchUp SDK. See [Writing](#writing) below.\n\n## Installation\n\n```bash\nnpm install openskp\n```\n\n## Quick Start\n\n```typescript\nimport { SkpFile } from 'openskp';\n\n// Node.js\nconst skp = SkpFile.open('model.skp');\nconst model = skp.parse();\n\n// Browser: parse from a File/Blob's ArrayBuffer\nimport { parseSkp } from 'openskp';\nconst buffer = await file.arrayBuffer();\nconst model2 = parseSkp(buffer);\n\nconsole.log(model.version, model.layers.length, 'layers');\n\n// Inspect definitions (component geometry) - model.definitions is a Map\nfor (const [id, defn] of model.definitions) {\n  console.log(`${defn.name}: ${defn.faces.length} faces, ${defn.vertices.length} vertices`);\n}\n\n// model.root holds whatever is placed directly in the model, not inside\n// any component/group\nconsole.log(model.root.instances.length, 'root-level instances');\n\n// Opt-in: full placed scene graph, triangulated, world-space, GLB-ready\nconst scene = skp.buildScene();\nconsole.log(scene.glbPrimitives.length, 'renderable mesh primitives');\n\n// Or keep the file's instancing instead of baking it out: unique geometry\n// once, plus a transform per placement.\nconst instanced = skp.buildInstancedScene();\nconsole.log(instanced.meshResources.length, 'unique meshes');\n```\n\n## Choosing an API\n\nThree entry points, in increasing order of what they compute. Each one\nre-parses the file independently, so you only pay for the one you call.\n\n| Use | When |\n|---|---|\n| `parseSkp()` / `.parse()` | You want the file's raw contents — definitions, layers, materials, metadata — with no scene-graph instancing resolved. Fastest and lightest. |\n| `buildScene()` / `.buildScene()` | You want a flat, world-space, triangulated scene to hand straight to a renderer or an exporter (`toGLB`, `toOBJ`, `toSTL`, `toIFC`, …). Every placement is baked into its own vertex buffers. |\n| `buildInstancedScene()` / `.buildInstancedScene()` | You want the same geometry, but with the file's instancing preserved: each definition triangulated once and referenced by every placement. |\n\n### The memory tradeoff\n\n`buildScene()` bakes each placed instance into its own world-space buffers,\nso its output scales with:\n\n```\ndefinition geometry x number of placed instances\n```\n\n`buildInstancedScene()` stores each distinct definition once and puts the\nplacement on the node, so it scales with:\n\n```\nunique geometry + instance transforms\n```\n\nFor a model that reuses components heavily — furniture, facade panels,\nfixtures, anything repeated — that is the difference between an output that\ngrows with the model's *placement count* and one that grows with its\n*distinct content*. On a synthetic scene of one 24-face component repeated\n1,000 times, the geometry buffers are 1,000x smaller (3,562 KB vs 3.6 KB)\nand the exported GLB is 48x smaller.\n\nThe cost is that you must apply the node transforms yourself (or hand the\nresult to `toInstancedGLB()`, or to any glTF/three.js-style scene graph,\nwhich do it natively). If you just want flat triangles, `buildScene()` is\nstill the simpler call.\n\n**This is lossless instancing preservation, not mesh decimation.** No\nvertices are removed, merged, quantised or approximated. The triangles are\nexactly the ones `buildScene()` produces; they are stored once and\nreferenced N times instead of copied N times. The test suite asserts this\ndirectly, by flattening the instanced result and comparing it against the\nbaked one on the repository's real `.skp` fixtures.\n\n### Coordinate systems and units\n\nSketchUp stores geometry in **inches on a Z-up** axis system. Both scene\nbuilders convert to **metres on glTF's Y-up** axes, applying the same\n`(x, y, z) -> (x, z, -y)` swap, so:\n\n- `LocalPrimitive.positions` / `normals` are in metres, Y-up, and in\n  **definition-local space** — no instance transform applied.\n- `InstancedNode.matrix` is a 16-element **column-major glTF matrix**, in\n  metres, Y-up, and is **relative to its parent**. Compose the chain by\n  walking the tree, exactly as glTF does. The root node's matrix is the\n  identity.\n- `InstancedNode.positionMm` is the one exception: it is the node's\n  **absolute** position in **millimetres on SketchUp's Z-up** axes, kept in\n  that frame so it matches the baked path's `InstanceNode.positionMm`\n  field for metadata comparisons.\n\nNormals are left in local space deliberately. Transforming them is the\nconsumer's job (glTF's own rule: inverse-transpose of the node's upper-left\n3x3), and deferring it is what keeps non-uniform and mirrored\n(negative-determinant) scales correct without baking a per-placement copy of\nthe normal buffer.\n\n### How material variants affect resource reuse\n\nTwo placements share a mesh resource when their *effective rendered\ngeometry* is identical — which is not the same as sharing a definition ID.\nThe same component renders differently depending on where it is placed, so\nresource identity also accounts for:\n\n- the **inherited instance material** (SketchUp's \"paint the component\"),\n  which sets both the colour of unpainted faces and, through its texture's\n  tile size, their UVs;\n- **texture identity**, not just averaged colour — two different images can\n  average to the same RGB;\n- the **effective layer's fallback colour**, which is what an entirely\n  unpainted face renders as.\n\nSo two instances of one definition painted with different materials produce\ntwo resource *variants*, while two instances with the same effective context\nshare one. Front/back material resolution, per-face UV mapping and\ndouble-sided-vs-split geometry all follow deterministically from the\ndefinition plus those inputs. `InstancedMeshResource.variantKey` exposes the\nresolved context if you need to see why a definition produced more than one\nresource. Resource IDs (`mesh_0`, `mesh_1`, …) are stable and deterministic\nfor a given file.\n\n### Edge and face visibility\n\nSketchUp does not draw every edge it stores. Three flags suppress an edge:\n`hidden` (explicitly hidden), and `soft`/`smooth` — the smoothing flags\nthat make a faceted surface read as curved. That last pair is why a\nrounded model carries far more edges than it appears to: every curve is\ntriangles stitched by edges that define the shape and are never shown.\n\nThese are parsed and exposed on `Edge`, but acting on them is opt-in.\n\n```typescript\nimport { parseSkp, isDrawableEdge } from 'openskp';\n\nconst model = parseSkp(buffer);\nconst visible = model.root.edges.filter(isDrawableEdge);\n```\n\nHow much that saves is strongly model-dependent — measured across this\nrepository's fixtures, 27.3% of edges are non-drawable on aggregate, but\nthat ranges from **0.2% on a mostly-flat model to 66.1% on a\ncurved-surface one**. Use it in wireframe/hidden-line renderers built on\n`parseSkp()` output, where drawing suppressed edges is both slower and\nvisually wrong.\n\nFor faces, both scene builders take an opt-in flag:\n\n```typescript\nconst scene = buildScene(buffer, { respectEdgeVisibility: true });\n```\n\nThis skips faces carrying SketchUp's \"Hide\" flag. It does **not** filter\nedges, because neither scene builder emits edges — their output is face\ntriangles. Hidden faces are rare in practice (none in this repository's\nfixtures), so expect this to be correct rather than dramatic; the edge\nhelper above is where the real saving lives. Off by default, since what\nSketchUp draws is a display policy rather than a parsing fact.\n\n### Cataloguing models\n\nTwo things an asset browser or block library needs, without paying for a\nfull parse or a render:\n\n```typescript\nimport { extractThumbnail, buildScene } from 'openskp';\n\n// The preview image SketchUp already saved inside the file. Reads\n// container metadata only - no geometry parsing, no renderer.\nconst thumb = extractThumbnail(buffer);\nif (thumb) {\n  // thumb.data (raw bytes), thumb.mimeType, thumb.width, thumb.height\n  fs.writeFileSync('cover.png', thumb.data);\n}\n\n// The model's overall size, computed during the bake.\nconst scene = buildScene(buffer);\nif (scene.bounds) {\n  const [w, h, d] = scene.bounds.size;       // metres, glTF Y-up\n  console.log(`${w.toFixed(2)} x ${h.toFixed(2)} x ${d.toFixed(2)} m`);\n  console.log('centre:', scene.bounds.center); // e.g. to frame a camera\n}\n```\n\n`extractThumbnail()` prefers SketchUp's clean `model_thumbnail` over\n`preview_thumbnail`, which has the red/green/blue axis lines drawn in and\nreads as clutter on a catalogue card; `thumb.source` says which was used.\n\nIt returns `null` rather than throwing when there is no usable preview.\nThat includes **legacy (pre-2021 MFC) files**: those embed PNGs too, but\nthe container stores them without entry names, so a thumbnail cannot be\ndistinguished from a material's texture image without guessing.\n\n`scene.bounds` is `null` for a model with no geometry, so an empty model\nstays distinguishable from one sitting at the origin.\n`buildInstancedScene()` exposes the same field, computed from the placed\nnode transforms so both builders agree.\n\n### Exporting an instanced GLB\n\n```typescript\nimport { SkpFile, toInstancedGLB } from 'openskp';\nimport * as fs from 'fs';\n\nconst instanced = SkpFile.open('model.skp').buildInstancedScene();\n\n// Multiple glTF nodes reference the SAME mesh - the vertex and index\n// buffers are written once, not once per placement.\nfs.writeFileSync('model.glb', toInstancedGLB(instanced));\n\n// Pass { textures: true } to embed the texture images, as with toGLB().\nfs.writeFileSync('textured.glb', toInstancedGLB(instanced, { textures: true }));\n```\n\nA definition that resolves to several materials becomes one glTF mesh with\nseveral primitives, which is glTF's normal representation — not several\nnodes. `toGLB()` and `buildScene()` are untouched and still produce exactly\nwhat they always have.\n\n## Exporting\n\n```typescript\nimport { toGLB, toInstancedGLB, toOBJ, toMTL, exportOBJ, toSTLAscii, toSTLBinary, exportSTL, toPLYAscii, toPLYBinary, exportPLY, toDXF, exportDXF, toIFC, exportIFC, toFragments, toJSON } from 'openskp';\n\n// Serialize a built scene straight to .glb bytes (in-memory, no disk I/O).\n// Index buffers are written as UNSIGNED_SHORT when every index fits, which\n// is the usual case - roughly halving the index data at no loss.\nconst glbBytes = toGLB(scene);\n\n// Instancing-preserving GLB: one mesh, many nodes (see Choosing an API)\nconst instancedGlb = toInstancedGLB(instanced);\n\n// Export to Wavefront OBJ string, plus a companion .mtl material library\nconst objText = toOBJ(scene, 'output.mtl');\nconst mtlText = toMTL(scene);\n\n// Node.js only: writes both output.obj and output.mtl together\nexportOBJ(scene, 'output.obj');\n\n// Export to STL ASCII or Binary string/buffer\nconst stlText = toSTLAscii(scene);\nconst stlBytes = toSTLBinary(scene);\n\n// Export to PLY ASCII or Binary string/buffer\nconst plyText = toPLYAscii(scene);\nconst plyBytes = toPLYBinary(scene);\n\n// Export to AutoCAD 3D DXF text format (R2000 / AC1015 compliant)\nconst dxfText = toDXF(scene);\n\n// Node.js only: export directly to a .dxf file\nexportDXF(scene, 'output.dxf');\n\n// Export to IFC4 / BIM (ISO 10303-21 STEP format string / file)\nconst ifcText = toIFC(scene);\nexportIFC(scene, 'output.ifc');\n\n// Export to ThatOpen Fragments (.frag binary format for Web BIM 3D streaming)\nconst fragBytes = toFragments(instanced);\n// Or directly via SkpFile:\n// const fragBytes = skp.toFragments();\n\n// Full metadata as a JSON-compatible object\nconst meta = toJSON(model, scene);\n```\n\n## Writing\n\nOpenSKP can also *create* new `.skp` files from scratch — a genuine,\nfrom-scratch binary writer for the legacy MFC `CArchive` format (SketchUp\n2013–2020), with no SketchUp SDK involved at any point. Ports the same\nfeature set as the Python package's writer, verified byte-identical to\nPython's own output on the same input: geometry, materials (solid +\nPNG/JPEG textures), layers (with color and default visibility),\ncomponent definitions with multiple instances, groups, nested\ndefinitions and nested group instances, per-instance rotation and\nvisibility, explicit per-side texture positioning, custom key/value\nattribute dictionaries, circular faces and partial arcs, freeform\npolyline curves, faces with holes cut out, and non-planar\nauto-triangulation. `openExisting()` loads an *existing* legacy-format\nfile and rebuilds it as a new builder, so more geometry can be added\nbefore saving. See [`src/create.ts`](src/create.ts) for the full scope\nnotes.\n\n```typescript\nimport { create } from 'openskp';\n\nconst builder = create();\n\n// Materials and layers\nconst red = builder.addMaterial('Red', [255, 0, 0]);\nconst brick = builder.addTextureMaterial('Brick', brickPngBytes);\nconst roofLayer = builder.addLayer('Roof', { color: [180, 60, 40] });\n\n// All addComponentDefinition/addGroup calls must come before any\n// addInstance/addFace call - placing anything locks in the file's\n// internal slot numbering for everything after it\nconst chair = builder.addComponentDefinition('Chair', (def) => {\n  def.addFace([[0, 0, 0], [20, 0, 0], [20, 20, 0], [0, 20, 0]]);\n});\nbuilder.addInstance(chair, { translation: [50, 0, 0] });\nbuilder.addInstance(chair, { translation: [100, 0, 0], hidden: true });\n\nbuilder.addFace(\n  [[0, 0, 0], [100, 0, 0], [100, 100, 0], [0, 100, 0]],\n  { material: red, layer: roofLayer }\n);\n\nbuilder.save('output.skp');   // Node.js only; use builder.toBytes() in the browser\n```\n\n### Editing an existing file\n\n```typescript\nimport { openExisting } from 'openskp';\n\nconst { builder, warnings, definitions } = openExisting('building.skp');\nfor (const w of warnings) console.log('not fully reproduced:', w);\n\nbuilder.addCircle([0, 0, 100], [0, 0, 1], 50);\nbuilder.save('building_edited.skp');\n```\n\n### Generating code from a file\n\n`toTypeScriptCode()` takes the opposite approach: instead of a builder you\nkeep editing, it returns a **string of source code** — a re-runnable\ntranscript of `create()` calls that rebuilds an equivalent file when run:\n\n```typescript\nimport { SkpFile, toTypeScriptCode } from 'openskp';\n\nconst model = SkpFile.open('building.skp').parse();\nconsole.log(toTypeScriptCode(model));\n```\n\nUseful for handing a real model to an AI coding agent as editable\nstarting code, or for a diffable, reviewable text representation of a\n`.skp` file. Shares the same fidelity scope as `openExisting()` above.\n\n`warnings` is the honest account of what couldn't be faithfully\nreproduced from that specific source file. Every material/layer the\nsource had is reachable on `builder.materialsByName`/`builder.layersByName`\nwithout a separate lookup, and `definitions` maps each replayed component\ndefinition's own name to its builder for placing more instances of\nsomething the source already defined.\n\n## Observability\n\n`parse()`/`buildScene()` accept an optional options object for progress\nreporting and structured errors — silent by default:\n\n```typescript\nconst model = skp.parse({\n  onProgress: (info) => console.log(`${info.stage}: ${info.current}/${info.total}`),\n  onLog: (level, message) => console.log(`[${level}] ${message}`),\n});\n```\n\nParse failures throw `SkpParseError`, carrying `stage`, `recordIndex`,\n`totalRecords`, `tag`, and `definitionId` context, with the original\nerror preserved as `.cause`. See\n[docs/OBSERVABILITY.md](../../docs/OBSERVABILITY.md) for the full\ncross-language reference.\n\n## Known limitation: large files\n\nMemory use scales worse than the other four ports on very large files —\na 113 MB file needs 8–16 GB of Node heap, and files beyond ~150-200 MB\nmay not parse in a browser tab at all (a typical tab's heap ceiling is\n~4 GB). Root cause: V8's per-object overhead on millions of small\ngeometry objects. See\n[docs/DEVELOPER_GUIDE.md](../../docs/DEVELOPER_GUIDE.md#performance) for\nverified numbers before parsing very large files in this package.\n\n## Package Structure\n\n| Module | Purpose |\n|---|---|\n| `parser.ts` | TLV binary parser for SketchUp's internal format |\n| `model.ts` | Interfaces for geometry, layers, materials, scenes |\n| `legacy.ts` | Legacy MFC container support (SketchUp 2013–2020) |\n| `vff.ts` | VFF/ZIP container handling (`fflate`-based) |\n| `triangulator.ts` | Planar polygon triangulation (ported `earcut`) |\n| `transforms.ts` | 3D matrix transforms and coordinate conversions |\n| `observability.ts` | Progress/log callback types |\n| `errors.ts` | `SkpParseError` and structured failure context |\n| `face-groups.ts` | Local-space face grouping shared by both scene builders |\n| `instanced.ts` | Instancing-preserving scene builder (`buildInstancedScene`) |\n| `instanced-glb.ts` | GLB exporter that reuses one mesh across many nodes |\n| `index.ts` | Public entry point — `SkpFile`, `parseSkp`, `buildScene`, `buildInstancedScene`, `toGLB`, `toInstancedGLB`, `toJSON` |\n\n## Requirements\n\nNode.js ≥ 16, or any modern browser. No native dependencies.\n\n## Used in Production\n\nOpenSKP powers the SketchUp import pipeline for\n[FrameSmart](https://frame-smart.com/) (a 3D collaboration platform with\nnearly 200 active users) and [IngeTrazo](https://ingetrazo.com/) (a\nSketchUp-alternative 3D modeler with a BIM → IFC bridge). Using OpenSKP in\nyour own project? [Open an issue](https://github.com/iamahsanmehmood/openskp/issues)\nor a PR to get added here.\n\n## Contributing\n\nThe Python package in `../python/` and this package are both full,\nindependent implementations at parity — neither is a stub for the other.\nSee [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.\n\n## License\n\nMIT — see [LICENSE](../../LICENSE)\n","readmeFilename":"README.md"}