SigmaCog Platform · Design System v0.1

From the screen
into the specimen.

A unified light theme and reading-first type scale for the nine sigmacog properties. Built on paper, weighed in ink — designed for clinicians, operators, and forty-something eyes that need to work all day.

9Properties unified
11Tokens replace ≥60 hex
18 pxNew body baseline
≥7:1Primary text contrast
§ 01

Foundation — paper, ink, rule

The platform reads on cream paper. Every surface, every line of type, every line of rule derives from three layered ramps. Avoid pure white — its coldness on a 4K panel tires older eyes within hours of clinical use.

Paper ramp — surface layers

--paper-deep #efe9d8
Page wrapper / footer / inset surface
--paper-base #f6f1e4
Default body background — sigmacog's canonical paper
--paper-raised #fbf8ef
Card surface, sidebar, slight elevation
--paper-card #ffffff
Maximum elevation — modals, focused inputs

Ink ramp — text on paper

Aa
--ink-primary #0c1620
Headings, primary body text, key data values
16.85:1 · AAA
Aa
--ink-secondary #394a5e
Sub-headings, supporting copy, sidebar items
9.27:1 · AAA
Aa
--ink-muted #6a7a8d
Metadata, captions, table labels, kickers
4.41:1 · AA
Aa
--ink-faint #a2adba
Placeholders, disabled state, decorative rules
2.45:1 · ≥18pt only

Rule ramp — borders, dividers, hairlines

--rule-strongink × .22
Section dividers, table head rules
--ruleink × .12
Default border (cards, inputs, nav items)
--rule-softink × .08
Row separators, sub-section breaks
--rule-faintink × .04
Background grid, decorative whisper-lines
§ 02

Brand accents

Seven semantic accents replace the 60+ scattered hex values currently spread across nine repos. Every accent is vetted against --paper-base — the primary surface — for WCAG AA contrast or stronger.

Primary brand
Sapphire
#1e4a8f  ·  --brand

Replaces every navy, indigo, and "primary blue" across the platform. Used for primary buttons, active nav, key headings, link color.

vs --paper-base9.56 : 1 · AAA
Accent · cyan
Cyan
#0e7d8e  ·  --accent-cyan

Inherits artisebio's signature cyan, darkened for paper. EEG and bio-signal accents, hover states, secondary key data.

vs --paper-base5.36 : 1 · AA
Accent · teal / success
Jade
#0f8f72  ·  --accent-teal · --signal-success

Dual-purpose: positive metrics, completed states, "good" health indicators, neurofeedback reward markers.

vs --paper-base5.27 : 1 · AA
Signal · warn
Amber
#8a5e08  ·  --signal-warn (text) · #bd8411 bg

Caution states, draft banners, "needs review" markers. Pair with #bd8411 background tint for badge / alert chips.

vs --paper-base6.87 : 1 · AAA
Signal · danger
Vermilion
#c8442a  ·  --signal-danger

Errors, destructive actions, "out of credits" alerts, hard-stop indicators. Use sparingly to preserve its weight.

vs --paper-base5.51 : 1 · AA
Accent · secondary
Lavender
#6a4bb1  ·  --accent-lavender

Secondary categorization, cognitive-task family markers, MyndScape domain labels, optional decorative role.

vs --paper-base7.83 : 1 · AAA
Primary brand · deep
Midnight
#14315c  ·  --brand-deep

Hover state for sapphire buttons, emphasis headings, the deepest tint of the brand family.

vs --paper-base13.92 : 1 · AAA

Forty-something eyes don't read fonts.
They read shapes, spacing, and the courage of a system to slow down.

§ 03

Typography — read at arm's length

Body baseline lifts from 16 px to 18 px — the single most impactful change for our 40+ users. Headings de-escalate proportionally; line-height generous; tap targets ≥ 44 px. All four families are already deployed in at least one sigmacog repo, so no new font dependency.

Display · headings
Fraunces
'Fraunces', 'Noto Serif TC', Georgia, serif
Italic · accent
Crimson Pro
'Crimson Pro', 'Noto Serif TC', Georgia, serif
Body · UI
IBM Plex Sans TC
'IBM Plex Sans TC', 'Noto Sans TC', system-ui
Mono · code, meta, data
IBM Plex Mono
'IBM Plex Mono', 'JetBrains Mono', monospace

Type scale

--text-display72 px Specimen
--text-4xl50 px Heading 1
--text-3xl38 px Heading 2
--text-2xl30 px Heading 3
--text-xl24 px Heading 4 · lead paragraph
--text-lg20 px Lead body — first paragraph emphasis, modal copy
--text-base18 px Primary body — instruction text, step guidance, default reading size for 40+ operators
--text-sm16 px Secondary body — captions, helper text, secondary metadata
--text-xs14 px Meta · kicker · table label

Reading specimen

Operation guide · sample

為個案進行 EEG 評估

A clinical-grade brain-wave assessment in five minutes.

為個案戴上 8 通道腦波儀,確認每個電極都貼合頭皮。在主畫面點「連接裝置」按鈕,從藍牙清單中選擇對應的腦波儀型號。連接成功後,進入「阻抗」分頁確認每個通道阻抗低於 10 kΩ(綠色)。

阻抗通過後,於「錄製」分頁點右上角綠色「開始錄製」按鈕,引導個案放鬆並閉上眼睛。錄製時長達到設定值後系統自動停止,也可手動點「停止」結束錄製。

本評估僅供討論與訓練參考,不取代醫療專業意見。

§ 04

Drift, now resolved

Nine properties; nine different navies, eight different ambers, eight different greens. Every "brand role" has fragmented into a constellation of near-misses. One unified accent token absorbs them all.

Before — nine palettes (top three hues per repo)

artisebio-web
navy · cyan · teal
sgimacog-web
bg · teal · cyan
rppg-webapp
deep · blue · cyan
acpt-web
indigo bg · indigo · gold
ViboMynd
mauve bg · mauve · plum
NFB-Webapp
mauve bg · mauve · plum
poseidon
navy · amber · teal
BrainQ10-Web
paper · sapphire · jade
MyndScape
sage · forest · amber
unified into

After — one paper, four ink tones, seven accents

sigmacog/* — unified light theme
paper · ink · sapphire · cyan · jade · amber · vermilion · lavender

The two light-theme prior arts — BrainQ10 (paper/ink/sapphire) and MyndScape (sage/forest) — already work. We collapse the seven dark repos onto BrainQ10's foundation rather than invent a new aesthetic.

§ 05

Components — before / after

Layout, structure, copy, and JavaScript are unchanged. Only color values, font-family, font-size, and line-height shift. Every dark frame on the left is current production; every light frame on the right is the proposed migration target.

Nav bar

before · dark navy#0d1b2e
after · paper#f6f1e4

Buttons

beforecyan #38c8e8
aftersapphire #1e4a8f

Form field

before
afterfocus halo brand-tint

Card

before
Pro tier

專案管理

建立個案、追蹤訓練進度、寄送報告 — 整合所有 sigmacog app 的個案管理面板。

after
Pro tier

專案管理

建立個案、追蹤訓練進度、寄送報告 — 整合所有 sigmacog app 的個案管理面板。

Data table

before
個案App分數
c_8a72f1EEG52.4
c_4f93b8SoraMynd48.1
c_2c815dPoseidon56.7
after
個案App分數
c_8a72f1EEG52.4
c_4f93b8SoraMynd48.1
c_2c815dPoseidon56.7

Alerts

before
本評估僅供討論與訓練參考,不取代醫療專業意見。
VisioMynd 試用次數剩 2 次。
VisioMynd 使用次數已用完,請升級訂閱方案。
after
本評估僅供討論與訓練參考,不取代醫療專業意見。
VisioMynd 試用次數剩 2 次。
VisioMynd 使用次數已用完,請升級訂閱方案。
§ 06

App surfaces — nine tiles, one voice

Each property keeps a single accent role to preserve its identity within the family — EEG stays cyan-flavored, VisioMynd stays vermilion-flavored, SoraMynd stays jade-flavored. The shared paper-ink-rule foundation makes the family read as one product.

sigmacog EEGeeg.sigmacog.xyz
Brain-wave assessment

8-channel QEEG in five minutes.

戴上 8 通道腦波儀,五分鐘完成臨床級腦電評估,輸出 7 項認知指標報告。

7
indices
256Hz
sampling
VisioMyndvisiomynd
rPPG vital signs

Vitals from video, no wearable.

以攝影機進行非接觸式心率、HRV、血氧、呼吸與壓力指數量測。

60s
recording
6
vital signs
VeloMyndvelomynd
Continuous performance test

Animal CPT for attention.

動物主題的持續注意力表現測驗,適用兒童與成人雙模式版本。

200
child trials
400
adult trials
ViboMyndvibomynd
Binaural beats

Modulating brain rhythms.

可調頻雙耳節拍播放器,輔助放鬆、專注與情緒調節練習。

1–100Hz
beat range
4
presets
SoraMyndsoramynd
Neurofeedback training

Closing the loop in real time.

以腦波即時回饋的神經回饋訓練遊戲,四款基礎情境可調節獎勵機制。

8ch
EEG
4
games
Poseidonposeidon
sLORETA neurofeedback

Source-localized training.

多通道 sLORETA 來源定位神經回饋,搭配 26 個功能網絡離線分析。

20–32ch
channels
26
networks
ScalarMyndscalarmynd
Questionnaire assessment

Standardized scales, instant scoring.

13 份標準化心理與發展量表,依年齡與填答者關係自動篩選適用量表。

13
scales
free tier
MyndScapemyndscape
Cognitive task suite

A landscape of cognition.

12 項認知作業組成的測驗套組,涵蓋注意力、工作記憶、執行功能等領域。

12
tasks
3
tiers
artisebiowww.sigmacog.xyz
Main platform

Closed-loop cognitive health.

整合評估、監測、訓練三軸的閉環方案,將神經解碼從實驗室帶進日常生活。

8
sub-apps
4
subscription tiers
§ 07

Engineering — tokens & migration

The complete token set, ready to paste into each repo's :root. Per-repo migration touches CSS only — no JavaScript, no HTML structure, no functional logic.

tokens.css — single source of truth

/* sigmacog design tokens v0.1 — light theme */
:root {
  /* paper · ink · rule */
  --paper-deep:    #efe9d8;
  --paper-base:    #f6f1e4;
  --paper-raised:  #fbf8ef;
  --paper-card:    #ffffff;
  --ink-primary:   #0c1620;
  --ink-secondary: #394a5e;
  --ink-muted:     #6a7a8d;
  --ink-faint:     #a2adba;
  --rule-strong:   rgba(12,22,32,.22);
  --rule:          rgba(12,22,32,.12);
  --rule-soft:     rgba(12,22,32,.08);
  --rule-faint:    rgba(12,22,32,.04);

  /* brand · accent · signal */
  --brand:        #1e4a8f;
  --brand-deep:   #14315c;
  --brand-light:  #4a78c2;
  --brand-tint:   rgba(30,74,143,.08);
  --accent-cyan:  #0e7d8e;
  --accent-teal:  #0f8f72;
  --accent-lavender: #6a4bb1;
  --signal-warn:    #8a5e08;
  --signal-warn-bg: #bd8411;
  --signal-danger:    #c8442a;
  --signal-danger-bg: #e0654a;
  --signal-success:   #0f8f72;

  /* typography */
  --font-display: 'Fraunces','Noto Serif TC',Georgia,serif;
  --font-italic:  'Crimson Pro','Noto Serif TC',Georgia,serif;
  --font-body:    'IBM Plex Sans TC','Noto Sans TC',system-ui,sans-serif;
  --font-mono:    'IBM Plex Mono','JetBrains Mono',monospace;

  --text-xs:    0.875rem;
  --text-sm:    1rem;
  --text-base:  1.125rem;  /* ← 40+ baseline */
  --text-lg:    1.25rem;
  --text-xl:    1.5rem;
  --text-2xl:   1.875rem;
  --text-3xl:   2.375rem;
  --text-4xl:   3.125rem;
  --text-display: 4.5rem;

  --lh-tight: 1.2;
  --lh-snug:  1.4;
  --lh-base:  1.75;
  --lh-loose: 1.85;

  --tap-min: 44px;
}

Migration sequence — 1 → 9

  1. Place tokens.css in each repo — copy the same file into css/tokens.css (or framework equivalent). No build pipeline required.
  2. Map existing variables forward. In each repo's :root, replace declarations with token references — e.g. --navy: var(--brand-deep). Existing component CSS continues to work via the indirection.
  3. Flip body background from var(--navy) family to var(--paper-base); flip default text color to var(--ink-primary).
  4. Sweep hardcoded hex. Any literal #xxxxxx in component CSS gets mapped to its closest token role. Estimate 30–90 minutes per repo.
  5. Set body font-size to var(--text-base) (1.125 rem). Adjust component sizes proportionally — most will already scale via em-based padding.
  6. Verify focus halos. Every interactive element receives box-shadow: 0 0 0 3px var(--brand-tint) on :focus-visible.
  7. Audit on staging — push to staging branch, walk every operator-facing screen, log any deviation. No prod deploy until the family reads as one.

Non-goals

  • No layout restructure. Grid, flex, spacing rhythms untouched.
  • No JavaScript edits. No HTML structural changes.
  • No iconography swaps. No new dependencies.
  • No animations or transitions added beyond what already exists.
  • No authentication, session, or security flow changes.
§ 07

App identity — shared chassis, distinct voice

Each sub-app keeps its own primary accent so operators recognise it at a glance. The chassis (paper, ink, rule) is identical across the suite; only the brand-position accent shifts. Do not paint a sub-app with another's identity. When in doubt, default to --brand.

App Identity token Used for
sgimacog EEG --brand #5b7593 primary CTA, active tab, logo wordmark
SoraMynd NFB --accent-teal #7a9580 + lavender-deep logo success cards, NFB reward state, "Sr" logo italic
VeloMynd CPT --velo-indigo #7e7ea5 card top accent, "Ve" logo glyph, primary button, monitor dp-val
VisioMynd rPPG teal→brand gradient (CVRI ring) CVRI score ring, step indicator done state
ViboMynd BNB — pending demo not yet migrated; audit baseline missing

Per-device colors (sgimacog multi-device only)

sgimacog operates 1–4 STEEG devices in parallel. Each gets a Morandi-desaturated accent; these replace the legacy high-saturation RGB palette. Per-channel waveform colors form a separate 8-color set shared across all devices — channels are identified by colour, not by device.

--dev-1
#6c8c8e
--dev-2
#7a9580
--dev-3
#b88574
--dev-4
#9b8aa0
§ 08

Pitfalls — the lint checklist no PR escapes

Five recurring failure modes burned ≈ 10 round-trips during the 2026-05-25 migration. Every one is mechanical. Run the four greps below before submitting any theme change.

--*-tint tokens are background-only

Every --*-tint in the palette is a 12–16% alpha. Using one as a foreground color: gives ≤ 1.5:1 contrast — invisible on paper-cream. Text colour must use --ink-*, --brand-deep, --*-deep, or full-opacity accent.

grep -rnE "color: ['\"]var\(--[a-z-]+-tint\)['\"]" src/

② Dark-theme residue RGBA

Pre-Morandi text colours from the dark theme — pale blue, mint green, salmon — render invisible on paper. Any rgba(1NN, 1NN, 2NN, 0.5–0.9) in a color: property is suspect.

grep -rnE "color: ['\"]rgba\(1[0-9]{2},[12][0-9]{2}" src/

③ paper-card vs paper-raised inversion

The chassis convention: cards sit on white (--paper-card), chrome sits on cream (--paper-raised). VeloMynd's monitor had these inverted across 10 surfaces, making cards visually receded and chrome bright. When porting from dark theme, double-check every background.

④ Legacy palette hex literals

Pre-Morandi: bright teal #48baa6 / rgba(72,186,166, …); lime green #80c854 / rgba(63,185,80, …); GitHub red #f85149 / rgba(248,81,73, …); per-device hi-sat #52b8d8 / #80c854 / #dc7860 / #b060c8.

grep -rnE "#48baa6|#f85149|#52b8d8|#80c854|#dc7860|#b060c8|rgba\(72,186,166" src/

⑤ Numeric-display reflow

Proportional fonts (Crimson Pro, Cormorant Garamond) render "1000" wider than "999". When the value sits in a banner alongside fixed-width siblings, the row bounces with every refresh. Two fixes: set font-variant-numeric: tabular-nums; font-feature-settings: "tnum" on the value, and give the container a fixed width (not just min-width).

⑥ Async gate races

Unlocking a UI option behind cond1 && asyncCond2 is a race trap — if setState(asyncCond2 = true) is batched out or the resolution dispatches before the consumer remounts, the option stays disabled forever. Decouple UI gates from compute gates. Gate the picker by the synchronous condition only; let the compute gate sit deeper.

§ 09

Build & deploy — two flags, no surprises

Two non-obvious build flags decide whether the staged bundle works on the staged Worker. Miss either and the symptom is silent — the page renders, but EEG packets never flow.

VITE_API_BASE='' when building for *-staging

Every sub-app's wasm.ts defaults API_BASE to 'https://www.sigmacog.xyz' for prod. A local bun run build with no env override bakes that prod URL into the bundle — the staged bundle then fetches the WASM key from prod (different key) and decryption fails. Always prefix with VITE_API_BASE='' so the bundle uses same-origin (= staging.sigmacog.xyz).

VITE_API_BASE='' bun run build
bunx wrangler pages deploy dist \
  --project-name=<app>-staging --branch=staging --commit-dirty=true

# verify: deployed bundle must contain Bt=`` (empty), not Bt=`https://www.sigmacog.xyz`
PROXY=$(grep PROXY_SECRET ~/.staging-secrets | cut -d= -f2-)
curl -s -H "x-proxy-secret: $PROXY" $URL/assets/main-*.js | grep -oE 'Bt=`[^`]*`'

② WASM encryption chain (NFB / Poseidon)

bun run build alone copies the raw .wasm into dist. Runtime expects AES-GCM ciphertext. NFB & Poseidon must run build:full (build:wasm → encrypt:wasm → build) the first time, then incremental edits can use plain build since the encrypted blob is committed. sgimacog auto-chains since 2026-05-02 (commit d0bf7a5).

③ Deploy-then-audit, no exceptions

Every theme push to staging is followed by an inline audit against the deployed bytes — fetch the bundle, grep for the four expected fingerprints (root tokens, identity colours, legacy hex absent, VITE_API_BASE empty). "It compiled" is not evidence the change is live; CF Pages edge cache can serve stale bytes for hours after the deployment URL is announced.

# post-deploy audit — minimum 4 checks
curl -s -H "x-proxy-secret: $PROXY" $URL/assets/main-*.css | grep -oE '--paper-base:[^;}]+'
curl -s -H "x-proxy-secret: $PROXY" $URL/assets/main-*.css | grep -oE '--brand:[^;}]+'
curl -s -H "x-proxy-secret: $PROXY" $URL/assets/main-*.js  | grep -oE 'Bt=`[^`]*`'
curl -s -H "x-proxy-secret: $PROXY" $URL/assets/main-*.js  | grep -cE '#52b8d8|#80c854|#f85149'   # must be 0

Per-app deploy targets

App Source path Staging project
sgimacog/Users/swryociao/sgimacog-web/websgimacog-web-staging
SoraMynd/Users/swryociao/NFB-Webapp/webnfb-webapp-staging
VisioMynd/Users/swryociao/rppg-webapprppg-web-staging
VeloMynd/Users/swryociao/acpt-web (→ "Animal CPT Web" GH mirror)animal-cpt-web-staging