Design Brief β 2026-08-04
Frozen snapshot β do not update. Kept for how a decision was reached, not for what is true now. Current state lives in Architecture β Current State.
Date: 2026-08-04
Scope: content and structure brief for three surfaces β acesense-landing (marketing web), acesense-frontend (Flutter athlete app), acesense-admin (internal console).
This brief specifies what each screen must contain, which states it must cover, and what the user must be able to do. It deliberately does not prescribe colour, type, spacing, motion, or component styling β those are the designer's call. Existing tokens live in acesense-brand (design-system) and acesense-frontend/lib/ds/tokens.
0. Shared ground rulesβ
Product in one line. Record a tennis session on a phone β AceSense returns a post-match report: shots detected and classified, stroke quality, ball/player tracking, court heatmap, clips per shot, and coaching insight.
The three hard constraints every screen inherits:
- Analysis is asynchronous and slow. A 5-minute video takes minutes, not seconds, and runs on a GPU fleet that can be at capacity. Every surface that references a session must design the waiting and failed states as first-class, not as afterthoughts. Queued β processing β done β failed is the spine of the product.
- Never fabricate a number or an identity. Where the pipeline reports low confidence (unclassified stroke, uncertain player attribution), the design must have a way to show "we don't know" rather than a confident-looking value. Two real states already exist in the app: Stroke type not classified and Low classification confidence.
- Media is heavy. Video, clips, heatmaps and PDFs are the payload. Every list and detail screen needs a defined poster/placeholder, a loading skeleton, and a behaviour for "media not ready yet".
States to specify for every screen (deliverable is incomplete without them): first-run / empty, loading, populated, partial (some data missing), error, offline. For the app, additionally: dark and light, small-phone and tablet, and a text-scaled variant β the app is localised (lib/l10n/arb), so no fixed-width text containers.
Deliverable format per surface: screen inventory β per-screen frames covering the states above β interaction notes for anything non-obvious β a component list rolled back into the design system.
1. Landing β acesense.ioβ
React + Vite SPA, prerendered. This is an SEO surface as much as a conversion surface: it carries ~40 markdown-backed content pages across five hubs. The design must make a long content library feel like one product site, not a blog bolted onto a landing page.
1.1 Home /β
Sections in order, all currently present:
| Section | Must contain |
|---|---|
| Hero | One headline, one sub-line, exactly one primary action (get the app). Platform availability must be honest β Android is beta; label state comes from content, not hardcoded copy. |
| Partners / social proof | A row that degrades gracefully when there are few logos. Design for 3 and for 8. |
| Features β "everything in the post-match report" | The report's actual contents: shot detection, ball tracking, stroke quality, court heatmap, coaching report. Each needs a visual that shows the real output, not an abstract icon. |
| How it works β 3 steps | Record β upload β report. Must set the expectation that analysis takes minutes. |
| Closing CTA | Repeat of the single hero action. |
| Floating CTA | Persistent, appears on scroll, must not cover content on small screens or collide with the cookie-consent banner. |
| Cookie consent | Analytics is opt-in. Needs a state where the user has declined and the banner is gone permanently. |
1.2 Get the app /getβ
Single job: route the visitor to the right store. Must show both platforms, mark Android's beta status, and handle the case where the visitor is on desktop (needs a QR or send-to-phone affordance).
1.3 Hub pages /compare /alternatives /use-cases /features /how-toβ
Five index pages sharing one layout. Each lists its child pages. Design once, parameterised by hub. Needs: hub title + one-line framing, a card/row per entry that carries enough for a click decision, and behaviour at 3 entries and at 30.
1.4 Content page /<hub>/:slug and static pagesβ
One markdown-body template serving comparisons, alternatives, use-cases, features, how-tos, and ~15 standalone pages (/how-it-works, /camera-guide, /accuracy, /pricing, /faq, /changelog, /android, /ios, /examples, /sample-report, /about, /founder, /biomechanics, /sweden, /agents).
Required from the markdown body style: h2/h3 hierarchy, tables (comparison pages lean on them heavily), lists, blockquote, inline links, images with captions, and code-free content. Long pages need in-page navigation. Each page needs a tail CTA back to the app.
Two of these carry extra structure and need their own treatment:
/pricingβ a tiers block renders above the markdown. Tier cards must handle a free tier, a paid tier, and a "contact" tier, and must not imply live billing where it does not exist./sample-reportand/examplesβ these are the proof pages. They should show a real report, and are the strongest argument on the site. Treat as a designed page, not a markdown dump.
1.5 Blog /blog, /blog/:slugβ
~30 posts, mixed editorial and comparison. Index needs filtering or grouping that survives growth. Post page needs author/date, reading structure, and a related-posts tail that pulls from the hubs.
1.6 404β
Real not-found page with routes back to home, hubs, and the app.
2. App β acesense-frontend (Flutter, iOS + Android)β
Bottom-tab shell with four tabs (Home, Sessions, Practice, Profile) plus a stack of detail routes pushed over it. Design system components already exist (ds_*: app shell, bottom tab bar, top bar, sidebar, card, stat card, button, chip, badge, text field, sheet, insight banner, section label, count-up, skeleton bar) β the brief is to design screens against that vocabulary and extend it only where a screen genuinely needs something new.
2.1 Auth & onboarding β /splash, /sign-in, /sign-up, /forgot-password, /onboardingβ
- Splash β brand moment, resolves to signed-in or signed-out. Must tolerate a slow auth check.
- Sign in / Sign up β email + password plus whichever social providers ship. Needs inline validation, a visible error region, and a disabled/in-flight submit state.
- Forgot password β request state and "check your email" confirmation state.
- Onboarding β collects the profile that personalises the report: handedness, playing style/level, goals. Must be skippable, resumable, and must state why each answer is asked. Also the correct home for the AI consent gate β consent is durable and gated, so it needs an explicit, readable screen, not a checkbox buried in a form.
2.2 Home /β
The daily surface. Contains, in priority order:
- Greeting + streak β time-of-day greeting, returning-user vs first-run variants, streak state.
- Skill Score β the headline number, with an explicit empty state: "Analyze a session to unlock your Skill Score." Needs a delta/trend treatment and an improvement ring.
- Latest analysis β the most recent session with its status. If it is queued or processing, this card is the progress indicator. If it failed, this card carries the retry.
- Today's insight β one coaching statement with a "start the fix" action leading into practice.
- Upload prompt β the path to a new session, always reachable.
- Past insights β a scannable history.
First-run home (no sessions, no score, no streak) must be designed as its own frame β it is the screen most new users see and currently has the least to show.
2.3 Sessions /sessions and session detail /sessions/:idβ
List β one row per session showing date, duration, thumbnail, and status. Statuses to design: queued ("Queued in lineβ¦"), processing, done, failed ("Analysis failed" + retry). Row actions: open, download PDF report, delete (with confirm). A sample session ships with the account and must be visually distinguishable from real ones and must survive deletion of real sessions. Also carries a progress strip (e.g. peak-speed progress) across sessions.
Detail β the match analysis screen. The most important screen in the product. Structure:
- Video player with overlay layer (ball track, player boxes, court mapping) and a toggle for overlays. Needs a mini-player that persists while the user browses tabs, and a fullscreen mode.
- Player roster β attribution of tracks to players, including the case where the model is unsure.
- Court minimap β spatial position synced to playback.
- Three tabs:
- Stats β session totals and per-stroke breakdown. Every metric needs a defined unit, an unknown state, and a plain-language explanation available on tap.
- Shots β the shot list with stroke type, speed band (slow/medium/fast), and per-shot clip. Must render Stroke type not classified and Low classification confidence without looking broken. Tapping a shot opens shot detail with its footage.
- Heatmap β court coverage. Needs a legend and an empty state for sessions too short to produce one.
Non-done detail states matter as much as the done state: a session opened while still processing needs a real screen (what's happening, roughly how long, what to do), and a failed session needs a cause-and-recovery screen.
2.4 New session /new and camera guide /camera-guideβ
- New session β pick or record a video, then upload. Upload is the single largest source of user-visible failure (client uploads that never complete), so this flow needs: explicit progress with bytes/percent, a resumable or retryable failure state, a background-upload indication, and a warning for very large files or poor connectivity. Do not design a flow that assumes upload succeeds.
- Camera guide β how to position the phone (height, angle, distance, framing). Illustrated, correct-vs-incorrect. This screen directly determines analysis quality, so it deserves the same care as the report. Must be reachable from both the new-session flow and help.
2.5 Practice /practice, drill detail /practice/:idβ
Drills recommended off the analysis. List needs grouping and a "recommended for you" distinction from the general library. Drill detail needs: objective, why it was recommended (tied back to a specific weakness), steps, duration, and a completion action that feeds the streak.
2.6 Profile /profileβ
- Player card β shareable artefact: name, level (Club / Player / etc.), handedness, style (Baseline / All-Court / net-forward), skill score, fastest shot, top shot, sessions count, streak. Because it is shared outward, design the export frame explicitly, not just the in-app view.
- Weekly recap β a short state-of-the-week block with variants for an active week, a returning week ("Back on the court this week"), and a fresh/empty week.
- Entry points to settings, notifications, billing, help, legal, roadmap, badges, wrapped, coaching.
2.7 Progression β /roadmap, /badges, /wrappedβ
- Roadmap β tier ladder Rookie β Club β Competitor β Elite, showing current position, what closes the gap to the next tier, and locked-tier treatment.
- Badges β earned vs locked, with the criterion visible on locked ones.
- Wrapped β "Your Week, Wrapped": skill score this week, sessions, fastest shot, longest rally, top moments, and a share artefact. This is a story-format, outward-facing screen; design the shared image as a deliverable in its own right, and design the not-enough-data variant.
2.8 Coaching β /coaching, /coach (roster), /coach/student/:idβ
Two audiences on the same surface:
- Athlete-facing coaching β check-in, a recommended drill, a "why it matters" rationale, and actions (start / upload / direct message).
- Coach mode β roster of students with each student's latest session status and trend; student detail with their sessions and progression. Design for a coach with 2 students and with 40.
2.9 Support & account β /settings, /notifications, /help, /how-it-works, /billing, /privacy, /termsβ
- Settings β account, units, language, notification preferences, AI consent (revocable), data export/deletion.
- Notifications β list of events, primarily analysis ready, with read/unread and a deep link into the session.
- Help and How it works β content screens; how-it-works should set realistic expectations about processing time and accuracy.
- Billing β currently no live consumer billing (RevenueCat removed; Stripe is test-mode gated). Design the tier/entitlement display and an upgrade path, but do not design a checkout flow as if it ships now β flag it as future state.
- Legal β privacy policy and terms, long-form scrollable.
2.10 App-wideβ
Needed as designed states, not left to defaults: offline banner, force-update screen (features/update), generic error screen with retry, permission-denied (camera/photos), and the loading skeletons for every list.
3. Admin β acesense-admin (internal console)β
Desktop-first, sidebar + command palette (βK). Audience is one to three operators. Optimise for density, scanning, and fast recovery actions β not for onboarding. Every screen here exists to answer "is the system healthy" or "what happened to this user's job".
Sidebar order (existing): Dashboard, Users, Jobs, Operations, Analytics, Campaigns, Storage, Audit Log, Developer, API Keys, Research Decisions, Settings.
| Screen | Route | Must contain |
|---|---|---|
| Login | /login | Admin-only auth, clear rejection state for non-admin accounts. |
| Dashboard | / | The single-glance health view: jobs in each state right now, failures in the last 24h/7d, live GPU workers vs queue depth, user count, and anything currently red. Every tile links to the screen that explains it. |
| Users | /users | Searchable table: id, email, signup date, session count, tier and how it was granted (tiers are manual grants), consent state. Row detail with that user's sessions and jobs. Actions are consequential β grant, revoke, delete β so each needs confirmation and lands in the audit log. |
| Jobs | /jobs | The operational core. Filter by state (queued / processing / done / failed) and date. Per job: user, video, size/duration, provider and region it ran on, per-stage timings, wall_total, and on failure failedPhase, errorType, errorMessage, wallSeconds. Requeue is the primary recovery action. Design the timing breakdown as a real visual β the pipeline now publishes per-stage numbers specifically so this screen can answer "is shot detection getting slower". |
| Operations | /operations | Fleet control: live workers, scaler configuration (maxAutoInstances, maxLaunchesPerTick, maxQueueDepth), the region rung ladder and which regions are seeded, and provider health including a fallback provider that can be out of credit. Needs an unmistakable treatment for "a provider is down" and for "capacity is exhausted". |
| Analytics | /analytics | Product metrics: signups, uploads, completion rate, retention, funnel. Charts must have defined empty and sparse states. |
| Campaigns | /campaigns | Outbound/beta campaign tracking, download attribution. (/downloads redirects here.) |
| Storage | /storage | Bucket usage by prefix, largest objects, retention/cleanup actions with confirmation. |
| Audit Log | /audit-log | Append-only record of admin actions: actor, action, target, timestamp, result. Filterable, never editable. |
| Developer | /developer | Deploy/build parity β what is live vs what is on HEAD per repo, function health, feature flags. |
| API Keys | /admin-api-keys | Key list with created/last-used/status. Reveal-once on creation, revoke action. Never re-display a secret. Design the rotation path β key leakage has been a real incident here. |
| Research Decisions | /research-decisions, /research-decisions/:id | Decision log index and detail: question, options considered, decision, rationale, date. Long-form reading layout. |
| Settings | /settings | Console preferences and admin roster. |
| Command palette | βK | Navigation to every screen plus quick actions (refresh data, view all jobs, add user). Needs designed empty-query, results, and no-match states. |
Admin-wide: every table needs sort, filter, pagination-or-virtualisation, an empty state, a loading state, a stale-data indicator with manual refresh, and a defined behaviour at 10 rows and 10,000. Every destructive action needs a confirm that names what is being destroyed.
4. What the designer should hand backβ
- Screen inventory matching the routes above, with anything judged unnecessary explicitly called out rather than silently dropped.
- Frames per screen covering empty / loading / populated / partial / error, plus dark+light and text-scaled for the app.
- The four proof surfaces designed to a higher finish, because they carry the product: landing
/sample-report, app match-analysis detail, app Wrapped share artefact, app player card share artefact. - Component inventory folded back into
acesense-brand, flagging every new component the screens required. - Open questions list β anything in this brief where the content requirement is ambiguous, so it gets resolved before build rather than during it.