{
  "version": "1.0.0",
  "updated": "2026-08-05",
  "license": "CC BY 4.0",
  "licenseUrl": "https://creativecommons.org/licenses/by/4.0/",
  "attribution": "ClickStorm (https://clickstorm.app)",
  "source": "https://clickstorm.app",
  "documentation": "https://clickstorm.app/api",
  "humanReadable": "https://clickstorm.app/methodology",
  "clock": {
    "api": "performance.now()",
    "monotonic": true,
    "why": "Date.now() can jump backwards when the system clock is corrected mid-test, which would produce a negative elapsed time.",
    "resolutionNote": "Browsers deliberately coarsen this timer against timing side-channel attacks, typically to about 0.1 ms. Irrelevant for click counting, and the smallest term in the reaction-time error budget.",
    "countdownDriver": "requestAnimationFrame",
    "backgroundTabBehaviour": "Frames stop being delivered when the tab is hidden, so the countdown pauses rather than running on unobserved. Missing time is not credited."
  },
  "tests": {
    "cps": {
      "eventCounted": "mouse button press (mousedown / touchstart), not click",
      "whyNotClick": "A click event only fires when press and release land on the same element, which discards real presses at high rates.",
      "formula": "clicks / selectedDurationSeconds",
      "firstClickConvention": "The first press both starts the clock and counts as click one.",
      "firstClickBiasCps": {
        "1": 1,
        "5": 0.2,
        "10": 0.1,
        "30": 0.033,
        "60": 0.017,
        "100": 0.01
      },
      "firstClickBiasNote": "Crediting one click for zero elapsed time inflates the score by 1/duration CPS. This is the same convention every competing site uses, so scores stay comparable, but on a one second run it is more than ten percent of a typical result. Subtract one click to get the strict interval rate.",
      "rounding": "two decimals, round-half-to-even. Never rounded upward.",
      "syntheticEvents": "Rejected. Events with isTrusted === false are discarded.",
      "syntheticEventsLimit": "A hardware auto clicker and a debugger-protocol extension both produce trusted events and are not detectable by any web page. ClickStorm does not claim to detect them.",
      "personalBest": "Stored in localStorage on the visitor's device only. Overwritten only when the new score is genuinely higher."
    },
    "reactionTime": {
      "attempts": 5,
      "reported": "mean of the five attempts, rounded to whole milliseconds",
      "falseStart": "A click before the go signal is discarded and the attempt is retried. It is not recorded as a very fast time.",
      "randomDelayMs": [
        1200,
        3500
      ],
      "t0Stamp": "Taken in a nested requestAnimationFrame callback after the go frame is handed to the compositor, not when the state changes. Stamping t0 at state-change time, which is what most implementations do, adds up to one full frame to every result.",
      "knownErrorSources": [
        {
          "stage": "Display refresh",
          "typicalCost": "up to 16.7 ms at 60 Hz, up to 6.9 ms at 144 Hz",
          "why": "The colour change is drawn into a frame. If the frame has just been sent, the pixels do not change until the next one. That wait is added to your score and it is not your reflexes."
        },
        {
          "stage": "Panel response",
          "typicalCost": "roughly 1 to 20 ms depending on the panel",
          "why": "The time the pixels themselves take to actually change colour after the frame arrives. An office IPS panel sits at the slow end of that; a gaming panel at the fast end."
        },
        {
          "stage": "Mouse polling",
          "typicalCost": "up to 8 ms at 125 Hz, up to 1 ms at 1000 Hz",
          "why": "Your click is not reported the instant you press. It waits for the mouse's next report to the PC. Run the polling rate test to see which of these applies to you."
        },
        {
          "stage": "Event dispatch and timer resolution",
          "typicalCost": "sub-millisecond, plus browser clock coarsening",
          "why": "Browsers deliberately blunt performance.now() as a defence against timing attacks, typically to 0.1 ms or coarser. That is small next to the display, but it means the last decimal of any browser timing is decoration."
        }
      ],
      "totalOverheadMs": {
        "min": 10,
        "max": 45,
        "note": "Adding the chain up, a browser reaction test on typical hardware reports roughly 10 to 45 ms more than your actual reflex, and almost all of that is the screen. That overhead is why a result here is only comparable with another result measured on the same setup."
      },
      "comparability": "Comparable against your own earlier results on the same screen and mouse. Not comparable against a number produced on different hardware.",
      "colourIndependence": "The go/wait state is always spelled out in words as well as colour, so the test does not depend on distinguishing red from green."
    },
    "pollingRate": {
      "method": "Times the gaps between pointer events delivered to the page while the mouse moves.",
      "reported": "Current, maximum and average Hz, plus a 'likely polling rate' rounded to the nearest standard value.",
      "systematicBias": "underestimates",
      "note": "A browser can only count the mouse events it is actually handed, and it is handed them per animation frame. Your measured Hz is therefore a floor, not a ceiling: it lands at or below your true polling rate, and it only approaches the true figure while you are moving the mouse continuously and fast. A reading well under a standard value usually means you did not move enough, not that your mouse is slower than advertised."
    },
    "aim": {
      "accuracyFormula": "hits / totalClicks",
      "note": "A click that lands outside a target counts as a miss rather than being ignored."
    }
  },
  "privacy": {
    "dataLeavesDevice": false,
    "storage": "localStorage",
    "accounts": false,
    "leaderboard": false,
    "leaderboardReason": "A public ranking that cannot verify its scores fills with automated ones, which would undermine the honesty the rest of this file is for."
  }
}
