Sakuga Back to Sakuga
Theme
Sound
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.

@anicanon/sakuga/anicanonkitv1.0Used onWeb · iOS · AndroidFrom AniCanon™

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

Guidelines

  • voice takes playing, onToggle and onSeek, as AudioPlayer does; its play button is named for the character's voice.
CharacterCardExample.jsxReact
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

namerequired
string
role
string
stage
{ kind: 'icon' | 'avatar' | 'portrait'; image?: string; icon?: IconName; alt?: string; }
stats
(CharacterStat & { icon: IconName; })[]
Drawn as 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; }
Listen-only player.
note
string
className
string

An IconName is any of the names Icon lists.

Types

interface CharacterStat {
    icon?: IconName;
    value: string;
    label: string;
    changed?: boolean;
}
CharacterCardExample.swiftiOS · coming soon
CharacterCardExample.ktAndroid · coming soon

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#ffffff
bg-surfaceneutral-900#111117
character-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#07070a
bg-medianeutral-950#07070a
character-card-roleKit CharacterCard: role eyebrow.
text-accentcamellia-700#b42354
text-accentcamellia-400#f4779f

Space and shape

character-card-width
its own value
360px
character-card-radius
radius-xl
24px
character-card-after-inset-ring-width
line-hairline
1px
character-card-stage-height
its own value
300px
character-card-portrait-stage-aspect-ratio
ratio-portrait
2/3
character-card-avatar-size
its own value
148px
character-card-avatar-ring-width
line-heavy
3px
character-card-silhouette-opacity
opacity-muted
0.6
character-card-body-padding-top
inset-lg
16px
character-card-body-padding-x
inset-lg
16px
character-card-body-padding-bottom
inset-lg
16px
character-card-body-gap
gap-lg
12px
character-card-traits-gap
gap-sm
6px
character-card-trait-gap
gap-sm
6px
character-card-trait-height
its own value
28px
character-card-trait-padding-right
inset-sm
8px
character-card-trait-padding-left
inset-sm
8px
character-card-trait-radius
radius-full
9999px
character-card-voice-padding
inset-md
12px
character-card-voice-radius
radius-md
12px
character-card-silhouette-icon-size
its own value
180px
character-card-trait-icon-size
icon-size-xs
14px

Type

character-card-font-family
font-sans
Funnel Sans
character-card-role-font
text-eyebrow
700 11px/14px "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif
character-card-role-letter-spacing
tracking-caps
.06em
character-card-name-font
text-title-2
700 24px/30px "Funnel Display", "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif
character-card-trait-font
text-small-strong
600 12px/16px "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif
character-card-note-font
text-small
500 12px/16px "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif

Motion

character-card-portrait-develop-animation
motion-develop
sk-develop 560ms cubic-bezier(0, 0, 0, 1)

Checked 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 is stage.alt or the name, an avatar's is stage.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 with voice.onSeek its 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.