Clinical balance and mobility assessment using smartphone sensors
GabApp is a mobile application that enables clinicians to conduct standardised balance and gait assessments using only a patient's smartphone. It leverages the device's built-in gyroscope, accelerometer, magnetometer, and pedometer to collect high-frequency sensor data during timed clinical tests. Results are packaged as a JSON attachment and emailed directly to the clinician via the SendGrid API, eliminating the need for specialised laboratory equipment.
Home | Prepare | Instructions | Assessment | Submit
flowchart LR
A["Select Test"] --> B["Prepare"]
B --> C["Instructions"]
C --> D["Assessment"]
D --> E["Submit"]
E -->|"Email via SendGrid"| F["Clinician Inbox"]
E -.->|"Retake"| D
flowchart TD
subgraph Device Sensors
G["Gyroscope"]
Ac["Accelerometer"]
M["Magnetometer"]
P["Pedometer"]
end
G & Ac & M & P -->|"100 Hz sampling"| Buffer["In-Memory Log Buffer\n(ref-based, no re-renders)"]
Buffer -->|"JSON serialise"| Encode["Base64 Encode"]
Encode -->|"Attachment"| SG["SendGrid API"]
SG -->|"Email"| Clinician["Clinician"]
Config["clinicians-config.yaml"] -->|"Test definitions\nSampling rate\nRecipient email"| App["App Runtime"]
| Category | Technology |
|---|---|
| Framework | React Native 0.79 + Expo 53 |
| Language | TypeScript 5.8 (strict mode) |
| Routing | Expo Router, file-based routing with grouped layouts |
| Sensors | expo-sensors (gyroscope, accelerometer, magnetometer, pedometer) |
| Voice | expo-speech (TTS) + expo-speech-recognition (STT) |
| SendGrid API via Axios | |
| Forms | React Hook Form + Zod validation |
| Config | YAML-driven test definitions parsed at build time |
| State | React Context (PatientTestingProvider) |
| Storage | react-native-mmkv for local key-value persistence |
| Styling | Material Design 3 tokens, DM Sans / DM Mono typography |
| Animation | Moti + React Native Reanimated 3 |
| Build / CI | EAS Build with development, staging, and production profiles |
- Configuration-driven tests: clinicians define test title, instructions, and duration in a YAML file; no code changes needed
- High-frequency sensor capture: configurable sampling rate (default 100 Hz) across gyroscope, accelerometer, magnetometer (calibrated + uncalibrated), and pedometer
- Ref-based data buffering: sensor readings accumulate in
useRefbuffers to avoid expensive re-renders during active collection - Voice narration: text-to-speech announces test instructions and completion, hands-free operation during assessment
- Voice command support: speech recognition integration for hands-free test control
- Automatic email delivery: sensor data is serialised to JSON, Base64-encoded, and sent as an email attachment via SendGrid
- Multi-environment support: separate
.envfiles and EAS build profiles for development, staging, and production - Zod-validated config: all environment variables and YAML configuration are runtime-validated with Zod schemas
- Accessibility: ARIA roles, labels, and hints throughout; colour contrast meets WCAG guidelines
- Screen keep-awake: prevents the device from sleeping during active data collection
src/
app/ # Expo Router file-based screens
index.tsx # Home, test selection
_layout.tsx # Root layout, font loading, providers
(assessment)/ # Assessment flow route group
prepare.tsx # Safety checklist
instructions.tsx # Step-by-step guidance
assessment.tsx # Active sensor collection
submit.tsx # Results review and email submission
components/
theme.ts # Material Design 3 colour/typography/spacing tokens
lib/
email.ts # SendGrid email with Base64 JSON attachment
speech-commander.ts # Singleton speech recognition manager
load-domain-configuration.js # YAML config parser
storage.tsx # MMKV storage wrapper
react/
use-sensors.ts # Multi-sensor hook with configurable sampling
use-patient-testing.tsx # Context provider for test session state
use-voice-command.ts # Voice command hook
types/
index.ts # Shared TypeScript definitions
clinicians-config.yaml # Clinician-defined test configuration
env.js # Build-time env loading + Zod validation
app.config.ts # Expo app configuration
# Clone
git clone https://github.com/henryennis/gabapp.git
cd gabapp
# Install dependencies
pnpm install
# Configure environment (copy the example and fill in your values)
cp .env.example .env.development
# Start the development server
pnpm startpnpm ios # iOS simulator
pnpm android # Android emulator
pnpm web # Web browserTest definitions are managed in clinicians-config.yaml, allowing clinicians to customise assessments without modifying application code:
sensor-sampling-rate-hz: 100
clinician-email: clinician@example.com
clinical-tests:
- title: 'Standing Test'
instructions: >
Stand still with your feet together on a firm, flat surface.
The sensors will measure your postural sway and balance stability.
duration: 60000 # millisecondsEnvironment-specific secrets (SendGrid API key, sender email) are configured via .env.development, .env.staging, and .env.production. See .env.example for the required variables.
-
Configure: A clinician defines tests (title, instructions, duration) and the recipient email in
clinicians-config.yaml. The YAML is parsed at build time, validated against a Zod schema, and injected into the app via Expo Constants. -
Select: The patient opens the app and selects a test from the home screen. The selected test is stored in React Context (
PatientTestingProvider). -
Prepare and instruct: Two guided screens walk the patient through safety checks and phone placement (front pocket, screen facing body).
-
Assess: On pressing "Start", the
useLogginghook subscribes to all sensors at the configured sampling rate. Readings are timestamped and accumulated in auseRefbuffer to avoid re-renders.expo-keep-awakeprevents the screen from sleeping. A timer fires when the test duration elapses. -
Submit: The patient enters a referral code and accepts the privacy agreement. The sensor data is serialised to JSON, Base64-encoded, attached to an email, and sent to the clinician via the SendGrid API.
- Offline-first storage: queue results locally and sync when connectivity resumes
- On-device signal processing: compute sway path length, RMS acceleration, and frequency-domain features before submission
- Clinician dashboard: web portal for longitudinal patient tracking and trend visualisation
- External sensor integration: Bluetooth pairing with research-grade IMU devices for validation studies
- HIPAA-compliant pipeline: replace email delivery with a secure API endpoint and encrypted storage




