{"_id":"@amirhossein-shk/tournament-bracket-js","_rev":"6-a3e60b3d4a8166a136159087d87a4d42","name":"@amirhossein-shk/tournament-bracket-js","dist-tags":{"latest":"1.0.7"},"versions":{"1.0.0":{"name":"@amirhossein-shk/tournament-bracket-js","version":"1.0.0","keywords":["tournament","bracket","javascript","vanilla-js","single-elimination"],"author":"","license":"MIT","_id":"@amirhossein-shk/tournament-bracket-js@1.0.0","maintainers":[{"name":"amirhossein-shk","email":"amirhossein.shk@gmail.com"}],"homepage":"https://github.com/amirhossein-shk/tournament-bracket#readme","bugs":{"url":"https://github.com/amirhossein-shk/tournament-bracket/issues"},"dist":{"shasum":"c16c5244523c4aaa433d6589371833df884e91d6","tarball":"https://registry.npmjs.org/@amirhossein-shk/tournament-bracket-js/-/tournament-bracket-js-1.0.0.tgz","fileCount":10,"integrity":"sha512-Tj+mGmOJoxVu14992ZFtJfTVPZo2Q9L5dMn9NcfboPJok2lWGPdwIiMal8zKwyY3h+FFgVRJkRdNNtaJFBuOMQ==","signatures":[{"sig":"MEYCIQC4AV/6dpU7mkJUlEhTyTOHnKnY72gaDbaAZKG7/Vic0AIhAMwvsdhXFMpvcLaCoufYB52iOJqQdmikbf/XLTLum2tB","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":75610},"main":"tournamentBracket.js","type":"commonjs","style":"dist/tournament-bracket.css","module":"dist/tournament-bracket.esm.js","gitHead":"fa2c46c0aab0183458a868564085346a4be1d26c","scripts":{"css":"sass src/tournament-bracket.scss dist/tournament-bracket.css --style expanded","esm":"vite build --mode esm","build":"npm run clean && npm run browser && npm run browser:min && npm run esm && npm run esm:min && npm run css && npm run css:min && npm run clean:temp","clean":"shx rm -rf dist dist-temp","browser":"vite build --mode browser","css:min":"sass src/tournament-bracket.scss dist/tournament-bracket.min.css --style compressed","esm:min":"vite build --mode esm-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.esm.js dist/tournament-bracket.esm.min.js","clean:temp":"shx rm -rf dist-temp","browser:min":"vite build --mode browser-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.js dist/tournament-bracket.min.js"},"_npmUser":{"name":"amirhossein-shk","email":"amirhossein.shk@gmail.com"},"repository":{"url":"git+https://github.com/amirhossein-shk/tournament-bracket.git","type":"git"},"_npmVersion":"11.6.2","description":"Lightweight vanilla JS tournament bracket library","directories":{},"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"devDependencies":{"shx":"^0.4.0","sass":"^1.101.0","vite":"^8.0.16","terser":"^5.48.0"},"_npmOperationalInternal":{"tmp":"tmp/tournament-bracket-js_1.0.0_1782258305998_0.2630677169539821","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@amirhossein-shk/tournament-bracket-js","version":"1.0.3","keywords":["tournament","bracket","javascript","vanilla-js","single-elimination"],"author":{"name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"},"license":"MIT","_id":"@amirhossein-shk/tournament-bracket-js@1.0.3","maintainers":[{"name":"amirhossein-shk","email":"amirhossein.shk@gmail.com"}],"contributors":[{"url":"https://github.com/amirhossein-shk","name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"}],"homepage":"https://github.com/amirhossein-shk/tournament-bracket#readme","bugs":{"url":"https://github.com/amirhossein-shk/tournament-bracket/issues"},"dist":{"shasum":"8c4756cefad385daaced5f9646c4850ac3e0e5e9","tarball":"https://registry.npmjs.org/@amirhossein-shk/tournament-bracket-js/-/tournament-bracket-js-1.0.3.tgz","fileCount":10,"integrity":"sha512-GzfJyFfjBVtYB5Ie/fWMEt6+XQfuNDQC3iGzOj6WcaS78/y+V14EvElgreH8ilhsKhoemOqL0OwCvKEEHbSlSg==","signatures":[{"sig":"MEQCIDCiT4ztrRYSuHoHXi+jWbhM7I5R5JKD+ZDuaqhroic0AiAQzugZodq/hoUlqp+ZPi/b5xavDtkrvP3hrNyewGsHxg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amirhossein-shk%2ftournament-bracket-js@1.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":75066},"main":"tournamentBracket.js","type":"commonjs","style":"dist/tournament-bracket.css","module":"dist/tournament-bracket.esm.js","gitHead":"ed470273f032cf4c7b25c466f18f7b43f32bf500","scripts":{"css":"sass src/tournament-bracket.scss dist/tournament-bracket.css --style expanded","esm":"vite build --mode esm","build":"npm run clean && npm run browser && npm run browser:min && npm run esm && npm run esm:min && npm run css && npm run css:min && npm run clean:temp","clean":"shx rm -rf dist dist-temp","browser":"vite build --mode browser","css:min":"sass src/tournament-bracket.scss dist/tournament-bracket.min.css --style compressed","esm:min":"vite build --mode esm-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.esm.js dist/tournament-bracket.esm.min.js","clean:temp":"shx rm -rf dist-temp","browser:min":"vite build --mode browser-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.js dist/tournament-bracket.min.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1b444e21-0d4e-44e4-b0eb-57854285595f"}},"repository":{"url":"git+https://github.com/amirhossein-shk/tournament-bracket.git","type":"git"},"_npmVersion":"11.17.0","description":"Lightweight vanilla JS tournament bracket library","directories":{},"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"shx":"^0.4.0","sass":"^1.101.0","vite":"^8.1.0","terser":"^5.48.0"},"_npmOperationalInternal":{"tmp":"tmp/tournament-bracket-js_1.0.3_1782304623781_0.4886711411286029","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@amirhossein-shk/tournament-bracket-js","version":"1.0.4","keywords":["tournament","bracket","javascript","vanilla-js","single-elimination"],"author":{"name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"},"license":"MIT","_id":"@amirhossein-shk/tournament-bracket-js@1.0.4","maintainers":[{"name":"amirhossein-shk","email":"amirhossein.shk@gmail.com"}],"contributors":[{"url":"https://github.com/amirhossein-shk","name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"}],"homepage":"https://github.com/amirhossein-shk/tournament-bracket#readme","bugs":{"url":"https://github.com/amirhossein-shk/tournament-bracket/issues"},"dist":{"shasum":"f6fd9b342259ac39967ec123b0982c5b96764615","tarball":"https://registry.npmjs.org/@amirhossein-shk/tournament-bracket-js/-/tournament-bracket-js-1.0.4.tgz","fileCount":10,"integrity":"sha512-Mp9rqiS9y1XMkRXQTs+oxlXKFAMNsKqNJVnjoT5i9vy7gQIsvKPxuYEzFeT9EHFDWIBNwY/1Hmc4bsAkjEsjbQ==","signatures":[{"sig":"MEUCIQDDY6SCyZSv8UVXO8ImqIjultwoiJ38GphM7KLgb8KArQIgLOelxXTGsH7Q79wSHcyZ1yQeDH4rc9+fjyLp4nOjd0Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amirhossein-shk%2ftournament-bracket-js@1.0.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":75068},"main":"tournamentBracket.js","type":"commonjs","style":"dist/tournament-bracket.css","module":"dist/tournament-bracket.esm.js","gitHead":"c0126c0cdb0a486f26eaee575fbc2ec3886d3bdf","scripts":{"css":"sass src/tournament-bracket.scss dist/tournament-bracket.css --style expanded","esm":"vite build --mode esm","build":"npm run clean && npm run browser && npm run browser:min && npm run esm && npm run esm:min && npm run css && npm run css:min && npm run clean:temp","clean":"shx rm -rf dist dist-temp","browser":"vite build --mode browser","css:min":"sass src/tournament-bracket.scss dist/tournament-bracket.min.css --style compressed","esm:min":"vite build --mode esm-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.esm.js dist/tournament-bracket.esm.min.js","clean:temp":"shx rm -rf dist-temp","browser:min":"vite build --mode browser-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.js dist/tournament-bracket.min.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1b444e21-0d4e-44e4-b0eb-57854285595f"}},"repository":{"url":"git+https://github.com/amirhossein-shk/tournament-bracket.git","type":"git"},"_npmVersion":"11.17.0","description":"Lightweight vanilla JS tournament bracket library","directories":{},"_nodeVersion":"22.23.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"shx":"^0.4.0","sass":"^1.101.0","vite":"^8.1.0","terser":"^5.48.0"},"_npmOperationalInternal":{"tmp":"tmp/tournament-bracket-js_1.0.4_1782385624924_0.8770940691248181","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@amirhossein-shk/tournament-bracket-js","version":"1.0.5","keywords":["tournament","bracket","javascript","vanilla-js","single-elimination"],"author":{"name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"},"license":"MIT","_id":"@amirhossein-shk/tournament-bracket-js@1.0.5","maintainers":[{"name":"amirhossein-shk","email":"amirhossein.shk@gmail.com"}],"contributors":[{"url":"https://github.com/amirhossein-shk","name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"}],"homepage":"https://github.com/amirhossein-shk/tournament-bracket#readme","bugs":{"url":"https://github.com/amirhossein-shk/tournament-bracket/issues"},"dist":{"shasum":"6388ca2f20b3ed2dbc7fb60d50970ca3605cc025","tarball":"https://registry.npmjs.org/@amirhossein-shk/tournament-bracket-js/-/tournament-bracket-js-1.0.5.tgz","fileCount":10,"integrity":"sha512-bwGYAu4VOw57tJzGod25aiIAPmgQFrWmQVk5vgwsgyzlNPU737uGXrXQahGL8uwAvvesKwLdstZ/MhJWMCDqMQ==","signatures":[{"sig":"MEQCIFBu+GBf5UkdNCZkUGfSWORoatK2oPZB/i8rws0cUfluAiAOibciJyn7hceAWbvTIquHvmcykwoDW6E8DPeH5IJ8wA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amirhossein-shk%2ftournament-bracket-js@1.0.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":75129},"main":"tournamentBracket.js","type":"commonjs","style":"dist/tournament-bracket.css","module":"dist/tournament-bracket.esm.js","gitHead":"759f5ed98be193bb961a08f0c0a9b0efc5adac27","scripts":{"css":"sass src/tournament-bracket.scss dist/tournament-bracket.css --style expanded","esm":"vite build --mode esm","build":"npm run clean && npm run browser && npm run browser:min && npm run esm && npm run esm:min && npm run css && npm run css:min && npm run clean:temp","clean":"shx rm -rf dist dist-temp","browser":"vite build --mode browser","css:min":"sass src/tournament-bracket.scss dist/tournament-bracket.min.css --style compressed","esm:min":"vite build --mode esm-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.esm.js dist/tournament-bracket.esm.min.js","clean:temp":"shx rm -rf dist-temp","browser:min":"vite build --mode browser-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.js dist/tournament-bracket.min.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1b444e21-0d4e-44e4-b0eb-57854285595f"}},"repository":{"url":"git+https://github.com/amirhossein-shk/tournament-bracket.git","type":"git"},"_npmVersion":"11.17.0","description":"Lightweight vanilla JS tournament bracket library","directories":{},"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"shx":"^0.4.0","sass":"^1.101.0","vite":"^8.1.0","terser":"^5.48.0"},"_npmOperationalInternal":{"tmp":"tmp/tournament-bracket-js_1.0.5_1782386181052_0.050119936741595206","host":"s3://npm-registry-packages-npm-production"}},"1.0.6":{"name":"@amirhossein-shk/tournament-bracket-js","version":"1.0.6","keywords":["tournament","bracket","javascript","vanilla-js","single-elimination"],"author":{"name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"},"license":"MIT","_id":"@amirhossein-shk/tournament-bracket-js@1.0.6","maintainers":[{"name":"amirhossein-shk","email":"amirhossein.shk@gmail.com"}],"contributors":[{"url":"https://github.com/amirhossein-shk","name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"}],"homepage":"https://github.com/amirhossein-shk/tournament-bracket#readme","bugs":{"url":"https://github.com/amirhossein-shk/tournament-bracket/issues"},"dist":{"shasum":"8381cd86bc42e3bd18d81cf1d93ef00bb84a08bc","tarball":"https://registry.npmjs.org/@amirhossein-shk/tournament-bracket-js/-/tournament-bracket-js-1.0.6.tgz","fileCount":10,"integrity":"sha512-96GDnH+NsJBt/FLkvE5p709JlZtFsHVREwCtJQubTZilyTJ0ab1ww/uDq33EQwFUJfSf1echT/Tiza9OEXWvcQ==","signatures":[{"sig":"MEQCIHjZVqSex7HdjF/Z173suhy27pTxVI56vM6Tpl0ry6OpAiANy+QIJoeVwOygZttjN9Ye0Y6QAts/kdITqzSWDzhAwg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amirhossein-shk%2ftournament-bracket-js@1.0.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":75170},"main":"tournamentBracket.js","type":"commonjs","style":"dist/tournament-bracket.css","module":"dist/tournament-bracket.esm.js","gitHead":"a7e09b3b558aff1ff1ab33fce13f1e8270bb6668","scripts":{"css":"sass src/tournament-bracket.scss dist/tournament-bracket.css --style expanded","esm":"vite build --mode esm","build":"npm run clean && npm run browser && npm run browser:min && npm run esm && npm run esm:min && npm run css && npm run css:min && npm run clean:temp","clean":"shx rm -rf dist dist-temp","browser":"vite build --mode browser","css:min":"sass src/tournament-bracket.scss dist/tournament-bracket.min.css --style compressed","esm:min":"vite build --mode esm-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.esm.js dist/tournament-bracket.esm.min.js","clean:temp":"shx rm -rf dist-temp","browser:min":"vite build --mode browser-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.js dist/tournament-bracket.min.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1b444e21-0d4e-44e4-b0eb-57854285595f"}},"repository":{"url":"git+https://github.com/amirhossein-shk/tournament-bracket.git","type":"git"},"_npmVersion":"11.17.0","description":"Lightweight vanilla JS tournament bracket library","directories":{},"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"shx":"^0.4.0","sass":"^1.101.0","vite":"^8.1.0","terser":"^5.48.0"},"_npmOperationalInternal":{"tmp":"tmp/tournament-bracket-js_1.0.6_1782386445197_0.3736942021842886","host":"s3://npm-registry-packages-npm-production"}},"1.0.7":{"name":"@amirhossein-shk/tournament-bracket-js","version":"1.0.7","description":"Lightweight vanilla JS tournament bracket library","main":"dist/tournament-bracket.js","module":"dist/tournament-bracket.esm.js","style":"dist/tournament-bracket.css","scripts":{"build":"npm run clean && npm run browser && npm run browser:min && npm run esm && npm run esm:min && npm run css && npm run css:min && npm run clean:temp","clean":"shx rm -rf dist dist-temp","clean:temp":"shx rm -rf dist-temp","browser":"vite build --mode browser","browser:min":"vite build --mode browser-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.js dist/tournament-bracket.min.js","esm":"vite build --mode esm","esm:min":"vite build --mode esm-min --outDir dist-temp && shx cp dist-temp/tournament-bracket.esm.js dist/tournament-bracket.esm.min.js","css":"sass src/tournament-bracket.scss dist/tournament-bracket.css --style expanded","css:min":"sass src/tournament-bracket.scss dist/tournament-bracket.min.css --style compressed"},"repository":{"type":"git","url":"git+https://github.com/amirhossein-shk/tournament-bracket.git"},"keywords":["tournament","bracket","javascript","vanilla-js","single-elimination"],"author":{"name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"},"contributors":[{"name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com","url":"https://github.com/amirhossein-shk"}],"publishConfig":{"access":"public"},"type":"commonjs","bugs":{"url":"https://github.com/amirhossein-shk/tournament-bracket/issues"},"homepage":"https://github.com/amirhossein-shk/tournament-bracket#readme","devDependencies":{"sass":"^1.101.0","shx":"^0.4.0","terser":"^5.48.0","vite":"^8.1.0"},"license":"MIT","gitHead":"f8b58a9ddaf73346a0c7f804e99c3b441bd7cecf","_id":"@amirhossein-shk/tournament-bracket-js@1.0.7","_nodeVersion":"22.23.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-63iguGpLY+5b8a/A6BtEaaIhsu/heZxW+kQUQFSgKLlECzB5NurZjSkb0u9EUPSLnl02kGNb3vVFoobe6Memww==","shasum":"cfeef31cd6ad1c47fd977f0aef82b78d3104dbd8","tarball":"https://registry.npmjs.org/@amirhossein-shk/tournament-bracket-js/-/tournament-bracket-js-1.0.7.tgz","fileCount":10,"unpackedSize":76046,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amirhossein-shk%2ftournament-bracket-js@1.0.7","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCh72SFcDLxCV1AsUTD8qpmqf89qR2AFArs0sMS0OR32gIhAM1vs7aOj/bpdEqjtxwRR+neZaaVw6AmhwruNuNqBHq4"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1b444e21-0d4e-44e4-b0eb-57854285595f"}},"directories":{},"maintainers":[{"name":"amirhossein-shk","email":"amirhossein.shk@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/tournament-bracket-js_1.0.7_1782399227280_0.340183796956941"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-23T23:45:05.819Z","modified":"2026-06-25T14:53:47.689Z","1.0.0":"2026-06-23T23:45:06.139Z","1.0.3":"2026-06-24T12:37:03.920Z","1.0.4":"2026-06-25T11:07:05.114Z","1.0.5":"2026-06-25T11:16:21.198Z","1.0.6":"2026-06-25T11:20:45.345Z","1.0.7":"2026-06-25T14:53:47.416Z"},"bugs":{"url":"https://github.com/amirhossein-shk/tournament-bracket/issues"},"author":{"name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com"},"license":"MIT","homepage":"https://github.com/amirhossein-shk/tournament-bracket#readme","keywords":["tournament","bracket","javascript","vanilla-js","single-elimination"],"repository":{"type":"git","url":"git+https://github.com/amirhossein-shk/tournament-bracket.git"},"description":"Lightweight vanilla JS tournament bracket library","contributors":[{"name":"Amirhossein Shk","email":"amirhossein.shk@gmail.com","url":"https://github.com/amirhossein-shk"}],"maintainers":[{"name":"amirhossein-shk","email":"amirhossein.shk@gmail.com"}],"readme":"# Tournament Bracket\n\nA lightweight JavaScript library for rendering and managing single-elimination tournament brackets in the browser.\n\nIt supports both classic browser usage with a `<script>` tag and modern ESM usage with `import`. The library renders bracket rounds, matches, players, scores, avatars, and SVG connector lines, while also exposing a small API for updating matches, finishing matches, reading state, and handling events.\n\n---\n\n## Features\n\n- Render single-elimination tournament brackets\n- Use with a normal browser `<script>` tag\n- Use with modern ESM `import`\n- Support player names, scores, avatars, and fallback avatars\n- Automatically normalize missing player data\n- Validate bracket structure before rendering\n- Update match data after initialization\n- Set individual player scores\n- Finish matches and propagate winners\n- Listen to match click, update, and finish events\n- Ship separate JavaScript and CSS builds\n- Include both minified and non-minified output files\n\n---\n\n## Demo\n\nTry the live demo:\n\n[https://amirhossein-shk.github.io/tournament-bracket/demo/](https://amirhossein-shk.github.io/tournament-bracket/demo/)\n\n---\n\n## File Structure\n\nRecommended project structure:\n\n```txt\nproject/\n  src/\n    tournament-bracket.js\n    tournament-bracket.scss\n    entry-browser.js\n\n  dist/\n    tournament-bracket.js\n    tournament-bracket.min.js\n    tournament-bracket.esm.js\n    tournament-bracket.esm.min.js\n    tournament-bracket.css\n    tournament-bracket.min.css\n\n  demo/\n    index.html\n    tournament-bracket.min.js\n    tournament-bracket.min.css\n\n  README.md\n  package.json\n  vite.config.js\n```\n\n### Folder Purpose\n\n| Folder | Purpose |\n|---|---|\n| `src/` | Source code of the library |\n| `dist/` | Final build output for users |\n| `demo/` | Live demo and usage reference |\n\n---\n\n## Build Files\n\nThe `dist` folder contains the final files that users should consume.\n\n```txt\ndist/\n  tournament-bracket.js\n  tournament-bracket.min.js\n  tournament-bracket.esm.js\n  tournament-bracket.esm.min.js\n  tournament-bracket.css\n  tournament-bracket.min.css\n```\n\n### JavaScript Files\n\n| File | Usage |\n|---|---|\n| `tournament-bracket.js` | Browser build, non-minified |\n| `tournament-bracket.min.js` | Browser build, minified |\n| `tournament-bracket.esm.js` | ESM build, non-minified |\n| `tournament-bracket.esm.min.js` | ESM build, minified |\n\n### CSS Files\n\n| File | Usage |\n|---|---|\n| `tournament-bracket.css` | Stylesheet, non-minified |\n| `tournament-bracket.min.css` | Stylesheet, minified |\n\nThe CSS is intentionally shipped separately from JavaScript. This makes styling easier to override, easier to debug, and easier to use with bundlers or CDNs.\n\n---\n\n## Browser Usage\n\nUse this option when you want to include the library directly in an HTML page.\n\n```html\n<link rel=\"stylesheet\" href=\"./dist/tournament-bracket.min.css\" />\n<script src=\"./dist/tournament-bracket.min.js\"></script>\n```\n\nAfter loading the browser build, the global function is available as:\n\n```js\ntournamentBracket(...)\n```\n\n### Complete Browser Example\n\n```html\n<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\" />\n  <title>Tournament Bracket</title>\n  <link rel=\"stylesheet\" href=\"./dist/tournament-bracket.min.css\" />\n</head>\n<body>\n  <div id=\"tournament-bracket\"></div>\n\n  <script src=\"./dist/tournament-bracket.min.js\"></script>\n  <script>\n    const tb = tournamentBracket({\n      targetId: \"tournament-bracket\",\n      rounds: [\n        {\n          roundId: \"r1\",\n          name: \"Quarter Finals\",\n          matches: [\n            {\n              matchId: \"m1\",\n              isFinished: true,\n              players: [\n                { name: \"Player 1\", score: 2, avatarUrl: \"\" },\n                { name: \"Player 2\", score: 1, avatarUrl: \"\" }\n              ]\n            },\n            {\n              matchId: \"m2\",\n              players: [\n                { name: \"Player 3\", score: \"-\" },\n                { name: \"Player 4\", score: \"-\" }\n              ]\n            }\n          ]\n        },\n        {\n          roundId: \"r2\",\n          name: \"Semi Finals\",\n          matches: [\n            {\n              matchId: \"m3\",\n              players: [{}, {}]\n            }\n          ]\n        }\n      ]\n    });\n\n    tb.init();\n  </script>\n</body>\n</html>\n```\n\n---\n\n## ESM Usage\n\nUse this option when working with a module-based setup.\n\n```js\nimport tournamentBracket from \"./dist/tournament-bracket.esm.js\";\nimport \"./dist/tournament-bracket.css\";\n```\n\n### Complete ESM Example\n\n```js\nimport tournamentBracket from \"./dist/tournament-bracket.esm.js\";\nimport \"./dist/tournament-bracket.css\";\n\nconst tb = tournamentBracket({\n  targetId: \"tournament-bracket\",\n  rounds: [\n    {\n      roundId: \"r1\",\n      name: \"Quarter Finals\",\n      matches: [\n        {\n          matchId: \"m1\",\n          isFinished: true,\n          players: [\n            { name: \"Player 1\", score: 2, avatarUrl: \"\" },\n            { name: \"Player 2\", score: 1, avatarUrl: \"\" }\n          ]\n        },\n        {\n          matchId: \"m2\",\n          players: [\n            { name: \"Player 3\", score: \"-\" },\n            { name: \"Player 4\", score: \"-\" }\n          ]\n        }\n      ]\n    },\n    {\n      roundId: \"r2\",\n      name: \"Semi Finals\",\n      matches: [\n        {\n          matchId: \"m3\",\n          players: [{}, {}]\n        }\n      ]\n    }\n  ]\n});\n\ntb.init();\n```\n\nIf you use ESM directly in the browser, load your code with:\n\n```html\n<script type=\"module\" src=\"./your-file.js\"></script>\n```\n\nDo not open ESM files directly with `file://`. Use a local development server instead.\n\n---\n\n## Required HTML\n\nThe page must contain a target container element:\n\n```html\n<div id=\"tournament-bracket\"></div>\n```\n\nThe `targetId` option must match this element ID:\n\n```js\nconst tb = tournamentBracket({\n  targetId: \"tournament-bracket\",\n  rounds: []\n});\n```\n\n---\n\n## Configuration\n\nCreate a bracket instance by calling:\n\n```js\nconst tb = tournamentBracket(config);\n```\n\n### Available Options\n\n| Option | Type | Default | Description |\n|---|---|---:|---|\n| `targetId` | `string` | `\"tournament-bracket\"` | ID of the container element |\n| `rounds` | `Array` | required | Tournament rounds data |\n| `distance` | `number` | `42` | Internal spacing used for layout and connectors |\n| `width` | `number` | `196` | Width of each match card |\n| `matchHeight` | `number` | `94` | Height of each match card |\n| `roundGap` | `number` | `96` | Horizontal gap between rounds |\n| `avatarFallbackUrl` | `string` | `\"./images/avatar.png\"` | Fallback avatar when a player avatar is missing |\n| `connectorColor` | `string` | `\"white\"` | Color of SVG connector lines |\n| `onMatchClick` | `function` | noop | Called when a match is clicked |\n| `onMatchUpdate` | `function` | noop | Called when a match is updated |\n| `onMatchFinish` | `function` | noop | Called when a match is finished |\n\n---\n\n## Full Configuration Example\n\n```js\nconst sampleConfig = {\n  targetId: \"tournament-bracket\",\n  distance: 80,\n  width: 196,\n  matchHeight: 72,\n  roundGap: 80,\n  connectorColor: \"#64748b\",\n  rounds: [\n    {\n      roundId: \"r1\",\n      name: \"Quarter Finals\",\n      matches: [\n        {\n          matchId: \"m1\",\n          isFinished: true,\n          players: [\n            {\n              name: \"Player 1\",\n              score: 2,\n              avatarUrl: \"\"\n            },\n            {\n              name: \"Player 2\",\n              score: 1,\n              avatarUrl: \"\"\n            }\n          ]\n        },\n        {\n          matchId: \"m2\",\n          players: [\n            {\n              name: \"Player 3\",\n              score: \"-\"\n            },\n            {\n              name: \"Player 4\",\n              score: \"-\"\n            }\n          ]\n        }\n      ]\n    },\n    {\n      roundId: \"r2\",\n      name: \"Semi Finals\",\n      matches: [\n        {\n          matchId: \"m3\",\n          players: [{}, {}]\n        }\n      ]\n    }\n  ]\n};\n```\n\n---\n\n## Data Structure\n\n### Rounds\n\nThe `rounds` array defines the complete tournament structure.\n\n```js\nrounds: [\n  {\n    roundId: \"r1\",\n    name: \"Quarter Finals\",\n    matches: [\n      {\n        matchId: \"m1\",\n        players: [\n          { name: \"Player 1\", score: 2 },\n          { name: \"Player 2\", score: 1 }\n        ]\n      }\n    ]\n  }\n]\n```\n\n### Round Object\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `roundId` | `string` | no | Optional custom round ID |\n| `name` | `string` | no | Optional round name |\n| `matches` | `Array` | yes | List of matches in this round |\n\n### Match Object\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `matchId` | `string` | no | Optional custom match ID |\n| `isFinished` | `boolean` | no | Marks the match as completed |\n| `players` | `Array` | yes | Exactly two players |\n\n### Player Object\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `name` | `string` | no | Player display name |\n| `score` | `number \\| string` | no | Player score, or `\"-\"` for pending score |\n| `avatarUrl` | `string` | no | Player avatar URL |\n\n---\n\n## Default Player Values\n\nIf a player is missing or partially defined, the library fills missing fields with default values.\n\n```js\n{\n  name: \"-\",\n  avatarUrl: \"\",\n  score: \"-\"\n}\n```\n\nThis is valid:\n\n```js\nplayers: [{}, {}]\n```\n\nThis is also valid:\n\n```js\nplayers: [\n  { name: \"Player 1\" },\n  {}\n]\n```\n\nEmpty player objects are useful for future rounds where participants are not known yet.\n\n---\n\n## Validation Rules\n\nThe library validates the tournament structure before rendering.\n\nThe rules are:\n\n- `rounds` must be a non-empty array\n- every round must be an object\n- every round must contain a `matches` array\n- every match must be an object\n- every match must contain exactly `2` players\n- the first round match count must be a power of two\n- each next round must contain exactly half the matches of the previous round\n- the final round must contain exactly `1` match\n\n### Valid Bracket Shape\n\n```txt\nRound 1: 8 matches\nRound 2: 4 matches\nRound 3: 2 matches\nRound 4: 1 match\n```\n\n### Invalid Bracket Shape\n\n```txt\nRound 1: 3 matches\nRound 2: 2 matches\nRound 3: 1 match\n```\n\nThis is invalid because the first round has `3` matches, and `3` is not a power of two.\n\nTournament math is strict. Sadly, it does not accept emotional arguments.\n\n---\n\n## Instance API\n\n`tournamentBracket(config)` returns an object with these methods:\n\n```js\n{\n  init,\n  updateMatch,\n  setMatchScore,\n  finishMatch,\n  destroy,\n  getState,\n  onMatchClick,\n  onMatchUpdate,\n  onMatchFinish\n}\n```\n\n---\n\n## Methods\n\n### `init()`\n\nInitializes and renders the bracket.\n\n```js\ntb.init();\n```\n\nCall this after creating the instance.\n\n---\n\n### `updateMatch(matchId, patch)`\n\nUpdates an existing match by ID.\n\n```js\ntb.updateMatch(\"m2\", {\n  players: [\n    { name: \"Player 3\", score: 1 },\n    { name: \"Player 4\", score: 2 }\n  ]\n});\n```\n\nUse this when you want to update match data after initialization.\n\n---\n\n### `setMatchScore(matchId, score1, score2)`\n\nUpdates both player scores in a match.\n\n```js\ntb.setMatchScore(\"m2\", 3, 1);\n```\n\nArguments:\n\n| Argument | Description |\n|---|---|\n| `matchId` | ID of the match |\n| `score1` | First player score |\n| `score2` | Second player score |\n\n---\n\n### `finishMatch(matchId, score1, score2)`\n\nMarks a match as finished with final scores.\n\n```js\ntb.finishMatch(\"m2\", 3, 1);\n```\n\nWhen a match is finished, the library can resolve the winner and move the winner forward according to the bracket structure.\n\n---\n\n### `destroy()`\n\nClears the rendered bracket from the target container.\n\n```js\ntb.destroy();\n```\n\nUse this when you want to remove the bracket or re-render from scratch.\n\n---\n\n### `getState()`\n\nReturns the current internal bracket state.\n\n```js\nconst state = tb.getState();\nconsole.log(state);\n```\n\nThis is useful for debugging, inspection, or syncing with external application state.\n\n---\n\n## Event Callbacks\n\nCallbacks can be passed in the initial configuration.\n\n```js\nconst tb = tournamentBracket({\n  ...sampleConfig,\n  onMatchClick: function (match) {\n    console.log(\"clicked\", match);\n  },\n  onMatchUpdate: function (match) {\n    console.log(\"updated\", match);\n  },\n  onMatchFinish: function (match) {\n    console.log(\"finished\", match);\n  }\n});\n```\n\nThey can also be registered or replaced later using the instance API.\n\n---\n\n### `onMatchClick(fn)`\n\nRegisters a callback for match click events.\n\n```js\ntb.onMatchClick(function (match) {\n  console.log(\"clicked\", match);\n});\n```\n\n---\n\n### `onMatchUpdate(fn)`\n\nRegisters a callback for match update events.\n\n```js\ntb.onMatchUpdate(function (match) {\n  console.log(\"updated\", match);\n});\n```\n\n---\n\n### `onMatchFinish(fn)`\n\nRegisters a callback for match finish events.\n\n```js\ntb.onMatchFinish(function (match) {\n  console.log(\"finished\", match);\n});\n```\n\n---\n\n## Complete Event Example\n\n```js\nconst tb = tournamentBracket({\n  ...sampleConfig,\n  onMatchClick: function (match) {\n    console.log(\"config.onMatchClick\", {\n      matchId: match.matchId,\n      players: match.players\n    });\n  },\n  onMatchUpdate: function (match) {\n    console.log(\"config.onMatchUpdate\", {\n      matchId: match.matchId,\n      players: match.players,\n      isFinished: match.isFinished\n    });\n  },\n  onMatchFinish: function (match) {\n    console.log(\"config.onMatchFinish\", {\n      matchId: match.matchId,\n      players: match.players\n    });\n  }\n});\n\ntb.init();\n```\n\n---\n\n## Typical Usage Flow\n\nA common usage flow looks like this:\n\n```js\nconst tb = tournamentBracket(sampleConfig);\n\ntb.init();\n\ntb.setMatchScore(\"m2\", 2, 0);\n\ntb.finishMatch(\"m2\", 2, 0);\n\nconsole.log(tb.getState());\n```\n\n---\n\n## Demo\n\nThe `demo/` folder can contain a live example of the library.\n\nRecommended demo structure:\n\n```txt\ndemo/\n  index.html\n  tournament-bracket.min.js\n  tournament-bracket.min.css\n```\n\nThe demo should show both:\n\n- the rendered tournament bracket\n- the code used to create it\n\nThis way, users can see how the library works and copy the usage code from the same place.\n\n---\n\n## Styling\n\nThe library requires CSS for proper visual presentation.\n\n### Browser Usage\n\n```html\n<link rel=\"stylesheet\" href=\"./dist/tournament-bracket.min.css\" />\n<script src=\"./dist/tournament-bracket.min.js\"></script>\n```\n\n### ESM Usage\n\n```js\nimport \"./dist/tournament-bracket.css\";\nimport tournamentBracket from \"./dist/tournament-bracket.esm.js\";\n```\n\nIf the JavaScript works but the bracket looks broken or unstyled, the CSS file is probably missing.\n\nWithout CSS, the bracket technically works, but visually it may look like it lost a fight with a spreadsheet.\n\n---\n\n## Troubleshooting\n\n### The bracket does not render\n\nCheck that the target container exists:\n\n```html\n<div id=\"tournament-bracket\"></div>\n```\n\nAlso check that the `targetId` matches:\n\n```js\ntargetId: \"tournament-bracket\"\n```\n\n---\n\n### The browser says `tournamentBracket is not defined`\n\nMake sure the browser build is loaded before your script:\n\n```html\n<script src=\"./dist/tournament-bracket.min.js\"></script>\n<script>\n  const tb = tournamentBracket(config);\n</script>\n```\n\n---\n\n### ESM import does not work\n\nMake sure you are using the ESM build:\n\n```js\nimport tournamentBracket from \"./dist/tournament-bracket.esm.js\";\n```\n\nIf you are testing directly in the browser, use a local server and a module script:\n\n```html\n<script type=\"module\" src=\"./tournament-bracket.min.js\"></script>\n```\n\nDo not rely on `file://` for ESM testing.\n\n---\n\n### Styles are missing\n\nInclude the CSS file:\n\n```html\n<link rel=\"stylesheet\" href=\"./dist/tournament-bracket.min.css\" />\n```\n\nor import it in your module setup:\n\n```js\nimport \"./dist/tournament-bracket.css\";\n```\n\n---\n\n### Invalid rounds error\n\nCheck these structure rules:\n\n- first round match count must be a power of two\n- each next round must have half the matches of the previous round\n- final round must have exactly one match\n- every match must have exactly two players\n\n---\n\n## Links\n\n- [Live Demo](https://amirhossein-shk.github.io/tournament-bracket/demo/)\n- [GitHub Repository](https://github.com/amirhossein-shk/tournament-bracket)\n- [NPM Package](https://www.npmjs.com/package/@amirhossein-shk/tournament-bracket-js)\n\n---\n\nauthor: \namirhossein.shk@gmail.com\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md"}