Loading…
Studio19

Corporate Identity

S19Labs design system

The visual language of the Studio19 players app, documented as the corporate identity. Ported verbatim from lib/theme/tokens.dart — itself a port of the iPad app's DesignSystem/Theme.swift.

Dark-first · near-black neutral base One accent, used sparingly

The mark

Studio19 app icon
App icon

The Studio19 script wordmark, white, on the neutral base with a turquoise bloom behind it. Shipped on iOS and Android; also this site's favicon.

Squircle radius scales with the mark — l (20px) around 72–82px, s (6px) at favicon sizes. Never outline it, never recolour it, never set it on a mid-tone.

Studio19
Wordmark

The same script as pure vector — studio19-logo.svg, white paths, no background. Use this wherever the mark must sit on an existing surface or scale past icon sizes.

White only. On light surfaces the fill must be overridden to the base colour, never tinted with the accent.

Naming, unresolved. The mark reads Studio19 — the product — while this site and the top bar say S19Labs — the company. They are currently used side by side. Worth deciding whether the public site leads with the company or the product before this hardens into two competing identities.

Colour

Four families. Surfaces layer; ink is white at declining opacity; the accent is brand-only; semantic colours mean something and are never decorative.

Surfaces

bg
#0a0a0b
Page base
surface
#161618
Cards
surfaceElev
#202023
Raised / inputs
surfaceElev2
#2a2a2e
Highest layer
base
#0a0a0c
Liquid-glass base — carries no colour
bloom
#22c8d2
Ambient light only, never a fill

Ink

ink
#ffffff
Primary
textPrimary
#f2f2f7
Body copy
ink2
EBEBF5 · 60%
Secondary
ink3
EBEBF5 · 30%
Tertiary / hints
ink4
EBEBF5 · 18%
Disabled

Brand accent

accent
#00da9b
Brand + ONE primary action per view
accentPressed
#00b886
Pressed state
accentSoft
accent · 16%
Tonal fill
accentGlow
accent · 36%
Blur/shadow ONLY — never a fill
featureGold
#ffc23d
Feature requests
The one rule that matters. The accent #00DA9B is brand identity, not "good". The semantic positive green is #30D158 — a different colour. Using the accent to mean "this value is healthy" is the single most common way this system gets broken.

Semantic

positive
#30d158
Good data
caution
#ff9f0a
Warning
negative
#ff453a
Error / duff
info
#0a84ff
Informational
premium
#bf5af2
Premium

Rating ramp

Monotonic green→red for 0–100 shot ratings. In the app this collapses to a three-band traffic light: green ≥ 70, amber 30–69, red < 30.

excellent
#30d158
good
#8ad13f
acceptable
#ffd60a
poor
#ff9f0a
bad
#ff453a

Typography

System sans throughout. Tight negative tracking on display sizes, neutral below. Every row below is set in the style it names.

displayStudio1956 / 700 / 1.04 / −2%
h1Session review40 / 700 / 1.08 / −2%
h2Your progress28 / 600 / 1.18 / −2%
h3Driver · carry20 / 600 / 1.28
h4Shot 14 of 4016 / 600 / 1.32
bodyYour coach marked this swing for review.15 / 400 / 1.55
bodySSecondary copy sits on ink2.13 / 400 / 1.5 · ink2
captionRecorded 12 Jun · 240fps11 / 500 / 1.4 · ink2
sectionSection opener11 / 500 / +0.14em / caps
monocarry 214.6y · 1.48 smashNumeric / IDs only

Space & radius

Spacing scale

xs·4
s·8
m·16
l·24
xl·40
xxl·64

Corner radius

xs·4
s·6
m·12
l·20
xl·28
pill

Motion

Three curves, three durations. Hover a track to run it.

easeOut
.16, 1, .3, 1 — entrances
easeInOut
.65, 0, .35, 1 — moves
easeCinema
.22, 1, .36, 1 — video / hero
fast180ms
medium320ms
slow640ms

Usage

One accent action per view. If two things are turquoise, neither reads as primary.
Layer surfaces upward — bg → surface → elev → elev2. Depth comes from layering, not from borders.
Hairlines at 8% white. Visible structure, invisible lines.
Mono for numbers and identifiers only — carry, smash, ticket ids.
Never use the brand accent for "good". That's positive #30D158.
Never fill with accentGlow — it is a shadow colour.
Never tint the base surface turquoise. All warmth is light from the bloom; the surface stays neutral.
No pure-white body text at small sizes — textPrimary #F2F2F7 and below.
Known drift. Mission Control's own chrome predates this system and uses #06D6A0 as its accent, not the brand #00DA9B. The two are close enough to look like a rendering difference and far enough apart to be wrong. Unifying it means restyling the dashboard, so it is recorded here rather than silently patched.

The P4 Problem · an S19Labs challenge

Measure the swing where the camera goes blind.

A golf swing hides its own mechanics. Build something that measures them anyway — on one phone, in one swing, with no markers and no setup ritual. Any method you like.

Reading the terms first? The rules, IP and data agreement are public — no account needed.

Mean occlusion across the swing · down-the-line camera

Occlusion values are illustrative and hand-authored, not measured. Once the reference capture set exists this widget will be driven by measured occlusion labels from the rig, and this caption replaced.

Format
8-week remote challenge · teams of 1–4
Divisions
Video only · open sensor
Prize pool
TBC
Submissions close
TBC

The problem

One camera encodes the axis that matters worst.

Rotation about the vertical axis is what coaches actually measure — how far the pelvis and thorax have turned, and the difference between them.

Filmed down the line, that rotation lives on the depth axis. Depth is precisely what a single camera encodes worst.

And at P4, the top of the backswing, the trail arm sits behind the torso on the same frame where rotation peaks. The measurement you most need is taken where the body hides itself.

Any method

Pose estimation is not required.

Keypoints are one route, not the route. Body-model fitting, direct video-to-measurement regression, club tracking, wearable IMUs, audio for impact timing — all valid. You are scored on the numbers you output, not on how you got them.

Two divisions

Division A

Video only

  • One phone cameraNo additional sensors.
  • On-device inferenceRuns inside the performance envelope.
  • Hardest constraintDepth from a single view.
Division B

Open sensor

  • Add what you likeIMUs, wearables, audio, depth.
  • Same output contractScored on the same measures.
  • Declare your rigHardware listed in the report.

Timeline

Registration closes
TBC
Kickoff & dataset drop
TBC
Submissions close
TBC
Demo day
TBC

What you keep

Your work stays yours.

  • Apache-2.0Submissions are licensed Apache-2.0.
  • You keep copyrightEntrants retain copyright in their own code.
  • A prize, not a purchasePrize money is a prize. It does not buy your IP.

Register your team.

Registration captures your team members, university affiliation, the division you're entering, and acceptance of the data agreement. Signing up unlocks Hackathon MC — the briefing, output contract, dataset, rubric and submission flow.

Video only is one phone camera and no other sensors. Open sensor lets you add IMUs, wearables, audio or depth. Same output contract either way.

8+ characters Uppercase Lowercase Number

Minimum entrant age is TBC and will be stated in the rules before registration opens.

The rules, IP position and data agreement are readable without an account.

Rules, IP & data

Public rules page

Eligibility, the IP and licensing position, the dependency allow/block list, the data agreement and POPIA summary, submission requirements and the judging process. Deliberately ungated — nobody should have to register to read terms they are being asked to accept, and supervisors need to see them first.

Awaiting source content. The allow/block list, FAQ answers and full IP wording live in the p4-problem.html prototype, which I don't have yet. Rather than paraphrase legal and licensing terms, this page waits for it.
live · prod

Overview

The pulse of the S19Labs player app — pulled live from the backend.

Users
loading…
Open bugs
loading…
Needs retest
resolved · verify
Production
checking…
studio19-coaching-api
Staging
checking…
…-api-staging
Recent reports from the app
loading…

Missions

The build backlog — split by who owns it. Open a card for the plan; Edit to change it. Arm ⚔ to queue it for a war.

loading…

Ready for WAR

The armed queue, grouped by person. Toggle ⚔ on mission cards to arm them; each person's Declare war locks their set into a WAR-n order for Claude.

Shared headless key (studio19-public-dashboard-api-key, Secret Manager · s19labs) is not created yet — so for now, Declare war → Copy war order bundles a fresh ~1h admin token into the prompt; paste it into your own Claude session to run the war. No key needed.
loading…
War room

Team Performance

Who's carrying what — live from the missions board, with a git-activity snapshot.

loading…

Ideas

The idea inbox, by person. Capture loosely, then promote the good ones into missions.

loading…

Planning

Market landscape, competitors, and opportunities. Edited in epsza.S19Labs.websitepublic/data/planning.json.

loading…
loading…

Players App

Redesign roadmap — click a status chip to cycle To do → Doing → Done. Updates live for everyone.

loading…
loading…

Play Store

Google Play publishing checklist — click a status chip to cycle, assign an owner, add deliverables.

loading…
loading…

App Store

Apple App Store publishing checklist — click a status chip to cycle, assign an owner, add deliverables.

loading…
loading…

Environments

Watch prod and staging — health checked live.

Production
checking…
Servicestudio19-coaching-api
Regionafrica-south1
AuthFirebase · s19labs
Health
Staging
checking…
Service…-api-staging
Regionafrica-south1
AuthFirebase · s19labs (shared)
Health

Deploy

Publish this dashboard to Firebase Hosting.

Deploy this dashboard
Publish epsza.S19Labs.website to s19labs.web.app
Runs the deploy-hosting GitHub Action (manual trigger — no secrets in the browser). Or locally, from the website repo root: firebase deploy --only hosting.
Deploy…
Build distribution
Sideload builds are no longer served from this dashboard. Ship releases through the store pipelines, and see PROD-PUSH-CHECKLIST.md in the players repo for the push runbook.

Users & coaches

Everyone in the player app, pulled live. Tap a person to suspend or remove them.

loading…

Bug board

Live from the in-app ladybug. Drag a card or open it to move it through the loop — fire it off, then verify the fix.

Open
In progress
Needs retest
Closed
Total

Security

Access, posture, and the audit trail of admin actions.

Posture
Admin access
Grant via node scripts/set-admin.js <email>
Session

Settings

Console configuration.

Projects19labs · africa-south1
Mission Control hosts19labs.web.app
Prod API
Staging API
Connected reposplayers · service
Mission Control boardmissions · wars · to-dos (backend: .NET /api)
Skill API keystudio19-public-dashboard-api-key — not created yet
The board's own reads/writes use the signed-in admin's Firebase token. The studio19-public-dashboard-api-key secret is only needed for headless callers — the /mission skill and Claude running a war. Until it exists, use the interim token below: paste it into a Claude session so it can hit the API (Authorization: Bearer) without the shared key. (War orders embed one automatically on copy.)
A short-lived credential — for local Claude sessions only.