{"_id":"@cardanvil/frame-kit","_rev":"6-490c81e8a90d562f25cc4bf3f4266f7b","name":"@cardanvil/frame-kit","dist-tags":{"latest":"0.6.0"},"versions":{"0.2.0":{"name":"@cardanvil/frame-kit","version":"0.2.0","license":"MIT","_id":"@cardanvil/frame-kit@0.2.0","maintainers":[{"name":"amodsoul","email":"amodsoul@gmail.com"},{"name":"alextaxiera","email":"alex.taxiera@gmail.com"}],"homepage":"https://github.com/Card-Anvil/frames#readme","bugs":{"url":"https://github.com/Card-Anvil/frames/issues"},"bin":{"frame-kit":"dist/cli/main.js"},"dist":{"shasum":"47a1dca196f015bab7af84169045c57313949f58","tarball":"https://registry.npmjs.org/@cardanvil/frame-kit/-/frame-kit-0.2.0.tgz","fileCount":69,"integrity":"sha512-ykcDNs1kX/7DZm+HF1wrUahQPuxXzOM8tIINgP30AYZXVidoH5UwstnJwgqGWsHBqIxG3KYtZ6ZIFg0n7kWcow==","signatures":[{"sig":"MEUCIHv+95oUA6MxcuQFQvT3h2GikXMzMOK33lSHd2E+BdkiAiEAxWhSWGT4mAxiEKgAniIACy50jdYnqgU4ANYrQM+b2pw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1712151},"type":"module","_from":"file:cardanvil-frame-kit-0.2.0.tgz","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./manifest":{"types":"./dist/manifest/index.d.ts","default":"./dist/manifest/index.js"},"./packaging":{"types":"./dist/cli/index.d.ts","default":"./dist/cli/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json && node dist/cli/emitSchemas.js"},"_npmUser":{"name":"alextaxiera","email":"alex.taxiera@gmail.com"},"_resolved":"C:\\Users\\Alex\\Source\\frames\\packages\\frame-kit\\cardanvil-frame-kit-0.2.0.tgz","_integrity":"sha512-ykcDNs1kX/7DZm+HF1wrUahQPuxXzOM8tIINgP30AYZXVidoH5UwstnJwgqGWsHBqIxG3KYtZ6ZIFg0n7kWcow==","repository":{"url":"git+https://github.com/Card-Anvil/frames.git","type":"git","directory":"packages/frame-kit"},"_npmVersion":"11.13.0","description":"The contract Card Anvil frames are authored against: schemas, types, authoring helpers, and the distributable manifest format.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","dependencies":{"yazl":"^3.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.6","@types/node":"^24.13.2","@types/yazl":"^3.3.1"},"peerDependencies":{"zod":"^4","vite":"^6 || ^7"},"peerDependenciesMeta":{"vite":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/frame-kit_0.2.0_1788984798674_0.6508848830648548","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@cardanvil/frame-kit","version":"0.3.0","license":"MIT","_id":"@cardanvil/frame-kit@0.3.0","maintainers":[{"name":"amodsoul","email":"amodsoul@gmail.com"},{"name":"alextaxiera","email":"alex.taxiera@gmail.com"}],"homepage":"https://github.com/Card-Anvil/frames#readme","bugs":{"url":"https://github.com/Card-Anvil/frames/issues"},"bin":{"frame-kit":"dist/cli/main.js"},"dist":{"shasum":"ed01cd32c0b3ca2b00907d2d79e392b40585d93d","tarball":"https://registry.npmjs.org/@cardanvil/frame-kit/-/frame-kit-0.3.0.tgz","fileCount":73,"integrity":"sha512-y7FOzLMxKL3qVCoSydwIueyBuJfRBy51FL5HoE96Iok60L/AcBcNmDE9g2S5CFeFEiVnSeJrTDxXAe3CasK9Cg==","signatures":[{"sig":"MEYCIQD0IAgeMtjj8M0u7t95QtsimEwhKRd4ehTxnmxWJ/sUDQIhAP/fiL206H9mdr9GBgsmTOochwVRs/ygCKGc0hpOTsk3","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCWTS4twb1/1Ew3F+eBy2jAcMAxLcOScEjj9zwskvTLOgIhAJrJddfUQgq0lXvDSZks06VCzSaeOt0st81C0+bv46hd","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@cardanvil%2fframe-kit@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1729922},"type":"module","_from":"file:packages/frame-kit/cardanvil-frame-kit-0.3.0.tgz","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./manifest":{"types":"./dist/manifest/index.d.ts","default":"./dist/manifest/index.js"},"./packaging":{"types":"./dist/cli/index.d.ts","default":"./dist/cli/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json && node dist/cli/emitSchemas.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5a790aff-7b4b-445a-813b-b82a7c3ec74a"}},"_resolved":"/home/runner/work/frames/frames/packages/frame-kit/cardanvil-frame-kit-0.3.0.tgz","_integrity":"sha512-y7FOzLMxKL3qVCoSydwIueyBuJfRBy51FL5HoE96Iok60L/AcBcNmDE9g2S5CFeFEiVnSeJrTDxXAe3CasK9Cg==","repository":{"url":"git+https://github.com/Card-Anvil/frames.git","type":"git","directory":"packages/frame-kit"},"_npmVersion":"11.13.0","description":"The contract Card Anvil frames are authored against: schemas, types, authoring helpers, and the distributable manifest format.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","dependencies":{"yazl":"^3.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.6","@types/node":"^24.13.2","@types/yazl":"^3.3.1"},"peerDependencies":{"zod":"^4","vite":"^6 || ^7"},"peerDependenciesMeta":{"vite":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/frame-kit_0.3.0_1789069617620_0.9024677970458534","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@cardanvil/frame-kit","version":"0.3.1","license":"MIT","_id":"@cardanvil/frame-kit@0.3.1","maintainers":[{"name":"amodsoul","email":"amodsoul@gmail.com"},{"name":"alextaxiera","email":"alex.taxiera@gmail.com"}],"homepage":"https://github.com/Card-Anvil/frames#readme","bugs":{"url":"https://github.com/Card-Anvil/frames/issues"},"bin":{"frame-kit":"dist/cli/main.js"},"dist":{"shasum":"5282f55bb7a17af24d82b5d160934947b1be188b","tarball":"https://registry.npmjs.org/@cardanvil/frame-kit/-/frame-kit-0.3.1.tgz","fileCount":73,"integrity":"sha512-mm/ZbW++2fTOgYgdJR98mw43IFad3kjcCki4JWaJAEihww1aJ8rlTP8vsnH+LuqkdBbeuvi1YjpJso8Ja+6kww==","signatures":[{"sig":"MEYCIQCJKV1DUTtzeZYbbrOd27+php68jpG1AGQvf1KumxPIfAIhAJcHfxsOeJOK17iMIBF+nKD256vdC+wOpeWGZ5wcxmfi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC2U53oHHbO5EiFFBGPHWktHLbfRaXH+dpPl2CgbO/j1QIgWiiTGFCczWemb3cMubAxBN7QmvCrE8F7JCB1NV7fZdY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@cardanvil%2fframe-kit@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1732121},"type":"module","_from":"file:packages/frame-kit/cardanvil-frame-kit-0.3.1.tgz","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./manifest":{"types":"./dist/manifest/index.d.ts","default":"./dist/manifest/index.js"},"./packaging":{"types":"./dist/cli/index.d.ts","default":"./dist/cli/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json && node dist/cli/emitSchemas.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5a790aff-7b4b-445a-813b-b82a7c3ec74a"}},"_resolved":"/home/runner/work/frames/frames/packages/frame-kit/cardanvil-frame-kit-0.3.1.tgz","_integrity":"sha512-mm/ZbW++2fTOgYgdJR98mw43IFad3kjcCki4JWaJAEihww1aJ8rlTP8vsnH+LuqkdBbeuvi1YjpJso8Ja+6kww==","repository":{"url":"git+https://github.com/Card-Anvil/frames.git","type":"git","directory":"packages/frame-kit"},"_npmVersion":"11.13.0","description":"The contract Card Anvil frames are authored against: schemas, types, authoring helpers, and the distributable manifest format.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","dependencies":{"yazl":"^3.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.6","@types/node":"^24.13.2","@types/yazl":"^3.3.1"},"peerDependencies":{"zod":"^4","vite":"^6 || ^7"},"peerDependenciesMeta":{"vite":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/frame-kit_0.3.1_1789080830062_0.522071660823497","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@cardanvil/frame-kit","version":"0.4.0","license":"MIT","_id":"@cardanvil/frame-kit@0.4.0","maintainers":[{"name":"amodsoul","email":"amodsoul@gmail.com"},{"name":"alextaxiera","email":"alex.taxiera@gmail.com"}],"homepage":"https://github.com/Card-Anvil/frames#readme","bugs":{"url":"https://github.com/Card-Anvil/frames/issues"},"bin":{"frame-kit":"dist/cli/main.js"},"dist":{"shasum":"38614e52fc960c5b05ca672026c5e6a544116ab7","tarball":"https://registry.npmjs.org/@cardanvil/frame-kit/-/frame-kit-0.4.0.tgz","fileCount":73,"integrity":"sha512-HicJqLtX4VRxNH0jypD2AoRp3piXl/MiVGLz+MLzzFu9qJR4qSZtMWKp2dBl+VidDL09hBXKoBm+1/1bUMvGKg==","signatures":[{"sig":"MEQCIDW0edTsgZKxxeq7J+0T8n1U53GX/YvpfeoH3iaxp1YTAiBYAkAebelY+RVvS8aGKps3vl4cvH3lbymCHkaRQ48I0A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIEJBDVRCUe9lfroQxtla76FL6PzGXgxLGWOFFvz4aTvxAiBR55CS2jmsNF5Sbfh9Jgs/f79ar3OFGRce+iKa1IH8wg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@cardanvil%2fframe-kit@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1734935},"type":"module","_from":"file:packages/frame-kit/cardanvil-frame-kit-0.4.0.tgz","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./manifest":{"types":"./dist/manifest/index.d.ts","default":"./dist/manifest/index.js"},"./packaging":{"types":"./dist/cli/index.d.ts","default":"./dist/cli/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json && node dist/cli/emitSchemas.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5a790aff-7b4b-445a-813b-b82a7c3ec74a"}},"_resolved":"/home/runner/work/frames/frames/packages/frame-kit/cardanvil-frame-kit-0.4.0.tgz","_integrity":"sha512-HicJqLtX4VRxNH0jypD2AoRp3piXl/MiVGLz+MLzzFu9qJR4qSZtMWKp2dBl+VidDL09hBXKoBm+1/1bUMvGKg==","repository":{"url":"git+https://github.com/Card-Anvil/frames.git","type":"git","directory":"packages/frame-kit"},"_npmVersion":"11.13.0","description":"The contract Card Anvil frames are authored against: schemas, types, authoring helpers, and the distributable manifest format.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","dependencies":{"yazl":"^3.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.6","@types/node":"^24.13.2","@types/yazl":"^3.3.1"},"peerDependencies":{"zod":"^4","vite":"^6 || ^7"},"peerDependenciesMeta":{"vite":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/frame-kit_0.4.0_1789163881515_0.632332736795282","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@cardanvil/frame-kit","version":"0.5.0","license":"MIT","_id":"@cardanvil/frame-kit@0.5.0","maintainers":[{"name":"amodsoul","email":"amodsoul@gmail.com"},{"name":"alextaxiera","email":"alex.taxiera@gmail.com"}],"homepage":"https://github.com/Card-Anvil/frames#readme","bugs":{"url":"https://github.com/Card-Anvil/frames/issues"},"bin":{"frame-kit":"dist/cli/main.js"},"dist":{"shasum":"1c2cd57c5dab4fd493a63a068a19f77fcb4d1a78","tarball":"https://registry.npmjs.org/@cardanvil/frame-kit/-/frame-kit-0.5.0.tgz","fileCount":73,"integrity":"sha512-mKjS5CcUvQetNQQHKh63wIHqsNvd4GDE/IL3TDzDM1VplPCqDKphC94y+h03EMB3XWqqPnQmTFYDsSnniAaRig==","signatures":[{"sig":"MEQCIFIe7TED6IImuv6zFYOuEH6PgzGUASM9/XAnefwGALNOAiBcVCL/WAgYsgFMSOgp300l1C7TiDXSoPfo/n/Mu0Q8/g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDZM3aWNPlk4qhX8JEvRb/y/Cab+pNpvwaVo7HRk9rb6gIgZ3KDEAQiK8YLKKYnvc6a+rAiNTfduETcUBxDx+JaMKk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@cardanvil%2fframe-kit@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1793633},"type":"module","_from":"file:packages/frame-kit/cardanvil-frame-kit-0.5.0.tgz","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./manifest":{"types":"./dist/manifest/index.d.ts","default":"./dist/manifest/index.js"},"./packaging":{"types":"./dist/cli/index.d.ts","default":"./dist/cli/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json && node dist/cli/emitSchemas.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5a790aff-7b4b-445a-813b-b82a7c3ec74a"}},"_resolved":"/home/runner/work/frames/frames/packages/frame-kit/cardanvil-frame-kit-0.5.0.tgz","_integrity":"sha512-mKjS5CcUvQetNQQHKh63wIHqsNvd4GDE/IL3TDzDM1VplPCqDKphC94y+h03EMB3XWqqPnQmTFYDsSnniAaRig==","repository":{"url":"git+https://github.com/Card-Anvil/frames.git","type":"git","directory":"packages/frame-kit"},"_npmVersion":"11.13.0","description":"The contract Card Anvil frames are authored against: schemas, types, authoring helpers, and the distributable manifest format.","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","dependencies":{"yazl":"^3.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.6","@types/node":"^24.13.2","@types/yazl":"^3.3.1"},"peerDependencies":{"zod":"^4","vite":"^6 || ^7"},"peerDependenciesMeta":{"vite":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/frame-kit_0.5.0_1789265011247_0.9505436301611574","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"_id":"@cardanvil/frame-kit@0.6.0","bin":{"frame-kit":"dist/cli/main.js"},"bugs":{"url":"https://github.com/Card-Anvil/frames/issues"},"dist":{"shasum":"59321e6480401653acd027b5847c80f722e09fdf","tarball":"https://registry.npmjs.org/@cardanvil/frame-kit/-/frame-kit-0.6.0.tgz","fileCount":108,"integrity":"sha512-FT+W/iN4BK12KR7hjk6agKPqwTt27cB44xbqG3Pk20k7Ul5IGw49BhVwjfhL2ppt+u3tS3W9GxTy+Eh12YFKFA==","signatures":[{"sig":"MEQCIBFk7ztYygM3+LM+IKbAUu+U7YTN3pNTkJ2QzCmpK6PsAiAwALDs3Pb8rDqvjxS57JHrmzcOs91d5xWLAF4fX147rA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCvCBKeLKPaycdpcuUX+oG7lemxNPK0ezWO5foDppM9lAIgZ/kXJJOMSUAAiNFQFfag9mJ22gEkoyW4ZTbsizZU08Y="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@cardanvil%2fframe-kit@0.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":3238620},"name":"@cardanvil/frame-kit","type":"module","_from":"file:packages/frame-kit/cardanvil-frame-kit-0.6.0.tgz","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./layout":{"types":"./dist/layout/index.d.ts","default":"./dist/layout/index.js"},"./manifest":{"types":"./dist/manifest/index.d.ts","default":"./dist/manifest/index.js"},"./packaging":{"types":"./dist/cli/index.d.ts","default":"./dist/cli/index.js"},"./package.json":"./package.json"},"license":"MIT","scripts":{"build":"pnpm run build:lib && pnpm --filter @cardanvil/frame-studio build","build:lib":"tsc -p tsconfig.build.json && node dist/cli/emitSchemas.js"},"version":"0.6.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:5a790aff-7b4b-445a-813b-b82a7c3ec74a"}},"homepage":"https://github.com/Card-Anvil/frames#readme","_resolved":"/home/runner/work/frames/frames/packages/frame-kit/cardanvil-frame-kit-0.6.0.tgz","_integrity":"sha512-FT+W/iN4BK12KR7hjk6agKPqwTt27cB44xbqG3Pk20k7Ul5IGw49BhVwjfhL2ppt+u3tS3W9GxTy+Eh12YFKFA==","repository":{"url":"git+https://github.com/Card-Anvil/frames.git","type":"git","directory":"packages/frame-kit"},"_npmVersion":"11.13.0","description":"The contract Card Anvil frames are authored against: schemas, types, authoring helpers, and the distributable manifest format.","directories":{},"maintainers":[{"name":"amodsoul","email":"amodsoul@gmail.com"},{"name":"alextaxiera","email":"alex.taxiera@gmail.com"}],"sideEffects":false,"_nodeVersion":"24.16.0","dependencies":{"yazl":"^3.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.6","@types/node":"^24.13.2","@types/yazl":"^3.3.1"},"peerDependencies":{"zod":"^4","vite":"^6 || ^7","typescript":"^6"},"peerDependenciesMeta":{"vite":{"optional":true},"typescript":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/frame-kit_0.6.0_1789520136559_0.9590477491755331"}}},"time":{"created":"2026-09-09T20:13:18.491Z","modified":"2026-09-16T00:55:37.134Z","0.2.0":"2026-09-09T20:13:18.822Z","0.3.0":"2026-09-10T19:46:57.745Z","0.3.1":"2026-09-10T22:53:50.166Z","0.4.0":"2026-09-11T21:58:01.627Z","0.5.0":"2026-09-13T02:03:31.346Z","0.6.0":"2026-09-16T00:55:36.735Z"},"bugs":{"url":"https://github.com/Card-Anvil/frames/issues"},"license":"MIT","homepage":"https://github.com/Card-Anvil/frames#readme","repository":{"url":"git+https://github.com/Card-Anvil/frames.git","type":"git","directory":"packages/frame-kit"},"description":"The contract Card Anvil frames are authored against: schemas, types, authoring helpers, and the distributable manifest format.","maintainers":[{"name":"amodsoul","email":"amodsoul@gmail.com"},{"name":"alextaxiera","email":"alex.taxiera@gmail.com"}],"readme":"# @cardanvil/frame-kit\n\nThe contract [Card Anvil](https://github.com/Card-Anvil) frames are authored against: the schemas that\ndefine what a frame is, the helpers you author one with, and the format frames are distributed in.\n\n```sh\npnpm add -D @cardanvil/frame-kit zod\n```\n\n`zod` is a peer dependency — the frame types are inferred from zod schemas, so you and this package\nmust share one copy.\n\n> **Building a frame?** Start from\n> [Card-Anvil/frame-template](https://github.com/Card-Anvil/frame-template) instead of wiring this up\n> by hand. This package is the contract underneath it.\n\n## A frame is data\n\nA frame is one plain object: box geometry, asset URLs, and a few render knobs. Nothing in it runs at\nrender time. That constraint is the whole reason frames are distributable — a frame can be serialized\nto a `frame.json` plus a folder of images and loaded by an app that never compiled it, precisely\nbecause there is no behaviour to carry across.\n\n```ts\nimport { type Frame, withCollectorInfoDefaults } from \"@cardanvil/frame-kit\";\n\nimport preview from \"./preview.jpg\";\nimport { regularLayoutConfig } from \"./regular/config\";\n\nexport const myFrame = {\n  name: \"Parchment\",\n  description: \"A hand-inked parchment frame.\",\n  previewImage: preview,\n  tags: [\"Custom\"],\n  config: {\n    layouts: {\n      normal: withCollectorInfoDefaults(regularLayoutConfig, collectorBounds),\n    },\n  },\n} as const satisfies Frame;\n```\n\n`as const satisfies Frame` is the idiom: `satisfies` checks the object against the contract, `as const`\nkeeps the literal types.\n\n## Entry points\n\n| Import                           | What it gives you                                                                                                                                                                    |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `@cardanvil/frame-kit`           | The schemas (`FrameSchema`, `LayoutConfigSchema`, `FrameAssetsSchema`, …), the inferred types (`Frame`, `LayoutConfig`, `CardBoxes`, `TextBox`, `Layout`), and the authoring helpers |\n| `@cardanvil/frame-kit/manifest`  | The distributable format: `frameToManifest`, `manifestToFrame`, `walkAssets`, `FrameManifestSchema`, `isContractCompatible`, `assertDeclarative`                                     |\n| `@cardanvil/frame-kit/packaging` | The packaging tools the CLI is built on: `validateFrames`, `buildFrames`, `FrameIndexSchema`. Needs Node and Vite, so it is deliberately not on the main entry point                 |\n\n## The `frame-kit` command\n\n```bash\nframe-kit validate                # check every frame, write nothing\nframe-kit build --out dist        # check, then pack each one\nframe-kit build --out dist --watch  # …and repack whenever a source changes\nframe-kit schema meta             # a format as JSON Schema\nframe-kit --help\n```\n\nA frame is any directory holding a `frame.meta.json`, so this works both in a\nworkspace of packages and in a flat repository.\n\n`validate` loads every frame through Vite, parses it against `FrameSchema`,\nresolves every asset to a file that exists, and round-trips it through the\nmanifest in memory. Problems are collected rather than thrown, so one run\nreports everything; under GitHub Actions they become inline annotations.\n\n`build` adds hashing, zipping and the release index. Each frame becomes a\n`<slug>-<version>.cardframe`, and `frame-index.json` describes the set.\n\nExit codes: `0` clean, `1` one or more frames failed, `2` used wrongly.\n\n### Frames you do not want to ship\n\nA descriptor can opt its frame out of every build:\n\n```json\n{\n  \"id\": \"com.example.example\",\n  \"private\": true,\n  \"author\": { \"name\": \"Your Name\" },\n  \"license\": \"CC-BY-4.0\"\n}\n```\n\n`validate` still loads and checks it; `build` reports it as skipped and packs\nnothing, so it never reaches a bundle, the index, or a release. That is the\ncombination a worked example needs — a reference frame stays in the repository\nand stays correct, without an `id` that is permanent identity ending up in\nsomebody's release by accident.\n\n### `--watch`\n\n`build --watch` builds once, then rebuilds only the frames whose files changed,\nuntil you stop it. It is meant to be pointed at a folder Card Anvil is linked to,\nso saving a source file updates the preview without any manual step.\n\n```bash\nframe-kit build --out ~/CardAnvilFrames --watch\n```\n\nA failed rebuild leaves the previous bundle in place and prints the problem — the\napp keeps rendering the last good build rather than losing the frame mid-edit.\nBundles are written atomically, so a watcher on the other side never reads a\nhalf-written file. `--watch` refuses to combine with `--json` or `--summary-md`,\nwhich describe a single run that has finished.\n\nChanges are debounced 200 ms, and a rebuild already in flight is allowed to\nfinish before the next one starts: two builds writing one bundle would race.\nOutput files, dotfiles, `node_modules`, `dist` and editor droppings are ignored,\nso a rebuild cannot trigger itself.\n\nBecause bundles are byte-deterministic, saving a file that does not change the\nbuilt output produces an identical bundle, and a consumer watching for content\nchanges sees nothing happen — which is correct.\n\n⚠ **Frames are loaded through a long-lived Vite server**, and its SSR module\ncache is invalidated on each pass. Without that a rebuild would re-serve the\nmodule Vite loaded first, so an edited layout number would rebuild\nbyte-identically and the watch would appear to do nothing. If you embed the\nbuild API yourself, call `invalidateFrameModules` between passes on a server you\nreuse.\n\nPackaging needs Vite — it is what turns `import w from \"./w.png\"` into a file —\nso it is an **optional** peer dependency, loaded only when packaging runs. The\nschemas above work under plain Node and in a browser without it.\n\n### `frame-kit studio`\n\n```bash\nframe-kit studio [--root <dir>] [--port <n>] [--frame <slug>] [--no-write]\n```\n\nA visual box editor, served from `dist/studio` and opened at\n<http://localhost:4620>. It loads frames through the same Vite SSR loader\n`validate` uses, so what it draws is the validated frame, and it reloads when a\nsource file changes.\n\nThe card name and type line are previewed in Beleren at the authored size and\nflagged when they overflow — one line each, with no wrapping, symbols or\nauto-shrink, so the app remains the authority on a full render.\n\nWorking on the studio's own UI: `--dev` serves it from source with hot\nreloading, on the same port as the API, so one command covers both. It needs\nthe UI's source, which only exists inside the frames workspace.\n\nDragging a box rewrites the literal it came from, in place — nothing is\nreprinted, so comments and formatting survive. Editing needs `typescript`\ninstalled (an optional peer); without it the studio still runs read-only. Values\nthat are not written as literals are reported as such rather than edited.\n\n### `@cardanvil/frame-kit/layout`\n\nHow a frame's art is chosen and placed, as pure functions:\n\n- `selectFrameLayers(details, options)` — the base frame and section overlays a\n  set of `FrameDetails` selects. Split out of Card Anvil's `getFrameLayers`, so\n  the studio and the renderer cannot drift on two-colour splits, hybrid halves\n  or the coloured-artifact fallback.\n- `frameDetailsFor(shape)` — those details from a plain description of a card\n  (colours plus artifact / vehicle / land / enchantment / hybrid / devoid),\n  for callers with no Scryfall card to parse.\n- `placeAsset(path, config)` — where a piece of art is drawn. Most frame art is\n  full-sheet and centres, but crowns, nicknames and PT plates come from the\n  layout's own render config; centring those puts a legendary crown in the\n  middle of the card.\n- `resolveFrameAsset` / `resolveBaseFrame` — exact per-family lookup, and the\n  base-frame fallback chain.\n\nCard Anvil still owns the other half — reading a Scryfall card into\n`FrameDetails` — because that is where the Scryfall types live.\n\n## Type it, then validate it\n\nTyping a config as `Frame` is weaker than the schema a loading app enforces. The clearest example:\npassing a whole asset barrel to a typed field type-checks even when the barrel exports extra keys,\nbecause excess property checks do not apply to namespace objects — and those extra keys then enter the\nframe contract where nothing can resolve them.\n\n```ts\nimport { FrameSchema } from \"@cardanvil/frame-kit\";\n\nconst result = FrameSchema.safeParse(myFrame);\nexpect(result.error?.issues ?? []).toEqual([]);\n```\n\n## The coordinate space\n\nBoxes are **absolute pixels** on a **3264 × 4440** canvas.\n\n⚠ **A Magic card face is 63 × 88 mm** — _not_ 2.5 × 3.5 inches, which is the poker-card size and is\nwrong by 0.5 mm across and 0.9 mm tall, roughly 24 × 43 pixels at 1200 DPI. In inches the card is\n2.48 × 3.46.\n\nThe canvas is **not** the card face: it is the full printed sheet **including bleed** — 2.72 × 3.7 in\n(69.09 × 93.98 mm) at 1200 DPI, about 3 mm of bleed per edge. A box at `y: 0` sits in the bleed, above\nthe top of the card. Override the canvas per frame with `config.canvas`.\n\n`fontSize` is in **points**, not pixels; the renderer converts.\n\n## The distributable format\n\n`@cardanvil/frame-kit/manifest` converts a `Frame` into something an app can install: a `frame.json`\nwith every asset URL rewritten to a package-relative path, plus the files themselves.\n\nAsset positions are found by **walking the schema**, not from a hard-coded list of field paths, so a\nnew asset field in the contract is picked up automatically.\n\n```ts\nimport { frameToManifest } from \"@cardanvil/frame-kit/manifest\";\n\nconst manifest = frameToManifest(myFrame, {\n  id: \"com.example.parchment\",\n  version: \"1.0.0\",\n  resolveAsset: (url) => ({ path: `assets/${hashOf(url)}.png` }),\n});\n```\n\n`manifestToFrame` reverses it, turning package-relative paths back into URLs the renderer can load —\nan object URL for a zip, an `asset://` URL for a directory on disk, an absolute URL for a remote\npackage.\n\nA manifest carries a `contractVersion` of the form `MAJOR.MINOR`, independent of this package's\nversion. A differing major is refused; a newer minor loads with a reduced-fidelity warning, because\nadded fields are always optional. A layout the loader does not recognise is dropped with a\ndegraded note rather than failing the frame, so one new layout cannot cost an author every other\none. Packaging preserves everything the contract defines and drops everything it does not — keys\noutside the schema do not survive the round trip.\n\n## Licence\n\nMIT. See [LICENSE](https://github.com/Card-Anvil/frames/blob/trunk/LICENSE).\n","readmeFilename":"README.md"}