huddlie App kit. Styling and branding for every screen, ready for developers to wire up. Brand v1 applied; fonts and icons still provisional.

Every screen in huddlie

86 screens and states, built from the connected prototype in ../app/. Tap a phone to open it full size. Every screen is plain HTML on one shared token file, so a rebrand is a token change, not a redesign. Notes under each screen carry the behaviour the prototype encoded, for whoever wires it up.

Welcome and account

First launch, sign up, sign in, and the get-set-up home a new parent lands on before any player exists. No tab bar yet: the tabs arrive with the first player.

Launch screen

Added for launchsplash.html
  • The mark over the logotype (brand/huddlie-mark.svg + Fraunces 600 in brand plum). In the app this frame plays the brand reveal: ../brand/huddlie-reveal.json (Lottie), then holds on this lockup.
  • Native splash is static (iOS LaunchScreen / Android 12 SplashScreen API): paper background + app icon. This screen is the first frame after it.

Welcome

prototype: welcomewelcome.html
  • Lockup, promise line and two actions. The benefits moved to the four-page intro that plays before this screen (prototype), so the placeholder list is gone.
  • Promise line is the working tagline from the brand vision, always lowercase.

Create account

prototype: signupsignup.html
  • Sign-up and sign-in both land on the get-set-up home, unless a gated flow (team search while signed out) asked to be resumed.

Create account, field error

Added for launchsignup-error.html
  • Error pattern for every form: red ring on the field, the fix in plain words under it. Errors say what to do, never apologise.
  • Error copy here is provisional (the prototype has no validation states).

Sign in

prototype: signinsignin.html
  • "Forgot your password?" is added for launch; the reset flow itself is platform auth (email link).

Get set up (home before a player)

prototype: getsetgetset.html
  • Opens with the dark brand bar (colour logo). The tip is said by the mark.
  • One dominant action (add your player) and a quiet find-a-team link. Find a team is gated: signed out, it routes to sign-in first.
  • Roadmap caption "3 quick steps" is the list's accessible name, not a visible eyebrow.

Get set up, with a pending invite

prototype: getsetgetset-invite.html
  • The invite card shows only when a real invite exists.

Invitation to follow

prototype: acceptinviteacceptinvite.html
  • The follower's landing from a copied invite link. No account is needed to be invited.
  • Accepting is the contextual moment to ask for notification permission (next screen), never first launch.

Notification permission (system alert)

prototype: permissionpromptpermissionprompt.html
  • This is the system alert, drawn by the OS, not styled by us. iOS allows no custom text on it.
  • The prototype's reason line ("Schedule changes and new moments for the players you follow") belongs on the Accept screen above it, if the team wants to explain before asking.
  • Asked right after accepting an invite, never on first launch.

Onboarding: name, team, schedule

The child-first path: name the player, find their team, consent to the schedule fetch, and land in the app. Three steps, shown by the step dots only on this forward path.

Step 1: name your player

prototype: addplayeraddplayer.html
  • First name only. The round photo is optional: without one, the player shows as their initial everywhere.
  • Tapping the circle or "Add a photo" opens Add a photo (next screens).
  • Empty name: toast "Add a name / Your player needs a name to start."
  • If a team follow or a founded team was waiting on a player, finishing this step completes it and lands in the app instead of going to step 2.

Add a photo: choose where from

Added for launchaddphoto.html
  • The same sheet serves every photo slot: add player, edit player, the player profile.
  • "Choose an avatar" opens the drawn-avatar picker (next screen). A chosen avatar is stored like a photo and shows everywhere the player appears.
  • With a photo already set, a third option "Remove photo" (danger colour) appears, which falls back to the initial.
  • Camera and photo library permissions are asked here, at the moment of use, never on launch.

Add a photo: fit it in the circle

Added for launchaddphoto-crop.html
  • Pinch to scale, drag to move. Only the circle is kept, so the saved image is square and shown round everywhere.
  • Save at least 512 x 512 so it stays sharp on the profile; the lens avatar uses the same file.

Add a photo: choose an avatar

Added for launchaddphoto-avatar.html
  • The six drawn player avatars (../brand/avatars/*.svg). Tapping one uses it right away and closes both sheets, back to the form; the current one carries the magenta ring.
  • Offered as an alternative to a photo, for families who would rather not upload their child's face. The avatar can be swapped for a photo at any time from the same sheet.

Step 1: name and avatar chosen

prototype: addplayeraddplayer-avatar.html

Step 1: name and photo added

prototype: addplayeraddplayer-photo.html

Step 2: find their team

prototype: teamsearchteamsearch.html
  • "Add another player" (small, secondary) appears on the page right after a player is added. It opens a fresh add-player form; the player just added keeps their place, and each new player can find their own team afterwards.
  • Skip for now is shown only in onboarding. It lands in the app with a teamless player.
  • Matching: each typed word matches the START of a word in the team name, never the division (so "a" does not match "U11 A").

Step 2: search results

prototype: teamsearchteamsearch-results.html
  • Team crest is a letter avatar until leagues supply logos.

Step 2: no match, start your own

prototype: teamsearchteamsearch-nomatch.html

Step 3: get their schedule (consent)

prototype: teamfollowteamfollow.html
  • Reached from search outside onboarding, the same screen is titled with the division ("U11 A") and the button reads "Follow this team", with no step dots.
  • Following soft-links the team to the current player, then lands on Schedule with the "You're all set" toast.

Landed: schedule with the all-set toast

prototype: schedule + toastonboarded.html
  • If the league has not published yet the toast reads: "Following West Hill Golden Hawks. Games land here when GTHL publishes the schedule."
  • Toast auto-dismisses after about 3 seconds.

Start your team

prototype: groupcreategroupcreate.html
  • Users never see the word "group": it is always "team".
  • With no player yet, creating the team first asks to name the player, then seats them on it.

You're all set (founded a team)

prototype: allsetallset-founded.html
  • The one rationed celebration in onboarding: a ring draws, a tick settles, one glint. No confetti, no sound. Reduced motion shows the finished seal.
  • A followed team skips this beat and lands on Schedule with a toast instead.

Schedule hub

The forward-looking hub: what is coming up for the player in the lens. Every hub is scoped to one player, chosen in the lens at the top.

Schedule (following a published team)

prototype: scheduleschedule.html
  • Soonest first, grouped by month. Start time only on the card: no arrival or puck-drop time.
  • Score is a hand-entered overlay, shown when present. The arena name opens maps.
  • "updated by Coach Sean" marks a time the team admin changed from the published source.
  • Colour stripe on each card is the event type token (game, practice, tournament, personal).

Schedule (a team you manage, game live)

prototype: scheduleschedule-managed.html
  • The live card appears only while a game or practice is in progress (start to end time).
  • "Add an event" appears only for a team you manage (a parent-coach).
  • For a team founded by hand the source line reads "you author every game".

Schedule (September, nothing published yet)

prototype: schedule (preseason)schedule-preseason.html
  • The honest promise, never dimmed zero counts. "Add an event" here opens a personal event, something the parent can log now.
  • If the league simply hasn't published this team yet: "GTHL hasn't published Toronto Titans's U11 A schedule yet. It lands here the moment they post it. The keepsake is set up and waiting."

Schedule (no team yet)

prototype: scheduleschedule-noteam.html

Schedule (loading)

Added for launchschedule-loading.html
  • Skeletons keep the layout of the real content so nothing jumps when it arrives. Shimmer stops under reduced motion.

Schedule (offline, showing saved)

Added for launchschedule-offline.html
  • Copy is provisional. The schedule should always render from the last sync; the banner only states freshness.

Player menu (several players)

prototype: switcherswitcher.html
  • Opens from the player name in the header, always, even with one player, so adding another is always one tap away.
  • Your own players first, then players you follow (warm avatar). A player with a photo shows it; otherwise their initial.
  • "Add a player" opens the add-player screen without the onboarding step dots; the new player becomes the current one.
  • Changed from the prototype, where one player skipped this menu and opened the profile directly.

Player menu (one player)

Added for launchswitcher-single.html
  • With one player the menu still opens: it is where a second child gets added.

Add another player (from the menu)

Added for launchaddplayer-another.html
  • Same form as onboarding step 1, without the step dots. Continue goes on to "Find their team" with Skip for now, then lands on the new player's Schedule.

Season hub: the keepsake timeline

The backward-facing spine where moments live, newest on top, chaptered by month. This is the heart of the brand: a photo book, not a stats page. Moments are mounted like prints, captions set in the display italic.

Season (parent, full timeline)

prototype: season / timelineseason.html
  • Holds: played games (with a score or a moment), every practice, tournaments, personal events, and moments not tied to an event. Never bare upcoming games: those live in Schedule.
  • A game or practice with nothing attached renders slim; with a score or moments it renders as a card.
  • The year appears on a month chapter only where the timeline crosses a year.
  • Prototype placeholder "Ava · —" under each game (a per-player stat line) is left out until it has real data.
  • Add a moment floats above the tab bar so it is reachable anywhere on a long timeline (the prototype had it at the end of the list).

Season (a team you manage, participation)

prototype: season (managed)season-managed.html
  • Participation shows only on a team you manage. Coverage (how many were recorded) is always stated next to the figure.
  • The season switcher appears only once a second season is on record; it is absent at launch.
  • Prototype section labels "Participation, coverage always stated" and "The spine, newest on top" were spec notes; the rule now lives in the footer and these notes.

Season (nothing yet)

prototype: seasonseason-empty.html
  • First-run invitation. In September with a team followed but nothing published, the same state applies.

Season (with hidden moments)

prototype: seasonseason-hidden.html
  • The hidden count shows only when something is hidden. It opens Hidden moments.

A season that has wrapped

prototype: seasonquietseasonquiet.html
  • The prototype's callout ended with "huddlie does not nudge you to re-follow it yet, that is a rough edge we know about." That is an internal note, so it is left out of the UI.
  • Open product gap: a re-follow prompt for next season's calendar.

Team hub and roster

Thin and honest for a family that follows a published team; the management surface once a parent runs the team themselves.

Team (following a published team)

prototype: team (follow tier)team.html
  • Each team sits in its own card; with several teams the cards scroll under the pinned "Add another team" button (styled like "Add a moment"), which opens team search.
  • "Manage this myself" founds a team you own, subscribed to the same published calendar, with the player seated. The tab then shows the managed surface.

Team (no team yet)

prototype: teamteam-none.html

Team (managed by you)

prototype: team (found tier)team-managed.html
  • The team's identity sits in the card; the management sections scroll below it and under the pinned button.
  • The shadow callout shows only for a team graduated from a followed calendar. The prototype line also said "An honest limitation at launch, not the finished thing." (an internal note, left out).
  • Close vs delete: once games have happened a team can only be closed; the record stays readable for everyone on it.

Manage team (founded by hand)

prototype: teammanageteammanage.html

Roster

prototype: rosterscreenrosterscreen.html
  • "Linked" means the entry is tied to a family's player in huddlie. "Roster only" is a bare name and number: no parent, account or invitation needed.
  • "Add my own player" shows above "Add a player" until the founder's own player is on the roster.

Roster (empty)

prototype: rosterscreenroster-empty.html

Add a player to the roster

prototype: addentryaddentry.html
  • Position placeholder names hockey positions: fine for seed data, but lasting copy should stay activity-neutral.

Add a player, number taken

prototype: addentryaddentry-error.html
  • Missing name error: "A name is required."

Edit a roster entry

prototype: rosterentryrosterentry.html

Who is dressing for this game

prototype: gamerostergameroster.html

Take attendance

prototype: attendancetakeattendancetake.html
  • Only for a team you manage, on a game or practice that is not cancelled. Cancelling an event voids its attendance.

Event detail and authoring

One event page that adapts to where the event is in time: upcoming (the plan), live (capture), played (score and moments). The event detail is a moment's home.

Event: upcoming

prototype: eventdetail (upcoming)eventdetail-upcoming.html
  • Moments can be added in any state; no score is needed first.

Event: happening now (you manage the team)

prototype: eventdetail (live)eventdetail-live.html
  • Live = between start time and end time (games about 2 hours, practices 1.5).
  • "Take attendance" only for a team you manage.

Event: played, with score and moment

prototype: eventdetail (played)eventdetail-played.html
  • The prototype showed the result as a list row; here it is the event's one big number, since the score is the headline of a played game.
  • Without evidence (no score, no attendance) the destructive action is "Delete this event" instead.

Event: played, no score yet

prototype: eventdetail (played)eventdetail-played-noscore.html

Event: tournament

prototype: eventdetail (tournament)eventdetail-tournament.html
  • With nothing inside yet: "Nothing scheduled inside yet." It reads as pending, never as complete or incomplete.

Event: cancelled

prototype: eventdetail (cancelled)eventdetail-cancelled.html
  • Callout copy is provisional (the prototype showed only the Cancelled marker). No moment can be added to a cancelled event.

Add an event: game

prototype: eventauthoreventauthor-game.html
  • Date and time fields open the native pickers; values show formatted, not raw ISO as in the prototype.

Add an event: practice

prototype: eventauthoreventauthor-practice.html

Add an event: tournament

prototype: eventauthoreventauthor-tournament.html

Private note

prototype: addnoteaddnote.html

Moments

The keepsake unit: a note, a photo or a video, tagged to the game or practice it came from, with a chosen audience.

Add a moment (from an event)

prototype: composercomposer.html
  • Opened from an event: the event is inherited in the chip. Tapping the chip re-tags it.
  • Default audience: a parent gets Huddle; a follower gets Private. The last choice sticks for next time. Team appears only for a team you manage.
  • Posting with no text and no media: toast "Add something / A moment needs a word or a photo."

Add a moment (photo attached)

prototype: composercomposer-filled.html

Add a moment (as a follower)

prototype: composer (follower)composer-follower.html
  • The empty-huddle footnote shows whenever the huddle has no one in it.

Tag this moment

prototype: eventpickereventpicker.html

Manage a moment

prototype: momentactionsmomentactions.html

Hidden moments

prototype: hiddenviewhiddenview.html
  • Empty: "Nothing hidden."

Add a personal event

prototype: personaleventauthorpersonaleventauthor.html
  • Saving shows toast "Added to the timeline". The player's activity layer is derived from what they do here: nobody picks a sport.

Personal event

prototype: personaleventdetailpersonaleventdetail.html

The player, the huddle, co-parents

Everything about the player lives behind the lens, never in a tab. The huddle is the family and friends who follow along; a co-parent is an equal owner.

Player profile

prototype: playersheetplayersheet.html
  • The profile photo slot (avatar.lg) takes a real photo when the family adds one; the letter is the fallback.
  • With a co-parent, deleting is blocked: toast "Can't delete Ava / This player has a co-parent. The record belongs to both of you, so it can't be deleted here."
  • Deleting the last player returns to the get-set-up home.

Player profile (no activity yet)

prototype: playersheetplayersheet-new.html

Player profile (someone you follow)

prototype: playersheetplayersheet-followed.html
  • No Edit and no Delete for a player you only follow.

Edit player

prototype: editplayereditplayer.html
  • "Change photo" opens the same Add a photo sheet, with a "Remove photo" option added.

Ava's huddle

prototype: huddlehuddle.html

Ava's huddle (empty)

prototype: huddlehuddle-empty.html
  • Empty state carried by the mark as a tip, as in the prototype.

Invite to the huddle

prototype: invitehuddleinvitehuddle.html
  • Copying shows toast "Link copied / Send it to them however you like." Invites are copy-link, name only at launch; phone delivery is a fast-follow.

Co-parent (none yet)

prototype: coparentcoparent.html

Co-parent (invite pending)

prototype: coparentcoparent-pending.html
  • The prototype's "Simulate accept" button is a demo control and is not part of the app.

Co-parent (accepted)

prototype: coparentcoparent-accepted.html

Invite a co-parent

prototype: invitecoparentinvitecoparent.html

Following Ava (a follower's home)

prototype: followerchildviewfollowerchildview.html
  • Following several players adds a segmented switcher under the nav bar.
  • With notifications off, a small accent dot beside the name marks "new since you last looked".
  • Footer says "child": the brand vision reserves "child" for the parent's own layer. Suggest "nothing about anyone else on the team" here.

Settings, notifications, after the game

huddlie only asks for attention when it earns it. Settings sits behind the gear in the hub bar.

Settings

prototype: settingssettings.html
  • Only two notification categories at launch; RSVP and Team news are fast-follow and not shown.
  • The "How huddlie reaches you" link is added so the explainer screen has an entry point.

How huddlie reaches you

prototype: notificationsinfonotificationsinfo.html
  • "Interrupts" maps to iOS time-sensitive / Android high-priority; "Notifies" to a normal push; "Silent" to no push.

After the game (push notification)

prototype: postgamepromptpostgameprompt.html
  • Fires when the game's end time passes, off the schedule alone: no check-in at the rink, no result needed first. Only if the parent turned the prompt on in Settings.
  • The push icon is the app icon. It becomes the real icon when the brand lands.
  • The prototype drew this as an in-app card with Enter / Skip buttons; in the real app it is a system push that opens the After the game sheet.

After the game: score and photos

prototype: pgsheetpgsheet.html
  • Tapping a photo opens the composer with the photo attached and the game tagged.
  • Saving the score: toast "Score saved / It reads on the game now."

After the game: photo access needed

prototype: pgsheetpgsheet-permission.html

System states

States every real app needs that the clickable prototype skipped: confirmations, errors, and the toast family. All copy here is provisional.

Confirm a destructive action

Added for launchconfirm-delete.html
  • The prototype deletes on one tap. Launch needs a confirmation for anything permanent: delete player, delete team, delete event, remove from team.
  • Keep the destructive verb identical on the trigger, the sheet title and the confirm button.

Something went wrong

Added for launcherror.html
  • Name what failed, say how to fix it, reassure about the keepsake. Never a bare "Error".

Toast: a confirmation

prototype: toasttoast-saved.html
  • All prototype toasts use this one pattern: Link copied, Score saved, Refreshed, Result saved, Moved, New season opened, Team closed, Team deleted.
  • A toast confirms; it never asks. Anything that needs a decision is a sheet.

Toast: an action that can't happen

prototype: toasttoast-blocked.html