CRT Timing · Volume 4
Flash-Frame Detection — The Zapper Method in Timing Detail
What a test frame actually asks, the frame budget per target, why the light must drain out during vertical blanking, the hit zone a box and a patch make together, the scan-line hybrid that recovers Y, and the property that lets this method survive a lagging display

4.1 The question a test frame asks
The flash-frame method was described in its historical setting in History of Light Guns, Volume 3, which reproduces the NESdev wiki’s three-step sequence: check for no light during vertical blank, draw one black frame with a white box per target, poll the light bit through each such frame.1 This volume takes the method apart as a timing problem.
The Zapper reports two bits on the controller port, trigger and light. The light bit is the output of the line-rate band-pass filter and envelope detector of Volume 3 §3.6, so it is active for as long as the filtered burst stays above a threshold: “about 26 scanlines with pure white, 24 scanlines with light gray, or 19 lines with dark gray”, by the NESdev wiki’s test-ROM measurements.1 It carries no information about where in a line the light came from. The only question it can answer is whether the gun saw a scanning bright area during the period the program was polling.
A test frame makes that answer mean something. If the program has drawn exactly one bright box in an otherwise black frame, then “light during this frame” means “the gun is pointed at that box”. That converts a one-bit, frame-resolution sensor into a target selector.

4.2 The frame budget
Every answer costs a frame, and frames are 16.7 ms at 60 Hz. For a shot with N candidate targets on screen:
Table 1 — Every answer costs a frame, and frames are 16.7 ms at 60 Hz. For a shot with N candidate targets on screen
| Step | Frames | Purpose |
|---|---|---|
| Trigger seen | — | read during vertical blank |
| Check frame | 1 | the screen black (or the normal picture with the gun required to see nothing during blank); any light now is a lamp or a cheat |
| One test frame per target | N | black with one white box |
| Restore the picture | — | the next normal frame |
| Total added latency | N + 1 frames | 33 ms for one target, 50 ms for two, 83 ms for four |
The NESdev wiki gives the same order: verify no light during vertical blank, then a black frame with a single white box per target, waiting the entire frame each time.1 Some games compress the check into the vertical-blank test and spend frames only on targets; either way, latency and screen flicker grow linearly with the number of targets. That is the method’s structural limit, and why it suits games with one or two targets at a time. Nintendo’s own next gun, the Super Scope, used the other method for exactly this reason (History of Light Guns, Volume 4).
A game can cut the number of test frames by testing several targets at once and bisecting: two boxes in one frame, then one of the two. With N targets, log2 N frames resolve which was hit, at the cost of more complex code. Whether any released NES game did this was not established for this dive.

4.3 Letting the light drain out
The NES draws 240 picture lines (0 to 239) out of 262; the vertical-blank flag is set on line 241 and cleared on line 261, so vertical blank lasts 20 lines, about 1.27 ms.2 The Zapper’s light bit stays active for up to 26 lines after the beam has painted a white area.1
Put those together. A box drawn at the bottom of the picture, around line 230, can keep the light bit active until about line 256, which is well into vertical blank. A program that checks for “no light” at the start of vertical blank, to detect a cheat or a missing gun, will see the tail of the previous frame’s box and wrongly conclude that the gun is seeing a lamp. The NESdev wiki’s advice is precisely this: do the check “near the end of your vertical blank code to let the light ‘drain out’ if the gun happens to be pointed near the bottom of the screen”.1
This is a direct consequence of the Zapper’s filter design, not of the phosphor. The phosphor’s own fast light has gone within microseconds (Volume 2). What lingers is the filter’s envelope, which by the NESdev wiki’s emulator model behaves like “a capacitor, whose voltage drains out exponentially over the course of several scanlines”.1
The same arithmetic sets the earliest moment a test frame’s answer is final. The box in a test frame is painted on its lines; the light bit may assert up to several lines later as the envelope builds, and the program must keep polling “throughout a whole frame”, in the wiki’s words, because “the sensor may turn on and off in 10 to 25 scanlines”.1
4.4 The hit zone: box plus patch
The gun sees a disc of screen, not a point (Volume 1, §1.6, and Volume 3, §3.2). The light bit asserts if enough of the box falls inside that disc to drive the filtered envelope over the threshold. So the zone in which aiming counts as a hit is the box enlarged by roughly the patch’s radius, less a margin for how much overlap the threshold needs.
Worked for a 16-pixel box on the 27-inch set of Volume 1 (1.9 mm per NES pixel horizontally, 1.7 mm per line):
Table 2 — Worked for a 16-pixel box on the 27-inch set of Volume 1 (1.9 mm per NES pixel horizontally, 1.7 mm per line)
| Range | Patch diameter (1.7 mm sensor behind a 150 mm lens, as in Volume 3) | Box | Hit zone across, roughly |
|---|---|---|---|
| 1 m | ~10 mm | ~30 mm | ~40 mm |
| 3 m | ~32 mm | ~30 mm | ~60 mm |
| 5 m | ~55 mm | ~30 mm | ~85 mm |
The Zapper’s own optics were not documented in the sources read, so these use Volume 3’s example sensor and lens. What the table shows is the shape of the effect: the method becomes more generous with range, because the patch grows while the box does not. It also becomes less sure, because a smaller fraction of the patch is bright and the filtered signal is weaker; the NESdev measurements show the envelope shortening from 26 lines to 19 as the target dims, which is the same weakening seen from a different cause.1
4.5 The hybrid: Y from the scan line
The NESdev wiki lists an optional step that turns the Zapper part-way into a position sensor: “Turn the entire screen white or display white boxes on all targets, and use timed code or a scanline IRQ handler to wait for the Zapper to start detecting light in order to see how far down the screen the Zapper is pointed. This can narrow the set of targets that must be checked in the next step.”1
This works because the light bit, though it carries nothing about the position along a line, does assert at a moment that depends on which line the beam is on when the burst begins. The program knows which line the beam is on, from a scan-line interrupt or from counting cycles since vertical blank. So it can measure Y, roughly, and use it to rule out targets above or below.
Its resolution is set by the filter, not by the program’s timing. The envelope takes several lines to rise past the threshold, and how many depends on brightness and on how much of the patch is lit, so the first line on which the bit asserts is several lines below the top of the patch and varies from shot to shot. A Y estimate good to around ten lines is plausible from those figures; no measurement was found. X cannot be recovered this way at all. The Zapper’s band-pass and envelope detector have removed the information about where in a line the light arrived, and no amount of faster polling can bring it back.
4.6 What it rejects and what could fool it
The method’s defences against false hits stack up:
Table 3 — The method's defences against false hits stack up
| Defence | What it rejects | Source |
|---|---|---|
| Line-rate band-pass filter | lamps, daylight, anything not pulsing near 15.7 kHz | NESdev1 |
| No-light check during vertical blank or a black frame | a steady bright source the filter somehow passes; a gun pointed at another scanning screen showing white | NESdev1 |
| One box per frame in a known order | anything that is bright at the wrong frame | NESdev1 |
To fool all three, a source would have to emit a 15.7 kHz burst during exactly the test frame of the target the player wants to hit, and not during the check frame. The famous trick of pressing the Zapper against the screen does none of that: pressed against the glass, the gun sees whatever the beam paints at that spot, which is black in the check frame and white in the right test frame if and only if it is pressed against the target. That is not a defeat of the method but a demonstration that the method measures what it claims to.
The check frame is also why afterglow matters (Volume 2, §2.8). Sony’s figure of about 0.5 % of peak afterglow one frame after excitation means a frame that follows a white picture is not truly dark.3 At the Zapper’s filter the residue is a slow decay with no line-rate content, so it is rejected. A DC-coupled sensor would need its threshold set above it.
4.7 The property that outlived the CRT
Of the two CRT methods, flash-frame is the one that asks a question with a frame-level answer: “was the box on this frame visible to the gun?” Nothing in it needs microsecond timing. That gives it a property the latch method lacks: if a display shows the test frames intact, in order, a fixed number of frames late, the method still works once the program waits that many frames longer, provided the gun can see the display’s light at all.
Those conditions are exactly where a flat panel attacks it, and Volume 6 and Volume 7 work through them:
- The gun must see a non-scanning display. A line-rate band-pass sees nothing from a sample-and-hold LCD. A sensor that responds down to DC, with other means of rejecting room light, is needed.
- The display’s delay must be absorbed. The program must poll for a window as long as the display’s lag, or be told the lag by a calibration shot.
- The frames must arrive intact. A display that blends, interpolates or drops frames can smear the black frame into its neighbours or lose a test frame.
All three were met in practice by one documented project, Modern Mallard (2018): a replacement Zapper board that responds down to DC with logic to reject room light, and a cartridge patch board that rewrites Duck Hunt’s shot handling to tolerate variable delay, with a calibration shot on the menu.4 Its designer gave the lag it had to absorb as “somewhere between 16 and 100 ms” for typical LCD televisions.4 Volume 7 takes up what that implies.
4.8 What could not be verified
- Whether any released NES game bisected its targets to save test frames.
- The Zapper’s lens focal length and sensor size; the hit-zone table uses an example optic.
- How precise the scan-line Y hybrid is in practice. No measurement was found.
- The exact order of the check (vertical-blank test only, or a full black frame) in Duck Hunt itself; the NESdev wiki describes the general procedure, not one game’s code.
Sources
Footnotes
-
NESdev Wiki, “Zapper”, https://www.nesdev.org/wiki/Zapper, read 2026-10-19 via the Internet Archive. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12
-
NESdev Wiki, “NTSC video”, frame structure tables, https://www.nesdev.org/wiki/NTSC_video, read 2026-10-19 via the Internet Archive. ↩
-
Katsutoshi Ohno and others (Sony Corporation), US Patent 5,825,124 (1998), Table 1, read by OCR 2026-10-19. ↩
-
Teuobk, “Modern Mallard: a kit to make the NES game Duck Hunt work on an LCD TV”, EEVblog forum, 28 June 2018, https://www.eevblog.com/forum/crowd-funded-projects/modern-mallard-a-kit-to-make-the-nes-game-duck-hunt-work-on-an-lcd-tv/, and https://www.modernmallard.com/ (Metsasta LLC, © 2018), both read 2026-10-19. ↩ ↩2
Comments (0)