{"_id":"@bobfrankston/wallplater","_rev":"11-f53339e6cced8b8d21987018120b4a52","name":"@bobfrankston/wallplater","dist-tags":{"latest":"1.0.11"},"versions":{"1.0.1":{"name":"@bobfrankston/wallplater","version":"1.0.1","_id":"@bobfrankston/wallplater@1.0.1","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.ts"},"dist":{"shasum":"1c6b641c5bb7f8a1cc5e752aa500d25735ba9381","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.1.tgz","fileCount":10,"integrity":"sha512-cPvDaZnG0DbCsQRktoMsUJrbwmH3V9M9h71hxAMyG9KQqDJsmZ/pxQygpaUgO3qW4gtWghZM3D2GUcOXVtPPkA==","signatures":[{"sig":"MEUCIDoeMZpTy8liEQLsENC58K5lA/wXwcipuqp9JPLSy8uFAiEAn8wlaEsNJa7zW4QnJ7SZ7wcq5WlCNYD3nTZTQhyqb8c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43343},"type":"module","_from":"file:bobfrankston-wallplater-1.0.1.tgz","engines":{"node":">=24"},"scripts":{"gen":"node index.ts","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.1.tgz","_integrity":"sha512-cPvDaZnG0DbCsQRktoMsUJrbwmH3V9M9h71hxAMyG9KQqDJsmZ/pxQygpaUgO3qW4gtWghZM3D2GUcOXVtPPkA==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.14.1","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.1.0","dependencies":{"manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.1_1780956103147_0.5939228773199929","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@bobfrankston/wallplater","version":"1.0.2","_id":"@bobfrankston/wallplater@1.0.2","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.ts"},"dist":{"shasum":"72ea40d78a8755f4ea78b6d0305e65e48eb3563c","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.2.tgz","fileCount":10,"integrity":"sha512-uTiCfcXuezSz0PoIvPAH5owHdpTtn7FJV45JKcIzCNU9OH/UhPtfYRfigJclEeJrgJh2x9Xk3aVoFF0j1G+JoQ==","signatures":[{"sig":"MEUCIQCTSYdzJZnmD6DkRAUhwGmwmNBKfl2qvjyFd/hwl+U5hgIgR28NTfUirSmFXBRvfZu+udaR2PHH0LDqnv0y5MS9W4s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43343},"type":"module","_from":"file:bobfrankston-wallplater-1.0.2.tgz","engines":{"node":">=24"},"scripts":{"gen":"node index.ts","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.2.tgz","_integrity":"sha512-uTiCfcXuezSz0PoIvPAH5owHdpTtn7FJV45JKcIzCNU9OH/UhPtfYRfigJclEeJrgJh2x9Xk3aVoFF0j1G+JoQ==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.14.1","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.1.0","dependencies":{"manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.2_1780956128051_0.6522736434586711","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@bobfrankston/wallplater","version":"1.0.3","_id":"@bobfrankston/wallplater@1.0.3","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.js"},"dist":{"shasum":"5ecd317345ab0de2b7f8cf1846dae0c6d3d5eba8","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.3.tgz","fileCount":15,"integrity":"sha512-cHiK8KOTHSCXcu1pFtIRZSBkEMLAzFpncYq4rxV4R8VgS6YdJKZ8Yyo+WYYBGBc9LPQZ8TMtwdxm+PJrYi3mbw==","signatures":[{"sig":"MEUCIA9b2Iw8KOAtBPxL9hc/SfnIVak+OYucmt4cBNnsXsJ+AiEA+hvQxsvYe9ikQurSO9EwLd8N0mehwOR9hmA4xPvzkck=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43024},"main":"index.js","type":"module","_from":"file:bobfrankston-wallplater-1.0.3.tgz","types":"index.d.ts","engines":{"node":">=24"},"scripts":{"gen":"node index.js","build":"tsc","watch":"tsc -w","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.3.tgz","_integrity":"sha512-cHiK8KOTHSCXcu1pFtIRZSBkEMLAzFpncYq4rxV4R8VgS6YdJKZ8Yyo+WYYBGBc9LPQZ8TMtwdxm+PJrYi3mbw==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.14.1","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.1.0","dependencies":{"manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.3_1780956869151_0.4324472313460339","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@bobfrankston/wallplater","version":"1.0.4","_id":"@bobfrankston/wallplater@1.0.4","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.js"},"dist":{"shasum":"f91f0cd8ef5e9d5c66610f1df4ecd9d4db5da6e1","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.4.tgz","fileCount":15,"integrity":"sha512-9m3li1rCOXT4NRmEWEK52C1dQVt7eDoMGxqmpoC9/SazOn3saYhG9nZG1z6PbfSKa0KqL1R6bKYxUkOk0OY6uA==","signatures":[{"sig":"MEQCIDQUKdAQD6oGxiKXHsRu7c7lVFCH1m0O/1HOcYC6F8z5AiBoF6SXUNBAVLN+SnhRv2ckOcEDNHQv8ARa35RB8j42VQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":44343},"main":"index.js","type":"module","_from":"file:bobfrankston-wallplater-1.0.4.tgz","types":"index.d.ts","engines":{"node":">=24"},"scripts":{"gen":"node index.js","build":"tsc","watch":"tsc -w","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.4.tgz","_integrity":"sha512-9m3li1rCOXT4NRmEWEK52C1dQVt7eDoMGxqmpoC9/SazOn3saYhG9nZG1z6PbfSKa0KqL1R6bKYxUkOk0OY6uA==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.14.1","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.1.0","dependencies":{"manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.4_1780958245609_0.5440370641886456","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@bobfrankston/wallplater","version":"1.0.5","_id":"@bobfrankston/wallplater@1.0.5","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.js"},"dist":{"shasum":"e252cf6464c0d4c0627fb89da3627cc418b12e9e","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.5.tgz","fileCount":15,"integrity":"sha512-rfi+CfcMTf1iiLCo7XEOgft7YRuFTwXdpSTlaFh2uykaC6kJPsJrgFKzSrtzteR9uQSr/BgtG96DoRxU0TKyvw==","signatures":[{"sig":"MEYCIQCTxuY1GPWBQvOwLQspO99SVHP2PXRvXmO5M5uxdqAdEgIhAMF3n1HrICJVgk4tLqRKWgZ5VAv90LeWgWKv+s98lw1k","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":45624},"main":"index.js","type":"module","_from":"file:bobfrankston-wallplater-1.0.5.tgz","types":"index.d.ts","engines":{"node":">=24"},"scripts":{"gen":"node index.js","build":"tsc","watch":"tsc -w","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.5.tgz","_integrity":"sha512-rfi+CfcMTf1iiLCo7XEOgft7YRuFTwXdpSTlaFh2uykaC6kJPsJrgFKzSrtzteR9uQSr/BgtG96DoRxU0TKyvw==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.14.1","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.1.0","dependencies":{"manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.5_1780962097388_0.6182948531491608","host":"s3://npm-registry-packages-npm-production"}},"1.0.6":{"name":"@bobfrankston/wallplater","version":"1.0.6","_id":"@bobfrankston/wallplater@1.0.6","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.js"},"dist":{"shasum":"22fc2d03b73f37895bdac312a0dc8aeb4825ed91","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.6.tgz","fileCount":15,"integrity":"sha512-fwn3Fdvdz0SIIxmffmGVCxLGbGakUwFgXc0y4eqNt0cBMCY2QYPq7a6d68GOa58uumSQOHhQwwJ70GCd50K3Zg==","signatures":[{"sig":"MEQCIBowzGaPP5aNcdXagj2DFWHwdps9wfgBy/1AAWevAoEwAiA+MtVbItfTF7bckf9dnMCMG6HGKg0QTVeBDHsgAIrlRA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":52322},"main":"index.js","type":"module","_from":"file:bobfrankston-wallplater-1.0.6.tgz","types":"index.d.ts","engines":{"node":">=24"},"scripts":{"gen":"node index.js","build":"tsc","watch":"tsc -w","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.6.tgz","_integrity":"sha512-fwn3Fdvdz0SIIxmffmGVCxLGbGakUwFgXc0y4eqNt0cBMCY2QYPq7a6d68GOa58uumSQOHhQwwJ70GCd50K3Zg==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.14.1","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.1.0","dependencies":{"json5":"^2.2.3","manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.6_1781021251708_0.5269863604541536","host":"s3://npm-registry-packages-npm-production"}},"1.0.7":{"name":"@bobfrankston/wallplater","version":"1.0.7","_id":"@bobfrankston/wallplater@1.0.7","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.js"},"dist":{"shasum":"0a382a54fcf9eab9bba2fc8bed6ad072f5b9a140","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.7.tgz","fileCount":15,"integrity":"sha512-pvBLXlifKL21vvQx/l3oTWBBbS3mj87SCOS7fl6nHCDKe7F7SvGUKwaTGp6WVsK6lFKip6uwYXyj8M46VUUqRA==","signatures":[{"sig":"MEYCIQDsGM/IC8LtNxeddrMT717znGqQaT1zoFIDKYqqISHKjwIhAKr5Hu2hLjfScLPB4hmPnRoyIlUD1+qrgw89+IvfO3cL","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":64722},"main":"index.js","type":"module","_from":"file:bobfrankston-wallplater-1.0.7.tgz","types":"index.d.ts","engines":{"node":">=24"},"scripts":{"gen":"node index.js","build":"tsc","watch":"tsc -w","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.7.tgz","_integrity":"sha512-pvBLXlifKL21vvQx/l3oTWBBbS3mj87SCOS7fl6nHCDKe7F7SvGUKwaTGp6WVsK6lFKip6uwYXyj8M46VUUqRA==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.14.1","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.1.0","dependencies":{"json5":"^2.2.3","manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.7_1781203294748_0.45386670955537833","host":"s3://npm-registry-packages-npm-production"}},"1.0.8":{"name":"@bobfrankston/wallplater","version":"1.0.8","_id":"@bobfrankston/wallplater@1.0.8","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.js"},"dist":{"shasum":"b6631d9a063fa0abf1d8913b480dfdc469080e2c","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.8.tgz","fileCount":19,"integrity":"sha512-7nhtkMq+jVlSBRlAKI2Ot+BfticfoqoI5d4QJ2RWLwQkOWu4xA1FlxpFNh+L9T9tFLSc0nAPUWRznOZUJR4F8g==","signatures":[{"sig":"MEQCIFZnh8sOWIcnLCrxz/PCbzSyfRSG6fDAdr35pu6hjYjGAiAPtKHzdZYhTiaMIIPl/AW9t5vI5heGGKrDvcIRz6KEJw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIBFn6fkuwtJ7WezVUnBPCK6XXkJq36F5lmEyoCagsfoMAiEArVfBokyX4xYSpWNGU8RVKhtkYUagq9rBGSzdfLV4zvI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79745},"main":"index.js","type":"module","_from":"file:bobfrankston-wallplater-1.0.8.tgz","types":"index.d.ts","engines":{"node":">=24"},"scripts":{"gen":"node index.js","build":"tsc","watch":"tsc -w","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.8.tgz","_integrity":"sha512-7nhtkMq+jVlSBRlAKI2Ot+BfticfoqoI5d4QJ2RWLwQkOWu4xA1FlxpFNh+L9T9tFLSc0nAPUWRznOZUJR4F8g==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.17.0","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.4.0","dependencies":{"json5":"^2.2.3","manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.8_1788034555294_0.3887120319748687","host":"s3://npm-registry-packages-npm-production"}},"1.0.9":{"name":"@bobfrankston/wallplater","version":"1.0.9","_id":"@bobfrankston/wallplater@1.0.9","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.js"},"dist":{"shasum":"95be65f5c7b0b409d9955094cdcab90a32cd8942","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.9.tgz","fileCount":19,"integrity":"sha512-2hPDMVMGg0N6mhl4bm4sBFf4m7SZhJSkUNguf7d0RngeTKCndTEb1UnlojKi7RxIjpwsr9I8DTMsxsN6L65r/Q==","signatures":[{"sig":"MEUCIFGRMynFx+uKbkDOYZ2hfeKnAP6fIThaWFBqNCsAfGJVAiEAqn47n/8yMcp12mKZCiB/GZlH3uK2s32BBtQ+Z2/TeBk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIB1cyayAkQPiQ02vXxUpCj83G3Arslh9QcyJXOthy6cRAiEA4wLSpubFuYt4Q8o6pJhV+3pdMWJ1IdgMYc1aPQU6XWo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":85890},"main":"index.js","type":"module","_from":"file:bobfrankston-wallplater-1.0.9.tgz","types":"index.d.ts","engines":{"node":">=24"},"scripts":{"gen":"node index.js","build":"tsc","watch":"tsc -w","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.9.tgz","_integrity":"sha512-2hPDMVMGg0N6mhl4bm4sBFf4m7SZhJSkUNguf7d0RngeTKCndTEb1UnlojKi7RxIjpwsr9I8DTMsxsN6L65r/Q==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.17.0","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.4.0","dependencies":{"json5":"^2.2.3","manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.9_1788035256167_0.42441686326182704","host":"s3://npm-registry-packages-npm-production"}},"1.0.10":{"name":"@bobfrankston/wallplater","version":"1.0.10","_id":"@bobfrankston/wallplater@1.0.10","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"homepage":"https://github.com/BobFrankston/wallplater#readme","bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"bin":{"wallplater":"index.js"},"dist":{"shasum":"a7f20283d4ffbc8bb836d5c54425c741ecd47b58","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.10.tgz","fileCount":19,"integrity":"sha512-Q9uBbUvWQa7BmPBMST549fo4CKFof+rG2vMxvshelx/q9zJ/4OYnKLzPrJqqqdm32+2ABDG6Y4CiWI+g/xJQPQ==","signatures":[{"sig":"MEUCIQC/1eRONOj3Mk3flWBYITwBKzEta0lNmavoL+QfU5DTWwIgOEsR6q+xJ7YkjHvWga+AUaZmLcnmCiGcV6zUlz1GMvQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIBtwEDFDt1ThJqJ52P2xY35B9ZeiWkp8A4AWgpOSc0LXAiA9DFhbXN5EMPcjZb32E1EsdzMizp/zMSAQGyYRzhIOUA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":103727},"main":"index.js","type":"module","_from":"file:bobfrankston-wallplater-1.0.10.tgz","types":"index.d.ts","engines":{"node":">=24"},"scripts":{"gen":"node index.js","build":"tsc","watch":"tsc -w","release":"npmglobalize","typecheck":"tsc --noEmit"},"_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.10.tgz","_integrity":"sha512-Q9uBbUvWQa7BmPBMST549fo4CKFof+rG2vMxvshelx/q9zJ/4OYnKLzPrJqqqdm32+2ABDG6Y4CiWI+g/xJQPQ==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.17.0","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"_nodeVersion":"26.4.0","dependencies":{"json5":"^2.2.3","manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"tmp":"tmp/wallplater_1.0.10_1789070041071_0.014979266687479287","host":"s3://npm-registry-packages-npm-production"}},"1.0.11":{"_id":"@bobfrankston/wallplater@1.0.11","bin":{"wallplater":"index.js"},"bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"dist":{"shasum":"222fc0d6067add189faced767545bdca32464629","tarball":"https://registry.npmjs.org/@bobfrankston/wallplater/-/wallplater-1.0.11.tgz","fileCount":19,"integrity":"sha512-cIfl3MVEjnhnqvOhOQOWIURNxDLdL3xPxfDgYn6gRzZTfMlbWQFrjE3Ep11gqm1jj8p4fPPiTdSrqOvM0iU7xQ==","signatures":[{"sig":"MEYCIQCnOcrQfxB8y08zxH041sZvHRg6xgdgR3PbYFswZfwN+QIhAMIXVLob8g5fHxQWTtJqdF4yYmP0B1A1HsR7FfN9oQsk","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDMX0hZmegksviiVZuk5bPAljwC9v1uO4fUPYSq79uC2gIhAKvFQgT/6yP7w1qhqzqFrR0GmJEJkWnk30mGpD2vTHHa"}],"unpackedSize":106522},"main":"index.js","name":"@bobfrankston/wallplater","type":"module","_from":"file:bobfrankston-wallplater-1.0.11.tgz","types":"index.d.ts","engines":{"node":">=24"},"scripts":{"gen":"node index.js","build":"tsc","watch":"tsc -w","release":"npmglobalize","typecheck":"tsc --noEmit"},"version":"1.0.11","_npmUser":{"name":"bobfrankston","email":"npm@bob.ma"},"homepage":"https://github.com/BobFrankston/wallplater#readme","_resolved":"Y:\\dev\\projects\\3D\\stl\\house\\wallplate\\wallplater\\bobfrankston-wallplater-1.0.11.tgz","_integrity":"sha512-cIfl3MVEjnhnqvOhOQOWIURNxDLdL3xPxfDgYn6gRzZTfMlbWQFrjE3Ep11gqm1jj8p4fPPiTdSrqOvM0iU7xQ==","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"_npmVersion":"11.17.0","description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","directories":{},"maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"_nodeVersion":"26.4.0","dependencies":{"json5":"^2.2.3","manifold-3d":"^3.0.0","opentype.js":"^1.3.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@types/node":"^25.9.2","@types/opentype.js":"^1.3.8"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/wallplater_1.0.11_1789071016254_0.573154200409177"}}},"time":{"created":"2026-06-08T22:01:42.947Z","modified":"2026-09-10T20:10:16.512Z","1.0.1":"2026-06-08T22:01:43.288Z","1.0.2":"2026-06-08T22:02:08.199Z","1.0.3":"2026-06-08T22:14:29.270Z","1.0.4":"2026-06-08T22:37:25.740Z","1.0.5":"2026-06-08T23:41:37.554Z","1.0.6":"2026-06-09T16:07:31.870Z","1.0.7":"2026-06-11T18:41:34.888Z","1.0.8":"2026-08-29T20:15:55.378Z","1.0.9":"2026-08-29T20:27:36.260Z","1.0.10":"2026-09-10T19:54:01.207Z","1.0.11":"2026-09-10T20:10:16.368Z"},"bugs":{"url":"https://github.com/BobFrankston/wallplater/issues"},"homepage":"https://github.com/BobFrankston/wallplater#readme","repository":{"url":"git+ssh://git@github.com/BobFrankston/wallplater.git","type":"git"},"description":"JSON-driven wall-plate generator (Decora / duplex / blank). Direct-to-3MF via manifold-3d, with an optional OpenSCAD engine.","maintainers":[{"name":"bobfrankston","email":"npm@bob.ma"}],"readme":"# @bobfrankston/wallplater\n\nJSON-driven wall-plate generator (Decora / duplex / blank / button gangs). Reads\na small JSON (JSON5) config and emits a multi-object 3MF (plate + labels as\nseparate, individually colourable objects) or per-part STLs.\n\n## Engines\n\n| Engine | Flag | Needs OpenSCAD? | Speed | Notes |\n|---|---|---|---|---|\n| **manifold** (default) | — | no | ~1 s | Direct geometry via [manifold-3d](https://github.com/elalish/manifold) (Clipper2 + robust CSG). Text via [opentype.js](https://github.com/opentypejs/opentype.js). |\n| **scad** (legacy) | `-scad` or `\"engine\":\"scad\"` | yes | ~30 s | Writes a `.scad` and shells out to OpenSCAD. Reference / fallback. Renders all hole geometry (incl. button pips) but **not** rocker/header/per-button labels. |\n\nThe manifold engine has no system dependency beyond Node and is the path\nforward; `-scad` is kept for parity/verification.\n\nIf the `-scad` engine can't find OpenSCAD (neither the `openscad` config path nor\n`openscad` on `PATH`), it offers to install it for you — `winget` on Windows,\n`brew --cask` on macOS, `apt-get` on Linux — then re-checks. Decline (or a\nnon-interactive stdin) exits with a hint to install manually or drop `-scad`.\n\n## Build / install\n\nTypeScript compiled to co-located `.js` / `.d.ts` / `.map` (no `src`/`dist`\nsplit). `tsc` is the global install.\n\n```sh\nnpm install\nnpm run build        # tsc  (or: npm run watch  for tsc -w)\n```\n\nInstalled globally (`npm i -g @bobfrankston/wallplater`) it exposes a\n`wallplater` command. `defaults.json` is resolved relative to the module, so it\nruns correctly from any working directory.\n\n## Usage\n\nRequires Node 24+ (ESM). Run the compiled entry:\n\n```sh\nwallplater                                     # no arguments -> usage\nwallplater ../KitchenBack.json                 # manifold engine -> KitchenBack.3mf\nwallplater ../KitchenBack.json -describe       # explain the config, write nothing\nwallplater ../KitchenBack.json -scad           # OpenSCAD engine (same result)\nnode index.js ../KitchenBack.json              # same, without a global install\n```\n\n| Argument | Meaning |\n|---|---|\n| `<config.json>` | The config to build. Exactly one is required. |\n| `-describe` | Print what the config resolves to and write nothing (see below). |\n| `-scad` | Use the OpenSCAD engine instead of the built-in manifold engine. |\n| `-help` | Print the usage message. |\n\n- Outputs are written next to the **config file**, named after the config's `name`.\n- Flags take a single or double dash and are case-insensitive; unknown flags,\n  a missing config, and more than one config are all rejected with the usage.\n\n### Objects and filaments\n\n**One object, one part per element**: the plate, and one part per label,\nassembled into a single object named after the config — the structure Bambu\nStudio's own Assemble command produces. A three-gang plate with a legend, a\nper-gang breaker, a panel breaker and a note loads as one object with five\nseparately-selectable parts:\n\n```\nKitchenBack plate                   filament 1\nKitchenBack g1 legend Disposal      filament 2\nKitchenBack g1 breaker A32          filament 2\nKitchenBack breaker A36             filament 2\nKitchenBack note Note: A18 Behind   filament 3\n```\n\nNames are `g<n> <kind> <text>` so an element is findable in the slicer's object\nlist. The filament number is written per part via `Metadata/model_settings.config`\n(Bambu/Orca `extruder`), so the plate slices in colour 1 and the text in colour 2\nwith no manual assignment — but it is only a **default**: because each element is\nits own part, any of them can be remapped to any filament in the slicer without\nregenerating. Defaults are plate → 1, all labels → 2, the note → `note.extruder`\n(3). The colours in the config are **suggestions** — they paint the embedded\npreview; what actually prints is whatever filament is loaded in that slot.\n\nLabel parts sit flush in the plate's front-face pockets (printed\nfront-face-down), so they look hidden in the viewport until coloured. In a single\ncolour they still read as `labelDepth` (0.6 mm) engraving.\n\nParts, not separate objects, because Bambu Studio runs a toolpath conflict check\nbetween top-level objects and a label inside a pocket of the plate trips it\n(\"Conflicts of gcode paths have been found at layer 2 ... breaker A8 <-> plate\").\nParts of one object are exempt, exactly as if the objects had been assembled by\nhand. (Changed 2026-09-10; earlier files load as separate objects — select them\nall and Assemble to get the same result.)\n\n> Bambu Studio says *\"The 3mf file has invalid config, load geometry data only\"*\n> on load. That is [a Bambu bug](https://github.com/bambulab/BambuStudio/issues/11927)\n> affecting any geometry-only 3MF with no Bambu *project* config (their own sample\n> files included) — the object, part names and filament assignments still load. This\n> generator deliberately does not write a `project_settings.config`, which would\n> bake in a printer/filament profile.\n>\n> Also a Bambu quirk: an object assigned filament 2 shows as filament 1 until the\n> project actually has a second filament — add one in the Filament panel and the\n> labels flip to 2 on their own. (Observed 2026-09-10.)\n\nThe 3MF also embeds a **preview thumbnail** (`Metadata/thumbnail.png`, wired via\nthe OPC thumbnail relationship) so Windows Explorer and slicers show an image of\nthe plate. It's a pure-JS orthographic render of the front face in the configured\n`plateColor` / `accentColor` — no extra dependency, no STL/mesh rendering by the\nshell. (Without it, the file previews blank: the shell never renders the geometry\nitself, it only displays this embedded PNG.)\n\n### `-describe`\n\n`-describe` resolves the config (defaults merge, unit conversion, engine choice)\nand prints it in words instead of building anything — the plate's overall size,\neach gang's openings and screw holes, every accent label with its size,\nalignment and position, and the objects and files the run would write. Under\n`-scad` it also lists the labels that engine will silently drop.\n\n```\n$ wallplater ../buttons_demo.json -describe\nbuttons_demo — 2-gang plate, from Y:\\dev\\...\buttons_demo.json\n  engine manifold, output 3mf, printReady true (flipped front-face-down for printing)\n  plate  115.89mm (4.563in) wide x 114.30mm (4.500in) high x 4.00mm (0.157in) deep\n  ...\n  gangs (left to right, gang pitch 46.04mm (1.812in)):\n    1. decora at x -23.02mm — Decora opening 33.34mm (1.313in) x 66.67mm (2.625in), corner r 0.50mm\n       2 screws on the Decora line, 96.84mm (3.813in) apart\n       legend \"LIGHTS\"\n    2. button at x +23.02mm — 3 button holes d 12.70mm (0.500in), pip pitch 21.59mm (0.850in)\n  ...\n  accent text (5 placements in the \"labels\" object):\n    \"LIGHTS\"  5.00mm  center-aligned at (-23.02, +39.00)mm\n  ...\n  objects: buttons_demo plate (filament 1), buttons_demo labels (filament 2)\n  would write into Y:\\dev\\...\\wallplate: buttons_demo.3mf\n  nothing written (-describe)\n```\n\nThe label positions come from the same `accentPlaces()` the manifold engine\nbuilds from, so the description cannot drift from the model.\n\n## Config\n\nEach specific config is **deep-merged over `defaults.json`** (in this\ndirectory), so a specific file carries only what differs — often just `name`,\n`gangs`, and a `breaker.switch`. Every default lives in `defaults.json`, not in\ncode.\n\nConfigs are parsed with **JSON5** (the most lenient reader), so comments\n(`//`, `/* */`), trailing commas, and unquoted keys are all allowed — plain JSON\nstill works unchanged.\n\nLengths are written **CSS-style with a unit suffix**. Supported units:\n\n| Suffix | Meaning | mm |\n|---|---|---|\n| `in` | inch | 25.4 |\n| `ft` | foot | 304.8 |\n| `cm` | centimetre | 10 |\n| `mm` | millimetre | 1 |\n\ne.g. `\"0.375in\"`, `\"5mm\"`, `\"2cm\"`, `\"0.5ft\"`, `\"-42mm\"`. A bare number (no\nsuffix) is treated as millimetres. Angles (e.g. `cskAngle`) are plain numbers.\n\n```jsonc\n// KitchenBack.json — only what differs from defaults.json\n{\n  \"name\": \"KitchenBack\",\n  \"gangs\": [\n    { \"type\": \"decora\", \"legend\": \"Disposal\" },\n    { \"type\": \"blank\", \"screws\": false },     // middle blank, no screw holes\n    { \"type\": \"decora\" }\n  ]\n  // add later: \"breaker\": { \"switch\": \"A8\" }\n}\n```\n\n- `gangs[].type`: `\"decora\"` | `\"duplex\"` | `\"blank\"` | `\"button\"`.\n- `gangs[].screws`: `false` to omit that gang's screw holes (default true).\n- `gangs[].filler`: on a **blank** gang, marks it as backed by a filler/insert\n  plate, so its cover screws sit on the Decora line (wider spacing) instead of\n  the box-ear line.\n- `gangs[].legend`: single label centred above the gang's opening (positioned\n  clear of the screw holes; `legendY` / `legendSize`).\n- `gangs[].breaker`: per-gang breaker/circuit label, lower-right of the opening\n  and clear of the screws (`gangBreakerY` / `gangBreakerSize`).\n- `breaker`: `{ \"switch\": \"A8\", \"size\": \"0.375in\", \"inset\": \"0.25in\" }` — the\n  panel-wide breaker label in the lower-right corner. `switch` is the text;\n  `size`/`inset` come from `defaults.json`, so a config usually sets only\n  `breaker.switch`. Per-gang (`gangs[].breaker`) and panel-wide (`breaker`)\n  labels are independent — use either or both.\n\n### Stacked rocker labels (Leviton 1755 triple rocker, etc.)\n\nThe 1755 is three rockers stacked in one **standard Decora opening**, so the\nopening is unchanged — only the labelling differs. Per gang:\n\n```jsonc\n{\n  \"type\": \"decora\",\n  \"header\": \"ON / OFF\",                       // centred above the opening\n  \"rockers\": [                                // top -> bottom (1-3+ entries)\n    { \"left\": \"1\", \"right\": \"FAN\" },          // a label each side of every rocker\n    { \"left\": \"2\", \"right\": \"LIGHT\" },\n    { \"left\": \"3\", \"right\": \"HEAT\" }\n  ]\n}\n```\n\nRockers are spaced evenly down the opening; `left` labels are right-aligned snug\nto the opening, `right` labels left-aligned. `legend` / `header` / `rockers` /\nper-gang `breaker` all print in the accent colour (the **labels** object). Relevant defaults:\n`rockerSize` (3.5mm), `rockerGap` (1.5mm), `headerSize` (4mm), `headerGap`\n(5mm). Keep side labels short on multi-gang plates — the side margin is ~18 mm\non an end/single gang but only ~6 mm between interior gangs; long labels can\noverflow. See `../triple_demo.json` for a worked single-gang example.\n\n> Rocker/header labels are rendered by the **manifold engine only**. The\n> `-scad` engine ignores them (it warns).\n\n### Button gangs (round holes in a pip layout)\n\nA `\"button\"` gang punches a set of round button holes (default **0.5 in**\ndiameter) arranged symmetrically like the pips on a die / playing card — odd\ncounts put a single button in the centre. Set the count with `buttons` (1–9):\n\n```jsonc\n{\n  \"type\": \"button\",\n  \"legend\": \"FAN\",                       // the legend \"on top\" (above the buttons)\n  \"buttons\": 3,                          // 1-9; pip layout, single = centre\n  \"buttonD\": \"0.5in\",                    // optional per-gang diameter (default dims.buttonD)\n  \"buttonLegends\": [\"HI\", \"MED\", \"LO\"]   // optional small per-button labels\n}\n```\n\n- `buttons`: number of holes (1–9). Setting it implies `type:\"button\"`. The pip\n  pattern is the standard die/domino layout, read **top → bottom, left → right**:\n  `1`=centre, `2`/`3`=diagonal, `4`/`5`=corners (+centre for 5), `6`/`7`=two\n  columns (+centre for 7), `8`/`9`=full ring/grid. Counts above 9 are an error.\n- `buttonD`: per-gang hole diameter; defaults to `dims.buttonD` (`0.5in`).\n- `buttonLegends`: small labels, one per button in pip reading order (`\"\"` or a\n  short array skips some). They are **in addition to** the gang `legend` on top,\n  and print in the accent colour. Sizing/placement: `buttonLegendSize` (3 mm),\n  `buttonLegendGap` (1 mm, below each hole).\n- Pip spacing is `dims.buttonPitch` (`0.85in` centre-to-centre). A button gang\n  mounts like a device — it gets a screw pair on the Decora line unless\n  `\"screws\": false`.\n\nSee `../buttons_demo.json` for a worked Decora-plus-buttons example.\n\n> Per-button legends are rendered by the **manifold engine only** (the `-scad`\n> engine emits the button holes but skips the small labels, and warns).\n\nSee `../decora_wallplate_spec.md` for the dimensional reference and print notes\n(print front-face-down; PETG/ASA recommended for heat near devices; keep plate\nand labels the same material family — see the chat note on ABS+PLA).\n\n### Margin note\n\nA small note along the top or bottom edge — the circuit behind the plate, an\ninstall date — as its **own object on its own filament** (default 3), so it can\nprint in a third colour:\n\n```jsonc\n\"note\": \"Note: A18 Behind\"                  // shorthand: just the text\n\n\"note\": {                                   // or the full form\n  \"text\": \"Note: A18 Behind\",                // \"\\n\" stacks it over two lines\n  \"size\": \"4mm\",                            // the margin band is narrow — see the fit check\n  \"position\": \"bottom\",                     // \"bottom\" (default) | \"top\"\n  \"align\": \"left\",                          // \"left\" (default) | \"center\" | \"right\"\n  \"inset\": \"3mm\",                           // from the plate edge, and from the aligned side\n  \"x\": \"-60mm\", \"y\": \"-54mm\",               // optional: exact placement, overriding the above\n  \"color\": \"#b00020\",                       // preview suggestion, not the printed colour\n  \"extruder\": 3,                            // filament slot; set 2 on a two-colour printer\n  \"fontFile\": \"C:/Windows/Fonts/ariali.ttf\" // its own face; \"\" = the plate's fontFile\n}\n```\n\n**Yes, the note can have its own font** — `note.fontFile` takes any `.ttf`/`.otf`\nindependent of the plate's `fontFile` (manifold engine; the scad engine skips the\nnote entirely and warns).\n\nThe margin is tight, so `-describe` measures the fit from the real glyph outlines\nand reports it:\n\n```\n  note: bottom margin, left-aligned, inset 4.00mm\n        font C:/Windows/Fonts/arialbd.ttf\n        clear band in that margin: 1.96mm tall, centred 53.37mm from the plate centre (a note up to ~1.96mm clears the screw heads)\n        box 13.01mm x 7.39mm, x -76.96..-63.95, y -53.09..-45.71\n        clears the screw heads by 13.95mm, the bevel by 1.20mm\n```\n\nThe **clear band** is the gap between the countersink heads\n(`screwSpacing/2 + screwHeadD/2` out from the centre) and the inner edge of the\nfront chamfer — 1.96 mm on a standard plate with the default 2.8 mm bevel. The\n**box/clears** lines are the real thing: the note's glyphs measured in place, against every screw head (as circles)\nand against the plate outline including the corner radius. A clearance under\n0.25 mm is flagged `(tight)`, a negative one `OVERLAPS` — check this line before\nprinting rather than trusting the size alone.\n\nSizing, for reference: the default 4 mm gives 2.93 mm-tall glyphs (0.58 mm stems\nin Arial Bold — comfortably over one 0.4 mm nozzle line); 3 mm gives 0.43 mm\nstems, about the thinnest that prints cleanly. Neither fits the 1.96 mm band on\nthe screw columns, so a note on a standard plate needs an explicit `y` that pulls\nit inboard of the chamfer, and it must sit left or right of the screw columns\n(the heads reach 3.97 mm either side of each gang centreline). The sample above\nis a two-line note at the default size with `\"y\": \"-49.4mm\", \"inset\": \"4mm\"`.\n\n**Two lines:** put a `\\n` in `text` (\"A18\\nBehind\") and it stacks, each line\naligned on its own by `align`, the block centred on the note's position. Line\nspacing is the font's own ascender-to-descender height (~1.15x `size`).\n\nNote that stacking needs vertical room the margin does not have: two 5 mm lines\nare ~9.2 mm tall against a 1.96 mm band, so the default edge placement runs off\nthe plate. Give a two-line note an explicit `y` that pulls it inboard — on a\nstandard plate `\"y\": \"-49.4mm\"` clears the chamfer by 1.2 mm at the default size,\nand `inset` should be at least a millimetre more than `bevel` — and keep it left\nor right of the screw columns, where nothing else competes for the height.\n`-describe` measures the stacked block, so its `box`/`clears` lines stay honest.\n\n`inset` is measured from the plate edge **at the note's own height**, not from\nwhere the straight edge would be — otherwise a left- or right-aligned note in the\ncorner region hangs over the rounded corner. On a wide plate that makes no\ndifference; in the corner it shifts the note inwards by a few mm.\n\n### Appearance, output & engine\n\nTop-level keys (all have defaults in `defaults.json`):\n\n| Key | Default | Meaning |\n|---|---|---|\n| `output` | `\"3mf\"` | `\"3mf\"` (multi-object + thumbnail), `\"stl\"` (one binary STL per part), or `\"scad\"` (write the `.scad` only, no render — implies the scad engine). |\n| `engine` | `\"manifold\"` | `\"manifold\"` (direct) or `\"scad\"` (OpenSCAD). `-scad` on the CLI forces scad. |\n| `plateColor` | `\"#35589f\"` | Plate (filament 1) colour — used for the embedded preview and the scad-engine preview. |\n| `accentColor` | `\"#101010\"` | Label (filament 2) colour, same uses. |\n| `note` | `\"\"` | A note in the top or bottom margin, in its own colour/filament — see below. |\n| `printReady` | `true` | Flip the model front-face-down (rotate 180° about X) for printing. The preview camera follows the flip, so labels stay upright either way. |\n| `fontFile` | Arial Bold | Path to a `.ttf`/`.otf` for the **manifold** engine's text. |\n| `font` | Liberation Sans Bold | OpenSCAD fontconfig name for the **scad** engine's text. |\n| `openscad` | Program Files path | OpenSCAD executable; only used by the scad engine (auto-install offered if missing). |\n| `bevel` | `2.8mm` | Front-edge 45° chamfer: how far it runs in from the edge, and how deep. May run deeper than the face (it must stay under `dims.depth`, and `bevel - faceT` under `dims.rimW`). |\n| `labelDepth` | `0.6mm` | Recess depth of the label pockets / height of the label solids. |\n\nPlate geometry, opening sizes, screw spacing, etc. live under the `dims` object\n(see `defaults.json` for the full list, all unit-suffixed lengths). Override any\nsingle dim by deep-merge, e.g. `\"dims\": { \"depth\": \"5mm\" }`.\n\n**Plate profile.** The front edge is a 45° chamfer taking most of the depth\n(`bevel` `2.8mm` of `dims.depth` `4mm`, leaving a 1.2 mm vertical back edge),\nfollowing the original Wally-customizer plate's profile (4 of 6 mm there —\n`\"dims\": { \"depth\": \"6mm\" }, \"bevel\": \"4mm\"` reproduces it). The chamfer follows\nthe plan corners (`dims.cornerR`, 5 mm). On the back, the cavity wall is drafted\n45° from the rim (`dims.rimW`, 3 mm at the back) down to the floor, as the\noriginal's is. The Decora opening\ncorner radius `dims.openR` is `0.5mm` — effectively square, so devices seat; a\nlarger radius curves the corners inward and some Decora devices no longer fit.\n\n## Files\n\n- `index.ts` — CLI entry / usage / engine dispatch / arg validation\n- `config.ts` — schema, unit parsing, defaults.json merge, loader\n- `parts.ts` — object names/filenames, default filament per group, scad-engine part list\n- `describe.ts` — `-describe` report (reads geometry.ts / parts.ts, writes nothing)\n- `defaults.json` — all default values (merged under each specific config)\n- `geometry.ts` — manifold engine (direct geometry)\n- `text.ts` — glyph outlines -> filled contours (opentype.js)\n- `scad.ts` — legacy OpenSCAD engine (`.scad` generation + STL readback)\n- `threemf.ts` — multi-object 3MF writer, binary STL writer\n","readmeFilename":"README.md"}