A Persistent Row and Repeat Counter for Knitting Projects
Row & Repeat is a persistent row counter for multiple projects. Each project tracks its own row count, an auto-wrapping pattern-repeat position, and notes pinned to specific rows that surface as you reach them. Every tap writes to storage immediately, and the tool can hold the screen awake mid-project. It is a single-file, offline tool [1].
The problem
A mechanical clicker counts rows but not repeats, holds one project, and loses its place if it is knocked. A phone note is worse. The specific failures are: forgetting which row of a repeat you are on after a break, losing the count when a tab closes or a battery dies, and reaching a row that needed a pattern change one row too late. Row & Repeat addresses each — it derives the repeat position from the count, saves on every increment, and pins notes to the rows that need them.
How it works
Tap + when a row is finished; − undoes one. The large number is rows completed; the line beneath it is the row now on the needles. A progress ring around the number acts as a stitch marker: one lap per pattern repeat, one tick per row, a filling arc for rows done in the current lap, and a bead at the working row's position. Projects are named and switched from a dropdown that sorts the most recently updated first. Increments give a short haptic pulse via navigator.vibrate(12) where supported.
Notes are pinned to a row number and surface automatically: a muted "next row" banner appears one row ahead, and a highlighted "this row" banner appears when that row is current. The Keep screen awake button requests a Screen Wake Lock so the tablet does not dim between rows.
The math
Repeat position
For done rows completed and a repeat length L, the row now on the needles is:
row-in-repeat = (done mod L) + 1
repeat number = floor(done / L) + 1
This rolls over correctly at the boundary: completing the last row of a repeat advances to row 1 of the next. When no repeat is set, the ring falls back to overall progress toward a total-rows or total-repeats target.
Persistence and wake lock
Every increment and decrement writes the full state to localStorage (rowcounter.v1) immediately — there is no batch save, so a closed tab or dead battery loses nothing. The Wake Lock uses navigator.wakeLock.request("screen") and re-acquires automatically on a visibilitychange back to visible, since the browser releases the lock whenever the tab is hidden:
document.addEventListener("visibilitychange", () => {
if (wakeWanted && !wakeLock && document.visibilityState === "visible")
acquireWake();
});
On browsers without the Wake Lock API the button disables itself with a visible "unsupported" label rather than failing silently.
Editing the config
There is no facility table here — the tool is driven entirely by the projects a user creates. The one constant at the top of the <script> block is LS_KEY, the storage key. A new project's default shape is the mkproj() factory (row count, repeat length, repeat/row targets, notes). The repeat arithmetic is the repeatInfo() function; the haptic pulse duration is the argument to navigator.vibrate() in buzz().
Limitations
- Storage is per-device and per-browser. Projects do not sync between a phone and a tablet; clearing the browser's site data clears the counts.
- The repeat model is a single flat repeat length. Nested or staggered repeats (a lace repeat inside a larger panel repeat) are tracked only as the one length you set.
- Wake Lock availability depends on the browser and, on some platforms, on the page being served over HTTPS. Where it is unavailable the device's own display timeout applies.
- Deleting a project is guarded by a prompt but cannot be undone, and the last remaining project cannot be deleted.
References
- Row & Repeat Counter
- Screen Wake Lock API (
navigator.wakeLock) — browser support varies.