NaNDL Precision Calculator

Read off the precision needed to average a target-time completion — from a frame-window histogram, or from an exact list of timed inputs.
offline-ready

Setup

1 frame = 1/fps seconds
used when time positions are entered as frames
total level time; also used for % positions
added to every attempt
precision is solved for this expected time
grind entropy is measured at this precision
grind time is measured at this precision

Input mode

Total inputs: 0  ·  evenly spread across the level

Run / segment — score just a slice of the level as its own run

Calculate a run only inputs between from and to are scored, re-based to start at 0 — like 23.2 - 81.8
Off — the whole level is scored.

Modifiers — off by default; constants are the calibrated values from the official NaNDL calculator

Nerveλ = e^(−k·t): later inputs (in seconds) are shakier
Fatigueλ = e^(−k·i): later inputs (by index) degrade
CPSWIPλ = (4 / max(1, 2c))^k: fast clicking hurts precision — upstream calls this one unreliable
Required Precision  L*
Enter a level length and at least one input.

Grind entropy  G — an additive difficulty scale

bits
expected attempts ≈ 2G
at reference precision
bits per input (avg)

Grind time  T — difficulty weighted by where it hurts

expected attempts
at reference precision
costliest input
the winning run itself
How it works & assumptions

Each input i has a window of Nₕ frames, so its duration is wₕ = Nₕ / fps seconds. A player with precision L (bigger = sharper; L = 1/σ of their timing error in seconds) clears that input if their timing lands inside the half-window, giving pₕ = erf( (½·wₕ·L) / √2 ).

Level metrics

Completion probability P(C) = ∏ pₕ. Reach probability rₕ = ∏₃₂ₓₖ p₋. Expected time per attempt E[T₉] = tₙ·P(C) + ∑ tₕ·rₕ·qₕ (qₕ=1−pₕ, tₙ = level length), and expected time to complete E[T╕] = E[T₉] / P(C). The tool bisects on L for L*, where E[T╕] equals your target time. It also shows σ = 1/L* in milliseconds.

Two input modes

Histogram — you give counts per frame-window size; the tool assumes inputs are evenly spaced across the level and evenly interleaved by difficulty (no clustering). With modifiers off, the result depends only on the histogram, level length and target.

Manual list — you give each input's exact time and window, so ordering, gaps and per-input positions are taken directly from your data (nothing is scattered evenly). The Seconds / % switch reads times either as seconds or as a percentage of the level length, where % grows evenly across the level (50% = halfway in time).

Run settings

Window FPS is the timing-window rate (wₕ = Nₕ/fps). Game FPS only converts time positions when the Frames unit is selected. Respawn time is added to every attempt — because ∑rₕqₕ + P(C) = 1, it contributes exactly its own value per attempt.

A row's window may be - to mark it ignored: it passes automatically, though its time position still counts toward attempt timing. With CPS enabled it instead takes one more than the run's largest numeric window, matching the official calculator. The # column is the input number i, which drives Fatigue (e^(−k·i)) and the local CPS numerator (cₕ = (i − i′)/(tₕ − tₕ′)) — so non-consecutive numbering models skipped clicks.

Fixed precision mode reverses the calculation: instead of solving for L*, it reports P(C), expected attempts and completion time at a precision you supply.

Run / segment

Turn on Calculate a run and give a range like 23.2 - 81.8 to score only the inputs inside it. The slice is treated as its own level: its inputs are re-based so the run starts at 0 and its length becomes to − from. The range is read in whatever the Seconds / % switch is set to.

Modifiers

Each enabled modifier multiplies an input's effective window before the probability is taken: Nerve e^(−k·tₕ), Fatigue e^(−k·i), CPS (4/max(1,2c))^k where c is the local clicks/sec from the gap to the previous input. All three are off by default and use the calibrated constants published by the official NaNDL calculator (k_t = 0.0016520833717346, k_u = 0.0002727763242154, k_c = 0.2784421686721826), and remain editable for experimentation. CPS keeps a WIP tag because the official calculator itself still describes that multiplier as work-in-progress and unreliable.

Grind entropy (G)

L* answers “how sharp must you be?” but it compresses an enormous range into a small number and cannot be added: two levels played back to back do not have L*₁ + L*₂. G fixes both by measuring difficulty in log space:

G = −log₂ P(C) = ∑ −log₂ pₕ  (bits)

Physically it is the information content of one clean run — how many bits of luck a completion costs. Expected attempts ≈ 2ᵍ, so one extra bit means twice the grind, everywhere on the scale. Because logs add, G(A then B) = G(A) + G(B) exactly, and each input carries its own gₕ (shown in the per-input breakdown), so any segment's difficulty is just the sum of its inputs' bits.

G is measured at a reference precision you set — that is what buys the additivity, since a level's improbability depends on who is playing it. Respawn time does not affect G: it changes how long an attempt costs, not how improbable one is.

Grind time (T)

P(C) is a product, so G cannot tell where a hard input sits — a 1-frame window on the first click scores the same as one on the last. The expected completion time can, because failures are weighted by how far you got:

T = E[T╕] = tₙ + respawn/P(C) + ∑ costₕ, where costₕ = tₕ·rₕ·qₕ / P(C)

Miss the first input and you lose a fraction of a second before retrying; miss the last and every failure burns a whole run, and you only get there rₕ of the time. So costₕ — each input's share of the total grind, shown in the breakdown's time lost column — climbs steeply toward the end of a level. T has its own reference precision (default 200) since the times explode at lower ones.

The three measures answer different questions: L* “how sharp must you be?”, G “how improbable is a clean run?” (additive, position-blind), T “how long will this actually take?” (position-sensitive, not additive).

JSON interchange

Import JSON / Export JSON exchange runs with the official calculator. A document carries the frame-window rows plus gameFps, windowFps, respawnTime and useFrames. Time positions given as frame numbers (useFrames: true) are converted to seconds using gameFps, and rows with an ignored window ("-") are skipped and reported. Key spellings are matched loosely, so gameFps, game_fps and "Game FPS" all read the same.