Diamond Stone Platform: How the Interface Is Built
Date: 2026-11-11. Revision 2. Status: draft for owner and developer review. Diagrams and
live samples: docs/ui-build.html. The look and the rules it implements:
docs/DESIGN.md sections 4, 6, 7 and 11, and docs/BRAND.md.
This document says how the glass, the elements and every movement are coded, and why, in terms of what a person sees and feels. Browser facts were checked on 11 November 2026; items marked unverified were not read at the source.
1. Layers
Six layers; each uses only the one beneath it (drawn in ui-build.html section 1).
| Layer | What it holds | Rule |
|---|---|---|
| Tokens | Colour, type, space, radius, the two size sets; glass by level; motion (durations, curves, springs); haptic patterns | The only place a value is written. A build check fails on any colour, size or timing written elsewhere |
| Engines | Quality monitor; glass engine; motion engine; the rules engine (money, VAT, validation in Rust/WASM) | Small modules with no markup |
| Primitives | Surface, Pressable, Motion, Draggable, layout | Behaviour only, no look. Everything that is glass, pressable, animated or dragged goes through one of these four |
| Components | Button, chip, toggle, field, row, card, strip, ring, bar, route line, stage dots, avatar, figure, suggestion panel, toast, skeleton, empty state | One job each. Every state built in: pressed, focused, disabled, busy, error, loading, empty |
| Patterns | Halo band, Stream, Omnibar, Record, Sheet, Composer, Camera | The shell and repeated layouts |
| Screens | Routes | Composed from patterns only. No styling, no timing |
Because glass and motion each live in one primitive, changing how either works changes it everywhere, and no screen can get it wrong.
2. Glass
What is drawn at each level
| Level | Drawn | Coded as |
|---|---|---|
| 0 Solid | An opaque surface, one fine edge | A background colour |
| 1 Frosted | A fixed pale gradient; nothing behind is sampled. Content fades as it nears the bar | A gradient, a border, and a fade mask on the content |
| 2 Glass | What is behind, blurred and slightly richer, under a tint; a light top edge; a soft shadow | The browser's backdrop blur, with the tint over it |
| 3 Edge light | Level 2, plus light bending at the rim and a highlight | A bending map applied by the browser as a filter on what is behind |
How level 3 works, and its limits
- The bending map is worked out from the bar's shape (how a curved glass edge bends light), stored as an image where one colour channel moves pixels sideways and another moves them up and down. A second image carries the rim highlight.
- Only Chrome-family browsers can use such a filter on what is behind an element. Safari and Firefox cannot, so iPhones stop at level 2. Samsung Internet should follow Chrome but has not been tested by anyone: it is tried on the real S25.
- The map must match the surface's exact size. Rebuilding it is costly; using it is cheap. So maps are made once for each fixed size (the Omnibar, the Halo band at rest, a sheet top) in Rust/WASM at start-up, or shipped as ready images, and cached. A surface that is changing size drops to level 2 until it rests.
- WASM makes the optics correct; it cannot make the blur faster. The blur is the browser's work.
Keeping it fast and readable
- Glass only on floating controls: the Omnibar, the Halo band once content is under it, sheet tops. Never on content, never one glass surface inside another.
- At most two glass surfaces at once on the S25 and one on the A55.
- Blur strength is never animated. On a mid-range phone a surface turns frosted while it moves and returns to glass at rest.
- A tint floor. Apple's Liquid Glass drew wide complaints about text that could not be read over busy content, and Apple added a more opaque option within weeks. Here the tint is set so text keeps 4.5 to 1 contrast over the lightest and darkest content that can pass beneath, checked by test, and it is never lowered for effect.
- The cost of backdrop blur grows with the area blurred and repeats whenever the content beneath changes, so scrolling under glass is the worst case (engineering consensus, unverified by measurement here). It is measured on the A55, not assumed.
Choosing the level on each phone
Drawn in ui-build.html section 3.
- Read the phone's settings: less transparency, more contrast, less motion, power saving. Any of them starts the level at 0 or 1.
- A one-second test draws the real bar over moving content and times every frame.
- The highest level that held the frame rate is used.
- While the app is used, long frames during scrolling and transitions are counted. Repeated drops lower the level for the session, and it is remembered.
- It goes up again only after a fresh test, on an update or on request.
- The person can choose any level under Me → Appearance.
Timing uses the browser's frame clock on every phone; Chrome's own long-frame report adds detail where it exists (not on iPhones). Memory and processor hints are used only as a starting guess, since iPhones hide them.
3. Motion
Superseded in part by docs/MOTION.md (11 November 2026), which evaluates this
section, fixes the spring definition so it can be coded, and adds what was missing.
The component layer in section 1 is expanded in docs/COMPONENTS.md.
Vocabulary
Every movement uses one of these (live in ui-build.html section 4). Nothing else is
allowed; a movement that needs a new value needs a new token and a reason.
| Token | Value | For |
|---|---|---|
tap |
90 ms, ease out | Press feedback |
quick |
150 ms, ease out | Colour and fade |
move |
220 ms, ease out | Arriving, changing shape |
sheet |
280 ms in | Sheets and screens arriving |
leave |
200 ms, ease in | Anything going away |
settle |
A spring: stiffness 300, damping 0.75, about 3 % overshoot | A completed step, and nothing else |
spring.snappy |
Stiffness 1400, fully damped | Toggles, chips, press release |
spring.standard |
Stiffness 700, fully damped | The Halo band, sheets, drawers after release |
spring.gentle |
Stiffness 300, damping 0.9 | Large surfaces settling |
The springs are the calm end of what the platforms themselves use (Material's standard
scheme; Apple's "no bounce" default). Nothing bounces in everyday use. One exception, decided by the owner on 11 November
2026: settle, used only when a step is completed (approved, delivered, month closed),
keeps a small overshoot of about 3 %. It is one pass beyond the end and back, never a
wobble.
Which technique
| The movement | Coded with | Why |
|---|---|---|
| Follows a finger | Pointer events; position set directly each frame; on release a spring that starts at the finger's speed (Svelte's Spring, keeping momentum) |
A fixed-time animation would restart from rest and feel taken out of the hand. It can be grabbed again at any moment |
| Press feedback | A CSS transition on scale and a light under the finger | Starts in the same frame as the touch |
| A card becoming its record; a screen changing | The browser's view transitions, called from SvelteKit's navigation hook | The browser moves one thing into another across two screens. Supported on Chrome, Samsung Internet and iPhones. Cannot be interrupted, so they are kept short and used only for navigation |
| Appearing and disappearing in place | CSS entry and exit styles; height animated to its natural size where the browser allows, a fade where it does not | Runs off the main thread |
| Neighbours making room | Measure before and after; animate the difference with transform | No layout work during the movement |
| A value changing | Two stacked values cross-fading | Exact at every instant |
| Scroll-linked (the Halo band shrinking) | Scroll-driven animation | No script while scrolling |
| Less motion asked for | Every spatial movement becomes a 120 ms fade; dragging still follows the finger | The setting is read in code as well as in CSS, because Svelte's own transitions ignore a CSS-only rule |
Only position, scale and opacity are animated. Shadows, blur strength and sizes that cause re-layout are never animated; a shadow that must change fades a second layer instead.
Every element
The full tables are in ui-build.html sections 6 and 7: fifteen small movements and
eleven large ones, each with when it happens, what moves, the token, how it is coded and
what the person takes from it. The sequences in section 8 show what moves when for four
moments: opening a record, tapping a Halo ring, approving, and a delivery being signed.
Haptics
Three patterns on Android: a light tick on confirm, a double tick on error, a soft step at a snap point. iPhones do not support this from a web page. It needs a recent touch and is silent when the phone is on silent, so it is never the only signal.
4. What it does to the person
Drawn as "Why each rule" in ui-build.html section 11.
| What is done | What happens in the person | How sure |
|---|---|---|
| A response in the same frame as the touch | Seen as caused by the touch. Around a tenth of a second is the limit for "instant"; for dragging, even a few thousandths of a second of lag can be seen | Well established |
| Whole movements of a fifth to two fifths of a second | Shorter cannot be followed; half a second already "feels like a drag"; frequent actions want the short end | Platform guidance; rules of thumb, not experiments |
| Things travel from where they were to where they go | People keep track of what moves and lose what jumps; a change not seen happening is often missed | Supported for tracking change; animation does not by itself make things easier to understand |
| Arrive easing out; leave faster | A quick start feels responsive, a soft landing lets the eye settle | Convention |
| Springs after a finger lets go | The movement keeps the speed the hand gave it, so it feels like the person's own | Platform guidance |
| No bounce, except one small overshoot on a completed step | Bounce reads as playful, so everyday movement has none. A single small overshoot marks a finished step | Owner decision |
| The same direction every time | A picture of where things are, so people move from memory | Supported |
| One thing moves; nothing loops at rest | Movement at the edge of vision pulls the eye whether wanted or not | Well established in general; not measured here |
| Figures cross-fade | A rolling figure cannot be read while it rolls | Brand decision |
| Placeholders only after 300 ms | Evidence is mixed: one study found placeholders felt longer than a spinner, another the opposite | Mixed; tested with staff |
| One fuller moment for a finished step | The end of an experience is remembered more than its middle | Reasonable; not checked at source |
| Less motion is a real mode | Large movement, zoom and parallax make some people dizzy or ill | Accessibility standard |
| Strongly tinted glass, solid one tap away | Translucency costs contrast | Widely reported |
How it should feel: quick and quiet. Things answer at once, move a short way, and stop without fuss. The one place it slows is when something is finished.
5. Browser support that the plan rests on
| Needed for | Chrome on Android | Samsung Internet | iPhone Safari |
|---|---|---|---|
| Backdrop blur (level 2) | Yes | Yes | Yes |
| Bending filter on the backdrop (level 3) | Yes | Should; untested | No |
| View transitions within the app | Yes | Yes | Yes (18 and later) |
| Shared elements by class | Yes | Yes | Yes (18.2 and later) |
| Spring-shaped CSS curves | Yes | Yes | Yes |
| Entry and exit styles | Yes | Yes | Yes |
| Animating to natural height | Yes | Yes | No: fades instead |
| Scroll-driven animation | Yes | Yes | Yes (26 and later) |
| Frame timing report | Yes | Yes | No: the frame clock is used |
| "Less transparency" setting | Yes | Yes | No: "more contrast" is used |
| Vibration | Yes | Yes | No |
The current Samsung Internet's exact engine version was not confirmed, so every row for it is checked on the two phones in Stage 0.
6. Checks
| Check | Limit | How |
|---|---|---|
| Frame time while anything moves | One frame at the screen's rate on the S25 (8 ms at 120 a second); never worse than 60 a second on the A55 | Recorded on the phones for every movement |
| What animates | Position, scale, opacity | Build check |
| Glass surfaces at once | Two on the S25, one on the A55 | The Surface primitive refuses more |
| Response to a touch | Visible within 100 ms | Measured on the phones |
| Looping movement | One at most, only during real work | A test that fails on idle animation |
| Less-motion mode | Every movement has its fade | Screenshot run with the setting on |
| Every level, both size sets, light and dark | Each component | Screenshot comparison |
| Contrast on glass | 4.5 to 1 over light and dark content | Automated, per token pair |
| No value outside tokens | Build fails |
7. Order of building
- Tokens and the build checks.
- The four primitives, with a test page for each: Surface at all four levels; Pressable; Motion; Draggable.
- The quality monitor and its one-second test, run on the S25 and A55. This decides whether level 3 is real.
- The shell patterns: Halo band (with its drag), Omnibar, Sheet.
- Components, each with all its states.
- Screens.
Nothing in step 5 or 6 is started until steps 2 and 3 have been felt on both phones by the owner.
8. Decisions
- ~~Overshoot on completed steps.~~ Decided: keep a small one, on
settleonly. - Whether level 3 is pursued if the S25 passes but only in Chrome and not in Samsung Internet.
- Whether staff may choose "always solid" for the whole company, for battery or legibility.
9. Sources
Read directly on 11 November 2026: browser support data from caniuse and MDN; kube.io on reproducing Liquid Glass with CSS and SVG; Chrome's notes on view transitions and long animation frames; web.dev's animation guide; Svelte's motion and transition documentation and SvelteKit's navigation hook; Apple's "Designing Fluid Interfaces" (2018) and "Animate with springs" (2023); Material 3's motion tokens in the Android source; Nielsen Norman Group on animation duration and response-time limits; WCAG 2.2 on animation from interactions; MDN on vibration.
From search summaries only (unverified): the studies on touch latency, on animated transitions and object tracking, on placeholders against spinners, on progress indicators, and the reports on Liquid Glass legibility.
10. What the plan was missing (revision 2)
An audit of this plan on 11 November 2026 against the accessibility standard (WCAG 2.2),
browser documentation and published studies. Drawn in docs/ui-build.html sections 13
to 23. In order of risk to people using the S25 and A55.
Changes to the design itself
| # | Finding | Change |
|---|---|---|
| 1 | Bright sun. The A55 reaches about 1,000 nits only on automatic brightness and under 450 set by hand; the S25 about 2,600 (display reviews, not measured here). Text over a translucent surface fails outdoors. Studies also find dark text on light reads better than the reverse, more so at small sizes | A fifth surface level, Sun: opaque, maximum contrast, heavier text, no glass. One tap under the "You" ring. The light theme is the default for field roles; dark is a choice, and is not justified by battery (it saves little except at full brightness) |
| 2 | Reach. The top of a 6.2 to 6.6 inch phone is outside the thumb's comfortable area, and about half of use is one-handed | The Halo band is for looking. Nothing in it is the only way to do something. The Place chip in the Omnibar carries the count of what is waiting, and tapping the count brings the Halo down to the thumb. Pulled down, the rings that need the person sit lowest. Decision 4 |
| 3 | Drawing under the status bar is not documented for an installed web app on Android; only the bottom edge is | Tested on both phones in Stage 0. Fallback: the band starts below the status bar, and the status bar is given the band's colour so the two read as one |
Things the code must do
| Area | Rule | Source |
|---|---|---|
| The phone's text-size setting | Chrome on Android ignores it unless the page opts in (available since March 2026). The app opts in; all sizes are relative; every bar has a minimum height, never a fixed one; checked at 200 % on a 320 px screen | Chrome documentation |
| No drag required | The pull-down, sheets and swipe actions each have a button that does the same. A screen reader takes over swipes, so drags never reach the page for those users | WCAG 2.5.7 |
| Focus never covered | Scroll padding equal to the band and bar heights. The Omnibar hides when the keyboard opens and the form's action sits above the keys | WCAG 2.4.11 |
| Touch areas | 24 px is the legal floor. Here: 48 px, and 56 for main actions in the comfortable set. Walking lowers accuracy and bigger targets help; no dependable figure exists for gloves, so the yard's own gloves are tried on the A55 | WCAG 2.5.8; Schildbach and Rukzio 2010 |
| Meaning for assistive tools | Real dialogs for sheets and the drawer; the background inert; focus returned to where it came from; announcements for counts, toasts and "sent". Each ring is a button with a full name | WCAG 4.1.3 |
| Colour never alone | About 1 man in 12 has a red-green deficiency. Every status has an icon or word too | WCAG 1.4.1 |
| Arabic text | No letter-spacing or capitals; its own, larger line height; fallback fonts matched in size so nothing shifts | W3C Arabic layout requirements |
| Mixed direction | Every changing value (name, amount, phone, code) is isolated from the text around it. Phone, bank and code fields are always left to right. Western digits for money and codes | W3C |
| Mirroring | Layout, arrows, progress, the route line, slide direction and the Back swipe mirror. Digits, the logo, photographs, clocks and ticks do not. Arabic readers scan from the top right | Convention; Nielsen Norman Group |
| The Back gesture | Every sheet, drawer and dialog is a step in history, so Back closes it | Practice |
| Calculations off the main thread | A tap must show a result within 200 ms. The rules engine runs in a background worker; press feedback is painted first | web.dev |
| Offline sending | iPhones have no background sending. An outbox sends when the app is next opened; each item shows queued, sent or failed | Platform limits |
| Data states | Saved copy at once with its age; placeholders only after 300 ms; changed figures cross-fade; a failure keeps the work | Section 20 of the sheet |
| Fonts | Served from our own address (a German court fined a site for sending visitors' addresses to Google Fonts), cut down to the letters used, Arabic loaded only for Arabic users, fallbacks matched | Court ruling 2022; practice |
| Layers | One fixed order: content, sticky headings, dim, Omnibar, Halo band and drawer, sheet, dialog, toast | Section 15 of the sheet |
| Bottom edge | The gesture bar's inset is applied to position, not padding, so the layout does not jump | Chrome documentation |
| Security | A strict content policy that allows WebAssembly explicitly; no framing; caches and local data cleared on sign-out; a "hide amounts" switch, since a web page cannot stop screenshots | MDN; practice |
| Heat and battery | The quality monitor lowers the surface level whenever frames slow mid-session, whatever the cause | Practice |
| Interruptions | Drafts saved as typed; reopening returns to the same place | Mark and others 2008 |
| Choice | The pulled-down Halo has at most four groups; recent and last-used come first | Cowan 2001 |
| Plurals, dates, printing | The platform's own formatters (Arabic has six plural forms); print and share layouts for quotes and proformas | Practice |
What a web app cannot do, and the way round
| Limit | Way round |
|---|---|
| No barcode reader built into iPhones' browser; unconfirmed on Samsung Internet | Our own reader in WebAssembly |
| No sending in the background on iPhones | The outbox |
| Notifications on iPhones only after installing | An "install, then turn on alerts" step for iPhone customers |
| On iPhones a link never opens the installed app, and the installed app has its own sign-in | Every link works in Safari; notifications lead; the person is told they will sign in once more (docs/INSTALL.md) |
| Samsung Internet cannot install on Android 14 and later | Sent to Chrome |
| Browsers inside WhatsApp and similar apps cannot install or use a fingerprint | Detected; code sign-in only; "Open in Chrome" |
| No position while the app is closed, anywhere | Stage buttons now; the Android driver app later |
| No vibration on iPhones | Never the only signal |
| Stored data may be cleared on iPhones | Ask for it to be kept; never hold the only copy on the phone |
Testing
Automatic accessibility checks find a little over half of problems at best (one large study: 57 % by volume). The grid in the sheet's section 23 multiplies phone, browser, language, text size, theme, surface level, size set, motion and network, and adds what only a person can check: a screen reader walk of each role's flows, and use outdoors at midday, walking, with gloves and one hand.
Not established
No dependable published figure was found for touch targets with gloves, for how polarised sunglasses affect these screens, or for how Samsung Internet treats the phone's text-size setting. The brightness figures are from reviews. Each is on the Stage 0 test list.
Decisions added
- Whether the Omnibar's Place chip carries the Halo count and opens the Halo from the bottom, as proposed for reach.
- Whether Sun is offered automatically (when the phone has been at full brightness) or only by hand.
- Whether charts mirror in Arabic. This plan: they do not.
Sources added in revision 2
Read directly: WCAG 2.2 "what's new"; Chrome's documentation on edge-to-edge and on respecting the phone's text scale; web.dev on responsiveness to input; Deque's study of automated accessibility testing; WebKit on storage; MDN on the viewport, the on-screen keyboard, barcode detection and content policy; the W3C's Arabic layout requirements. From search summaries only (unverified): display brightness reviews; Piepenbrock and others 2013 and 2014 and Dobres and others 2017 on light and dark text; Dash and Hu 2021 on dark mode and battery; Schildbach and Rukzio 2010 on walking; Hoober, Bergstrom-Lehtovirta and Oulasvirta 2014 and Le and others 2018 on reach; Cowan 2001; Mark and others 2008; the Google Fonts ruling.