Frontend
There's no client-side framework, bundler, or transpiler in this app — every page is a server-rendered
EJS template, and interactivity is plain JavaScript loaded via <script> tags. This page catalogs
what each script does; see Using the App for what the features actually look like
to use.
Build
package.json has exactly two frontend-relevant scripts, both Sass-only:
build-css— compilespublic/scss/main.scss→public/css/main.cssonce.watch-css— the same, in watch mode, for local development.
JavaScript ships as-is, one file per concern, included directly by whichever EJS views need it. Each
script is written as a self-contained IIFE that checks for the DOM elements it needs before doing
anything, so it's safe to include a shared script (like nav.js or theme.js) on every page without
guarding inclusion per-route.
Scripts (public/js/)
| File | Purpose |
|---|---|
nav.js | Hamburger menu open/close, including outside-click and Escape to close. |
theme.js | Light/dark mode toggle button; persists the choice to localStorage. |
about.js | Opens/closes the "About" info popup (build info, version). |
muscleDiagram.js | window.buildMuscleDiagram(primary, secondary) — builds two inline front/back-body SVGs with muscle regions highlighted, from a hardcoded muscle-name-to-SVG-region map. No external image assets — the body outlines are drawn entirely in code. |
exercisePopup.js | window.openExercisePopup(exercise) and window.openPlanUsagePopup(name, plans) — the shared modal for viewing an exercise's full detail (built on top of muscleDiagram.js) or seeing which plans reference it. |
exerciseChart.js | window.buildExerciseChart(container, data, type) — renders a Chart.js line chart of an exercise's logged reps/weight/duration history, reading theme colors from CSS custom properties so it matches light/dark mode automatically. |
license.js | The public /license page — handles both the trial-request form (posts to /api/license/trial, then swaps in a "check your email" message and reveals the key-entry form) and the activation form (posts to /api/license/activate, redirects home on success). |
adminLicense.js | The admin license screen's activation form — same /api/license/activate endpoint, reloads the page on success to reflect the newly-cached status. |
planBuilder.js | The plan create/edit UI. Maintains an in-memory days array of exercises and supersets, serializes it into a hidden daysJson field on form submit, and includes the exercise picker modal plus an inline "quick-create exercise" flow (POST /exercises/api/quick-create) so you never have to leave the plan you're building. |
dayEditor.js | The "Edit Day" modal available mid-workout to a plan's owner or an admin — add/remove/reorder exercises or supersets for the day currently being executed. Saves via PUT /plans/:id/days/:dayIdx and hands the updated day back to workout.js via window.WorkoutExec.refreshDay. Shares its exercise-picker pattern with planBuilder.js. |
workout.js | The guided workout execution state machine (idle → exercise → rest → complete) — the largest script in the app. Handles both regular exercises (sequential sets) and supersets (rounds across multiple exercises); tracks elapsed time; autosaves progress to POST /plans/:id/save-progress; builds completed-set log entries split by distinct rep count (mirroring how plansController.js#complete and ExerciseHistory's bucketing work server-side); supports ad-hoc "Add Set" (with an option to save it back to the plan permanently); an Auto-Advance preference persisted to localStorage; and resuming or discarding an in-progress WorkoutProgress document. |
Styles (public/scss/)
Hand-rolled — no CSS framework. Structured as Sass partials compiled into one stylesheet:
abstracts/_variables.scss— shared Sass variables.layout/_base.scss— base layout and the CSS custom properties that a user'sthemeColorsoverrides (see Data Model → User) target directly, so per-user appearance customization works by overriding CSS variables rather than generating per-user stylesheets.components/*.scss— one partial per UI area (_admin,_buttons,_cards,_dashboard,_exercise-chart,_forms,_muscle-viz,_nav,_planbuilder,_profile,_timer,_about-popup), all pulled together bymain.scss.