One 3D character, built from KayKit Adventurers parts (CC0) on a shared skeleton. It mirrors the user type set in Profile > User Type and takes its colours from the live theme, so it reads as part of the UI rather than as an illustration. Code: js/profile-persona-character.js (rendering) and js/profile-persona.js (user type to recipe).
Live specimen
The real module on this page. Pick parts or a profile; drag the figure to turn it. Switch Light / Dark in the menu, or pick a Multi-color theme in Profile > Theme, to see the recolour.
Anatomy: slots and recipe
Every KayKit character is skinned to the same 23-bone rig (Rig_Medium), so parts from different characters mix on one skeleton and every animation plays on every mix. A recipe names one option per slot.
| Slot | Options (source model) | Driven by |
|---|---|---|
| Head | rogue (Rogue) | Fixed: one face for every profile |
| Headwear | none · helmet (Knight) · hat (Mage) | Financial knowledge: low · medium · high |
| Outfit | barbarian · ranger · knight (body, arms, legs) | Banking products: few · some · many |
| Back | none · quiver (Ranger) · cape (Knight) | Banking products: few · some · many |
| Loop | Idle_A · Walking_A · Running_A | Digital affinity: low · medium · high |
Slider tiers: 0 to 33 low, 34 to 66 medium, 67 to 100 high. The sliders snap to 0, 50 and 100, so each lands in the middle of a tier.
Profiles
The average of the three sliders picks the profile. The profile sets the title, the story, the UI preview and the legibility preset; the parts follow each slider on its own, so mixed answers give mixed figures.
| Average | Profile | Persona | Legibility preset |
|---|---|---|---|
| below 34 | Newbie | Beat | Large |
| 34 to 66 | All-rounder | Lena | Regular |
| 67 and up | Power user | Max | Small |
Colour
The figure follows the app, not the asset. All colour is computed in OKLCH from the live tokens and updates whenever the theme or a custom colour theme changes.
Monochrome body
Each texture pixel keeps its lightness and takes the theme hue: from whichever of --color-fg and --color-bg carries more chroma (fallback hue 264, brand blue), at the ds4 neutral tint of 0.25. Lightness is squeezed into L 0.32 to 0.97 on Light and L 0.24 to 0.86 on Dark, so the figure never matches the background.
One accent
Colour is spent in one place. The dyeable cloth swatches, the helmet's metal and, bare-headed only, the newbie's hair take the hue of --color-fg-interactive on the ds4 ramp law C = 0.22 × (1 − L), anchored at step 700 on Light and 600 on Dark. In Monochrome themes that is the theme hue; in Multi-color themes it is the primary accent. Under a helmet or hat the hair stays neutral, so headwear and hair never merge.
Light and shadow
| Light | Dark | |
|---|---|---|
| Stage | Transparent canvas; the floor only catches the shadow | |
| Shadow | --color-overlay-tint at 20 % | black at 55 % |
| Spotlight pool | none | --color-overlay-tint at 25 %, the Dark content-indication strength, so the shadow stays visible |
| Key · fill · rim | 2.2 · 1.15 · 0 | 1.8 · 0.85 · 2.2 |
The key light comes from the right, so the shadow falls back left onto the page rather than out of the viewport.
Staging
| Where | Size | Behaviour |
|---|---|---|
| Profile > User Type | 1.5× | Editable through the sliders; drag to turn |
| Overview, Payments, Account details, Custody account, Position details | 1× | Decoration: reads the saved recipe, no interaction |
| Below 62rem | Profile: beside the UI preview, in the flow. Other screens: hidden, no room next to dense content |
On desktop the stage is fixed to the lower right corner. The figure keeps 64dp to the right and bottom edges, measured on one fixed capsule (2.65 m tall, 0.8 m radius), so it stands on the same spot whatever it wears. The stage sits behind the content but in front of the page background: .main-content gets isolation: isolate on these screens and the stage takes z-index: -1. The canvas is click-through; the figure is hit-tested against an invisible capsule.
Motion
| Moment | Spec |
|---|---|
| Part swap | Squash out 168 ms, ease-in (0.4, 0, 1, 1) to scale 1.06 / 0.92, swap the parts, spring back 420 ms, ease-out (0.22, 1, 0.36, 1). During a drag only the latest recipe waits. |
| Loop change | Cross-fade 280 ms between Idle, Walk and Run |
| Rest pose | Turned 30° toward the viewer's left, heading for the bottom centre of the screen |
| Scroll | About 7° per 100 px, tied to the scroll position and eased |
| Drag | Turns with the pointer, then coasts out (damping 0.92 per frame) |
| Reduced motion | No loops, tweens, coasting or scroll turn: a still pose; swaps happen instantly |
The canvas renders only while it is on screen and the tab is visible.
Add the character to a screen
- Load the two scripts at the end of the page:
<script src="js/profile-persona.js"></script> <script type="module" src="js/profile-persona-character.js"></script>
- Add the page's
data-screentoAMBIENT_SCREENSinjs/profile-persona-character.js. - Add
.body[data-screen="…"] .main-contentto theisolation: isolaterule incss/styles.css. Without it the figure renders behind the page background and stays invisible.
Assets
assets/3d/kaykit/: knight, mage, rogue, barbarian, ranger (.glb, parts on Rig_Medium) plus rig-medium-general.glb and rig-medium-movement.glb (animation clips). KayKit Adventurers 2.0 by Kay Lousberg, CC0. Runtime: three.js 0.170 from jsDelivr.