KQ-1280 · MEETING/CARD

Meeting Card

An upcoming-meeting card that counts down from now: a ring around the start time drains over the last few minutes on a tween per tick, and at the start swells and settles on springs.recoil, sends one ring out and turns into the meeting's elapsed share in the live colour. Attendees light up as each one's join time passes, filling with colour and landing on recoil with a ring going out, and once live the Join button breathes a halo, only while the card is on screen. The agenda is a sheet tucked under the card: dragging its lip pulls it out 1:1 with rubber-banding and a release commits by projection on springs.snap, to open, closed or, row by row, to each detent. The lip is a disclosure button: Enter or Space toggles and moves focus into the agenda, arrow keys pull it out and push it back, Escape closes.

KQ-1280 · MEETING/CARD

Design review

10:30–11:15 · Fern room · video

2 of 7 here

  1. 10:30Welcome and goals5m · IO
  2. 10:35Search results review15m · MT
  3. 10:50Mobile navigation options10m · RD
  4. 11:00Accessibility pass10m · OM
  5. 11:10Decisions and owners5m · TV
Drag down or press Enter to open; arrow keys pull it out and push it back; Escape closes.

starts in 4m · 2 of 7 here

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/meeting-card

Props

title
string
default "Design review"
The meeting's name: the card's heading.
place
string
default "Fern room · video"
Where it happens, after the times.
start
Date | number
default 2 Oct 2026, 10:30 UTC
When it starts.
end
Date | number
default 2 Oct 2026, 11:15 UTC
When it ends.
now
Date | number
default 2 Oct 2026, 10:26 UTC
The clock; update it (every second, say) for a live countdown. The card never reads the time itself.
timeZone
string
default "UTC"
The zone times print in, so the server and the browser print the same.
attendees
MeetingAttendee[]
default defaultAttendees
Who is invited (id, name, joinedAt, image); each lights up once now passes their joinedAt.
agendaItems
MeetingAgendaItem[]
default defaultAgenda
The agenda under the card (id, title, minutes, owner); times count from the start.
joined / defaultJoined
boolean
default false
Whether the viewer has joined, controlled or initial.
onJoinedChange
(joined: boolean) => void
default —
Fires from the Join press, with true for joined.
open / defaultOpen
boolean
default false
Whether the agenda is pulled out, controlled or initial.
onOpenChange
(open: boolean) => void
default —
Fires from the drag, press or key that pulled the agenda out or pushed it back.
ring
number
default 5
The countdown window the ring spans before the start, in minutes.
glow
number
default 0.5
How strongly the Join button breathes once the meeting is live, 0 to 1.
agenda
"sheet" | "rows"
default "sheet"
How the agenda comes out: in one pull, or a row at a time with a detent at each.
agendaRows
number
default 3
Agenda rows shown before the sheet scrolls inside.
joinLabel
string
default "Join"
The Join button's text.
joinedLabel
string
default "Joined"
Its text once joined; the button keeps the widest label's width.
endedLabel
string
default "Ended"
Its text after the end, when it is disabled.
youLabel
string
default "You"
The viewer's own face, waiting at the end of the row and lit when joined.
accent
string
default "var(--accent-bright)"
The countdown ring and the Join halo; any CSS colour.
headingLevel
2 | 3 | 4
default 3
The heading's level.
sound
boolean
default false
A chime as the viewer joins, a tick at each agenda detent the viewer pulls past. Nothing sounds on its own.
disabled
boolean
default false
Locks Join and the agenda and dims the card.
className
string
default —
Classes for the article.