{"_id":"@bpim/bpicalc","_rev":"3-6d209ec563ee1f23f3cb5ae8d3ee5f7f","name":"@bpim/bpicalc","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@bpim/bpicalc","version":"0.1.0","keywords":["bpi","beatmania","iidx","score"],"license":"MIT","_id":"@bpim/bpicalc@0.1.0","maintainers":[{"name":"bpimanager","email":"msqkn310@gmail.com"}],"homepage":"https://github.com/BPIManager/bpicalc#readme","bugs":{"url":"https://github.com/BPIManager/bpicalc/issues"},"dist":{"shasum":"881011178190b18784ecbed50dbc3cfbf93f4d72","tarball":"https://registry.npmjs.org/@bpim/bpicalc/-/bpicalc-0.1.0.tgz","fileCount":29,"integrity":"sha512-ONQ63e0hnUcAXYOXv71ttzsIJl1x463xuT2EBcXWUZhAwA5jyPjQk+KNAkwfsAPPIU69mF1vnzSjFm8+PPGwZQ==","signatures":[{"sig":"MEQCIE3r6qSOI1SK5zsyi5DR6fpqW1xkSZ+MG69ZbGBqhBhSAiBtgYf0zXo9Jwwz3lbUgSTH830X1qz0hqIrywM3uIA2lQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":136070},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./v1":{"types":"./dist/v1.d.ts","import":"./dist/v1.js","require":"./dist/v1.cjs"},"./v2":{"types":"./dist/v2.d.ts","import":"./dist/v2.js","require":"./dist/v2.cjs"}},"gitHead":"0b35b20c8d542bf3b7115a3010150581b7ee1420","scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"pnpm typecheck && pnpm test && pnpm build"},"_npmUser":{"name":"bpimanager","email":"msqkn310@gmail.com"},"repository":{"url":"git+https://github.com/BPIManager/bpicalc.git","type":"git"},"_npmVersion":"11.19.1","description":"BPI (Beat Power Indicator) calculation, rank estimation and total BPI. Data-agnostic pure computation, zero runtime dependencies.","directories":{},"sideEffects":false,"_nodeVersion":"26.8.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.23.0","devDependencies":{"tsup":"^8.5.0","vitest":"^4.1.0","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/bpicalc_0.1.0_1789016434543_0.6720968521093844","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bpim/bpicalc","version":"0.2.0","keywords":["bpi","beatmania","iidx","score"],"license":"MIT","_id":"@bpim/bpicalc@0.2.0","maintainers":[{"name":"bpimanager","email":"msqkn310@gmail.com"}],"homepage":"https://github.com/BPIManager/BPIM-bpicalc#readme","bugs":{"url":"https://github.com/BPIManager/BPIM-bpicalc/issues"},"dist":{"shasum":"42111458c525e7ec069f57f74dab11d893b26393","tarball":"https://registry.npmjs.org/@bpim/bpicalc/-/bpicalc-0.2.0.tgz","fileCount":29,"integrity":"sha512-2bcsId4Oyeh/lwAVtHNabLbQja6PN18DNLxbnfcXyWkPaeemLXmknfVwQBam5xAOGem3/5a7PtUoTSZresBZkw==","signatures":[{"sig":"MEQCIAG6av4wWeNZUAscu1MioOmmPkxDf1ZlvdVg1mB97fgXAiAmzWEc7qbPCurhFyshzwVH8ohyZJxrwgAFJIqAPEd5NA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bpim%2fbpicalc@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":138820},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./v1":{"types":"./dist/v1.d.ts","import":"./dist/v1.js","require":"./dist/v1.cjs"},"./v2":{"types":"./dist/v2.d.ts","import":"./dist/v2.js","require":"./dist/v2.cjs"}},"gitHead":"8266cb98c7bf78fcf6a03988eddd29f33bfd40c1","scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"pnpm typecheck && pnpm test && pnpm build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:6c55a2e4-e829-4113-af91-a2ca16e425c8"}},"repository":{"url":"git+https://github.com/BPIManager/BPIM-bpicalc.git","type":"git"},"_npmVersion":"11.19.1","description":"BPI (Beat Power Indicator) calculation, rank estimation and total BPI. Data-agnostic pure computation, zero runtime dependencies.","directories":{},"sideEffects":false,"_nodeVersion":"26.8.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.23.0","devDependencies":{"tsup":"^8.5.0","vitest":"^4.1.0","typescript":"^5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/bpicalc_0.2.0_1789017959660_0.18139641264748607","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"_id":"@bpim/bpicalc@0.3.0","bugs":{"url":"https://github.com/BPIManager/BPIM-bpicalc/issues"},"dist":{"shasum":"929203e8f22a2bef26b1a2d14e1959c1936339da","tarball":"https://registry.npmjs.org/@bpim/bpicalc/-/bpicalc-0.3.0.tgz","fileCount":29,"integrity":"sha512-FDbzVvcykCn9Kcxe0ZTx3ECaKddFI7jgSCCHp0ETmTRMwYe+6V8VtC6glSDQVRjQT3okjcrRQZeDAgi7S/1Ocw==","signatures":[{"sig":"MEQCIBsgEJEFXY5qFuUVvLxUZhoss6caBNkbtVqQHstOzQBwAiAS0nQTo9dpZxiGZ9QUFhBiMZ60l1BbHAT3ly9nogXRIA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBZZBGQXlzp1vSdUVE6bmSymgFiEPN18g+lN13PYWFv5AiEA4P58fCfdBL2StHiZFUwfPiq9KmUeU8Z3pKYeX4AfJGM="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bpim%2fbpicalc@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":139842},"main":"./dist/index.cjs","name":"@bpim/bpicalc","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./v1":{"types":"./dist/v1.d.ts","import":"./dist/v1.js","require":"./dist/v1.cjs"},"./v2":{"types":"./dist/v2.d.ts","import":"./dist/v2.js","require":"./dist/v2.cjs"}},"gitHead":"4c6d506be87d911000140dc559e46dcf74aed7e4","license":"MIT","scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"pnpm typecheck && pnpm test && pnpm build"},"version":"0.3.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:6c55a2e4-e829-4113-af91-a2ca16e425c8"}},"homepage":"https://github.com/BPIManager/BPIM-bpicalc#readme","keywords":["bpi","beatmania","iidx","score"],"repository":{"url":"git+https://github.com/BPIManager/BPIM-bpicalc.git","type":"git"},"_npmVersion":"11.19.1","description":"BPI (Beat Power Indicator) calculation, rank estimation and total BPI. Data-agnostic pure computation, zero runtime dependencies.","directories":{},"maintainers":[{"name":"bpimanager","email":"msqkn310@gmail.com"}],"sideEffects":false,"_nodeVersion":"26.8.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.23.0","devDependencies":{"tsup":"^8.5.0","vitest":"^4.1.0","typescript":"^5.9.3"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/bpicalc_0.3.0_1789314253916_0.18327213502429718"}}},"time":{"created":"2026-09-10T05:00:34.321Z","modified":"2026-09-13T15:44:14.347Z","0.1.0":"2026-09-10T05:00:34.696Z","0.2.0":"2026-09-10T05:25:59.801Z","0.3.0":"2026-09-13T15:44:14.002Z"},"bugs":{"url":"https://github.com/BPIManager/BPIM-bpicalc/issues"},"license":"MIT","homepage":"https://github.com/BPIManager/BPIM-bpicalc#readme","keywords":["bpi","beatmania","iidx","score"],"repository":{"url":"git+https://github.com/BPIManager/BPIM-bpicalc.git","type":"git"},"description":"BPI (Beat Power Indicator) calculation, rank estimation and total BPI. Data-agnostic pure computation, zero runtime dependencies.","maintainers":[{"name":"bpimanager","email":"msqkn310@gmail.com"}],"readme":"# @bpim/bpicalc\n\nBPI (Beat Power Indicator) calculation for beatmania IIDX scores: single-chart BPI,\nrequired-score inversion, total BPI, and rank estimation.\n\n- **V1** — the original / current definition (PGF-based, per-song `coef`).\n- **V2** — the distribution-based redefinition (2-parameter latent-ability model, ALS). Experimental.\n\nZero runtime dependencies. No data is bundled — you pass in the per-chart parameters\nand, for V2, the model constants for your data vintage.\n\n## Install\n\n```sh\npnpm add @bpim/bpicalc\n# npm i @bpim/bpicalc   /   yarn add @bpim/bpicalc\n```\n\n## Quick start\n\n### V1\n\n```ts\nimport { BpiV1 } from \"@bpim/bpicalc\";\n\nconst v1 = new BpiV1();\n\nconst chart = { notes: 1500, kaidenAvg: 2700, wrScore: 2960, coef: 1.0 };\n\nv1.chart(chart).bpi(2890);          // single-chart BPI\nv1.chart(chart).scoreFor(90);       // EX score needed for BPI 90\nv1.chart(chart).scoreFor(90, false);// same, unrounded\n\nv1.total([92, 71, 60, 44, -15], 650); // total BPI over 650 charts (missing filled with -15)\nv1.rankFromTotal(78);                  // estimated rank from total BPI\nv1.rankFromSingle(78);                 // estimated rank from a single-chart BPI\n```\n\nBind a chart once and reuse it for many scores:\n\n```ts\nconst c = v1.chart(chart);\nscores.map((s) => c.bpi(s));\n```\n\n### V2\n\n```ts\nimport { BpiV2 } from \"@bpim/bpicalc\";\n\n// One set of constants per data vintage (from your params file / model table).\nconst v2 = new BpiV2({\n  z0: -0.1938,\n  zRef: 1.9481,\n  z100Median: 6.5164,\n  z100Iqr: 1.1916,\n  residualRmse: 0.3012,\n  coefMedian: 0.949,\n  arenaPopulationSize: 4867,\n  rankCurve: [ /* { percentile, a } ..., ascending percentile */ ],\n});\n\n// A chart row carries the ALS parameters (mu / sigma / residualVar) plus notes / wr / coef.\nconst chart = {\n  notes: 1500, kaidenAvg: 2700, wrScore: 2960, coef: 0.9,\n  mu: -3.1, sigma: 0.42, residualVar: 0.09,\n};\n\nv2.hasParams(chart);            // false if mu / sigma are missing\nv2.chart(chart).bpi(2890);     // single-chart BPI (exactly 100 at the WR score)\nv2.chart(chart).scoreFor(90);  // EX score needed for BPI 90 (ceiled, like V1)\nv2.chart(chart).params;        // { mu, sigma, z0, z100, gamma, coef, k }\n\n// Player-level: bind the player's scores once.\nconst played = [{ chart, exScore: 2890 }, /* ... */];\nconst p = v2.player(played);\n\np.latentSkill;                       // shrunk latent skill a  (null if no usable scores)\np.info;                              // precision-unit information\np.predictUnplayed(someChart);        // predicted BPI for a chart the player hasn't touched\n\n// Total BPI: pass every chart in scope; entries with an exScore are measured,\n// the rest are predicted from latent skill. Shift-method aggregate.\np.totalBpi(\n  allCharts.map((c) => ({ chart: c, exScore: scoreById.get(c.id) })),\n  allCharts.length,\n);\np.estimatedRank();                   // estimated rank within the reference population\n```\n\n## Data source\n\n`@bpim/bpicalc` never reads a file. Supply the numbers from wherever you keep them:\n\n| value | today (bpim2) | later |\n| --- | --- | --- |\n| `notes`, `kaidenAvg`, `wrScore`, `coef` | `songDef` row | `songDef` row |\n| `mu`, `sigma`, `residualVar` (V2) | `songParams.json` lookup, merged onto the row | `songDef` row |\n| `BpiV2Config` (`z0`, `zRef`, …) | `songParams.json` top-level | model config table |\n\nWhen the ALS parameters move into `songDef`, a `songDef` row *is* a `ChartV2` — pass it straight through.\n\n## API\n\n### `new BpiV1(config?)`\n\n| method | returns |\n| --- | --- |\n| `chart(row)` | `ChartBpiV1` — `.bpi(exScore)`, `.scoreFor(targetBpi, ceiled?)`, `.exponent` |\n| `total(bpis, count)` | total BPI (signed power mean) |\n| `totalBpiExponent(count)` | `max(1, log2(count))` |\n| `rankFromTotal(totalBpi)` / `rankFromSingle(bpi)` | estimated rank |\n\n`config` (all optional, override the defaults in `V1_DEFAULTS`):\n`defaultPowCoef` (1.175), `rankBaseTotal` (2699), `rankBaseSingle` (2616).\n\n### `new BpiV2(config)`\n\n| method | returns |\n| --- | --- |\n| `hasParams(row)` | `boolean` |\n| `chart(row)` | `ChartBpiV2` — `.bpi(exScore)`, `.scoreFor(targetBpi, ceiled?)`, `.params`, `.hasParams` |\n| `player(scores)` | `PlayerBpiV2` — `.latentSkill`, `.info`, `.predictUnplayed(row)`, `.totalBpi(charts, count?)`, `.estimatedRank()` |\n| `rankFromSingle(bpi)` / `rankFromSkill(a)` | estimated rank |\n\n`config` — required: `z0`, `zRef`, `z100Median`, `z100Iqr`, `residualRmse`, `coefMedian`,\n`rankCurve`, `arenaPopulationSize`. Optional (override the defaults in `V2_DEFAULTS`):\n`bpiFloor` (-15), `totalBpiShift` (15), `gammaClamp` (`[0.3, 3]`),\n`curveExpClamp` (`[0.62, 3]`), `rankBaseSingle` (2616).\n\n`bpi(exScore)` / `scoreFor(...)` / `params` return `null` when the chart has no V2 parameters.\n`latentSkill` / `estimatedRank()` return `null` when the player has no usable scores.\n\n## Develop\n\n```sh\npnpm install\npnpm test        # vitest\npnpm typecheck   # tsc --noEmit\npnpm build       # tsup -> dist/ (ESM + CJS + d.ts)\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}