A walkthrough of the four recommended desktop programs — builder, scanner, counter, and viewer — in the order an election actually uses them: design the ballot, scan it, count it, review it. See the top-level README.md for installation, building, and configuration; this guide is about what each screen does once the program is running.
All four are ordinary double-clickable desktop programs. None of them need an internet connection — see Running Offline / Air-Gapped in the README.
Default login: admin / ChangeMe123! works for scanner, counter,
and viewer — each seeds this account itself the first time it runs
against an empty database, so you can sign in right away and start
clicking around. Change the password once you're done exploring.
(builder has no login of its own.)
Launch builder and you land on the Home screen: a numbered checklist
of the setup steps, in the order the app expects them (though every screen
is also reachable any time from the Setup / Ballots / Admin
menus at the top).
Steps 1–4 (Elections, Regions, Parties, Ballot Types) are simple CRUD screens — a table with New / Edit / Delete / Refresh buttons, one row per record. Contests & Candidates (step 5) is the same idea with more depth: each contest also gets a candidate list and a set of assigned regions, edited via their own dialogs.
Opening a contest shows the rest of what a race or measure can carry
beyond a title: Voting Method (Plurality, Ranked Choice, Approval, or
Measure — each drives its own tabulation in counter), a per-contest
Percent Required to Win (default 50%, overridable for supermajority
measures), and an optional Preamble/Postamble — statutory text,
a fiscal-impact note, a write-in reminder, whatever a real contest needs
printed before or after its candidate list, each with its own Print
checkbox.
Saving a contest cascades straight into Candidates: one row per
candidate/option in an editable table. A name is all that's required, but
each row also has Write-In, Party, Order, a printed
Prefix/Suffix on the candidate's own name line, and an
Explanatory Text note printed in italics beneath the name (e.g.
"Incumbent (Ind)") — Alice Johnson below shows that note; Bob Williams
shows the plain case. A brand-new Measure contest arrives here with
"Yes"/"No" already filled in — every builder flavor (this app, blBuilder,
bBuilder) creates them automatically the first time a Measure contest is
saved with no candidates of its own yet, since that's what the overwhelming
majority of real measures need. Rename or replace them freely; this only
ever fires on a contest that currently has none.
Step 6 (Design Templates) is where you choose paper size, column count, and vote-indicator style (oval, rectangle, or connect-the-dots — see the README's Vote Indicator Styles table). Step 7 (Ballot Combinations) defines each unique ballot variant as an Election + Precinct + Party + Ballot Type combination — a jurisdiction with primaries and multiple precincts will have many of these; a simple nonpartisan single-precinct election will have just one.
Once steps 1–7 are done, Print generates the actual ballot: pick a
combination, a design template, a language, and how many copies, then
Generate PDF. This writes both the printable PDF and the YAML layout
file counter will need later into the ballot templates folder —
Open Output Folder takes you straight there.
builder has no login of its own (the Admin menu still manages the
same User records bBuilder/blBuilder use, for when you're running
those alongside it) — see builder/README.md for
the full screen list and what's deliberately left out of the CRUD forms.
scanner drives a physical document scanner (NAPS2, scanimage, or a
custom shell command — see scanner/README.md) and
deposits ballot images into the folder counter will read from. Sign in
with an ADMINISTRATOR- or OPERATOR-role account.
The Output folder field is pre-filled with the shared default
(~/pbss_data/cast_ballot_scans unless overridden — see the README's
property-override section).
Start notes is a free-text field for anything worth recording about
this batch before it begins (e.g. "Beginning Precinct 7 batch — box 1 of
3") — it's logged immediately with its own timestamp, not just folded
into the end-of-batch summary.
Click Start Scan and the scanner backend runs; a live progress line shows images scanned and the last file written. Stop halts a batch in progress. Once a batch finishes, an End notes field appears — for flagging something noticed after the fact (a misfeed found while reviewing the physical stack, say), tagged in the log against the batch it refers to regardless of how much later it's written.
Print Batch Sheet sends the current start/end notes to a printer as a
physical page — meant to be inserted into the paper ballot stack at the
point it documents. If scanner.notes.print-flag-pages=true is set, the
same thing happens automatically whenever a note is saved, with no click
needed; either way, a printer problem is only ever logged, never allowed
to interrupt scanning.
counter is deliberately the smallest of the four: two folders, Start,
Stop, and a results link — everything else (darkness threshold, DPI,
assumed paper width) is fixed in application.properties rather than
exposed as a control (see counter/README.md).
Sign in with a COUNTER_OPERATOR- or ADMIN-role account.
Both folder fields are pre-populated: Ballot images folder points at
where scanner (or a physical scanner configured directly) deposits
images; Ballot templates folder points at the YAML layout files
builder's Print screen generated. Click Start Counting and it works
through the images — corner detection, QR decode, vote-indicator
sampling — updating a live pass/processed/duplicate/flagged-for-review
count as it goes.
A ballot that fails corner detection, has an unreadable QR code, or trips
the scribble-detection heuristic gets flagged for manual review rather
than silently miscounted — the screenshot above shows the normal
successful case (4 counted, 0 flagged) on a small test batch that
includes a deliberately messy-marks ballot and a deliberate overvote,
both counted correctly rather than rejected. Open Results Folder
opens results_report.html and its companion reports (RCV tabulation,
overvotes, write-ins, scribbles — see the README's
bCounter report-files table) in the OS file
browser; Print Results sends results_report.html straight to a
printer via the OS's own HTML print handling.
results_report.html is a plain per-contest tally, with a banner calling
out any contest using a non-default win threshold so a 55% result on a
60%-required measure can't be misread as a win:
Ranked-choice contests get their own rcv_report.html, a full
round-by-round instant-runoff breakdown — who was eliminated each round
and where their ballots' next choice went, down to a final winner:
Both are real, unedited output from a real count — the same 10-ballot demo
election used throughout this guide — copied into
docs/sample_reports/ so you can open
results_report.html and
rcv_report.html directly, live, in a
browser. That same run also flagged a stray, unrelated hand-scribbled note
on one ballot (scribble_report.html)
and captured a marked write-in vote's hand-written name for review
(writein_report.html) — both
report pages carry "View" links back into the running app, so they won't
resolve outside of it, but the tables themselves are static and browsable
as-is.
viewer is read-only — it never writes to counter_results.db, so it's
always safe to run alongside counter, even mid-scan, or on a separate
machine dedicated entirely to reviewing results (see the README's
viewer-only station
setup for a multi-station election). Sign in with a VIEWER- or
ADMIN-role account.
The ballot list is every scanned image, filterable by name/glob:
Double-click (or select and click View →) to open a ballot. Each vote-indicator box is color-coded — green for a counted mark, blue for an unmarked box, amber for an overvote — with candidate names labeled directly on the image. Next/Prev step through the filtered list without going back to it; Fit/+/− control zoom; hovering a box shows its contest, candidate, and status in the status bar. The screenshot below is zoomed in past the header/barcode band to the three contests themselves — exactly what +/− or dragging the zoom percentage let you do interactively.
This is the same image-plus-overlay rendering blCounter's embedded Viewer produces, but drawn directly with Java2D rather than a browser engine — see viewer/README.md for why that distinction exists and what the standalone viewer deliberately leaves out (SQL filtering, RCV/scribble reports, auto-advance review mode) compared to blCounter's fuller-featured version.
View → Contests & Candidates (or Ctrl+L / Cmd+L) opens a second window listing every contest on the ballot currently on screen — click a contest to expand it into its candidates, each with a color swatch matching its status (green voted, amber overvoted, blue unmarked). It's the Swing equivalent of bCounter's embedded web Viewer's sidebar, as a separate toggleable window rather than a fixed panel, so it doesn't compete with the image for space. Clicking a candidate here highlights its box on the ballot image, and clicking a box on the image highlights the matching candidate here — same bidirectional highlighting the web version does.
bBuilder/bCounter/bScanner (web) and blBuilder/blCounter/blScanner
(JavaFX) cover the same workflow with a browser or native-desktop UI
respectively — see the README's
Other Versions Available section.













