A plate calculator and offline gym companion, backed by a Go API.
Run the app locally at http://localhost:8080/. The public API lives at
gorack.pachevjoseph.com;
the web app lives on GitHub Pages.
Successful CI runs on master deploy the web app to Pages. The Go API uses a
separate hosting deployment.
- Find the closest load at or below your target, using the fewest plates
- Calculate in pounds or kilograms, including fractional weights
- Save equipment presets on your device, with custom bars and plate inventories
- Support custom bar weights, including specialty bars such as 55lb bars
- Plan warm-up loads and see what to add or remove on each side between sets
- Install the web app and calculate offline after the first visit
- Use the same calculation rules through the REST API
Note: All plate values in responses represent pairs (e.g.,
"fortyFives": 2means two 45lb plates on each side of the barbell)
- Choose lb or kg, set your bar weight, and enter the plate pairs you have.
- Give that equipment a name and save it as a preset for next time.
- Enter your total working weight, including the bar, and calculate.
- Use the warm-up ladder or calculate your next set. The app lists the plates to add and remove on each side relative to the previous selected load.
Pounds and kilograms keep separate equipment and targets. Switching units selects that unit's saved setup; it does not convert plate labels or weights. Check the achieved load when your inventory cannot reach a target exactly.
Use Install app for your browser's installation instructions. Visit once while online and wait for offline readiness before relying on an offline reload. Presets belong to this browser and device; clearing site data removes them. If browser storage is unavailable, calculations still work, but settings cannot be saved.
- mise for the pinned Go and Node versions
The project includes a mise.toml configuration file for easy setup:
# Install dependencies and tools defined in mise.toml
mise install
# Build the project
mise run build
# Run the server
mise run run# Get dependencies
go mod download
# Build the binary
go build -o ./tmp/gorack .
# Run the server
./tmp/gorackOpen http://localhost:8080/ for the gym app, /docs/ for API documentation,
or /health for a health check. The API base path is /v1/api.
API_PORT: Set custom port (default: 8080)API_PORT=9000 mise run run
For quick calculations with default plate availability:
GET /v1/api/rack?weight=225
Response:
{
"unit": "lb",
"barWeight": 45,
"fortyFives": 2,
"plates": [{"weight": 45, "count": 2}],
"desiredWeight": 225,
"achievedWeight": 225,
"message": "You got this!"
}For calculating with specific plate availability:
curl -X POST \
https://gorack.pachevjoseph.com/v1/api/rack \
-H 'content-type: application/json' \
-d '{
"barWeight": 35,
"fortyFives": 1,
"thirtyFives": 2,
"twentyFives": 2,
"tens": 3,
"fives": 2,
"twoDotFives": 2,
"desiredWeight": 255
}'Response:
{
"unit": "lb",
"barWeight": 35,
"fortyFives": 1,
"thirtyFives": 1,
"twentyFives": 1,
"fives": 1,
"plates": [
{"weight": 45, "count": 1},
{"weight": 35, "count": 1},
{"weight": 25, "count": 1},
{"weight": 5, "count": 1}
],
"desiredWeight": 255,
"achievedWeight": 255,
"message": "You got this!"
}The API accepts barWeight from 0 to 2,000 in quarter-unit increments.
For a specialty bar, send its weight, such as "barWeight": 55. An explicit
zero means no bar weight; omitting the field selects 45 lb or 20 kg.
Use plates for a custom inventory in either unit. Each count is the number
available per side, so one pair of 1.25 lb plates adds 2.5 lb to the bar.
curl http://localhost:8080/v1/api/rack \
-H 'Content-Type: application/json' \
-d '{
"unit": "kg",
"barWeight": 20,
"desiredWeight": 82.5,
"plates": [
{"weight": 20, "count": 2},
{"weight": 10, "count": 2},
{"weight": 1.25, "count": 2}
]
}'For a quick calculation with metric defaults:
GET /v1/api/rack?unit=kg&weight=82.5
The response always includes the used plates, unit, and achieved weight.
Named pound fields remain available for existing clients. Do not mix those
fields with plates or use them with unit: "kg".
Targets and bar weights accept quarter-unit increments up to 2,000. Targets must be at least the bar weight. An inventory can contain up to 16 distinct plate weights, each greater than zero and at most 100, in quarter-unit increments. Counts must be integers from 0 to 100. Request bodies are limited to 16 KiB.
Pound POST requests without inventory describe an empty rack. Metric POST
requests without inventory use metric defaults; an explicit plates: []
describes an empty rack. GET requests use defaults for the selected unit.
The API supports the following plate types (values represent pairs):
| JSON Parameter | Weight (lbs per plate) | Description |
|---|---|---|
hundreds |
100 | 100lb plates |
fortyFives |
45 | 45lb plates |
thirtyFives |
35 | 35lb plates |
twentyFives |
25 | 25lb plates |
tens |
10 | 10lb plates |
fives |
5 | 5lb plates |
twoDotFives |
2.5 | 2.5lb plates |
oneDotTwoFives |
1.25 | 1.25lb plates |
The project uses mise for streamlined development workflows:
# Live reload during development
mise run watch
# Check Go, browser calculation tests, and dependencies
mise run check
# Update module metadata after changing dependencies
mise run tidy
# Clean build artifacts
mise run cleanGorack searches the bounded inventory for the heaviest achievable load that does not exceed the target. Among equally heavy loads, it chooses the fewest plate pairs, then prefers heavier plates to break ties. Integer quarter-unit arithmetic keeps fractional plates exact.
The browser calculates locally. Equipment presets stay in browser storage; there is no account or server-side history. Offline use requires an initial online visit over HTTPS or localhost so the app can cache its files.
See operations for container deployment, checks, and the scheduled uptime monitor.
MIT