Case study · 2026—ongoing
Corner Coach — the system behind the app
I built a small design system for Corner Coach, a boxing training app for iOS. It helped me move from individual screens to a consistent product that could be built and maintained in SwiftUI. 93 tokens, 30 components, and the screens they create.
01 · The design-system goal
Corner Coach is a boxing training app built around rounds, moves, and a timer that needs to work while the phone is sitting on the gym floor.
I am designing and building it alone, so every screen could easily become a new set of decisions. Without a system, small differences quickly appear: one card is slightly different from another, buttons behave inconsistently, and implementation becomes a process of guessing.
The goal was not to create a large design library. It was to build a focused system that one person could finish and keep consistent.
It needed to be:
- iOS-first and dark-only
- based on semantic tokens rather than raw values
- explicit about interaction states
- small enough to support the MVP
- useful in both Figma and SwiftUI
Today, the system includes 93 public tokens, 24 private primitives, 30 components, 76 icons, and the foundations for a library of 409 boxing moves.
02 · Principles
The principles live in the Figma file itself. They are written for anyone who works with the system next: me, a developer, an AI coding agent, or another designer.
Build in layers
Private primitives define the raw values. Semantic tokens give those values meaning. Components apply them consistently. Screens are built from those components instead of being redrawn from scratch.
Shared values do not always share meaning
Several tokens currently use the same amber value, including action/primary, action/selected, focus-ring, and chart/bar.
They are still separate tokens because they describe different jobs. A primary button is an action. A selected card is a choice. A focus ring shows attention. A chart bar represents data.
If the value changes later, those roles may need to change independently.
Tokens that share a value are not interchangeable.
Design for iOS
The system defines pressed and selected states because they are real product states on a phone. Hover is not included because it is not part of the product experience.
Elevation belongs to surfaces such as cards, sheets, and overlays. Controls do not get shadows just to make them look more important.
Keep the product honest
- Content should reflow across type sizes and screen widths.
- Labels and structure should support colour, never replace them.
- Touch targets and safe areas should be preserved.
- Reduce Motion should have a calmer alternative.
- Workout states such as work, rest, warm-up, paused, and complete should be explicit.
03 · Tokens
Every token is authored in Figma and exported into the project. Nothing is manually copied from one tool to another.
The system includes:
- 43 semantic colours for surfaces, text, icons, borders, actions, feedback, phases, and charts
- 24 dimensions covering spacing, radii, and layout values
- 15 text styles across Archivo, Sora, and Barlow Condensed
- Motion and elevation tokens for timing, easing, shadows, and gradients
Spacing with meaning
The spacing scale is semantic rather than arbitrary.
space/5 is used for stacked content. space/6 is used for screen gutters and spacing between cards. space/7 is used inside larger cards.
Choosing a spacing token means choosing a relationship between elements, not just selecting a number.
Three typefaces, three jobs
Archivo handles titles and display text. Sora is used for body copy and labels. Barlow Condensed is reserved for timers, counters, and large numeric values.
A timer and an instruction do not have the same job, so they do not need to use the same typeface.
Tokens for boxing
The system also includes tokens specific to the workout experience.
Warm-up, work, and rest each have their own accent and tint. The same tokens are used across badges, counters, and live workout screens so the current phase is communicated consistently.
surface/card and text/secondary, rather than naming raw colour values.04 · Components
The system includes 30 components, with 29 currently implemented.
Each component has a description in Figma that explains what it is for and when to use something else. This makes the library easier to use for both people and code.
This matters because a coding agent can know every colour in the system and still create a new button from scratch. The goal is to make the available components just as clear as the available tokens.
Core components
- Button
CornerButtonStyle— six tones, three sizes, icon forms, and icon-only forms.- Card
- A family of navigation, selectable, setup, and composite cards.
- Chip
CornerChip— selectable controls for filters, periods, and multi-select options.- Segmented control
CornerSegmentedControl— for two or three visible choices.- Bar chart
CornerBarChart— for showing one value per period.
Buttons
Buttons are where many system decisions come together.
The system defines primary, secondary, ghost, danger, alternative, and dotted buttons. Each tone has default, pressed, disabled, loading, and focused states.
Some rules are specific to the product:
- The alternative button uses the work-phase accent because it starts or resumes an active round.
- The dotted button represents an empty or available slot, not a secondary action.
- Icon-only buttons are sized separately because their padding and shape change.
- Buttons do not use shadows. Elevation belongs to surfaces.
A component is not finished when it is drawn. It is finished when its states are decided.
Cards
The original Card component evolved into four behavioral families:
- Navigation — opens another screen
- Selectable — represents a choice
- Setup — controls a value such as rounds or timer settings
- Composite — contains content and nested actions
The same foundation is shared across the families, but each one has only the states it actually needs.
This prevents the system from creating meaningless combinations, such as an expanded navigation card or a selected link card.
05 · Real screens
These are not mockups. They are screenshots from Corner Coach running on an iPhone simulator.
Home, the workout library, and training progress have different jobs, but they are built from the same system.
Home
The Home screen uses cards, badges, and a primary button to help the user start a workout quickly.
Coach-built workouts
The workout library combines search, dropdowns, chips, and navigation cards to help users find a session.
Progress
The Progress screen uses chips, a bar chart, stats cards, and supporting cards to show training history.
Each screen is an arrangement of existing parts, not a collection of new visual decisions.
One component, different jobs
The same chip component is used in several contexts:
- A single-select period control on Progress
- A multi-select filter in the workout library
- An equipment selector on the Profile screen
The component stays consistent while the screen defines the specific behavior.
Content can change underneath a component
A card can contain different content without needing a separate variant for every situation.
For example, the same card structure can support both a populated state and an empty state. The body changes, but the surrounding system remains familiar.
06 · From Figma to a working iOS product
The system is not only documented in Figma. It compiles into the app.
The workflow is:
- Figma variables, styles, components, and descriptions
- An export plugin that produces token data
- A Swift compiler that creates tokens, assets, and component mappings
- SwiftUI screens built from named components
- Automated checks that catch inconsistencies
The checks look for problems such as raw colours, magic numbers, incorrect fonts, and unsupported effects.
The Swift types also make invalid combinations harder to create. A missing font is checked separately because valid code can still render with the wrong typeface.
The toolchain is intentionally small: Swift, Foundation, SwiftUI, and a Figma plugin. A solo project needs a system that is useful without becoming another product to maintain.
How the checks work, and what they do and do not claim, is its own piece of work: a design system that compiles.
The system is not proof that AI wrote good code. It is a way to stop incorrect code from quietly passing as finished.
The one-person training experience runs on device today, including onboarding, workout creation, live sessions, progress, sharing, audio, and haptics. The coach-to-athlete experience is specified but not yet built.
07 · Results and reflection
The system was built for one product, so its value is easiest to see in the product itself.
- Screens are assembled from known parts instead of redrawn.
- New design decisions are easier to review.
- Interaction states are defined once and reused.
- Design and code share the same vocabulary.
- The MVP has a stable foundation for future work.
What the system still owes
The system is not finished, and that is documented too.
The remaining work includes:
- Replacing a few incorrect or overly broad token assignments
- Adding a disabled state to the segmented control
- Aligning a few components with the published size scale
- Improving the SwiftUI handling of inner shadows
- Moving Dynamic Type and VoiceOver from documented principles to verified behaviour
- Expanding documentation so another designer could use the system without asking for help
The system was intentionally designed for the needs of the MVP. Its next stage will focus on accessibility validation, more flexible content, and documentation for future collaborators.
The product tests whether the system is useful. The system tests whether the product was truly decided.