Jump to a component
AniCanonKit · Characters
CharacterCard
A character as one card: stage (silhouette, avatar or 2:3 portrait), role, name, stat tiles, traits, an optional listen-only voice and a note. The same card in creation, editing, looks, voice and face flows. Built only from core components and tokens; it lives in AniCanonKit, not the core.
Live, from @anicanon/sakuga 2.0.0
Sakuga for iOS and Android is coming
iOS
Coming soon
CharacterCard for iOS is in the roughs. The tokens it will read are the ones on this page, the same on every platform.
Android
Coming soon
CharacterCard for Android is in the roughs. The tokens it will read are the ones on this page, the same on every platform.
- Use it for
- A character as one card in every character flow (creation, editing, looks, voice and face): the stage, role, name, stats, traits and a note.
- Not for
- A cast member on the cast pageCastCard
- A character's facts on their own, across their pageCharacterStats
- A character's face and name in a row or on a series pageCastAvatar
- One look of a characterLookPlate
- A place or backdrop being madePlaceCard
Guidelines
voicetakesplaying,onToggleandonSeek, asAudioPlayerdoes; its play button is named for the character's voice.
import { CharacterCard } from '@anicanon/sakuga/anicanonkit';
export default function CharacterCardExample() {
return (
<CharacterCard
name="Kiko"
role="Leads the E.R.A."
stage={{ kind: 'icon', icon: 'body-average' }}
stats={[
{ icon: 'gender-female', value: 'Female', label: 'Gender' },
{ icon: 'age-adult', value: 'Adult', label: 'Age' },
{ icon: 'height-average', value: 'Average', label: 'Height' },
]}
traits={[
{ icon: 'trait-calm', label: 'Calm' },
{ icon: 'trait-bold', label: 'Bold' },
]}
note="This card fills in as you go."
/>
);
}PropsCharacterCardProps
namerequiredstringrolestringstage{ kind: 'icon' | 'avatar' | 'portrait'; image?: string; icon?: IconName; alt?: string; }stats(CharacterStat & { icon: IconName; })[]CharacterStats tiles; changed rings a stat edited in this session.traits{ icon: IconName; label: string; }[]voice{ duration: number; value?: number; seed?: number; playing?: boolean; onToggle?: (playing: boolean) => void; onSeek?: (seconds: number) => void; }notestringclassNamestringAn IconName is any of the names Icon lists.
Types
interface CharacterStat { icon?: IconName; value: string; label: string; changed?: boolean; }
Each token reads a role, and the role lands on a value in each theme. Change the role and every component that reads it follows.
Colour
character-card-bgKit CharacterCard: card.bg-surfaceneutral-0#ffffffbg-surfaceneutral-900#111117character-card-borderKit CharacterCard: edge.border-dividershade-a12rgba(11,10,16,0.12)border-dividerwhite-a12rgba(255,255,255,0.12)character-card-stageKit CharacterCard: stage behind silhouette or avatar.bg-medianeutral-950#07070abg-medianeutral-950#07070acharacter-card-roleKit CharacterCard: role eyebrow.text-accentcamellia-700#b42354text-accentcamellia-400#f4779fSpace and shape
character-card-widthcharacter-card-radiusradius-xlcharacter-card-after-inset-ring-widthline-hairlinecharacter-card-stage-heightcharacter-card-portrait-stage-aspect-ratioratio-portraitcharacter-card-avatar-sizecharacter-card-avatar-ring-widthline-heavycharacter-card-silhouette-opacityopacity-mutedcharacter-card-body-padding-topinset-lgcharacter-card-body-padding-xinset-lgcharacter-card-body-padding-bottominset-lgcharacter-card-body-gapgap-lgcharacter-card-traits-gapgap-smcharacter-card-trait-gapgap-smcharacter-card-trait-heightcharacter-card-trait-padding-rightinset-smcharacter-card-trait-padding-leftinset-smcharacter-card-trait-radiusradius-fullcharacter-card-voice-paddinginset-mdcharacter-card-voice-radiusradius-mdcharacter-card-silhouette-icon-sizecharacter-card-trait-icon-sizeicon-size-xsType
character-card-font-familyfont-sanscharacter-card-role-fonttext-eyebrowcharacter-card-role-letter-spacingtracking-capscharacter-card-name-fonttext-title-2character-card-trait-fonttext-small-strongcharacter-card-note-fonttext-smallMotion
character-card-portrait-develop-animationmotion-developChecked automatically with axe-core 4.11.4 against WCAG 2.2 A and AA, on the live preview above, in light and dark, on 26 October 2026.
- Result
- No issues found, in light or in dark.
- By design
- A complementary region named by
name(or "Character"); a portrait's alt isstage.altor the name, an avatar's isstage.alt(empty, so hidden, by default), and the silhouette is hidden. The role, name, stats, traits and note read as text, the voice's play button is named for it ("Play Aiko's voice"), and withvoice.onSeekits waveform is a slider. - Not tested
- The automated check doesn't test keyboard use, focus order or what a screen reader says. The lines above are the design system's own account of them.