A cross-platform research questionnaire scorer for Circadia Lab.
ScoreMe is a mobile and desktop app for administering and scoring validated clinical and sleep health questionnaires across multiple research participants. It is designed for lab-based or clinic-based research sessions where a researcher needs to collect structured self-report data from a cohort, track completion, and export results for analysis.
It is part of the Circadia Lab toolchain and shares its visual identity with SleepDiaries.
- π 25 built-in validated instruments across 5 clinical domains β Sleep (ESS, ISI, DBAS-16, MEQ, PSQI, RU-SATED, STOP-BANG, KSS), Mental Health (PHQ-2, PHQ-9, PHQ-15, GAD-7, GAD-2, BDI-II, BAI, DASS-21, PANSS, STAI-S, STAI-T), Wellbeing (WHOQOL-BREF, MacArthur SSS), Physical Activity (IPAQ-S, GPAQ), and Neurodevelopmental (GSQ, AQ-10)
- π₯ Rich participant profiles β mandatory participant code plus optional name, demographics (age, sex, BMI), study fields (group, site, session), clinical fields (diagnosis, medication, referral), and arbitrary custom keyβvalue pairs
- π Search and sort β filter participants by code, name, group, site, or session; sort by date added, AβZ, or completion %
- π― Step-by-step questionnaire runner β one item at a time, automatic scoring and interpretation on completion, coloured result badge with glow shadow
- π Score history β re-scoring appends to a timestamped history array; no data is ever overwritten; attempt count shown in detail view; full history in JSON export
- π Enable/disable instruments β per-questionnaire toggles persisted across sessions; animated pill toggle; group by clinical domain
- π Analytics tab β score distributions (SVG box plots with whiskers, mean, median), descriptive statistics table (n, mean Β± SD, median, range), completion rates, switchable grouping by group/condition, sex, session, or site
- π₯ Custom questionnaire import β import any instrument as a JSON file following the built-in schema
- π€ CSV and JSON export β CSV includes all participant metadata fields and custom fields as dynamic columns, with latest score per questionnaire; JSON includes full timestamped score history with item-level answers; preview table in the export panel
- π₯οΈ Desktop split-panel layout β left participant list, right detail/scoring/edit panel, glassmorphic sidebar with About modal
- π Cross-platform β runs as a web app, iOS app, and Android app from the same codebase
- π Localisation β English and Brazilian Portuguese (PT-BR) for both UI strings and instrument content (item text, response options, instructions, score band labels), detected automatically from the device locale
- π First-run onboarding β 3-slide centred modal walkthrough, shown once; resettable from the About modal
ScoreMe/
βββ app/
β βββ _layout.jsx Root layout β fonts, WebShell, Stack
β βββ index.jsx Redirects to tabs
β βββ export.jsx Export screen + DesktopExportModal
β βββ score/[pid]/[qid].jsx Mobile scoring route
β βββ participant/[id].jsx Mobile participant detail + inline edit
β βββ (tabs)/
β βββ _layout.jsx Desktop shell; onboarding modal
β βββ index.jsx Dashboard
β βββ participants.jsx Participant list + search/sort + FAB + detail panel
β βββ questionnaires.jsx Questionnaire library + toggles + domain grouping
β βββ analytics.jsx Score distributions, stats table, completion rates
βββ components/
β βββ QuestionnaireRunner.jsx Step-by-step runner (desktop + mobile); applies localise()
β βββ OnboardingModal.jsx First-run centred square modal
β βββ ScreenBackground.jsx SVG gradient background (mobile)
β βββ DesktopBackground.jsx Dot-grid pattern background (desktop)
β βββ DesktopSidebar.jsx Sidebar nav + About modal + onboarding reset
β βββ charts/
β βββ BoxPlot.jsx SVG box-and-whisker plot with group support
β βββ CompletionBar.jsx Horizontal completion rate bars
β βββ chartUtils.js Descriptive stats, grouping, palette helpers
βββ data/
β βββ questionnaires.js Compatibility shim β re-exports from questionnaires/index.js
β βββ questionnaires/
β βββ index.js Central registry β QUESTIONNAIRES, getQuestionnaire,
β β compileQuestionnaire; imports all domain files
β βββ sleep.js ESS, ISI, DBAS-16, MEQ, PSQI, RU-SATED, STOP-BANG, KSS
β βββ mental_health.js PHQ-2, PHQ-9, PHQ-15, GAD-7, GAD-2, BDI-II, BAI,
β β DASS-21, PANSS, STAI-S, STAI-T
β βββ wellbeing.js WHOQOL-BREF, MacArthur SSS
β βββ physical_activity.js IPAQ-S, GPAQ
β βββ neurodevelopmental.js GSQ, AQ-10
β βββ utils.js localise(questionnaire, locale) β merges pt-BR translations
β over the base EN instrument object at runtime
βββ i18n/
β βββ index.js Locale detection + t() helper
β βββ en.js English UI strings
β βββ pt-BR.js Brazilian Portuguese UI strings
βββ storage/
β βββ storage.js AsyncStorage CRUD, score history, export helpers,
β disabled-Qs, onboarding flag
β Exports: getLatestResult, getAllResults
βββ theme/
β βββ typography.js FONTS, SIZES, COLOURS
β βββ responsive.js useLayout(), SIDEBAR_W, SIDEBAR_TOTAL
βββ docs/
β βββ questionnaire-schema.md Full schema reference + LLM prompt template
βββ scripts/
βββ setup.js Copies fonts from SleepDiaries sibling repo
- Node.js β₯ 18
- Expo CLI
- The SleepDiaries repo cloned as a sibling directory (for fonts and logo)
git clone https://github.com/circadia-bio/ScoreMe
cd ScoreMe
npm install
node scripts/setup.js # copies fonts from SleepDiariesIf SleepDiaries is not present,
setup.jswill skip missing files gracefully and the app will fall back to system fonts.
# Web (recommended for development)
npx expo start --web
# iOS simulator
npx expo start --ios
# Android emulator
npx expo start --androidEach participant stores a mandatory code and a set of optional fields exported in both CSV and JSON:
| Field | Type | Notes |
|---|---|---|
code |
string | Required. Unique participant identifier (e.g. P001) |
name |
string | Full name (optional) |
age |
string | Age in years |
sex |
string | Male / Female / Non-binary / Prefer not to say |
bmi |
string | Body mass index |
group |
string | Group or condition label (e.g. Control, Treatment A) |
site |
string | Recruitment or testing site |
session |
string | Session label (e.g. Baseline, Week 4) |
diagnosis |
string | Clinical diagnosis |
medication |
string | Current medication |
referral |
string | Referral source |
customFields |
{label, value}[] |
Arbitrary researcher-defined keyβvalue pairs; each becomes its own CSV column |
notes |
string | Free-text notes |
Metadata chips in the detail panel are colour-coded by category (demographics, study, clinical).
Each questionnaire result is stored as a timestamped array. Re-scoring appends a new entry rather than overwriting. getLatestResult(participant, qid) and getAllResults(participant, qid) are exported from storage.js for use across screens. Legacy single-object results are migrated automatically on next save.
Any validated questionnaire can be imported as a .json file. ScoreMe compiles scoring and interpretation logic from declarative fields β no code required.
To import: Questionnaires tab β Import JSON.
The minimum required fields are id, title, and items. A complete example:
{
"id": "pss10",
"title": "Perceived Stress Scale β 10 items",
"shortTitle": "PSS-10",
"domain": "Mental Health",
"construct": "Perceived stress",
"timeframe": "Past month",
"maxScore": 40,
"scoringMethod": { "type": "sum", "items": ["pss1","pss2","pss3","pss4","pss5","pss6","pss7","pss8","pss9","pss10"] },
"scoreBands": [
{ "min": 0, "max": 13, "label": "Low stress", "color": "#2E7D32", "description": "Low perceived stress." },
{ "min": 14, "max": 26, "label": "Moderate stress", "color": "#F59E0B", "description": "Moderate perceived stress." },
{ "min": 27, "max": 40, "label": "High stress", "color": "#DC2626", "description": "High perceived stress." }
],
"items": [
{
"id": "pss1", "number": 1,
"text": "In the last month, how often have you been upset because of something that happened unexpectedly?",
"type": "frequency_4",
"options": [
{ "value": 0, "label": "Never" },
{ "value": 1, "label": "Almost never" },
{ "value": 2, "label": "Sometimes" },
{ "value": 3, "label": "Fairly often" },
{ "value": 4, "label": "Very often" }
]
}
]
}See docs/questionnaire-schema.md for the full schema reference, all supported item types, and a ready-to-paste LLM prompt for generating new questionnaire files.
ScoreMe detects the device locale at startup using expo-localization and selects the matching translation bundle, falling back to English for unsupported locales.
Supported languages:
| Code | Language | Status |
|---|---|---|
en |
English | β Default |
pt-BR |
Portuguese (Brazil) | β Complete |
All interface strings are keyed in i18n/en.js and i18n/pt-BR.js. To add a new language, duplicate either file and register the new locale tag in i18n/index.js.
The t() helper supports {{variable}} interpolation and _one / _other pluralisation:
import t from '../i18n';
t('dashboard.title') // "Dashboard" / "Painel"
t('export.participants', { count: 3 }) // "3 participants" / "3 participantes"Item text, response option labels, instructions, hints, and score band labels for all 25 built-in instruments are translated inside a translations block on each instrument definition. The localise(questionnaire, locale) helper in data/questionnaires/utils.js merges the requested locale over the base English object at runtime, with per-key English fallback for any missing keys.
// Applied automatically in QuestionnaireRunner before rendering:
import { localise } from '../data/questionnaires/utils';
import { locale } from '../i18n';
const q = localise(questionnaire, locale);
// q.instructions, q.items[n].text, q.items[n].options[n].label
// are now in the device locale where translations existFields intentionally left in English: title, shortTitle, version, reference, credit, copyright, construct, constructDescription β these are proper names and citations.
| Package | Version | Purpose |
|---|---|---|
expo |
~55 | App framework and build toolchain |
expo-router |
~55 | File-based navigation |
expo-blur |
~14 | Glassmorphic BlurView components |
expo-document-picker |
~55 | JSON import from device |
expo-file-system |
~18 | File write for CSV/JSON export |
expo-font |
~55 | Custom font loading |
expo-localization |
~55 | Device locale detection for i18n |
expo-sharing |
~55 | Share sheet for export |
@react-native-async-storage/async-storage |
2.2 | Persistent storage |
react-native-safe-area-context |
5.6 | Safe area insets |
react-native-svg |
15.15 | SVG charts in analytics tab |
@expo/vector-icons |
~15 | Ionicons icon set |
| Role | Name | Affiliation |
|---|---|---|
| Developer / Researcher | Lucas FranΓ§a | Circadia Lab |
| Researcher | Mario Leocadio-Miguel | Circadia Lab |
- π SleepDiaries β participant-facing sleep diary app; shares visual identity and font assets with ScoreMe
- π¬ tallieR β companion R package for importing ScoreMe JSON exports, rescoring questionnaires, and returning tidy data frames
- π¬ circadia-bio β the Circadia Lab GitHub organisation
Copyright Β© Lucas FranΓ§a, Mario Leocadio-Miguel, 2026
Released under the MIT License.
Note on third-party questionnaire instruments: The validated questionnaires included in this app are the intellectual property of their respective authors and institutions. Their inclusion in this open-source repository does not grant any rights to use them beyond what is permitted by each instrument's licence. See the
creditandcopyrightfields indata/questionnaires/for per-instrument details.
