Media & effects
Matrix Clock
World time, one rolling matrix character at a time
detent-matrix-clock
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 4
- Wave
- phase-4-cinematic
- Group
- Media & effects
9.6 KB gzip for the class module · inlines the shared spring
Variants
A live world clock in 5×7 dot-matrix glyphs. Times come from the platform's IANA zone rules, so no time service is
contacted. Add a city through the native country and city selects, remove one with the row's × button
(the last row cannot be removed), and hover a row to watch its characters roll through the staggered rebuild. The
board announces one concise name and hides every decorative dot from assistive technology.
No city change yet.
Recorded states
errorrecorded state; no setterreduced motionrecorded state; no setter
Usage
Import
import '/components/matrix-clock/define.js';
// or register it yourself
import { DetentMatrixClock } from '/components/matrix-clock/matrix-clock.js';
Attributes
formatreduce-motionshow-controlsshow-countryshow-secondsupdate-interval
Properties
citiesonCitiesChangeonRemove
Slots
No slots are recorded for this component.
Events
detent-cities-change— { cities: AirportMatrixCityId[] }detent-remove— { id: AirportMatrixCityId }
Example
Runnable example: site/examples/matrix-clock.ts. The snippet below is generated from the catalogued attributes.
<detent-matrix-clock
format="24h"
reduce-motion
show-controls
show-country
show-seconds
update-interval="1000"
></detent-matrix-clock>
Property-only values
const element = document.querySelector('detent-matrix-clock');
if (element !== null) {
// cities: AirportMatrixCityId[]
element.cities = [];
// onCitiesChange: (cities: AirportMatrixCityId[]) => void
element.onCitiesChange = () => {};
}
Source
The pinned upstream source for this row:
src/components/ui/AirportMatrixClock.tsxsha256 2d9938547212…
Native files
The native module and its artifacts:
src/components/matrix-clock/matrix-clock.tssrc/components/matrix-clock/styles.csssrc/components/matrix-clock/define.tsdocs/components/matrix-clock.mdsite/examples/matrix-clock.tstests/browser/matrix-clock.spec.tsevidence/components/matrix-clock.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
format | format | '12h' | '24h' | '24h' | Kebab-case attribute; camelCase property. |
reduce-motion | — | — | — | Recorded in the catalog as an attribute. |
show-controls | showControls | boolean | true when cities is omitted | Presence semantics: present means true, absent means false. |
show-country | showCountry | boolean | false | Presence semantics: present means true, absent means false. |
show-seconds | showSeconds | boolean | false | Presence semantics: present means true, absent means false. |
update-interval | updateInterval | number | 1000 | Kebab-case attribute; camelCase property. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
cities | AirportMatrixCityId[] | ['los-angeles', 'london', 'tokyo'] | Property-only: assign from script; not accepted as an attribute. |
onCitiesChange | (cities: AirportMatrixCityId[]) => void | undefined | Property-only: assign from script; not accepted as an attribute. |
onRemove | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
Events
| Event | Upstream prop | Payload type | Notes |
|---|---|---|---|
detent-cities-change | onCitiesChange | (cities: AirportMatrixCityId[]) => void | Composed, bubbles; fires only for a user action. |
detent-remove | onRemove | (id: AirportMatrixCityId) => void | Composed, bubbles; fires only for a user action. |
Slots
No slots are recorded for this component.
CSS customisation
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- char, row-count, row-index, country, row and text are MatrixGlyph/MatrixText/CountryLabel/row params in the pinned source, not board settings; they are dropped from the native surface and recorded here so the row does not keep dead API.
- A clock tick rolls only the cells that changed, while upstream animates only on a pointerenter rebuild (its rebuildId never changes on the interval); the native port follows the row parity feature with springSnappy 380/30/0.5, +/-72% travel and a stagger of min(index*12, 90) ms.
- The clock pauses while hidden or offscreen; the upstream setInterval kept running.
- reduce-motion is an attribute as well as the media query.
- The error state is the pinned invalid-input fallback, not an error surface.
What it does
A live world clock drawn as an airport split-flap board: one compact 5×7 dot-matrix character per cell, the time and the city name in the same glyph alphabet, an optional country line, and built-in country/city selectors that add and remove cities.
Upstream behaviour
- IANA timezone formatting handles local time and daylight-saving changes without a time service
- Three-city default with a five-city maximum, duplicate removal, and safe fallback for invalid input
- Built-in country and city selectors let viewers add or remove cities from the supported set
- Compact bitmap glyphs for city names and 12-hour or 24-hour time
- Only changed character cells roll; unchanged cells retain their rendered state
- Hovering a city or time rolls its characters through a brief staggered rebuild
- Dedicated dark matrix board surface with authentic high-contrast dot matrix typography
Differences from upstream
- `className` prop is replaced by documented CSS parts/custom properties; no Tailwind in consumers.
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- char, row-count, row-index, country, row and text are MatrixGlyph/MatrixText/CountryLabel/row params in the pinned source, not board settings; they are dropped from the native surface and recorded here so the row does not keep dead API.
- A clock tick rolls only the cells that changed, while upstream animates only on a pointerenter rebuild (its rebuildId never changes on the interval); the native port follows the row parity feature with springSnappy 380/30/0.5, +/-72% travel and a stagger of min(index*12, 90) ms.
- The clock pauses while hidden or offscreen; the upstream setInterval kept running.
- reduce-motion is an attribute as well as the media query.
- The error state is the pinned invalid-input fallback, not an error surface.