From Printed Table to PWA: How One Designer Built SETLO — a Minimal Home-Workout Tracker Powered by React, Tailwind and LLMs

From Printed Table to PWA: How One Designer Built SETLO — a Minimal Home-Workout Tracker Powered by React, Tailwind and LLMs

Table of Contents

  1. Key Highlights
  2. Introduction
  3. From a Chatbot’s Routine to a Real Problem
  4. Choosing Minimalism over Feature Bloat
  5. The Stack: React, Tailwind, LLMs and Vercel
  6. Tailwind as a Composable Design System
  7. Designing for the Workout Flow
  8. Representing Exercise Data: A Compact Schema
  9. RIR Explained and Why It Matters
  10. Deploying as a Progressive Web App
  11. Privacy and Trade-offs of Local-Only Storage
  12. Why Ship "Good Enough" Now
  13. Iteration Pressure and Architectural Negotiations
  14. Real-World Comparisons: When Minimal Beats Feature-Rich
  15. How LLMs Changed the Learning Curve
  16. Practical Steps to Build a Similar App
  17. Future Roadmap: When to Add Sync, Analytics, or Native Builds
  18. Lessons Learned Beyond Code
  19. Practical Examples and Micro-Interactions
  20. When Minimalism Should Yield to Complexity
  21. Final Thoughts
  22. FAQ

Key Highlights

  • A minimalist workout app, SETLO, was built to replace printed routines by combining React, Tailwind CSS, Progressive Web App deployment, and LLM-assisted development — prioritizing a frictionless in-session experience and zero-account privacy.
  • Design decisions favored simplicity: local-only storage, no social features, no analytics, and a user flow that shows "what’s next" with large touch targets and an always-on timer; Tailwind acted as an off-the-shelf design system that played well with AI-generated code.
  • The project demonstrates a practical path for makers: use LLMs to accelerate setup and learning, ship a "good enough" PWA, iterate from real use, and keep feature creep at bay while preserving options for future sync or native builds.

Introduction

A printed table would have worked. A note on the phone would have worked. Instead, a designer who wanted to learn React and to solve a simple everyday friction built a Progressive Web App called SETLO (Set Log) and deployed it to his phone home screen. The app is intentionally spare: create a routine, add exercises, tap through sets, track reps and weight, and keep the screen awake during a session — nothing more.

This is the story of why that choice made sense, and what it reveals about designing tools for real-world use. It traces the decision from an AI-generated workout plan and the irritation of feature-bloated fitness apps, through the hands-on process of engineering a minimal product, to the deliberate choice to ship a PWA with local storage and no account system. Along the way are lessons about Tailwind CSS as a ready-made design system, how large language models speed up tooling work without replacing learning, and why "good enough" delivered now often beats a perfect app delivered never.

The narrative that follows explains the motivations, the technical choices, the UX constraints unique to workouts, and practical guidance for anyone considering the same path.

From a Chatbot’s Routine to a Real Problem

The starting point was ordinary: a list of equipment and a request to an LLM for a structured routine. The model returned a tidy upper/lower split, frequency guidance, sets, reps, rest windows, and a new term: RIR — reps in reserve. That last detail underlines an important difference between having a plan and using one mid-workout. A printed plan is static; a workout in progress is dynamic. You need a simple, glanceable interface to stay in flow.

Existing apps promise comprehensive tracking and progress analytics, but many introduce friction precisely when you want to eliminate it. Login screens, onboarding funnels, endless charts, and premium paywalls interrupt the experience and shift attention away from lifting. For someone who trains at home with a few implements — dumbbells, a pull-up bar, a yoga mat — the critical requirement is being able to see the current exercise, its parameters (sets, reps, RIR), and an easy way to mark a completed set. That modest brief is what SETLO addresses.

The decision to build came from a mix of frustration and curiosity. The author wanted an app that did one thing well and, importantly, wanted the learning experience of building it himself. That practical motivation is the same impulse that drives many side projects: solve a specific problem while learning a toolchain.

Choosing Minimalism over Feature Bloat

Fitness apps occupy a spectrum. At one end are single-purpose trackers — simple timers, rep counters, or printed plans. At the other are platforms that attempt to be everything: program generators, social networks, video libraries, coaching marketplaces, nutrition logs, and analytics dashboards. Most commercial products sit somewhere in between, layering features to appeal to the broadest audience and to justify subscription revenue.

That strategy works for companies. It does not always work for single users who want low friction. Adding features increases the cognitive load and the time spent interacting with the app rather than performing the workout. For the creator of SETLO, the user problem was narrow:

  • Know which exercise comes next.
  • See sets, reps, and rest time.
  • Record completed sets quickly.
  • Avoid distractions and unnecessary taps.

This focus led to deliberate eliminations. No accounts, no social feed, no cloud syncing, no charts, no suggested routines. The absence of those features reduces development overhead and preserves the privacy of user data — everything stays on the device. It also makes the product understandable: a smaller surface area to design, implement, and test.

Real-world implication: a user who wants a simple, local tracker will likely prefer an app that does a few things reliably over one that does many things inconsistently. This trade-off guided the architecture.

The Stack: React, Tailwind, LLMs and Vercel

The chosen stack reflects both personal preference and practical trade-offs.

  • React: A mature, component-based framework that scales from prototypes to production. It offers a familiar mental model for building stateful interfaces and an extensive ecosystem. React made it straightforward to map UI components (exercise card, set tracker, routine editor) to code.
  • Tailwind CSS: A utility-first CSS framework that behaves like an off-the-shelf design system. Tailwind provides consistent spacing, color tokens, and utility classes, enabling rapid composition of UI without building a custom system from scratch.
  • LLM assistance: Large language models helped bootstrap the process — from setting up the environment to converting designs into code snippets. They reduced the friction around configuration and provided step-by-step help that made learning manageable.
  • Vercel: A deployment platform that simplifies hosting React-based PWAs. It supports automatic builds and secure hosting, enabling the developer to deploy and iterate quickly.

Each choice reduced friction in a different area. Tailwind gave immediate visual coherence. React enabled straightforward UI state management. LLMs shortened the ramp time for setup. Vercel removed deployment complexity. The result was a small, modern toolchain that is forgiving for a solo maker.

Tailwind as a Composable Design System

For someone who designs and maintains design systems professionally, using Tailwind was an unexpected relief. Tailwind's utility classes embody a design system: spacing scales, color palettes, type scales, and responsive utilities are predefined. The framework isn't an approximation of a system; it is a system.

That has three effects:

  1. Speed: Instead of defining tokens, variables, and components from scratch, you compose utilities into components.
  2. Predictability: Sizes and spacing follow a consistent scale, which simplifies layout decisions.
  3. Legibility to LLMs: Because Tailwind utilities are predictable and verbose in a consistent way, LLMs can produce correct class combinations and translate visual designs into markup more reliably.

There is a trade-off. Once you accept Tailwind’s constraints, deep customization becomes less smooth; the last 10% of visual polish often requires bespoke CSS or component wrappers. For a minimal app where clarity and function trump brand differentiation, Tailwind’s tradeoffs tend to favor the developer.

Practical note: when working with AI to generate UI, provide clear prompts that describe spacing, alignment, and component states. Tailwind's deterministic utilities help the model produce stable output that requires fewer iterations to get right.

Designing for the Workout Flow

Workouts impose unique UX constraints that differ from many other app categories. A workout session is a sustained focus task where interruptions are costly. The UI must support fast, confident interactions under sweat and breath. Decisions for SETLO reflect that reality.

Key UX principles applied:

  • What’s Next: The next exercise must be the primary focal point. Hide secondary information during the set and reveal it on demand.
  • Large Touch Targets: Buttons to mark a set as complete need to be prominent and easy to tap, even with one hand or while breathing hard.
  • Minimal Text Entry: Typing mid-workout is disruptive. Use quick selectors, prefilled fields, and the option to edit after the session.
  • Keep the Screen Awake: Devices often dim or lock; offer an always-on mode for the session.
  • Offline First: Workouts must survive airplane mode or spotty service. Local-only data storage guarantees continuity.
  • Fast Feedback: Provide immediate visual confirmation when a set is logged (e.g., a simple check or a subtle vibration).

Walking through a session clarifies these points. The screen shows the current exercise with the target reps and RIR. A large "Complete Set" button sits beneath. Tapping it increments a set counter and reveals the rest timer. When the timer runs, the next exercise preview appears in a compact card. Users can edit reps or weight between sets but are not required to do so. This keeps the main path frictionless.

Small details matter. For example, offering a "skip rest" button or the ability to edit an accidental tap prevents annoyance. On-screen toggles for "keep screen on" and "sound on/off" are small features that yield outsized benefits.

Representing Exercise Data: A Compact Schema

Designing a simple, extensible data model makes features like moving an exercise between routines, repeating an exercise, or adding metadata straightforward. Here is a compact JSON schema that captures the core entities without over-engineering:

{ "routines": [ { "id": "routine-123", "name": "Upper Body", "exercises": [ { "id": "ex-1", "name": "Dumbbell Bench Press", "sets": [ {"targetReps": 8, "weight": 40, "completedReps": null, "rir": 1}, {"targetReps": 8, "weight": 40, "completedReps": null, "rir": 1} ], "restSeconds": 90, "notes": "" } ], "order": [ "ex-1" ] } ], "meta": { "lastUsed": "2026-01-12T10:00:00Z", "appVersion": "0.1.0" } }

This schema supports multiple important behaviors:

  • Exercises can be referenced in multiple routines without duplication by using IDs.
  • Sets are explicit, allowing capture of completed reps and weight.
  • RIR (reps in reserve) is stored per set, enabling progressive overload tracking later.
  • Timestamps and app version help with migration if the data structure evolves.

Local storage is sufficient for this schema at small scale and keeps the implementation lightweight. For longer-term sync or multi-device use, the same schema can be adapted to a server-backed datastore.

RIR Explained and Why It Matters

RIR stands for Reps in Reserve. It’s a simple measure of intensity: how many reps you have left at the end of a set before reaching momentary failure. A target of RIR = 1 means you stopped one rep shy of failure. It’s a useful concept for auto-regulating effort, especially in submaximal training.

Why include RIR in a minimal app? Because it encodes training quality without forcing complicated percentage math. Recording RIR alongside completed reps and weight lets a user track effort across sessions and adjust loads intuitively. For a lightweight tracker, RIR offers more insight than raw rep counts alone while remaining easy to log.

Practical prompt for the UI: present RIR as a small selector (0–3) adjacent to the rep input. A default value (e.g., 1) reduces decision fatigue and can be changed when needed.

Deploying as a Progressive Web App

Choosing a Progressive Web App rather than a native App Store release simplified distribution and matched the product philosophy of low friction.

Benefits of PWA deployment for this use case:

  • Installable from the browser: Users can add the app to their home screen and open it fullscreen like a native app.
  • No App Store approvals or fees required to iterate and deploy quickly.
  • Works offline once assets are cached — a primary requirement for sessions in poor connectivity.
  • Single codebase for web and mobile-like behavior.

Key implementation details for a reliable PWA:

  • Service Worker: Cache the minimal app shell and route network requests (if any) through a service worker. Ensure the service worker only intercepts what’s necessary to avoid complexity.
  • Web App Manifest: Provide icons, a name, and start URL to enable the "Add to Home Screen" prompt or manual installation.
  • Local Storage or IndexedDB: Persist routines and session state offline. IndexedDB scales better for complex data but localStorage suffices for compact schemas.
  • Keep it small: Small asset size leads to faster loading and a better first-run experience. Use minified builds and optimize images.

The author deployed SETLO on Vercel and used local browser storage. This approach addressed the immediate need: the app must be available without accounts and resilient to connection interruptions.

Privacy and Trade-offs of Local-Only Storage

Local-only storage makes privacy simple: nothing leaves the device. Users who dislike granting apps permission to upload workout logs or personal data will appreciate that. It also avoids the friction of account creation.

There are trade-offs:

  • No cross-device sync. If a user trains on phone and wants to see logs on desktop later, there’s no seamless path.
  • Limited backup options. Unless the app provides an export/import function, data risk exists if the device is wiped.
  • Harder to implement social or coaching features which typically require a server.

These trade-offs are explicit product choices. For a minimal, privacy-centered tool, the benefits outweigh the costs. If demand arises for sync, the app can add an opt-in server sync later, using the same data model but encrypting data in transit and at rest.

Why Ship "Good Enough" Now

Running a full dev environment on a phone between sets defeats the entire point of a workout companion. The author reached a threshold of "good enough" where the app reliably supported sessions without significant friction. That was the cue to ship.

Shipping a minimal viable product has multiple virtues:

  • You start collecting feedback from real usage.
  • Design and architectural assumptions face reality and either hold or require revision.
  • You avoid the sunk cost of polishing features that users don't need.
  • Learning accelerates: the gap between idea and reality exposes the trade-offs of implementation.

A live PWA also acts as a conversation starter. It lets peers test the app and offer grounded feature requests instead of hypotheticals. That feedback helps prioritize subsequent work — whether to add drag-and-drop reordering, persistent timers, or a lightweight export feature.

Iteration Pressure and Architectural Negotiations

Once the basic product existed, the developer found himself generating feature ideas: multiple routines sharing exercises, drag-and-drop ordering, in-session editing, keeping the screen awake between sets. Each change created architectural decisions. Adding drag-and-drop required rethinking how exercises are identified and ordered. Allowing exercises in multiple routines necessitated a normalized data model.

This moment captures why software design escalates quickly. What seems like a small UI change often implies data migrations, edge-case handling, and new integration points. For solo makers, these are the most instructive aspects of building: the code begins to constrain future choices, and the architecture becomes a negotiation with the product’s evolving needs.

The pragmatic approach: implement features incrementally and keep migrations trivial when possible. For instance, store exercises in a flat list with references (IDs) from routines instead of embedding full exercise objects inside routines. That leaves room for shared exercises without complex data duplication.

Real-World Comparisons: When Minimal Beats Feature-Rich

Popular apps like Fitbod, Strong, and Jefit offer robust feature sets: auto-generated plans, detailed analytics, logbooks, and community features. For many lifters these are valuable. For someone who wants "which exercise is next and tap when I finish," they are overkill.

Consider a real-world analogy: a pocket notebook vs. a spreadsheet. Both can track workouts. The notebook is always available, quick, and distraction-free. The spreadsheet offers analysis and filters but demands time and attention. SETLO deliberately positions itself closer to the notebook — but with the affordances of a small, usable UI.

This positioning resonates with a specific user segment: people who value privacy, speed, and minimal cognitive overhead. For them, removing bells and whistles is not a limitation but an advantage.

How LLMs Changed the Learning Curve

Before broadly accessible LLMs, setting up a modern React environment, wiring Tailwind, configuring service workers for PWA behavior, and deploying to Vercel required more hand-holding, piecing together tutorials, and often painful trial-and-error. LLMs act as context-aware assistants: they fill in gaps, suggest commands, generate boilerplate, and explain errors in plain language.

Important caveats:

  • LLMs accelerate routine work but do not replace conceptual learning. Understanding state management, component lifecycles, and data modeling still matters.
  • Generated code often needs review. Rely on the model for scaffolding, then clean up and test.
  • Be specific in prompts. The more narrowly scoped the request (e.g., "create a Tailwind-styled React component for a workout exercise card with an accessible 'Complete' button"), the more useful the output.

Using LLMs for this project was not about shortcuts — it was about lowering friction so the author could focus on the unique product decisions rather than the boilerplate.

Practical Steps to Build a Similar App

If you want to build a minimal workout PWA inspired by SETLO, the following sequence maps a pragmatic path:

  1. Define scope tightly. Limit the first release to routines, exercises, sets, reps, weight, RIR, and a rest timer.
  2. Sketch the main session flow on paper. Prioritize large tap targets and an uncluttered "now" view.
  3. Choose the stack: React for UI, Tailwind for styles, and Vercel for deployment.
  4. Initialize the project. Use create-react-app or Vite, add Tailwind per official docs.
  5. Implement the data model in a small module with clear interfaces for CRUD and persistence. Start with localStorage for simplicity.
  6. Build the session UI first — the path a user follows during a workout. Make it keyboard- and touch-friendly.
  7. Add a manifest.json and register a basic service worker to enable PWA behaviors.
  8. Test on devices: check screen awake behavior, tap sizes, and offline resilience.
  9. Ship to Vercel and add instructions for adding to home screen.
  10. Iterate based on real usage: optimize flows that feel clumsy and postpone non-essential features.

Shortcuts: Use LLMs to generate initial components, examples of IndexedDB wrappers, or service worker snippets. Validate outputs and adapt them for your app.

Future Roadmap: When to Add Sync, Analytics, or Native Builds

The minimal approach does not preclude growth. Possible next steps, prioritized by how they change the product’s nature:

  • Export/Import: Provide CSV or JSON export to let users back up or migrate data.
  • Opt-in Sync: Offer a user-controlled sync option that encrypts data client-side and stores it in a cloud service. Make it opt-in to preserve privacy-first principles.
  • Lightweight Analytics: Local analytics for personal progress, such as "volume lifted per muscle group," that stays on-device.
  • Native Clients: If demand warrants, wrap the PWA in a native shell or build platform-native apps to access platform-specific features (better background timers, hardware integrations).
  • Community Features: Only add social or coaching if there is clear demand and a product model to support moderation and privacy.

Every addition should be evaluated against the core tenet: does this feature reduce or increase in-session friction? If it increases friction, it needs strong justification.

Lessons Learned Beyond Code

The project crystallized several broader lessons relevant to makers and product thinkers:

  • Constraints drive clarity. Limiting features forces focus on what truly matters in a flow.
  • Learning by building beats passive consumption. Writing the code turns abstract architecture into lived experience.
  • Shipping matters more than perfection. A deployed small app surfaces real constraints and user needs faster than a polished prototype that never leaves the local machine.
  • Tooling shapes design. Tailwind’s utilities nudged visual choices; the stack influenced what was easy to implement.
  • LLMs are accelerants, not autopilots. They lower friction but do not substitute for thoughtful product and architectural decisions.

This combination of practical engineering and deliberate product minimalism produced a tool that solved the author’s specific problem and provided a reusable template for others who prioritize simplicity.

Practical Examples and Micro-Interactions

Several micro-interactions stand out as high-impact for workout UX. Implementing them increases perceived polish without bloating the product:

  • One-tap set logging: A large button that increases set count and vibrates briefly for confirmation.
  • Rest timer overlay: After logging a set, a transient overlay starts a rest timer with an audible or haptic cue at the end.
  • Quick edits: Swipe left on a set to undo or edit reps/weight. This minimizes disruptions for accidental taps.
  • Session resume state: If you exit the app mid-session, reopen to find the session state restored — current exercise, completed sets, and timer.
  • Dark/light theme toggle: Training conditions vary; offer both so the UI remains readable in bright outdoor light or dim home gyms.

These small features respect the primary flow and reduce time-on-app while increasing user confidence.

When Minimalism Should Yield to Complexity

Minimalism is a default, not an absolute. Certain user needs justify evolving complexity:

  • Coaches who manage multiple clients require multi-account and sync features.
  • Data analysts who need detailed tracking want exportable logs and charts.
  • Users who switch devices frequently need secure sync.

Let real user demand guide these transitions. The product’s architecture should avoid rigid assumptions that make later changes prohibitively expensive.

Final Thoughts

Building a simple tool often teaches more than a complex one. SETLO began as a solution for a single person’s workflow annoyance and became a compact lesson in product prioritization, the affordances of modern tooling, and the practical limits of solo development. The decisions made — to use Tailwind, to ship as a PWA, to store data locally, to keep the UI focused — are not universal prescriptions. They are a coherent set of trade-offs crafted for a clear problem: reduce friction mid-workout so the user can focus on training.

For makers contemplating a similar path, the advice is plain: start with the friction you experience, design around the "now" view, keep interactions tiny and reliable, and use the available tooling to speed the unavoidable scaffolding. The payoff is immediate: an app that sits on the home screen, ready to be used, without ceremony — exactly what a focused training session needs.

FAQ

Q: Why choose a Progressive Web App instead of an App Store native app? A: PWAs provide immediate, low-friction installation from the browser, offline resilience through service workers, and a single codebase. They avoid App Store approvals and fees, enabling rapid iteration. For a privacy-focused, single-user tool, a PWA is often the fastest way to get value into users' hands.

Q: How does SETLO handle data persistence? A: It uses the browser’s local storage (or IndexedDB for more complex needs) to persist routines, exercises, and session state. This keeps all data on-device, preserving privacy and ensuring workouts continue uninterrupted in offline conditions.

Q: What are the privacy implications of local-only storage? A: Local-only storage means user data does not leave the device unless the user exports it. It minimizes data-exposure risk but also means users do not get cross-device sync or cloud backup unless such features are explicitly added later.

Q: What is RIR and why include it? A: RIR stands for Reps In Reserve, a simple measure of how many reps you could have performed beyond the set’s end. Recording RIR gives a quick proxy for intensity, enabling better auto-regulation of training without complex percentage-based prescriptions.

Q: How did Tailwind CSS help with design? A: Tailwind provides a deterministic set of utility classes and a spacing/color scale that speeds up UI composition. For a minimal app, it acts as an off-the-shelf design system, helping produce coherent visual results quickly. Its predictability also makes it easier for LLMs to generate accurate markup.

Q: How were LLMs used in development? A: LLMs assisted with environment setup, code scaffolding, and translating design intents into component layouts. They reduced the time spent on boilerplate and allowed the developer to focus on product decisions. Generated code was reviewed and adapted rather than used verbatim.

Q: What trade-offs come with a single-user, local-first approach? A: Trade-offs include no automatic cross-device sync, potential data loss if a device is wiped, and no built-in social or coaching features. These are deliberate product choices to reduce friction and preserve privacy.

Q: Can SETLO scale into a more feature-rich product? A: Yes. The underlying data model can be extended for server-side sync, analytics, or native clients. Future features should be driven by clear user demand and designed to minimize impact on the core in-session flow.

Q: What practical advice do you have for someone building their own minimal workout tracker? A: Start by defining the primary flow and focus on in-session interactions. Use React and Tailwind to prototype quickly. Persist data locally first. Ship an early PWA to test assumptions. Iterate based on real usage rather than hypothetical features.

Q: Is there value in printing a table rather than building an app? A: For many users, a printed table is perfectly adequate. The decision to build an app should be driven by whether the digital solution reduces friction in a way a static table cannot — for example, by keeping the next exercise visible, preserving session state across interruptions, and offering quick completion actions. If those benefits matter, a simple PWA can be a better fit than paper.

Q: What are common pitfalls to avoid? A: Common pitfalls include overdesigning before shipping, adding complex sync or social features too early, and ignoring real-world usage patterns that reveal necessary micro-interactions. Prioritize reliability and speed in the primary workout flow.

Q: How do you handle updates and migrations for local data? A: Keep migration logic simple: include an app version in persisted data and write small, idempotent migration functions that transform older schemas to new ones. Test migrations locally before deploying.

Q: Will SETLO ever add accounts or cloud sync? A: That depends on user demand. The author prioritized privacy and simplicity for the initial release. If users request cross-device sync or backup, an opt-in, encrypted sync feature could be implemented without compromising the minimal core experience.

Q: Can I use SETLO’s approach for other one-off tools? A: Absolutely. The formula — identify a single friction point, design an uncluttered flow, use a modern stack for rapid iteration, and ship as a PWA — applies to many micro-tools beyond fitness: habit trackers, study timers, or any single-purpose companion app.

If you want help sketching a minimal data model, writing a Tailwind-styled exercise card, or crafting LLM prompts to bootstrap the project, share your constraints and I can provide targeted examples and code snippets.

RELATED ARTICLES