{"_id":"@dice-o-rolla/dice-assets","_rev":"6-58046a9ef1b16d34ff82a86266b0b2fc","name":"@dice-o-rolla/dice-assets","dist-tags":{"latest":"0.5.1"},"versions":{"0.2.0":{"name":"@dice-o-rolla/dice-assets","version":"0.2.0","keywords":["assets","dice","skins","sounds","typescript"],"license":"Apache-2.0","_id":"@dice-o-rolla/dice-assets@0.2.0","maintainers":[{"name":"zerodi","email":"mail@zerodi.ru"}],"homepage":"https://github.com/creepiest-space/dice-o-rolla#readme","bugs":{"url":"https://github.com/creepiest-space/dice-o-rolla/issues"},"dist":{"shasum":"057239336755cb23d57e865acd581a890ad5de96","tarball":"https://registry.npmjs.org/@dice-o-rolla/dice-assets/-/dice-assets-0.2.0.tgz","fileCount":32,"integrity":"sha512-8hF+m9U1LoANWI8VPz6mP2bqvTrIqLiUsQJQ+s+7PX1nwLpGvfa0xbaDZWFlwW+Ixw6t1/HIi1YojSC7+aRVtA==","signatures":[{"sig":"MEUCIQDj41aogXA/hJO44VVHBOAtibTPET/7lx1d1uR/nKjMYwIgKQovV1wd9tnmbQO1FYvNHfFBVQlSGARFRbipoV9tYeg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":339691},"type":"module","_from":"file:artifacts/npm/dice-assets-0.2.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./catalog.json":"./assets/runtime/catalog.json"},"_npmUser":{"name":"zerodi","email":"mail@zerodi.ru"},"_resolved":"/Users/zerodi/Development/Active/dice-o-rolla/artifacts/npm/dice-assets-0.2.0.tgz","_integrity":"sha512-8hF+m9U1LoANWI8VPz6mP2bqvTrIqLiUsQJQ+s+7PX1nwLpGvfa0xbaDZWFlwW+Ixw6t1/HIi1YojSC7+aRVtA==","repository":{"url":"git+https://github.com/creepiest-space/dice-o-rolla.git","type":"git","directory":"packages/dice-assets"},"_npmVersion":"11.19.0","description":"Optional Web Audio and KTX2/PBR asset system for Dice O Rolla.","directories":{},"sideEffects":false,"_nodeVersion":"26.7.0","dependencies":{"three":"^0.185.0","@types/three":"^0.185.0","@dice-o-rolla/dice-renderer-three":"0.2.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dice-assets_0.2.0_1788168329333_0.5257051433976645","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@dice-o-rolla/dice-assets","version":"0.3.0","keywords":["assets","dice","skins","sounds","typescript"],"license":"Apache-2.0","_id":"@dice-o-rolla/dice-assets@0.3.0","maintainers":[{"name":"zerodi","email":"mail@zerodi.ru"}],"homepage":"https://github.com/creepiest-space/dice-o-rolla#readme","bugs":{"url":"https://github.com/creepiest-space/dice-o-rolla/issues"},"dist":{"shasum":"0f46980247d15f7aa68757647642c3faf65edfe4","tarball":"https://registry.npmjs.org/@dice-o-rolla/dice-assets/-/dice-assets-0.3.0.tgz","fileCount":32,"integrity":"sha512-qTChip6UTBjcmRds157/tfaukfiqytP45JkHyHsC3yag7GkP40SCIeaAzmbntlhq8SZhk0IHOYA+mJx5B1XrxQ==","signatures":[{"sig":"MEUCIQDV6gAHdY7AjocR3xW3Vg2InnY4ej64yjLFuFtkKL/+DgIgZxCJjaTCqBNauY0nVY1HAQC4kGySH3mWDlvLQqHf74o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dice-o-rolla%2fdice-assets@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":339691},"type":"module","_from":"file:/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.3.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./catalog.json":"./assets/runtime/catalog.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:483b15fc-d985-4916-9c4e-4763e6bf6925"}},"_resolved":"/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.3.0.tgz","_integrity":"sha512-qTChip6UTBjcmRds157/tfaukfiqytP45JkHyHsC3yag7GkP40SCIeaAzmbntlhq8SZhk0IHOYA+mJx5B1XrxQ==","repository":{"url":"git+https://github.com/creepiest-space/dice-o-rolla.git","type":"git","directory":"packages/dice-assets"},"_npmVersion":"11.17.0","description":"Optional Web Audio and KTX2/PBR asset system for Dice O Rolla.","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","dependencies":{"three":"^0.185.0","@types/three":"^0.185.0","@dice-o-rolla/dice-renderer-three":"0.3.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dice-assets_0.3.0_1788276462940_0.25595772553779983","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@dice-o-rolla/dice-assets","version":"0.3.1","keywords":["assets","dice","skins","sounds","typescript"],"license":"Apache-2.0","_id":"@dice-o-rolla/dice-assets@0.3.1","maintainers":[{"name":"zerodi","email":"mail@zerodi.ru"}],"homepage":"https://github.com/creepiest-space/dice-o-rolla#readme","bugs":{"url":"https://github.com/creepiest-space/dice-o-rolla/issues"},"dist":{"shasum":"6615487b24a69214173cb0d624395b4072501042","tarball":"https://registry.npmjs.org/@dice-o-rolla/dice-assets/-/dice-assets-0.3.1.tgz","fileCount":32,"integrity":"sha512-tmMpO830AQcu+fCG2cRo09PAeRVs8/y2p7A6wBjjAT+pnnADXJedVInXXQn0afLVGx+zLAn8lhvb01PUqfUQUw==","signatures":[{"sig":"MEUCIQCNIjqj10i83FqLR8f7a72T6yfwqXktM4CYCFkJik4F/gIgOmkK0Aq7hpDmCvL1pnn43DozCfoAz/JxCLoHxJQaW/w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dice-o-rolla%2fdice-assets@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":339691},"type":"module","_from":"file:/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.3.1.tgz","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./catalog.json":"./assets/runtime/catalog.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:483b15fc-d985-4916-9c4e-4763e6bf6925"}},"_resolved":"/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.3.1.tgz","_integrity":"sha512-tmMpO830AQcu+fCG2cRo09PAeRVs8/y2p7A6wBjjAT+pnnADXJedVInXXQn0afLVGx+zLAn8lhvb01PUqfUQUw==","repository":{"url":"git+https://github.com/creepiest-space/dice-o-rolla.git","type":"git","directory":"packages/dice-assets"},"_npmVersion":"11.17.0","description":"Optional Web Audio and KTX2/PBR asset system for Dice O Rolla.","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","dependencies":{"three":"^0.185.0","@types/three":"^0.185.0","@dice-o-rolla/dice-renderer-three":"0.3.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dice-assets_0.3.1_1788278883137_0.20616464199705353","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@dice-o-rolla/dice-assets","version":"0.4.0","keywords":["assets","dice","skins","sounds","typescript"],"license":"Apache-2.0","_id":"@dice-o-rolla/dice-assets@0.4.0","maintainers":[{"name":"zerodi","email":"mail@zerodi.ru"}],"homepage":"https://github.com/creepiest-space/dice-o-rolla#readme","bugs":{"url":"https://github.com/creepiest-space/dice-o-rolla/issues"},"dist":{"shasum":"0abfa4db6553c7f90f76ac664464dadd4c093877","tarball":"https://registry.npmjs.org/@dice-o-rolla/dice-assets/-/dice-assets-0.4.0.tgz","fileCount":32,"integrity":"sha512-a/8z1WppdV/IrDTXbLLyLjlifpPMqTBA0G0+U0I5UTLh762zc4sXT+BE4sE/cVS8NmMUNIwhEPJooOoKtfMZvA==","signatures":[{"sig":"MEUCIDibhKXNQP6LKY+tuk9pvgn14XVpOfNKvtAt7mezmvuWAiEAkpXjfnScMZENZ3YsneLeWHboHpeH0LA1uVkXwarAQOc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dice-o-rolla%2fdice-assets@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":339716},"type":"module","_from":"file:/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.4.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./catalog.json":"./assets/runtime/catalog.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:483b15fc-d985-4916-9c4e-4763e6bf6925"}},"_resolved":"/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.4.0.tgz","_integrity":"sha512-a/8z1WppdV/IrDTXbLLyLjlifpPMqTBA0G0+U0I5UTLh762zc4sXT+BE4sE/cVS8NmMUNIwhEPJooOoKtfMZvA==","repository":{"url":"git+https://github.com/creepiest-space/dice-o-rolla.git","type":"git","directory":"packages/dice-assets"},"_npmVersion":"11.17.0","description":"Optional Web Audio and KTX2/PBR asset system for Dice O Rolla.","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","dependencies":{"three":"^0.185.0","@types/three":"^0.185.0","@dice-o-rolla/dice-renderer-three":"0.4.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dice-assets_0.4.0_1788373434065_0.05925610617037358","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@dice-o-rolla/dice-assets","version":"0.5.0","keywords":["assets","dice","skins","sounds","typescript"],"license":"Apache-2.0","_id":"@dice-o-rolla/dice-assets@0.5.0","maintainers":[{"name":"zerodi","email":"mail@zerodi.ru"}],"homepage":"https://github.com/creepiest-space/dice-o-rolla#readme","bugs":{"url":"https://github.com/creepiest-space/dice-o-rolla/issues"},"bin":{"dice-assets":"dist/tools/cli.js"},"dist":{"shasum":"189199fe341244daaba1821875f028dcac4171a6","tarball":"https://registry.npmjs.org/@dice-o-rolla/dice-assets/-/dice-assets-0.5.0.tgz","fileCount":62,"integrity":"sha512-kIaIvIlhGNDNZhTs95QbGRZV3iqzCaGwS9MSCiYLBH6HhY4S08Yo5Itp27shqFqnITj/dDuJ4MxKHGqyFDlQ4g==","signatures":[{"sig":"MEUCIHINE8xZ/5wLeijy3PKAwDtzu+s/03qryvSlROpXfyVtAiEArragfSk6wtN+MeqP+5KOsDZ67x06zWD3cY7SskrKF04=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dice-o-rolla%2fdice-assets@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2822423},"type":"module","_from":"file:/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.5.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js","default":"./dist/tools/index.js"},"./catalog.json":"./assets/runtime/catalog.json"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:483b15fc-d985-4916-9c4e-4763e6bf6925"}},"_resolved":"/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.5.0.tgz","_integrity":"sha512-kIaIvIlhGNDNZhTs95QbGRZV3iqzCaGwS9MSCiYLBH6HhY4S08Yo5Itp27shqFqnITj/dDuJ4MxKHGqyFDlQ4g==","repository":{"url":"git+https://github.com/creepiest-space/dice-o-rolla.git","type":"git","directory":"packages/dice-assets"},"_npmVersion":"11.19.0","description":"Web Audio and KTX2/PBR assets with texture authoring API and CLI for Dice O Rolla.","directories":{},"sideEffects":false,"_nodeVersion":"24.20.0","dependencies":{"three":"^0.185.0","@types/three":"^0.185.0","@xmldom/xmldom":"^0.9.12","@resvg/resvg-js":"^2.6.2","@dice-o-rolla/dice-geometry":"0.5.0","@dice-o-rolla/dice-renderer":"0.5.0","@dice-o-rolla/dice-renderer-three":"0.5.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/dice-assets_0.5.0_1788904594272_0.33648969252095773","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"_id":"@dice-o-rolla/dice-assets@0.5.1","bin":{"dice-assets":"dist/tools/cli.js"},"bugs":{"url":"https://github.com/creepiest-space/dice-o-rolla/issues"},"dist":{"shasum":"16a382100c3b07c0003662b720cf6d45100eb240","tarball":"https://registry.npmjs.org/@dice-o-rolla/dice-assets/-/dice-assets-0.5.1.tgz","fileCount":62,"integrity":"sha512-TyK0lzofsMLO0plV5BOTSGmW8XxnZ7Q7jEZjEtmRIOlCl8jcw8a5+XwEthYVTYNYAYfXtQE5xWnvG9qvVDqN4A==","signatures":[{"sig":"MEUCIA0XRpmKBin7c/yuNBBhBHlEJx5dIXYDmMyu4gZM5E0pAiEA9ubE/fCYwcAg2zwzWYaOU6mFVopRHBZWSggrOtNRr0s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDy8j9b7zBZTQgNCn68m8puy9AiWw1BWl7ryHC2nl4kMgIgbqyve7DTVAPXC6yoZWVHgpwPwlp00cJqgHBq0p+jav4="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dice-o-rolla%2fdice-assets@0.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2814234},"name":"@dice-o-rolla/dice-assets","type":"module","_from":"file:/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.5.1.tgz","types":"./dist/index.d.ts","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js","default":"./dist/tools/index.js"},"./catalog.json":"./assets/runtime/catalog.json"},"license":"Apache-2.0","version":"0.5.1","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"483b15fc-d985-4916-9c4e-4763e6bf6925"}},"homepage":"https://github.com/creepiest-space/dice-o-rolla#readme","keywords":["assets","dice","skins","sounds","typescript"],"_resolved":"/home/runner/work/dice-o-rolla/dice-o-rolla/artifacts/npm/dice-assets-0.5.1.tgz","_integrity":"sha512-TyK0lzofsMLO0plV5BOTSGmW8XxnZ7Q7jEZjEtmRIOlCl8jcw8a5+XwEthYVTYNYAYfXtQE5xWnvG9qvVDqN4A==","repository":{"url":"git+https://github.com/creepiest-space/dice-o-rolla.git","type":"git","directory":"packages/dice-assets"},"_npmVersion":"11.19.0","description":"Web Audio and KTX2/PBR assets with texture authoring API and CLI for Dice O Rolla.","directories":{},"maintainers":[{"name":"zerodi","email":"mail@zerodi.ru"}],"sideEffects":false,"_nodeVersion":"24.21.0","dependencies":{"three":"^0.185.0","@types/three":"^0.185.0","@xmldom/xmldom":"^0.9.12","@resvg/resvg-js":"^2.6.2","@dice-o-rolla/dice-geometry":"0.5.1","@dice-o-rolla/dice-renderer":"0.5.1","@dice-o-rolla/dice-renderer-three":"0.5.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dice-assets_0.5.1_1790942679764_0.7875705346960484"}}},"time":{"created":"2026-08-31T09:25:29.194Z","modified":"2026-10-02T12:04:40.567Z","0.2.0":"2026-08-31T09:25:29.473Z","0.3.0":"2026-09-01T15:27:43.128Z","0.3.1":"2026-09-01T16:08:03.305Z","0.4.0":"2026-09-02T18:23:54.265Z","0.5.0":"2026-09-08T21:56:34.510Z","0.5.1":"2026-10-02T12:04:39.955Z"},"bugs":{"url":"https://github.com/creepiest-space/dice-o-rolla/issues"},"license":"Apache-2.0","homepage":"https://github.com/creepiest-space/dice-o-rolla#readme","keywords":["assets","dice","skins","sounds","typescript"],"repository":{"url":"git+https://github.com/creepiest-space/dice-o-rolla.git","type":"git","directory":"packages/dice-assets"},"description":"Web Audio and KTX2/PBR assets with texture authoring API and CLI for Dice O Rolla.","maintainers":[{"name":"zerodi","email":"mail@zerodi.ru"}],"readme":"# `@dice-o-rolla/dice-assets`\n\nOptional production asset system for Dice O Rolla. The dependency direction stays one-way:\nengine, physics, and renderer packages never import `dice-assets`; an application opts in and wires\nopaque preset IDs to these adapters.\n\nThe catalog has independent registries for audio sprites, audio banks, PBR materials, reusable\npatterns, skins, skin sets, and face atlases. A skin references assets by ID, so recolor, hue, saturation,\npattern scale, and shader compositing create variants without duplicating KTX2 data.\n\n```ts\nimport catalog from '@dice-o-rolla/dice-assets/catalog.json' with { type: 'json' };\nimport {\n  DiceAssetRegistry,\n  ImpactSoundGate,\n  WebAudioSpritePlayer,\n} from '@dice-o-rolla/dice-assets';\n\nconst assets = new DiceAssetRegistry();\nassets.registerCatalog(catalog);\n\nconst audio = new WebAudioSpritePlayer(assets, { context: new AudioContext() });\nconst impactGate = new ImpactSoundGate();\nengine.on('roll:start', () => impactGate.clear());\nengine.on('die:collision', (event) => impactGate.observeCollision(event));\nengine.on('die:impact', (event) => {\n  if (!impactGate.consumeImpact(event) || event.soundPackId === undefined) return;\n  void audio.playImpact({\n    force: event.force,\n    dieMaterialBankId: event.soundPackId,\n    ...(event.otherDieId === undefined ? { surfaceMaterialBankId: 'classic-wood-table' } : {}),\n  });\n});\n```\n\nRapier reports contact force on every simulation step while two colliders remain touching.\n`ImpactSoundGate` combines that stream with collision start/end events so each physical contact\nproduces one sound instead of an overlapping retrigger on every fixed step.\n\nFor Three.js, pass a `materialProvider` factory to `ThreeDiceRenderer` or `TopDownDiceRenderer`; the\nfactory receives its active `WebGLRenderer` and can construct `ThreeAssetMaterialProvider`. Call\n`prepareSkin()` before dice using that skin can spawn. It loads KTX2 through Three's `KTX2Loader`,\nshares texture instances, uses the packed ORM map for AO/roughness/metalness, and composites the face\natlas in the material shader.\n\n## Prepared skin sets\n\nUse `prepareTexturedSkinSet({ registry, provider, skinSetId })` to validate and preload a textured\nset. Register the returned handle with `skinSet.register(engine)` and pass\n`{ visualPresetSelector: skinSet.visualPresetSelector }` to `engine.roll()` or `engine.simulate()`.\nThe helper handles paired tens variants, leaves absent types to engine defaults and does not\nchange defaults during registration. Repeated registrations through the helper are idempotent;\nconflicting content is rejected and failed registration rolls back entries added by that call.\n\nThe provider must use the same registry and owns the texture lifetime. Use separate registries and\nproviders when reloading changed assets. For a complete preparation and browser example, see\n[Preparing and connecting textured dice nets](https://github.com/creepiest-space/dice-o-rolla/blob/main/docs/textured-unwraps.md).\nThe `@dice-o-rolla/dice-assets/tools` entry point exports editable SVG templates and builds\nKTX2 catalogs under Node.js or Bun; it is not needed by browser consumers.\n\n## Texture authoring API and CLI\n\nThe same package provides Node.js 20+/Bun tools through `@dice-o-rolla/dice-assets/tools`.\nKeep this entry out of browser imports. Install KTX-Software (`ktx` on PATH) for encoding;\ntemplate export does not require it.\n\n```sh\nnpx dice-assets template --types d6 --id painted --out ./art/painted\n# Paint art/painted/d6.svg, then build the runtime catalog.\nnpx dice-assets build --input ./art/painted/skin-set.source.json --out ./public/dice/painted\n```\n\n```ts\nimport {\n  createTextureTemplate,\n  writeTextureTemplates,\n  buildTexturedSkinSet,\n} from '@dice-o-rolla/dice-assets/tools';\n\nconst template = createTextureTemplate('d6', { size: 2048 });\nawait writeTextureTemplates({ outputDirectory: './art/custom', types: ['d6'], id: 'custom' });\nconst built = await buildTexturedSkinSet({\n  input: './art/custom/skin-set.source.json',\n  outputDirectory: './public/dice/custom',\n});\nconsole.log(template.unwrap, built.catalog);\n```\n\nUse `--types standard` for all shapes and tens variants. The `artwork` and `labels` layers are\nrasterized; `guides` is removed. `--overwrite` replaces the entire generated destination only after\na successful build, so keep source files elsewhere. See the guide above for PBR maps and hosting.\nRun `bun run test:integration` in this workspace to verify real KTX encoding.\n\n## Connected surface unwraps\n\nA `DicePatternDefinition` can include `unwrap: DiceSurfaceUnwrap`: a `geometryId`, a `faces`\nrecord keyed by physical face value, and an optional SVG `preview` reference. Every face contains\none `[u, v]` pair per vertex, in the exact order of the geometry's `face.indices`. Coordinates are\nnormalized to `[0, 1]` with a **bottom-left origin**. Include all faces, including those whose visible\nlabels differ from their physical values. The material provider checks geometry compatibility and\ncomplete corner coverage before mesh allocation.\n\nUse `ktx create --convert-texcoord-origin bottom-left` when encoding surface maps from PNG. KTX2\ntextures are compressed and cannot rely on Three.js `flipY`. Base color, normal and ORM maps use\nUV channel 1 with clamp wrapping; label atlases retain local face UVs in channel 0. Unwrapped\npatterns cannot declare `repeat`; pattern scaling is ignored for surface sampling. Existing\npatterns without `unwrap` keep their per-face mapping.\n\n`DiceSkinSetDefinition` groups skins by application-level die type:\n\n```ts\nconst set = assets.skinSets.get('diagnostic');\nconst cubeSkinId = set?.skins.d6; // diagnostic-d6\n```\n\nThe bundled `diagnostic` set provides d4, d6, d8, d10, d12, d20, d100 tens and d66 tens. Each skin\nuses one connected, non-overlapping net; d6 uses a cross. Diagnostic labels are baked into the\ntexture, including d4's vertex labels and the separate tens variants. Register a visual preset for\neach skin using its pattern's `unwrap.geometryId`. For paired dice, select the tens preset through\n`roll`/`simulate`'s existing `visualPresetSelector`; its `component.role` and `component.groupType`\ndistinguish the tens component from the ordinary d10/d6 units component.\n\nPrepare each skin before creating dice. Dispose the provider when its renderer is released;\nin-flight texture loads settle and release resources without repopulating a disposed provider.\nThe loader resolves preview URLs relative to the catalog, just like texture URLs. Catalog schema\nversion remains 1; all new fields are optional.\n\n## Asset pipeline\n\nRun `bun run --filter @dice-o-rolla/dice-assets assets:build`. The documented build performs:\n\n- procedural generation of original mono WAV, PNG, and SVG masters;\n- SVG/font text rasterization through Resvg into a single face atlas;\n- `ktx create` conversion to UASTC KTX2 with offline mipmaps and Zstd supercompression;\n- KTX validation with `ktx validate`;\n- FFmpeg conversion and concatenation into mono WebM/Opus audio sprites;\n- connected diagnostic nets, SVG previews and KTX2 textures with edge padding and mipmaps;\n- production JSON catalog generation with clip offsets, material banks, atlas regions and skin sets.\n\nThe checked-in set combines original procedural test textures/audio with Unlicense impact WAV\nmasters from 3DDiceRoller. Runtime audio is split into dice, coin, felt, metal, wood-table, and\nwood-tray mono Opus sprites. See `THIRD_PARTY_NOTICES.md` and the upstream license copied beside the\nsource masters. No Dice So Nice assets are included.\n\nLicensed under Apache-2.0.\n\nDiagnostic sources are generated by `scripts/diagnostic-nets.ts` from the registered polyhedra.\nThe deterministic edge-unfolding search preserves lengths and rejects overlapping polygons.\nTests verify connectivity, corner distances, winding, shared edge identifiers, raster colors,\nKTX orientation and mipmaps. Regenerate through `assets:build`; do not hand-edit runtime files.\n","readmeFilename":"README.md"}