H
Code Blue Sim app icon visionOS · Medical XR

Code
Blue

Cardiac arrest training on Apple Vision Pro.

Overview

From a living room to a full hospital code.

Four training modes on Apple Vision Pro, hand-tracked CPR feedback, and a code team rehearsing together over SharePlay. I designed the mode architecture, every in-headset interface, and the real-time feedback system.

Timeline
2025 — 2026
MedVR Accelerator, then medVR
Role
Lead product & XR designer
Team
2 designers, 2 engineers, clinical advisors
Platform
visionOS · Figma, SwiftUI, RealityKit, ARKit, SharePlay

Full walkthrough, 1:45 — all four modes, on device and in the visionOS simulator.

0Training modes
0Roles in a code team
0Depth target
0Guided rate, per minute

01  /  Why

Six findings. Six decisions.

We started from the resuscitation literature rather than a product idea.

Deviation predicts outcome

Straying from ACLS during a code correlates with worse survival.

Score deviations, not completion Crowley et al., 2020

Skill decays in months

Retention tracks how often you practise, not how well you passed.

Make one more rep nearly free Nishiyama 2014 · Silva 2025

Practice is rationed

Manikin labs are expensive, scheduled and location-bound.

Any flat surface becomes the scene

A code is a team performance

Best-practice guidance trains the team, not individuals.

Multi-user by default, roles first Anderson et al., 2021

Bystanders are in the chain

Layperson training measurably improves out-of-hospital survival.

A mode with no clinical vocabulary Tabata et al., 2024

The bar is rising

The AHA's 2030 goals name training access as the lever.

Cost per rep is the product Merchant et al., 2024

02  /  The system

One system, four entry points.

The main menu is the whole product on one screen. Four modes sit in a rail that never moves; picking one only redraws the pane beside it, so you can weigh the options without losing your place.

Code Blue Sim main menu with the four training modes and an anatomical heart

Idle state. The heart stays on screen while you decide — the only ornament in the app that is also the subject.

Bystander mode running in a domestic room
Out of hospital

Bystander

First person on scene. Plain language, hands-only CPR, no prerequisites.

Solo tutorial mode with hand position guidance
Solo practice

Tutorial

Four skills — CPR, intubation, IV, defibrillator — drillable one at a time.

Multiplayer simulation with role assignment
Multiplayer

Simulation

A full code over SharePlay. Roles assigned before the clock starts.

Advanced training with AI teammates around the bed
Lead with AI

Advanced Training

You take team leader. AI teammates cover the other four roles.

The pane carries the difference.

Two modes need only a sentence and a start button. Two need a real decision made before the clock starts — which skills to drill, or which role you take.

Tutorial mode with a checklist of skills to practise
Tutorial — pick any subset of the four skills, or all of them. Image tracking is offered as a second button, never as a prerequisite.
Advanced training with the user as team leader and AI teammates
Advanced Training — you command; AI covers compressions, breaths, IV and pulse. Leading is the one role nobody can rehearse alone.
Base grade badge Green grade badge Orange grade badge Purple grade badge Broken heart failing grade badge Trophy badge

The broken heart is the only harsh mark in the set — the one place the product is blunt.

03  /  Design system

A system the build cannot drift from.

Four modes, five roles and two engineers is enough surface area for a UI to come apart. So the design system does not live in a Figma library that the code slowly stops matching — it lives in the repo as a markdown rule file scoped by file path, which means it is loaded into context automatically whenever anyone (or any coding agent) opens a SwiftUI view.

.claude/rules/design-style.md  —  867 lines, 10 sections
---
globs:
  - "**/Views/**/*.swift"
  - "**/*View.swift"
  - "**/*Style*.swift"
---

# CodeBlue Design System
Medical emergency training app for visionOS with a dark, immersive blue theme.

The frontmatter is the whole trick. Those three globs decide when the system is in the room.

01

Tokens are the source, not a screenshot of one

Every colour, size and radius exists once, as a markdown table in the repo. Spec and implementation move in the same commit, so there is no version of the system that is quietly out of date.

02

Each step encodes intent, not just lightness

A ten-step scale where 500 means “badge background” and 700 means “primary fill” is a rule an agent can follow. Slightly darker blue is not.

03

Reference sheets are generated, not redrawn

Python scripts render the token lists straight to swatch, type and component sheets. Re-exporting the system after a change is a command, not an afternoon of moving rectangles.

Ten steps, each with a job.

Six scales, all built the same way, and the step number is a job description, not a brightness. 300 is an elevated surface, 700 is the solid interactive fill, 900 is text on a dark plate. Nothing in the codebase is allowed to name a raw hex value.

Colour scales

The 700 step is the default interactive fill for every scale. Role colours map straight onto it — CPR is red-700, IV is green-700, Pulse is orange-700, Lead is blue-700.

100Deepest
200Surface
300Elevated
400Strong
500Subtle fill
600Medium fill
700Solid fill
800Bright fill
900Light text
1000Lightest
Blue
#000F1A
#061A35
#0B2545
#0A326B
#073E91
#0445B8
#024CE1
#2B76F0
#42A3FF
#80C2FF
Gray
#111113
#1C1C1E
#2C2C2E
#3A3A3C
#48484A
#636366
#7C7C80
#8E8E93
#B0B0B5
#F5F5F7
Green
#001A0F
#002E1B
#004228
#005838
#007048
#00945B
#00B86E
#2BCD88
#5DDEA5
#96ECC6
Red
#1F0A08
#3B1210
#571C18
#742622
#96312C
#CC3830
#FF3B30
#FF6259
#FF8A83
#FFB3AE
Purple
#130A1F
#221438
#332054
#462D72
#5A3A91
#7550B8
#AF52DE
#C77AE8
#D9A1F0
#EACBF7
Orange
#1A0F00
#331F00
#4D2F00
#664000
#805200
#B37300
#FF9500
#FFAA33
#FFBF66
#FFD599

Swipe the scale sideways →

Never colour alone: every status colour ships with an icon and a text label, because a green dot in a headset at arm’s length is not information.

Type sized for arm’s length.

visionOS text is read at a distance, through a lens, often by someone kneeling on the floor. The system floors standard UI text at 24 pt and caps it at 40 pt — and separates vital-sign numbers into their own family so they can be monospaced and never reflow mid-compression.

Type scale

Specimens are scaled down to fit this page; the labelled values are the real visionOS points.

Headings
heading-displayCode Blue SimulationMontserrat 40 pt Bold · lh 48 · ls −1.6
heading-36Code Blue SimulationSF Pro 36 pt Bold · lh 44 · ls −1.4
heading-32Code Blue SimulationSF Pro 32 pt Bold · lh 40 · ls −1.0
heading-28Code Blue SimulationSF Pro 28 pt Semibold · lh 36
heading-26Code Blue SimulationSF Pro 26 pt Semibold · lh 32
heading-24Code Blue SimulationSF Pro 24 pt Semibold · lh 30
Body
body-28Position the patient on the bed and begin compressions.SF Pro 28 pt Regular · lh 40
body-24Position the patient on the bed and begin compressions.SF Pro 24 pt Regular · lh 34
Metrics — Montserrat Semibold, monospaced digits
metric-56120 BPMMontserrat 56 pt Semibold · primary vital
metric-4803:42Montserrat 48 pt Semibold · timer
metric-402.1" depthMontserrat 40 pt Semibold · secondary vital
metric-3298% SpO2Montserrat 32 pt Semibold · compact metric

Compression depth and rate are read while someone is pushing on a chest, so metrics are monospaced — the number changes without the layout twitching.

States you cannot argue about.

Five variants, four states, and not a single hand-picked colour — every state is one step along the variant’s own scale. Typography is set by the button’s size, never by its variant, so a destructive button and a primary button are always the same shape.

Button variants & states

Hover moves one step brighter, active moves one step darker and scales to 0.97 so a press reads as pressure, and disabled is simply the default fill at 40% opacity. Swatches below show each variant’s fill token; Primary ships as a two-stop blue-800 → blue-700 gradient. No outlines anywhere — the fill difference carries the separation.

DefaultHoverActiveDisabled Primary
Button
blue-700
Button
blue-800
Button
blue-600
Button
blue-700
Secondary
Button
blue-400
Button
blue-500
Button
blue-300
Button
blue-400
Tertiary
Action
black@0.3
Action
blue-200
Action
blue-300
Action
black@0.3
Destructive
Button
red-700
Button
red-800
Button
red-600
Button
red-700
Success
Button
green-700
Button
green-800
Button
green-600
Button
green-700

Swipe the matrix sideways →

Radius encodes depth rather than component type: 46 pt for any surface floating directly in the immersive space, 16 pt for anything nested inside another surface. The same metric card is 46 pt beside the patient and 16 pt inside a window.

04  /  Interaction

Designing for hands that are already busy.

visionOS runs on look-and-pinch. During compressions you have no free hands and your gaze is on the chest — the default input model is simply unavailable.

01

Nothing in the loop needs a pinch

Compressions advance the step themselves. Taps exist only where hands are legitimately free.

02

World-anchored, never head-locked

Panels sit beside the patient at chest height, so looking down doesn't drag them over the chest.

03

Split feedback by urgency

Reviewable numbers on a persistent panel. Act-now corrections as audio plus one large card.

04

One instruction per card

Under stress, a five-bullet panel is a panel that gets skipped.

Live CPR metrics beside the patient
Metrics sit beside the patient, not in front of the face.
Pulse check target on the patient's wrist
Instruction and action share one location.

Rate, taught as music.

You cannot watch a rate meter while compressing, so in step 3 of the tutorial the target moves from the eyes to the ears.

110Beats per minute

Inside the AHA window of 100–120. Press play and stop watching the screen.

Step 1 — place hands in the correct position Step 2 — chest compressions: lock elbows, push with body weight, two inches deep Step 3 — maintain 100 to 120 compressions per minute with a music guide Step 4 — after two minutes, move away and await your next role

Four steps: hand position, mechanics, rate, rotation. Step 4 teaches rescuer rotation before the learner ever enters a team scenario.

05  /  Feedback

Show the gap, not a verdict.

Three correction states. Each names the distance to target instead of pass/fail — that is what lets someone calibrate on the very next stroke.

1.3″ / 2″ Compress deeper
Measured depth Distance to AHA target
Three CPR correction states

Too shallow, too fast, too slow. One instruction each, throttled so the panel never flickers.

06  /  Beyond one headset

Real resistance, real people.

Two places the product had to leave the single-user, all-virtual box.

A printed sheet and a foam heart.

Compressions against empty air teach the wrong motor pattern — but instrumented hardware would destroy the cost argument. So the CPR-cycle poster doubles as the image-tracking marker, and a foam heart supplies the resistance.

Marker, foam heart trainer and headset

Lay the marker on any surface and the patient registers to it, at real height in a real room. Tracking is always offered as an option, never a requirement.

Training the team, not the individual.

SharePlay puts people in different physical rooms around one patient. The hard part is not the sync — it is that nobody can see what the others know.

01

Roles before the clock

The lead assigns every participant a role before the scenario can start.

02

One shared holding state

While the group assembles everyone sees the same panel, so nobody wonders whether it is broken.

03

Personas carry attention

Position and gaze around the bed read the way they do in a real code.

Instructor tools panel

An instructor panel exposes the scenario's inner state, so a facilitator can steer a session without leaving the headset.

07  /  Iteration

What changed between builds.

A flat screen became a spatial one

The first menu was an iPad layout floating in mid-air — four photo cards on a single plane. The rebuild puts the mode rail on its own layer and a 3D heart in the depth behind it, so the first thing you see is a room, not a page.

The environment stopped being neutral

Early builds ran in a generic gallery space. Context is part of what is being trained, so later builds split into a hospital OR and a living room.

Early build main menu: four stock-photo cards in a row on one flat panel
Before — four modes as photo cards in a row, all on one plane. Correct information, but it could have been a website.
Current main menu: vertical mode rail beside a labelled 3D heart
After — a vertical rail you scan top to bottom, a labelled heart sitting behind it in depth, and the app identified in the corner. Layperson also became Bystander, the word clinicians actually use.
Later build with defibrillator and bag valve mask prompts

Equipment steps ended up on the same card pattern as compressions, inside environments that match the mode.

08  /  Outcome

Where it went, and what is still missing.

Co-designed with clinicians throughout rather than reviewed at the end — an MD, PhD from Johns Hopkins Medicine plus advisors from medVR and Northeastern University.

AWE 2026 MIT Connected Learning Summit MDIC MXR2025 Paper in progress
Code Blue SIM conference poster

Conference poster, designed by Jasmine Yiming Sun.

What I'd do differently.

Validated with experts, not learners

Nobody has yet run the retention study the literature points straight at. That is the line between a convincing prototype and a defensible claim.

Depth is estimated, not measured

I'd want to know how far hand tracking drifts from an instrumented manikin before showing a learner a number to hit.

Bystander mode needs its users

Designed from evidence about laypeople, not with them. Audio-led interaction is exactly what survives a demo and fails in a hallway.

References — six peer-reviewed sources
  1. Crowley, C.P. et al. (2020). The association between ACLS guideline deviations and outcomes from in-hospital cardiac arrest. Resuscitation 153, 65–70. doi
  2. Nishiyama, C. et al. (2014). Long-term retention of CPR skills after shortened chest compression-only training and conventional training. Academic Emergency Medicine 21, 47–54. doi
  3. Silva, J.K.B. et al. (2025). Analysis of acquisition and retention of CPR skills according to training frequency. Einstein (São Paulo) 23. doi
  4. Tabata, R. et al. (2024). Effect of CPR training for layperson bystanders on outcomes of out-of-hospital cardiac arrest. Resuscitation 201, 110314. doi
  5. Anderson, T.M. et al. (2021). Best practices for education and training of resuscitation teams for in-hospital cardiac arrest. Circ Cardiovasc Qual Outcomes 14. doi
  6. Merchant, R.M. et al. (2024). The AHA emergency cardiovascular care 2030 impact goals and call to action. Circulation 149, e914–e933. doi

Credits

Design   Hannah Yunbing Han (product & XR) · Jasmine Yiming Sun (brand, poster)

Engineering   Nandita Venkat · Sahil Mayenkar · Hunter Harris

Clinical & senior advisors   Christopher Robinson, MD, PhD · Steven Max Patterson · Y. Jenny Wang, PhD

Mentors   Dat Nguyen · Daniel Pillis · Jenna Fizel · Hunter Harris

Institutions   medVR · Northeastern University · Johns Hopkins Medicine

3D assets   Charité University Hospital OR and adult intubation demonstration, via Sketchfab

← BackHome Next →Icovela