Score card
A match, or a scoreboard of them, in any sport — the two teams face to face, the clock, the score by period and the match's events.
On this page
html
<aparte-chat-viewport style="height: 25rem"></aparte-chat-viewport>
<script>
// In an app: import { setupScoreCard } from '@aparte/plugin-cards/score';
const { setupScoreCard } = window.apartePlugins.cards.score;
setupScoreCard({ tool: 'get_match' });
const viewport = document.querySelector('aparte-chat-viewport');
viewport.appendMessage({ id: 'u1', role: 'user', content: 'What’s the score in the Northport game?', timestamp: Date.now() });
viewport.appendMessage({ id: 'a1', role: 'assistant', timestamp: Date.now(), segments: [{
id: 's1', type: 'tool_call', status: 'resolved',
toolCall: { id: 'c-s1', name: 'get_match', input: { team: 'Northport FC' } },
structuredResult: {
home: { name: 'Northport FC', shortName: 'NPT', color: '#c8102e', score: 2 }, away: { name: 'Riverside United', shortName: 'RIV', color: '#1d4ed8', score: 1 },
status: 'live', clock: 67, sport: 'football', competition: 'Coastal League', round: 'Matchday 12', venue: 'Harbour Ground',
events: [
{ minute: 12, team: 'home', type: 'goal', player: 'M. Okafor' },
{ minute: 38, team: 'away', type: 'goal', player: 'L. Varga' },
{ minute: 61, team: 'home', type: 'penalty', player: 'S. Dubois' },
],
},
}] });
</script>The two teams face to face, the score between them, and where the match stands: scheduled with its kick-off in the reader’s time, live with its clock, at half time, or finished with its winner. A team without a logo gets its monogram on its colour, in a text colour chosen to read on it.
Variants
Section titled “Variants”A scoreboard
Section titled “A scoreboard”html
<aparte-chat-bubble message-id="a1" data-role="assistant" name="Assistant"></aparte-chat-bubble>
<script>
// In an app: import { setupScoreCard } from '@aparte/plugin-cards/score';
const { setupScoreCard } = window.apartePlugins.cards.score;
// Tomorrow at 21:00, on the reader's clock.
const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); tomorrow.setHours(21, 0, 0, 0);
setupScoreCard({ tool: 'get_scores', variant: 'compact' });
document.querySelector('aparte-chat-bubble').setSegments([{
id: 's1', type: 'tool_call', status: 'resolved',
toolCall: { id: 'c-s1', name: 'get_scores', input: { date: 'today' } },
structuredResult: {
title: 'Tonight',
matches: [
{ home: { name: 'Northport FC', shortName: 'NPT', color: '#c8102e', score: 2 }, away: { name: 'Riverside United', shortName: 'RIV', color: '#1d4ed8', score: 1 }, status: 'live', clock: 67, sport: 'football' },
{ home: { name: 'Bay City Comets', shortName: 'BAY', color: '#f59e0b', score: 88 },
away: { name: 'Lakeside Owls', shortName: 'LAK', color: '#0f766e', score: 91 },
status: 'live', clock: 'Q4 2:41', sport: 'basketball' },
{ home: { name: 'Westmoor', shortName: 'WES', color: '#7c3aed', score: 24 },
away: { name: 'Eastcliff', shortName: 'EAS', color: '#be123c', score: 17 }, status: 'final', sport: 'rugby' },
{ home: { name: 'Riverside United', shortName: 'RIV', color: '#1d4ed8' },
away: { name: 'Hillcrest Athletic', shortName: 'HIL', color: '#15803d' }, status: 'scheduled', startTime: tomorrow, sport: 'football' },
],
},
}]);
</script>One row per match, any mix of sports and states. Several matches are always rows.
Detail
Section titled “Detail”html
<aparte-chat-bubble message-id="a1" data-role="assistant" name="Assistant"></aparte-chat-bubble>
<script>
// In an app: import { setupScoreCard } from '@aparte/plugin-cards/score';
const { setupScoreCard } = window.apartePlugins.cards.score;
setupScoreCard({ tool: 'get_match', variant: 'detail' });
document.querySelector('aparte-chat-bubble').setSegments([{
id: 's1', type: 'tool_call', status: 'resolved',
toolCall: { id: 'c-s1', name: 'get_match', input: { team: 'Northport FC' } },
structuredResult: {
home: { name: 'Northport FC', shortName: 'NPT', color: '#c8102e', score: 3, record: 'W7 D3 L1' }, away: { name: 'Riverside United', shortName: 'RIV', color: '#1d4ed8', score: 1, record: 'W5 D2 L4' },
status: 'final', sport: 'football', competition: 'Coastal League', round: 'Matchday 11', venue: 'Harbour Ground',
periods: [{ label: '1st half', home: 1, away: 1 }, { label: '2nd half', home: 2, away: 0 }],
events: [
{ minute: 12, team: 'home', type: 'goal', player: 'M. Okafor', detail: 'Assist: S. Dubois' },
{ minute: 29, team: 'away', type: 'yellow', player: 'T. Brandt' },
{ minute: 38, team: 'away', type: 'goal', player: 'L. Varga' },
{ minute: 61, team: 'home', type: 'penalty', player: 'S. Dubois' },
{ minute: 74, team: 'away', type: 'sub', player: 'J. Mensah', detail: 'For L. Varga' },
{ minute: '90+2', team: 'home', type: 'goal', player: 'A. Lindqvist' },
],
},
}]);
</script>The score by period and the match’s events, each on its team’s side: goals, penalties, cards, substitutions.
While the call runs
Section titled “While the call runs”html
<aparte-chat-bubble message-id="a1" data-role="assistant" name="Assistant"></aparte-chat-bubble>
<script>
// In an app: import { setupScoreCard } from '@aparte/plugin-cards/score';
const { setupScoreCard } = window.apartePlugins.cards.score;
setupScoreCard({ tool: 'get_match' });
// The call is still running: the card draws its skeleton, with what the input already says.
document.querySelector('aparte-chat-bubble').setSegments([{
id: 's1', type: 'tool_call', status: 'pending',
toolCall: { id: 'c-s1', name: 'get_match', input: { home: 'Northport FC', away: 'Riverside United' } },
}]);
</script>bash
npm install @aparte/plugin-cards @aparte/corets
import { setupScoreCard } from '@aparte/plugin-cards/score';
setupScoreCard({ tool: 'get_match', map: (result) => result.response, variant: 'detail' });readMatches takes API-Football, football-data.org, ESPN and TheSportsDB as they come. The
fields are in the guide.
Related
Section titled “Related”- Stats card — a season’s figures.
- Cards guide — every card, and a card of your own.