Skip to content

Workout: plate loading per set row — the plates for each row's weight, from the plates you own (No bar for Smith machines, #138) - #194

Merged
DuarteSantos8 merged 3 commits into
DuarteSantos8:mainfrom
kurktchiev:gh/plate-loading
Sep 28, 2026
Merged

DuarteSantos8 merged 3 commits into
DuarteSantos8:mainfrom
kurktchiev:gh/plate-loading

Conversation

@kurktchiev

@kurktchiev kurktchiev commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

What

A plate line under each set row of a plate-loaded exercise: the plates that make that row's weight, from the plates the user owns.

  • Barbell work: what goes on each side beyond the bar — 45 + 5 per side. The empty bar reads Bar only.
  • One stack — a dip belt, a landmine, a plate-loaded machine, a sled, or a body-weight exercise with added weight — reads Load 25.
  • A weight the inventory cannot make says so: … · 2.5 lb short.
  • The line appears on the first loaded row and wherever the stack changes from the loaded row before it (warm-up ramps and drop-sets included), so three equal work sets show their plates once. What to strip and what to add rides along (−10 +25); the compact workout view keeps the stack and drops the moves.
  • Per-side (unilateral) barbell exercises load from the sides' shared bar while both sides agree.

It replaces the one-line "Bar 45 lb · 50 lb per side" chip, which only ever described one set and never said which plates.

Settings and per-exercise choices

  • Settings → Equipment → Plates: pairs of each size you own, per unit. Absent = the standard set (six pairs of each common size), so nothing changes for anyone who never opens it. A home gym with one pair of 45s is never told to use two: heaviest-first when that lands exactly, otherwise the fewest plates that hit the weight, otherwise the closest load below and what is missing.
  • ⋯ → Plate loading (also in the exercise detail and routine config sheets): per side / single stack / off, the bar or base weight, and No bar — an explicit 0 in barWeights, which is what Being able to set Smith bar to 0 kg/lb. #138 asked for (a counterbalanced Smith machine). Deleting the key stays the way back to the default, so no existing profile changes meaning.
  • The default kind comes from the equipment: bars → per side; body weight, "weighted" and sleds → single stack; dumbbells, kettlebells, cables, pin machines and bands → off.

Unit switch

convertStateUnit used to convert bar weights like any other number, so a 45 lb bar became a 20.5 kg one and, with a kg plate set, every row read "1 kg short". A bar is a stamped object: an override equal to the old unit's default drops out so the new default applies (45 lb → the 20 kg bar, 25 lb EZ → 10 kg, and back); an explicit 0 stays 0; a custom bar still converts (33 lb → 15 kg). "Keep the numbers, change the label" is untouched.

State

S.plates ({ lb: { 45: 1, 35: 1, … }, kg: { … } }, per unit like the bar weight — no conversion on a unit switch) and S.loadKind ({ exId: 'pairs' | 'single' | 'none' }), both key-union merged in sync-merge.js like barWeights and exNotes. Logged weights stay totals; everything here is display.

Tests

lib/plates.test.js (inventory, stack search incl. the non-greedy case, delta, kind, base weight, row load), rendered rows in views/Workout.plates.test.jsx (ramp, bar only, short, no bar, single stack, dumbbell, drop-set, per-side lunge, band, compact), both sheets in sheets.plates.test.jsx, units.test.js for the bar rule. 20 new strings in all 14 packs, 2 dead ones removed, check-locales in sync, pt-BR guard re-pinned (655 overrides / 666 inherited). fmtPlate keeps the quarter (1.25, 21.25) that fmtNum rounds away.

Three commits, each standalone: the feature, the unit-switch rule, and a second round after training on it (per-side rows, + between plates, bands).

Closes #138.

🤖 Generated with Claude Code

kurktchiev and others added 3 commits September 21, 2026 15:47
… the plates you own

Under each set of a plate-loaded exercise, a line with the plates that make THAT
row's weight: per side beyond the bar ("45 · 5 per side"), one stack for a belt,
a landmine, a plate-loaded machine, a sled or a body-weight exercise with added
weight ("Load 25"), "Bar only" at or below the bar, "2.5 lb short" when the
inventory cannot make it. Shown where the stack changes from the loaded row
before it — warm-up ramps and drop-sets included — so a run of equal weights
shows its plates once; what to strip and what to add rides along, except in
the compact view. Replaces the one-line "Bar 45 lb · 50 lb per side" chip,
which only ever showed one set and never said which plates.

lib/plates.js: the inventory (S.plates, pairs per size, per unit like the bar
weight — absent = the standard set, six pairs each), the stack (heaviest-first
greedy when that lands exactly; else the fewest plates that hit the weight, so
a home gym with one pair of each size gets 45 · 35 · 15 · 5 for 100 per side
and is never told to use two 45s), the strip/add delta, the loading kind per
exercise (S.loadKind override; bars → pairs, body weight / weighted / sled →
single, the rest → none) and the base weight. An explicit S.barWeights[id] = 0
is now "No bar" (issue DuarteSantos8#138: a counterbalanced Smith machine) — deleting the
key stays the way back to the default.

Settings → Equipment → Plates counts the pairs you own. The ⋯ menu's "Plate
loading" sheet (also in the exercise detail and routine config sheets) picks
per side / single stack / off, the bar or base weight, and No bar. The editor
derives its default from the same session config the rows use.

fmtPlate keeps the quarter (1.25, 21.25) that fmtNum rounds away. Tests: lib,
the rendered rows (ramp, bar only, short, no bar, single stack, dumbbell, drop
set, compact) and both sheets. 20 locale keys in 14 packs, 2 dead ones out;
pt-BR guard re-pinned (655 / 654).

(cherry picked from commit f725668)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…r, not 20.5 kg

convertStateUnit converted S.barWeights like any other weight, so a kg profile
that had been lb ended up with a 20.5 kg bar (45 lb / 2.2046, rounded to the
quarter) and, with a kg plate set, every plate line read "1 kg short". A bar is
a stamped object, not a number: an override equal to the old unit's default for
its bar type drops out and the new unit's default takes over (45 lb → 20 kg,
25 lb EZ → 10 kg, and back). An explicit 0 ("no bar") stays 0. A custom bar
still converts (a 33 lb women's bar → 15 kg) and drops out too when it lands
on the new default. Junk in the map is dropped. The "keep the numbers, change
the label" path is untouched — that is the user asking for exactly that.

(cherry picked from commit 2d9dff9)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ates, bands never load

Three holes found by training on the first cut:

1. A per-side (unilateral) barbell exercise — a barbell lunge — showed nothing under
   its work sets: the rows are side sets, which the first cut skipped outright. A bar
   is the same bar for both legs, so the line now uses the sides' weight while they
   agree (or only one side has a number yet) and stays away once they differ.
2. "45 · 5 per side" did not read as a sum. Plates are joined with "+" now.
3. A band's "weight" is its tension, not plates — bands never get a line, even though
   the app counts them as body-weight equipment.

Rendered tests: the lunge (agreeing sides, differing sides), a band with a weight
logged, plus the existing suite with the new separator.

(cherry picked from commit ac49dc0, frontend half — the fork's coach sidecar changes stay there)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@DuarteSantos8
DuarteSantos8 merged commit cb9ea3a into DuarteSantos8:main Sep 28, 2026
4 checks passed
DuarteSantos8 added a commit that referenced this pull request Sep 28, 2026
…vice survive a sync with the other, and so does going back to the standard set or the equipment's own loading

S.plates and S.loadKind were a plain key union, newer copy first. A phone
that had since logged a set was the newer copy, so its older plate list or
load kind undid the one just set on the desktop, and "Back to the standard
set" or picking what the equipment implies (both a deleted key) came back
from the other device. They now merge like the Structural Balance overrides
(mergeStampedMap): each entry carries the time it was set, and the way back
is written as a stamped entry, a plate list with no sizes or a load kind of
null, so it wins like any other change. A unit's plate list stays one list,
kept whole as last counted. Bare kinds and unstamped lists from the first
builds still read as before.

lib/plates.js owns the stored shape (ownsPlates, withPlatePairs,
withStandardPlates, loadKindOf, withLoadKind); the editor, the inventory
sheet and the Settings row use it.
DuarteSantos8 added a commit that referenced this pull request Sep 28, 2026
…ls the workout screen while the plate line works out what cannot be loaded

When the plates you own cannot make a row's weight, plateStack searched for
the closest load below it with a table as long as the weight in quarter
units. Beyond everything in the inventory the answer is simply every plate
and the rest missing, which the greedy pass already has, but the search ran
anyway: about half a second per row per render for 999999, and gigabytes
for a longer typo, on every keystroke. It now stops there.
DuarteSantos8 added a commit that referenced this pull request Sep 28, 2026
…h unit's plate list, so the rows load from the new unit's plates and switching back finds the old list as it was

Pins what convertStateUnit does with the plate inventory: it carries S.plates
over untouched rather than converting it, since a 45 lb plate does not become
a 20.4 kg one. After the switch the rows read the new unit's own list, or the
standard set until one is counted; a list counted there is kept beside the
old one. A sled's or machine's base weight in S.barWeights is a weight and
converts, and the load kinds hold none.
DuarteSantos8 added a commit that referenced this pull request Sep 28, 2026
… rows' plate line, the Plate loading sheet and the plate list in Settings — and drop the two bar-weight strings the app no longer has

The pull request predates both packs. Its "No bar" also went into thirteen
packs a second time, next to the one v1.3.8 added; the copy it added is gone,
so the word on screen stays the one it was (in Hindi and Chinese the two
differed).
DuarteSantos8 added a commit that referenced this pull request Sep 28, 2026
…der a set start at the right edge, under the set's number, with the plates to strip and add at the far left, and on a 320 px screen the plate line lines up with the drops
DuarteSantos8 added a commit that referenced this pull request Sep 28, 2026
…te loading in its menu, as it showed no bar chip before the plate lines came in (#194, #203)
DuarteSantos8 added a commit that referenced this pull request Sep 28, 2026
… a plate-loaded machine set to per side with its own weight reads Per side, not Bar 50 lb
@DuarteSantos8

Copy link
Copy Markdown
Owner

Thanks @kurktchiev, plate loading per row is in, together with the 45 lb -> 20.5 kg bar fix you found along the way.

One change you should know about because your fork writes the old shape: S.loadKind entries are now {kind, _ts} and S.plates[unit] is {…pairs, _ts}, and "Back to the standard set" writes {_ts} instead of deleting the key. That is how balanceOverrides already sync, so the choice made last on one device survives a set logged on the other. Bare strings and unstamped lists from your builds still read.

Follow-ups on top: a typo like 99999 no longer stalls the screen while the plate line works out what can't be loaded, converting kg <-> lb keeps each unit's own plate list, the ⋯ menu only names a bar for bar exercises, and the plate line mirrors in Arabic.

Released in v1.3.9: https://github.com/DuarteSantos8/openGym/releases/tag/v1.3.9

@kurktchiev
kurktchiev deleted the gh/plate-loading branch September 29, 2026 11:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Being able to set Smith bar to 0 kg/lb.

2 participants