Open the tool
# Drop Curve Desk 1.0.0

An offline probability regression workbench for a single game reward. Compare a current design with a candidate; inspect the unlucky tail; save explicit acceptance checks; run the same model in a Node.js build pipeline.

## Start in two minutes
1. Extract the whole ZIP, then open index.html in a current desktop browser. No installation, subscription, network connection or build step is required for the interface.
2. Click **Load boss-reward example**. The baseline is a flat 1% chance. The candidate adds one percentage point on attempt 51, another on each subsequent miss, and guarantees success on attempt 80.
3. Review P50, P95, P99, capped/full means and the two acceptance checks. Switch the chart to the logarithmic tail view to see rare failures.
4. Save project JSON to preserve all model fields and checks. Download curve CSV for every attempt or a self-contained HTML review report.

Inputs stay in the current tab. Reloading clears them. Save project JSON before closing. There is no autosave, remote storage, analytics or file upload. Exported files contain your model names and settings.

## What is actually modeled
There is ONE target reward and one success/failure opportunity per attempt. The analysis ends at its first success. Every modeled player starts with the same number of consecutive misses. There are no intervening resets, changing eligibility, multiple drops, competing pity counters, inventories, collections or nested loot tables. Time is constant per attempt.

This is an analytical model, not a simulation of your game's engine. It cannot verify whether your implementation follows the entered probabilities. It is not a forecast of retention, enjoyment, revenue or player behavior. The calculation uses ordinary floating-point arithmetic; “analytical” does not mean infinite numerical precision.

## Model fields and off-by-one rules
The interface shows percentages. Project JSON uses probabilities in [0,1]. A UI base of 1 means JSON baseChance 0.01. A UI step of 1 means one percentage point, not a 1% multiplier.

- name: 1–100 characters.
- baseChance: initial success probability, inclusive 0–1.
- softStart: FIRST attempt that receives a step boost, counting from the start of the current miss streak. 0 disables it.
- step: additive probability boost per attempt starting at softStart. Set both step and softStart to 0 to disable soft pity.
- hardAt: attempt at which success is guaranteed; 0 disables it. It takes precedence over the other settings.
- initialMisses: misses already accumulated before the analysis. Must be smaller than hardAt when a hard guarantee is set.
- secondsPerAttempt: fixed attempt duration, 0–86,400 seconds.
- horizon (project level): number of FUTURE attempts to analyze, 1–100,000; omitted defaults to 1,000.

For future attempt n, lifetime attempt = initialMisses + n. If this reaches hardAt, the chance is 1. Otherwise:

    chance = min(1, baseChance + max(0, lifetimeAttempt - softStart + 1) * step)

The boost term is zero when soft pity is disabled. Example: base 10%, softStart 3, step 20 percentage points produces chances 10%, 10%, 30%, 50%, 70%, 90%, 100%. With hardAt 5, attempt 5 is instead 100%.

Initial misses condition the analysis on already having failed that many times. They do not count toward the returned future-attempt percentiles or time estimates. For a fresh player, use 0.

## Interpreting results
At each attempt n, survivor probability S(n) = product of (1 - chance(k)), for k = 1...n. First-hit probability on n = S(n-1) * chance(n). Acquired by n = 1 - S(n). Logs and log1p/expm1 preserve small-probability precision.

For a fixed probability p, this reduces to the geometric distribution with first-hit probability (1-p)^(n-1)*p and mean 1/p. See the primary [SciPy geometric-distribution documentation](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.geom.html) for that special case. The product does not depend on SciPy.

- P95 means the first future attempt by which at least 95% of modeled players have acquired the reward.
- Beyond horizon means that percentile or full expectation was not established in the analyzed range. Increase the horizon; do not read it as zero or infinity.
- Capped mean is E[min(T,horizon)] = sum S(n), n=0...horizon-1. Unsuccessful players contribute the entire horizon. It is NOT the mean among successful players.
- Full mean is given for the simple geometric case, or when all remaining probability is guaranteed by the analyzed horizon or the next attempt. An unreachable zero-chance model is labeled separately.
- Percentages in the interface are rounded. The CSV has more digits. A displayed 100.00% can still leave a tiny positive survivor probability.
- A guarantee is identified from an actual chance-1 attempt. A tiny survivor probability that underflows to numeric zero does NOT satisfy a zero-failure or 100%-success acceptance check. Checks use logarithmic probabilities; exported checks include guaranteed and logStillMissing. A null log means a genuine modeled guarantee.
- The tail chart has a floor at 1e-8%. A true guarantee and a smaller positive probability appear at that floor. Read the table/inspector to distinguish them.

## Acceptance checks
Checks apply to the CANDIDATE model at a FUTURE attempt within the horizon. Use one of these forms per check:

    {"label":"95% by 75", "attempt":75, "minSuccess":0.95}
    {"label":"No missing players at 80", "attempt":80, "maxMissing":0}

At most 100 checks. Unknown fields, invalid probabilities and out-of-range attempts are rejected. No checks means an analysis only, not evidence that any design target was tested.

## Command line and build pipelines
Install a current supported Node.js release from https://nodejs.org if you do not already have it. The runner uses only Node built-ins; no npm install is needed. It was tested with the Node version recorded in QA.md in this release.

    node cli.cjs examples/boss-reward.json
    node cli.cjs examples/boss-reward.json --out review-output

The second command creates a NEW directory containing summary.json, curves.csv and a copy of project.json. It refuses an existing directory to avoid overwriting reports. Parent directories must already exist. Inputs are never modified.

Exit codes: 0 = all configured checks pass (or no checks configured); 1 = at least one check fails; 2 = invalid input, bad arguments, inaccessible files or output error. A failure to write output is code 2, even if the numerical checks would pass. Fix the output problem and rerun.

Run tests:

    node --test test.cjs

For CI, commit the project JSON alongside your game and invoke the CLI from your existing pipeline after updating its model values. The CLI does not extract live probabilities from game code. Keeping the model synchronized with the game remains your responsibility. JSON project files are limited to 1 MB.

## Editions
Free Lite: editable baseline/candidate models, all three chart modes, percentiles, attempt inspector and curve CSV up to 1,000 future attempts.
Full: up to 100,000 attempts, acceptance checks, saved/reloaded JSON projects, self-contained HTML reports, Node.js CLI, source, tests and examples.

## Troubleshooting
- Blank numeric input: enter a value; empty fields are not silently treated as zero.
- Soft pity error: set both first boosted attempt and step, or set both to zero.
- Check beyond horizon: increase the horizon or move the check earlier.
- Results disappear after editing: intentional; the previous report is stale. Compare again.
- Browser download blocked: allow this local page to download its report using your browser's normal controls.
- Model with zero chance and no boost/guarantee: reward is unreachable; no finite expected attempt count.
- Very large horizons: charts are sampled for display. CSV contains all attempts. A 100,000-attempt analysis can use significant browser memory. Keep smaller horizons when they answer the design question.
- Non-English numbers: JSON needs dot decimal notation. Browser number entry behavior follows the browser locale.

## Files and limitations
index.html/app.js/style.css: interface. core.js: shared analytical engine. cli.cjs: command-line wrapper. test.cjs: numerical and validation tests. examples/: passing and intentionally failing cases. QA.md: actual checks performed. LICENSE.txt: usage terms.

No runtime integration, cryptographic RNG, random simulation, real-money gambling analysis, player telemetry, personalized manipulation, account system or server is included. No engine code is changed. Source can be adapted for internal design/CI use under the included license; this is not a redistributable game runtime.