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.

Row and Repeat counter showing the progress ring with per-row ticks, the completed count, and a pinned next-row note banner
The counter with the repeat ring, the working-row readout, and a pinned-note banner. Placeholder pending a real screenshot.

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

References

  1. Row & Repeat Counter
  2. Screen Wake Lock API (navigator.wakeLock) — browser support varies.