Configuration reference
Everything VDM knows about a venue lives in one flat text file. This page covers the file format, where the application looks for it, and what each group of keys does — starting with the ones that must be re-established on every new machine.
- Settings that must be re-established on a new laptop
- What carries over, and what does not
- File format and prefix conventions
- Where VDM looks for settings.txt
- How the file is written back
- Key reference by theme
- Stale and ignored keys
Settings that must be re-established on a new laptop
This is the single most important thing to understand about VDM's configuration. A
settings.txt copied from a working machine will not work as-is on
a different one. Some values describe the machine, not the venue — and the application
will not tell you they are wrong. It will run, and produce nothing, or produce something
subtly incorrect.
| Key | Ships as | Why it is machine-specific | How to re-establish |
|---|---|---|---|
*camera_device_path[0]*camera_device_path[1]*camera_device_path[2] |
Empty — by design. The key is absent from both the shipped configuration and the template. | These are Windows Media Foundation symbolic links. They encode the specific device instance on the specific machine and are regenerated per machine. An empty value means that feed is skipped entirely. | Tools → Select Cameras… in the controller. Assign each detected device to Feed 0 (TOP), Feed 1 (MIDDLE), Feed 2 (BOTTOM). Assigning a device auto-starts capture and motion for it. |
*capfile_nvenc_gpu_name |
NVIDIA GeForce RTX 3070 Ti Laptop GPU |
A substring matched against the installed adapters. On any other GPU it matches nothing. The companion key capfile_nvenc_gpu_index is -1, meaning resolve the index from this name. |
Tools → Select GPU. Leaving the name blank lets FFmpeg pick automatically, which is a reasonable fallback. |
big_window_widthbig_window_height |
2880 / 1620 |
Sized for one particular laptop panel. On a smaller display the window runs off-screen; on a larger one you waste working area. | Edit to suit the actual display, via the controller's Settings tab or a text editor. |
disable_nvenc_encoding |
1 (NVENC disabled) |
A workaround for the behaviour of one specific GPU — not a general setting. Leaving it at 1 on capable hardware silently gives up hardware encoding. |
Try 0 on new hardware and verify the encode path. Revert to 1 only if it misbehaves. See the NVENC constraint. |
None of these four are optional to review. The first two make the system non-functional if wrong. The third makes it unusable but obviously so. The fourth costs you the hardware encoder without any indication that it has.
What carries over, and what does not
Beyond the four above, a second class of settings is tied to the physical camera rig rather than to the computer. These carry over perfectly — but only if the cameras have not moved.
| Settings | Carries over if… | Must be redone if… |
|---|---|---|
@far[F][I] / @near[F][I] grid-line anchors, and the
meter_line_* geometry |
The cameras are mounted in exactly the same positions, at the same aim, at the same venue. | Any camera has been moved, re-aimed, or remounted — or you are at a different hill. Distances will be confidently wrong otherwise. |
motion_start_x/y[N], motion_end_x/y[N] |
Same camera framing. | Framing changed. The region is in frame pixel coordinates. |
ignore_start_x/y[N], ignore_end_x/y[N] |
Same camera framing and the same fixed distraction in shot (a flag, a marshal's post). | Framing changed, or the thing being ignored has moved. |
feed1_x0_translates_to_feed0_x,
feed2_x0_translates_to_feed1_x |
The relative geometry between the cameras is unchanged. | Any camera moved relative to its neighbour. |
Motion thresholds — ydiff_min[], min_blob_sizes[],
min_motion_count[], min_nomotion_count[] |
Usually. These are tuning values and travel reasonably well as a starting point. | Nothing forces a redo, but expect to re-tune for different light, snow conditions or camera distance. |
Movie logic — min_frames, max_frames,
min_type2_frames, padding, overlay_frame_offsets[] |
Generally yes. These describe the shape of a jump, not the hardware. | overlay_frame_offsets[] is timing-sensitive and worth re-checking after
auto-setup at a new venue. |
The practical rule
Same rig, same hill, new laptop → copy settings.txt, then fix the four
machine-specific keys above. Different rig or different hill → copy it anyway as a
starting point, then recalibrate motion regions and grid lines from scratch.
File format and prefix conventions
settings.txt is flat key=value text, one setting per line, parsed by
src/common/settings.c. There is no registry use, no %APPDATA% storage,
and no secondary config file — apart from pixel_frames.txt, which is generated
alongside it.
The type of a key is encoded in the key name itself, and the marker is part of the literal key — you must type it:
| Marker | Position | Type | Example |
|---|---|---|---|
* | Prefix | String | *font_file=numbers.txt |
@ | Prefix | Coordinate pair, written x,y | @far[0][ 0]=960,100 |
% | Suffix | Float | max_diff_y%=0.700000 |
| none | — | Integer | min_frames=60 |
% is a suffix, not a prefix
Unlike * and @, the float marker goes on the end of the
key name: max_diff_y%, not %max_diff_y. Some older notes describe all
three as prefixes. They are not.
Not every float key carries the marker — mouse_position_speed and
scene_trigger_f0_fraction are floats with no %. The marker is part of
the key's spelling, so match the existing file rather than reasoning from the type.
Comments and parsing rules
- Leading whitespace on a line is stripped.
#at the start of a line begins a comment.- Inside a value, a
#only starts a comment when it is preceded by whitespace or sits at the very start of the value. This is deliberate: Media Foundation device paths contain#characters, and this rule lets*camera_device_path[N]survive a save/load round trip intact. - Unrecognised keys are silently ignored. A typo in a key name is not an error — the line is skipped and the compiled-in default stands. This is the single easiest way to convince yourself you have changed a setting when you have not.
- Indexed keys use square brackets:
min_motion_count[0]. Grid-line anchors are doubly indexed and the inner index is space-padded to two characters:@far[0][ 0],@far[0][10]. The padding is part of the key.
The shipped settings.txt contains no comment lines at all
— it is machine-written. settings_sample.txt is the commented template, and
its comments are the best short description of each key it covers.
How many keys are there
| File | Keys | Notes |
|---|---|---|
settings.txt (live) | 356 | 176 scalar keys plus 180 @far/@near anchor entries. No comments. |
settings_sample.txt | 141 | Plus 49 comment lines. Contains no live anchor entries — the @far/@near examples in it are commented out. |
| Recognised by the parser | 387 | 207 scalar plus 180 coordinate entries. |
The template is not a subset of the live file
Each file contains keys the other lacks. settings_sample.txt has not kept pace
with the parser: about two dozen of its keys are no longer recognised, and it omits whole
families the live configuration uses (analytics, adaptive auto-setup, capfile encoding, ignore
regions). Treat it as documentation of the keys it covers, not as an authoritative inventory.
See Stale and ignored keys.
Where VDM looks for settings.txt
Configuration discovery is filesystem-based. In order:
- The controller walks up to five parent directories from the executable's
own location, looking for
settings.txt. - Failing that, the path given as the command-line argument:
VDM.exe settings_file. - Failing that,
settings.txtin the current working directory.
The settings file is a positional argument
It is VDM.exe settings.txt, not VDM.exe --settings settings.txt.
There is no --settings flag; any non-flag token on the command line is taken as
the settings path, and a second one is an error.
In a standard C:\VDM\ installation everything is flat, so the first rule finds
the file immediately. The parent-directory walk exists so that a developer running out of
build\Release\ picks up the repository-root configuration without arguments.
How the file is written back
VDM does not edit settings.txt in place. When settings are saved — from the
Settings tab, from Save Regions, from grid-line calibration, or
at the end of auto-setup — the application rewrites the entire file from
its in-memory state, writing to a temporary file and then renaming it over the original. The
rename is atomic, so an interrupted save cannot leave a half-written configuration.
pixel_frames.txt is regenerated at the same time.
Consequences of a wholesale rewrite
- Hand-written comments are lost. Anything you add to
settings.txtdisappears at the next save. Keep notes elsewhere. - Unrecognised keys are dropped. They were ignored at load, so they are not in memory to write back.
- Key order and formatting are normalised to the parser's canonical layout.
- A single UI action can overwrite calibration. This is the mechanism
behind the classic tournament-morning failure:
settings.txt was working yesterday
. Auto-setup or Save Regions rewrote it. Recovery is viasettings.txt.failsafeor thesettings.txt.bak.YYYYMMDD-HHMMSSseries — see Troubleshooting.
Take your own copy of a known-good settings.txt before any calibration session,
and keep it somewhere VDM will never write.
Key reference by theme
Values shown are from the shipped live configuration. Where the commented template gives a
different default, both are shown. Indexed keys are written [0..2] for per-feed
values; some motion keys carry a fourth index [3] used as a global entry.
Window and display geometry
| Key | Type | Live value | Meaning |
|---|---|---|---|
big_window_width | int | 2880 | Main window width in pixels. Machine-specific. |
big_window_height | int | 1620 | Main window height in pixels. Machine-specific. |
frame_position_bar_height | int | 15 | Height of the frame position bar, in pixels. |
mouse_position_speed | float | 2.000000 | Pixels of right-drag per frame when scrubbing. Higher is slower. |
cursor_line_width | int | 2 | Width of the cursor measurement line. |
cursor_line_Y / _U / _V | int | 180 / 180 / 100 | Cursor measurement line colour in YUV. |
crosshair_width | int | 12 | Crosshair width in pixels. |
default_view_frame_offset_from_end | int | 0 | Default view offset from the end of a clip. |
*font_file | string | 48 | Declared as the path to the bitmap font glyph table, but not read by any code. The font is always loaded from numbers.txt. See the note below. |
*font_file is vestigial — leave it alone
In the shipped configuration this key holds the literal value 48 rather than a
filename, which looks like a defect. It is not one, because nothing reads the
key. All four consumers — the viewer, the fileviewer, videogen and the practice
player — pass numbers.txt as a hardcoded literal, so the bitmap font is
always loaded from numbers.txt in the working directory regardless of what this
key says.
Setting it to a real path, setting it to a wrong path, and leaving it at 48 all
behave identically. The 48 is most likely an orphaned font_size value
left on the wrong key by the cleanup that removed font_size,
font_window_width and font_window_height as never-consumed.
The consequence that matters: if overlays fail to render, the cause is a
missing numbers.txt — never a font_file misconfiguration.
Editing this key cannot fix it. Because the filename is hardcoded with no setting to override
it, numbers.txt must sit in the working directory beside the executables.
Cameras and device selection
| Key | Type | Live value | Meaning |
|---|---|---|---|
*camera_device_path[0..2] | string | absent | Media Foundation symbolic link per feed. Set through Tools → Select Cameras…. Empty means the feed is skipped. Machine-specific — ships empty by design. |
feed_count | int | absent, defaults to 3 | Number of active feeds, 1–4. Changing it requires a VDM restart. |
feed_motion_on[0..2] | int | 1, 1, 1 | Enable motion detection per feed. Also toggleable live from the Feeds tab, where the change is memory-only. |
*practice_video_path[0..2] | string | absent | Per-feed video file for practice mode, set via Tools → Select Practice Files…. Empty falls back to the legacy file-naming convention. |
practice_video_sync_offset[0..2] | int | absent | Seek-to-sync frame offset per feed. A negative value selects the built-in fallback offsets. |
Motion detection
Detection regions
| Key | Feed 0 | Feed 1 | Feed 2 | Meaning |
|---|---|---|---|---|
motion_start_x[N], motion_start_y[N]motion_end_x[N], motion_end_y[N] |
0, 231 → 1919, 671 | 0, 503 → 1919, 839 | 0, 406 → 1919, 631 | The rectangle in each camera's frame where motion is detected. Narrow it to exclude trees, buildings, flags and spectators. All three span the full frame width; only the vertical band differs, isolating each camera's stretch of hill. An index [3] exists as a global entry. |
ignore_start_x[N], ignore_start_y[N]ignore_end_x[N], ignore_end_y[N] |
387, 394 → 603, 520 | unset | unset | A rectangle inside the motion region to exclude — for a fixed distraction such as a flag or a marshal's position. Set with Ign Reg N in the Preview tab. Only feed 0 uses one in the shipped configuration. |
*saved_motion_range |
A 12-integer CSV backup of the motion regions | Written before auto-setup runs, so the regions can be restored afterwards. | ||
Difference thresholds
| Key | Type | Live value | Meaning |
|---|---|---|---|
max_diff_y% | float | 0.700000 | Maximum share of Y-plane pixels allowed to differ before the frame is treated as a scene change rather than a jumper. |
max_diff_u% / max_diff_v% | float | 0.350000 | Same for the chroma planes. |
min_diff_y% | float | 0.002000 | Minimum share of differing pixels for the frame to count as containing motion at all. |
min_diff_u% / min_diff_v% | float | 0.000100 | Same for chroma. |
max_diff_y_quick%, max_diff_u_quick%, max_diff_v_quick% | float | 5.0 | Thresholds for the fast pre-pass. |
max_diff_y | int | 19287 | Absolute pixel-count ceiling for the Y plane. |
max_diff_u / max_diff_v | int | 9643 | Absolute ceilings for chroma. |
max_diff_y_quick, max_diff_u_quick, max_diff_v_quick | int | 3000 | Absolute ceilings for the fast pre-pass. |
ydiff_min[0..3] | int | 34, 34, 34, 34 | Minimum per-pixel Y difference for a pixel to join a blob, per feed. Index 3 is the global entry. |
udiff_min[0..3] | int | 7, 9, 9, 9 | Same on the U plane. |
vdiff_min[0..3] | int | 7, 6, 7, 7 | Same on the V plane. |
ydiff_max | int | 100 | Upper per-pixel difference bound on Y. |
udiff_max / vdiff_max | int | 64 | Upper per-pixel bounds on chroma. |
Blob detection
| Key | Type | Live value | Meaning |
|---|---|---|---|
min_blob_sizes[0..3] | int | 100, 300, 300, 250 | Minimum blob size in pixels to count as a jumper, per feed. Raise it to ignore small movement; lower it if distant jumpers are missed. |
max_blob_size | int | 12858 | Maximum blob pixel count. Filters out whole-scene changes such as a cloud shadow crossing the hill. |
max_blob_count | int | 25 | Maximum blobs retained per frame. |
min_blob_keep | int | 70 | Minimum size to keep a blob during filtering. |
min_blob_neighbors | int | 3 | Minimum neighbouring pixels required for a pixel to survive into a blob. |
min_blob_distance[0..3] | int | 4, 8, 14, 4 | Minimum inter-frame blob movement, per feed. |
max_blob_distance[0..3] | int | 50, 60, 80, 80 | Maximum inter-frame blob movement — beyond this the blobs are not the same object. |
blob_fuzz_x / blob_fuzz_y | int | 60 / 60 | Merge blobs within this pixel distance of each other. |
erase_shadows | int | 0 | Enable shadow removal. |
shadow_frames_back | int | 8 | How many frames back the shadow-removal secondary difference reaches. |
Motion markers
| Key | Live value | Meaning |
|---|---|---|
mark_motion | 0 | Draw motion markers into the frames. |
mark_motion_Y / _U / _V | 245 / 245 / 265 | Motion marker colour in YUV. |
making_movie_Y / _U / _V | 0 / 0 / 0 | Marker colour used while a movie is being committed. |
debug_motion | 1 | Verbose motion logging to motion_debug_N.log. |
Movie and clip logic
| Key | Type | Live value | Meaning |
|---|---|---|---|
min_frames | int | 60 | Minimum length of a committed movie clip, in frames. At 60 fps this is one second. |
max_frames | int | 518 | Maximum clip length. Bounded by the 520-frame shared-memory ring. |
min_type2_frames | int | 114 | Minimum frames for a type-2 movie — one whose lower half comes from feed 2 rather than feed 0. |
min_frames_between_movies | int | 2 | Debounce: minimum frame gap between two triggers. |
pre_movie_padding_frames | int | 10 | Safety padding added before every movie start. |
post_movie_padding_frames | int | 10 | Safety padding added after every movie end. |
movie_pad | int | 0 | Additional frames before and after a movie. The template default is 30. |
overlay_frame_offsets[0..2] | int | 142, 420, 200 | Per-feed frame offset applied when rendering overlays. Timing-sensitive; re-check after auto-setup at a new venue. |
min_motion_count[0..2] | int | 20, 20, 20 | Consecutive frames of motion required before a movie triggers. Lower is more responsive but produces more false triggers. |
min_nomotion_count[0..2] | int | 95, 30, 10 | Consecutive frames without motion required to end a movie. Higher gives longer clips that capture more of the landing. Note how different these are per feed — feed 0 waits far longer than feed 2. |
scene_trigger_f0_fraction | float | 0.900000 | Fraction of the frame width used for the feed-0 scene trigger. |
backward_scan_max_gap_frames | int | 4 | Maximum consecutive missed frames tolerated during backward scan. |
backward_scan_velocity_tolerance_percent | int | 40 | Velocity match tolerance during backward scan, as a percentage. |
viewer_ring_channels | int | 4 | Number of channels in the viewer's local movie review ring. Valid range 2–32; raising it costs memory. |
cli_wait_for_active_motion | int | 1 | CLI modes defer shutdown while motion is still active. |
Encoding
| Key | Type | Live value | Meaning |
|---|---|---|---|
disable_nvenc_encoding | int | 1 | Disables NVENC hardware encoding, forcing the software path. Machine-specific workaround — see above. |
*capfile_nvenc_gpu_name | string | NVIDIA GeForce RTX 3070 Ti Laptop GPU | Selects the NVENC GPU by name, matched as a substring. Blank lets FFmpeg pick. Machine-specific. |
capfile_nvenc_gpu_index | int | -1 | -1 resolves the index from the name above; 0, 1, 2… select an adapter directly. There is no separate gpu_index key. |
capfile_quality_cq | int | absent, defaults to 35 | NVENC constant-quality target for capfile recording. Clamped to 15–40; lower is higher quality and larger files. |
capfile_stitch_across_pause | int | absent | 1 produces a single seamless mp4 across pauses, dropping the pause-gap wall time from the output timeline. |
*capfile_output_dir | string | absent | Absolute output directory for capfile recordings. Blank means CapturedVideos under the working directory. |
Feed alignment and synchronisation
| Key | Type | Live value | Meaning |
|---|---|---|---|
feed1_x0_translates_to_feed0_x | int | 1880 | The X coordinate in feed 0's frame that corresponds to X=0 in feed 1's frame. This is how the system stitches the feeds into one continuous view of the hill. Tied to the camera rig. |
feed2_x0_translates_to_feed1_x | int | 1720 | The same relationship between feeds 2 and 1. Tied to the camera rig. |
blob_match_tolerance_us | int | 8333 | Timestamp tolerance in microseconds when matching a blob across feeds. 8333 µs is half a frame at 60 fps. |
feed_sync_offset[0..2] | int | absent | Sequence offset relative to feed 1, computed automatically. Feed 1 is always 0. |
Grid lines and hill calibration
| Key | Feed 0 | Feed 1 | Feed 2 | Meaning |
|---|---|---|---|---|
meter_line_count[N] | 6 | 9 | 6 | How many metre lines that feed draws. |
meter_line_start[N] | 35 | 40 | 55 | The metre mark of the first line. |
meter_line_increment[N] | 5 | 5 | 5 | Metres between adjacent lines. Feed 0 therefore covers 35–60 m, feed 1 from 40 m, feed 2 from 55 m. |
meter_line_radius[N] | 2 | 2 | 2 | Line thickness, in pixels from the centre. |
Line colours are given in YUV. meter_line_Y/U/V is 255/265/245,
meter1_line_Y/U/V (whole-metre lines) is 245/265/245, and
meterD_line_Y/U/V (sub-metre lines) is 245/245/265.
Anchor pairs
Each metre line is defined by two anchor points per feed:
@far[0][ 0]=960,100 far anchor for feed 0, line 0
@near[0][ 0]=960,900 near anchor for feed 0, line 0
@far[0][ 1]=985,100
@near[0][ 1]=990,900
The far anchor is where that metre mark crosses the far edge of the hill — toward the top of the frame and the vanishing point. The near anchor is the near edge, at the bottom, closer to the camera. The viewer draws the line between them and linearly interpolates distance between adjacent lines.
The key space is @far[F][I] and @near[F][I] with F = 0–2 and
I = 0–29, giving 180 entries in total. Single-digit inner indices are space-padded to two
characters: @far[0][ 0] through @far[0][29]. In the shipped
configuration, feed 0 has anchors 0–5 populated, feeds 1 and 2 have 0–6, and the rest
are 0,0.
Check the anchor count against the line count
In the shipped configuration meter_line_count[1] is 9, but only seven anchor
pairs (indices 0–6) are populated for feed 1. Lines with unset anchors have nothing to
draw between. Confirm during calibration that every feed has as many populated anchor pairs as
its line count claims. verify on target hardware
Anchors are normally set through the Setup Grid Lines panel rather than by
hand — see User guide § grid-line calibration.
Each anchor is written to settings.txt immediately as you place it.
Auto-setup and analytics
| Key | Live value | Meaning |
|---|---|---|
auto_setup_max_jumpers | 1 | Auto-setup stops after this many completed jumpers. |
auto_setup_max_frames | 1500 | Auto-setup stops after this many feed-1 frames, whichever limit comes first. |
practice_max_jumpers | 1 | Same limit for practice mode. |
practice_max_frames | 1500 | Same frame limit for practice mode. |
auto_setup_adaptive_width_enable | 1 | Enable adaptive narrowing of the analysis width when per-frame processing runs slow. |
auto_setup_adaptive_width_threshold_us | 14000 | Per-frame motion processing budget ceiling, in microseconds. |
auto_setup_adaptive_width_trial_frames | 300 | Frames sampled before deciding to narrow. |
auto_setup_adaptive_width_slow_pct | 5 | Share of frames allowed over budget before narrowing kicks in. |
auto_setup_adaptive_width_min_pct | 33 | Floor on how far the width may be narrowed. |
analytics_min_tracked_frames | 5 | Minimum tracked frames before analytics will act. |
analytics_adjustment_cooldown | 30 | Frames to wait between successive automatic threshold adjustments. |
analytics_threshold_step | 2 | Step size for each automatic adjustment. |
analytics_max_multiplier | 2 | Ceiling on cumulative automatic adjustment. |
analytics_retry_budget_us | 10000 | Time budget in microseconds for analytics retries. |
Paths and upload
These appear in settings_sample.txt with the defaults below but are absent from
the shipped live configuration, so the compiled-in defaults apply. Add them explicitly if you
need different values.
| Key | Default | Meaning |
|---|---|---|
*archive_dir | output_videos | Where videogen writes committed jump_*.mp4 clips. Created at startup if absent. |
*upload_host | thehansens.com | FTP host. Passed to upload_video.bat as VDM_UPLOAD_HOST. |
*upload_path | uploads | Remote directory. Passed as VDM_UPLOAD_PATH. By convention this is a server-side symlink the tournament admin repoints to the current event. |
*upload_signal_url | http://www.thehansens.com/tournament/signal_next.cgi | URL fetched after a successful upload. Passed as VDM_SIGNAL_URL. |
upload_enabled | 1 | Kill switch. 0 skips the upload spawn entirely; the encode still happens. |
Credentials never go in settings.txt
There is no username or password key, by design. FTP credentials live only in
%USERPROFILE%\.netrc, which curl --netrc reads. That file is
operator-provisioned, is never packaged, and does not exist until you create it. See
Installation § upload credentials.
Stale and ignored keys
Because unrecognised keys are silently dropped, both shipped files carry lines that do nothing. Knowing which they are saves you from tuning a value that has no effect.
In the live settings.txt
Two families are present but no longer read by anything — they were removed from the parser in a dead-write audit and are residue in the file:
n_frames_of_30_before_scene_trigger_contain_motion[0..2]min_dist_30_frames_before_scene_trigger[0..2]
They will disappear the next time VDM rewrites the file.
In settings_sample.txt
About two dozen keys in the template are no longer recognised. The ones most likely to mislead, because they sound like things you would want to change:
| Key in the template | Status |
|---|---|
feed_offset[0..2] | Not recognised. The template describes it as delaying a feed by N frames; feed alignment is now handled by feed_sync_offset[] and the feedN_x0_translates_to_* keys. |
min_type1_frames | Not recognised. Superseded by the per-pixel pixel_frames.txt mechanism. |
min_diff_y, min_diff_u, min_diff_v, min_quick_size | Not recognised. The percentage forms with the % suffix are the live ones. |
show_jumper_numbers, show_name, show_speed, font_size, only_one_viewer, show_lines_mode, draw_circle_around_blobs, showing_motion | Not recognised. Several of these functions are now controlled from the UI — blob circles by the Circles On/Off button, motion highlighting by Highlight ON/OFF. |
debug_distance, play4_show_frame_rate, distance_look_back_n_frames | Not recognised. |
meters_from_takeoff_to_visible, last_visible_meter_line | Not recognised. Hill geometry is expressed through the grid-line anchors. |
How to tell whether a key took effect
Save from the controller and re-open settings.txt. Because saving rewrites the
file from the parsed in-memory state, any key that survives the round trip is recognised, and
any key that vanishes never was.
Related pages
- User guide § calibration — setting motion regions and grid lines through the UI rather than by editing keys.
- Installation § first run — the camera and GPU selection steps.
- Troubleshooting § settings — recovering a configuration that was overwritten.
