Component reference
Every piece of state has two components — one on the operator's control surface, one on air — and they meet at a path. That pairing is the whole mental model:
| What it is | Control | Source |
|---|---|---|
| Text | Field, TextArea | Variable |
| Number | Stepper | Variable |
| A number, in icons | Stepper | Tally |
| One of a list | Select, Cycle | Variable |
| A yes/no | Cycle with one option | Variable |
| Colour | ColorPicker | Scene vars |
| A picture | ImagePicker, ImageSelect | Image |
| Several pictures | ImageSelect multiple | ImageList |
| A folder of them | the image library | Slideshow |
| On or off | Toggle, ImageToggle | Toggle |
| Counting down | Countdown, CountdownTo | Timer |
| Counting up | Stopwatch | Timer |
| A table | Leaderboard | yours |
| Scrolling text | TextArea | Ticker |
| Wall clock | — | Clock |
| Grouping | Panel, Break | Scene |
Every component takes a name, and knows for itself where that name lives: values under variables, on/off ones under toggles, clocks under timers. So a studio author writes name="home.score" and never has to think about it — each component's name row says which. The two that act on several values at once, ResetButton and SwapButton, take paths for the rare case of reaching outside variables.
Every component passes anything it does not recognise through to the DOM, so style, data-* and the rest stay available.
Control
What the operator drives the show from — @single-studio/core/control. These render in src/control/Control.jsx, which is an ordinary React component: put controls in a Panel and it arranges them. Anything you type stages until you save, so a half-finished name never reaches air; anything you press takes effect at once. Each entry below says which.
The board also carries a menu you do not place: the room, the image library, the OBS URLs, the keyboard shortcuts and the ways to start over. Hotkeys is the one piece of it you can also put on the board yourself.
FieldTextAreaStepperSelectCycleColorPickerImagePickerImageSelectImageToggleToggleSwapButtonResetButtonCountdownCountdownToStopwatchLeaderboardPanelBreakConfirmHotkeys
Field
import { Field } from '@single-studio/core/control'
One line of text an operator types, bound to a path. Staged until saved.
<Field name="home.name" label="Home" placeholder="Home team" />// A dotted name groups related values; nothing has to declare the group
<Field name="lowerthird.headline" label="Headline" />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
label | string | Shown above the control. | |
name | string | Yes | Names a value under variables — e.g. home.score. |
placeholder | string | Hint shown in the empty input. |
TextArea
import { TextArea } from '@single-studio/core/control'
Several lines of text an operator types, bound to a path. Staged until saved.
<TextArea name="guest.bio" label="Guest bio" rows={4} /><TextArea name="ticker" label="Crawl text" rows={2} placeholder="One item per line" />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
label | string | Shown above the control. | |
name | string | Yes | Names a value under variables — e.g. home.score. |
placeholder | string | Hint shown in the empty box. | |
rows | number | How many lines tall. Defaults to 3. |
Stepper
import { Stepper } from '@single-studio/core/control'
A number with minus and plus buttons, and a field to type into. The buttons add and subtract, so two operators pressing +1 at once come to +2 rather than +1. Writes immediately.
<Stepper name="home.score" label="Home score" />// A sport that scores in threes
<Stepper name="home.score" label="Home score" step={3} />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
label | string | Shown above the control. | |
name | string | Yes | Names a value under variables — e.g. home.score. |
step | number | How much the -/+ buttons add, and the field's arrow keys. Defaults to 1. |
Select
import { Select } from '@single-studio/core/control'
A dropdown of allowed values. Staged until saved.
<Select name="period" label="Period" options={['1st', '2nd', '3rd', 'OT']} />// What the operator reads, and what the graphic gets
<Select
name="round"
label="Round"
options={[
{ label: 'Quarter-final', value: 'qf' },
{ label: 'Semi-final', value: 'sf' },
]}
/>| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | Options as JSX, instead of options. | |
className | string | Added to the component's own classes. | |
label | string | Shown above the control. Defaults to "Select". | |
name | string | Yes | Names a value under variables — e.g. home.score. |
options | Array<string | { label: string, value: string }> | What can be chosen. A bare string is both. | |
placeholder | string | The empty choice. Defaults to "— none —". |
Cycle
import { Cycle } from '@single-studio/core/control'
One button that steps through a list of values in order, wrapping back to unset at the end. With a single option it is a checkbox: press to set it, press again to clear it — which is what to reach for when a graphic only needs "on or the value, or nothing". Writes immediately.
<Cycle name="period" label="Game" options={['Game 1', 'Game 2', 'Tiebreak']} />// One option, so it toggles between that value and nothing
<Cycle name="status" label="Live" options={['LIVE']} />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
label | string | Shown above the control. | |
name | string | Yes | Names a value under variables — e.g. home.score. |
options | string[] | Stepped through in order, wrapping back to unset. One option makes it a checkbox. |
ColorPicker
import { ColorPicker } from '@single-studio/core/control'
A colour, as a swatch to pick from and a hex field to type into. Pair it with Scene's vars to drive anything a stylesheet can express. Staged until saved.
<ColorPicker name="home.color" label="Home colour" presets={['#0a3161', '#c8102e']} />// and on the graphic
<Scene vars={{ '--home': 'home.color' }}>
<div style={{ background: 'var(--home, #0a3161)' }} />
</Scene>| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
fallback | string | Shown when nothing is set. Defaults to "#0ea5e9". | |
label | string | Shown above the control. Defaults to "Color". | |
name | string | Yes | Names a value under variables — e.g. home.score. |
presets | string[] | Swatches offered beside the picker. |
ImagePicker
import { ImagePicker } from '@single-studio/core/control'
One image, chosen by name from the studio's library, with a preview beside the dropdown and a magnifier to open the library itself. Writes asset:<key>. Staged until saved.
<ImagePicker name="guest.photo" label="Guest photo" /><ImagePicker name="sponsor.logo" label="Sponsor" />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
label | string | Shown above the control. Defaults to "Image". | |
name | string | Yes | Names a value under variables — e.g. home.score. |
ImageSelect
import { ImageSelect } from '@single-studio/core/control'
Choose by picture rather than by name — a grid of tiles, which is what an operator can aim at inside a draft timer. multiple collects several. Writes immediately, or staged to hold it for a save.
const FACTIONS = [
{ label: 'Vanguard', value: 'vanguard', image: './factions/vanguard.svg' },
{ label: 'Syndicate', value: 'syndicate', image: './factions/syndicate.svg' },
]
<ImageSelect name="home.faction" label="Faction" options={FACTIONS} />// The other half of the pair, in a graphic rather than on the board: the value
// this control writes ('vanguard') is what <Image> templates into a file name.
// Keep the list in one module and import it into both, so the two cannot drift.
<Image name="home.faction" src="./factions/:value:.svg" alt="" />// Several, capped, and held until saved
<ImageSelect name="home.army" label="Army" options={UNITS} multiple max={8} staged />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
label | string | Shown above the control. Defaults to "Select". | |
max | number | Cap on how many, when multiple. | |
multiple | boolean | Choose several. The value becomes a comma-separated list. | |
name | string | Yes | Names a value under variables — e.g. home.score. |
options | Array<string | { label?: string, value: string, image?: string }> | What can be chosen, shown as pictures. A bare string is all three. | |
size | 'sm' | 'md' | 'lg' | Tile size. Defaults to "md". | |
staged | boolean | Hold the choice until saved, rather than writing on click. |
ImageToggle
import { ImageToggle } from '@single-studio/core/control'
An on/off button with a picture on it. group makes a row of them behave like radio buttons, which is how a scene picker is usually built. Writes immediately.
<ImageToggle name="lowerthird" label="Lower third" image="/ui/lower-third.svg" />// One at a time. Same group name on each; nothing lists the others
<ImageToggle name="replay" image="/ui/replay.svg" group="feed" />
<ImageToggle name="live" image="/ui/live.svg" group="feed" />
<ImageToggle name="stats" image="/ui/stats.svg" group="feed" />// The picture comes from whatever the operator picked, not a fixed file
<ImageToggle name="sponsor" from="variables.sponsor.logo" image="/ui/sponsor.svg" />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
from | string | Read the picture from this path instead of image. | |
group | string | A group's name. Buttons sharing one behave as radio buttons. | |
image | string | The picture on the button. | |
label | string | Shown above the control. | |
name | string | Yes | Names a value under toggles — e.g. lowerthird. |
size | 'sm' | 'md' | 'lg' | Defaults to "md". |
Toggle
import { Toggle } from '@single-studio/core/control'
An on/off button for a path under toggles, which is what a graphic watches to know whether to be on air. group turns a set of them into radio buttons. Writes immediately.
<Toggle name="lowerthird" label="Lower third" />// Exactly one of these can be on at a time
<Toggle name="stats" label="Stats" group="panels" />
<Toggle name="roster" label="Roster" group="panels" />
<Toggle name="bracket" label="Bracket" group="panels" />| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | Replaces the generated "Show <label>" text. | |
className | string | Added to the component's own classes. | |
group | string | A group's name. Buttons sharing one behave as radio buttons. | |
label | string | Names what is toggled: the button reads "Show <label>". | |
name | string | Yes | Names a value under toggles — e.g. lowerthird. |
SwapButton
import { SwapButton } from '@single-studio/core/control'
Trade two sides of the board — teams changing ends. Asks first.
<SwapButton label="sides" names={['home.name', 'home.score', 'away.name', 'away.score']} />// Longer sides stay readable, because neither half is written backwards
<SwapButton
label="sides"
names={['home.name', 'home.city', 'home.colour', 'away.name', 'away.city', 'away.colour']}
/>// `paths` reaches outside `variables`, which `names` does not
<SwapButton label="scenes" paths={['toggles.left', 'toggles.right']} />| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | Replaces the generated text. | |
className | string | Added to the component's own classes. | |
confirm | boolean | Ask before trading. Defaults to true; pass confirm={false} to trade on one press. | |
label | string | Names what gets traded, on the button. Defaults to "Swap". | |
names | string[] | One side, then the other, spelled the same way. Cut in half and traded. | |
paths | string[] | Full paths, for trading values outside variables. |
ResetButton
import { ResetButton } from '@single-studio/core/control'
Clear a set of values back to each source's own fallback. It unsets rather than writing empties, so a graphic falls back rather than going blank. Asks first.
<ResetButton label="scores" names={['home.score', 'away.score']} />// One press, for something trivial to put back
<ResetButton label="the note" names={['lowerthird.note']} confirm={false} />| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | Replaces the generated "Reset <label>" text. | |
className | string | Added to the component's own classes. | |
confirm | boolean | Ask before clearing. Defaults to true; pass confirm={false} for a button that fires on one press. | |
label | string | Names what gets cleared: the button reads "Reset <label>". Defaults to "Reset". | |
names | string[] | Cleared back to each source's own fallback. | |
paths | string[] | Full paths, for clearing toggles or timers in the same press. |
Countdown
import { Countdown } from '@single-studio/core/control'
Counts down a duration — a break, a half, a stinger. Without duration the operator types one; with it the control is a single press. Writes immediately.
<Countdown name="round" label="Round" />// Always the same length, so one press starts it
<Countdown name="break" label="break" duration="5:00" />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
duration | string | number | A fixed length, e.g. "5:00". Without it the operator types one. | |
label | string | Shown above the control, and on the running clock. | |
name | string | Yes | Names a value under timers — e.g. round. |
placeholder | string | Hint in the duration field. Defaults to "5:00". |
CountdownTo
import { CountdownTo } from '@single-studio/core/control'
Counts down to a time of day rather than a length — "we go live at 19:30". Rolls to tomorrow if the time has already passed today. Writes immediately.
<CountdownTo name="showtime" label="Doors open" />// Something further out than today
<CountdownTo name="finals" label="Finals" as="datetime-local" />| Prop | Type | Required | Description |
|---|---|---|---|
as | 'time' | 'datetime-local' | "time" takes HH:MM and rolls to tomorrow if past. Defaults to "time". | |
className | string | Added to the component's own classes. | |
label | string | Shown above the control. Defaults to "Starts at". | |
name | string | Yes | Names a value under timers — e.g. round. |
Stopwatch
import { Stopwatch } from '@single-studio/core/control'
Counts up from when it was started, with pause and reset. Stores an origin rather than a running total, so every machine derives the same number. Writes immediately.
<Stopwatch name="match" label="Show elapsed" />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
label | string | Shown above the control. Defaults to "Stopwatch". | |
name | string | Yes | Names a value under timers — e.g. round. |
Leaderboard
import { Leaderboard } from '@single-studio/core/control'
A table an operator can paste into or edit row by row, stored as one delimited string. fields names the columns; the graphic parses it back out. Staged until saved.
<Leaderboard name="standings" fields={['Team', 'W', 'L']} rows={8} />// Pasted straight out of a spreadsheet
<Leaderboard name="results" fields={['Driver', 'Time']} delimiter="\t" />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
delimiter | string | What separates columns in the stored string. | |
fields | string[] | Column names, in order. | |
label | string | Shown above the control. Defaults to "Leaderboard". | |
name | string | Yes | Names a value under variables — e.g. home.score. |
rows | number | How many rows the table shows. |
Panel
import { Panel } from '@single-studio/core/control'
A titled group of controls that arranges itself. The controls sit side by side and drop onto the next line when they run out of room, so one board works both in a narrow OBS dock and full screen on a second monitor without you writing a layout for either.
<Panel title="Scores">
<Field name="home.name" label="Home" />
<Stepper name="home.score" label="Home score" />
</Panel>| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | Controls. They sit side by side and wrap onto the next line as needed. | |
className | string | Added to the component's own classes. | |
title | string | Heading for the group. |
Break
import { Break } from '@single-studio/core/control'
Forces a line break inside a Panel, for when the natural wrap puts related controls on different rows.
<Panel title="Scores">
<Stepper name="home.score" label="Home" />
<Break />
<Select name="period" options={PERIODS} />
</Panel>| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. |
Confirm
import { Confirm } from '@single-studio/core/control'
A destructive button that asks first, without a dialog: one click arms it, a second does it, and a few seconds of silence disarms it. Exported for actions of your own — the built-in controls that destroy something already ask on their own, so reach for this when a mutation you wrote needs the same care.
<Confirm label="Remove all" onConfirm={() => library.removeAll()} />// Reversible, so it warns rather than alarms, and says its own thing when armed
<Confirm label="Disconnect" tone="warn" ask="Leave the room?" onConfirm={leave} />// Ordinary enough not to shout, and off while there is nothing to do
<Confirm label="Clear queue" tone="quiet" disabled={!queue.length} onConfirm={clear} />// The children form, for a button that is an icon rather than a sentence
<Confirm tone="danger" ask="Again to delete" onConfirm={remove} aria-label="Delete">
<Icon name="trash" />
</Confirm>| Prop | Type | Required | Description |
|---|---|---|---|
ask | string | What it says once armed. Defaults to "Click to confirm". | |
children | ReactNode | Replaces label when idle. | |
className | string | Added to the component's own classes. | |
disabled | boolean | Nothing happens on click. | |
label | string | What the button says when idle. | |
onConfirm | () => void | Yes | Called on the second click. |
tone | 'danger' | 'warn' | 'go' | 'primary' | 'quiet' | What the button means. Defaults to "danger". |
Hotkeys
import { Hotkeys } from '@single-studio/core/control'
Lets an operator choose which keys save and discard. Ctrl/Cmd+S is a default rather than a rule — it collides with habits from other software, and on some layouts it is awkward — and discard can be put on a key too, which it is not by default. Bindings belong to the operator rather than the show, so rebinding one does not move anybody else's, and they are stored with the studio rather than the machine, so they travel with it. The board's menu already offers this, so place the panel only if you want it on the board itself.
<Panel title="Shortcuts">
<Hotkeys />
</Panel>| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. |
Source
What goes on air — @single-studio/core/source. Each of these lives in a graphic under src/sources/, one file per OBS browser source, wrapped in a Scene. They read the same paths the control surface writes and render nothing until the value has arrived, so a graphic reopening mid-show never flashes a placeholder over the programme.
Scene
import { Scene } from '@single-studio/core/source'
The root of a graphic — one per OBS browser source. vars maps CSS custom properties to values an operator controls, which is how a graphic follows input the framework has no component for.
export default function Scoreboard() {
return (
<Scene>
<Variable name="home.name" fallback="Home" />
</Scene>
)
}// A team colour driving anything the stylesheet can express
<Scene vars={{ '--home': 'home.color' }}>
<div style={{ background: 'var(--home, #0a3161)' }} />
</Scene>| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | The graphic. | |
className | string | Added to the component's own classes. | |
height | number | string | A fixed height. A number is pixels; a string is used as written. | |
vars | Record<string, string> | CSS custom property to value name, e.g. { "--accent": "home.color" }. | |
width | number | string | A fixed width. A number is pixels; a string is used as written. |
Variable
import { Variable } from '@single-studio/core/source'
One value on air, as text. This is the component most graphics are mostly made of — a name, a score, a subtitle.
<Variable name="home.name" fallback="Home" />// Shrink to fit rather than overflow a fixed box
<Variable name="guest.title" fallback="Guest" fit /><Variable name="lowerthird.headline" fallback="" />| Prop | Type | Required | Description |
|---|---|---|---|
as | string | The element to render. Defaults to "span", so a value can sit inside a sentence. | |
className | string | Added to the component's own classes. | |
fallback | string | Shown when the value is empty. Defaults to "". | |
fit | boolean | number | Shrink the text to fit its box. A number caps how far. | |
name | string | Yes | Names a value under variables — e.g. home.score. |
transition | string | Motion variants, space-separated — e.g. "slide-up ease-back". See the transitions guide. |
Image
import { Image } from '@single-studio/core/source'
A picture chosen by a value the operator controls. Loads and decodes off-screen first and only swaps once ready, so a change never leaves a hole on air.
// No `src`: the stored value is the URL, or an `asset:` key from the library
<Image name="sponsor.logo" alt="" />// Templated: "Single Studio" resolves /logos/single-studio.svg
<Image name="home.name" src="/logos/:value:.svg" slug fallback="/logos/tbd.svg" />// `value` instead of `name`: a plain string, not a path. Nothing is read from
// the store, so this is for a component already holding the value itself.
<Image value="https://cdn.example.com/acme.svg" alt="Acme" />
<Image value="asset:acme-logo" alt="Acme" />
<Image value="vanguard" src="./factions/:value:.svg" alt="Vanguard" />| Prop | Type | Required | Description |
|---|---|---|---|
alt | string | Alt text. | |
className | string | Added to the component's own classes. | |
fallback | string | URL used when the value is empty or fails to load. | |
fit | 'cover' | 'contain' | 'fill' | 'none' | 'scale-down' | Fill the box this way instead of sitting inside it — "cover" for a backdrop. | |
name | string | Yes | Names a value under variables — e.g. home.score. |
slug | boolean | Slugify the value first — "Single Studio" becomes single-studio. | |
src | string | URL template; :value: is replaced. Defaults to ":value:", so a pasted URL just works. | |
transition | string | Motion variants, space-separated — e.g. "slide-up ease-back". See the transitions guide. | |
value | string | A value outright rather than a path to one. Wins over name. |
ImageList
import { ImageList } from '@single-studio/core/source'
Several pictures from one value — what ImageSelect multiple writes. Each entry is templated exactly as Image templates one.
<ImageList name="home.army" src="/units/:value:.svg" slug />// Cap what goes on air, whatever the operator picked
<ImageList name="home.army" limit={8} itemClassName="h-10 w-10" />| Prop | Type | Required | Description |
|---|---|---|---|
alt | string | Alt text for every image. | |
className | string | Added to the component's own classes. | |
fallback | string | URL used for an entry that fails to load. | |
itemClassName | string | Added to each image rather than to the list. | |
limit | number | Render at most this many entries. | |
name | string | Yes | Names a value under variables — e.g. home.score. |
slug | boolean | Slugify each value first — "Single Studio" becomes single-studio. | |
src | string | URL template; :value: is replaced by each entry. Defaults to ":value:". | |
transition | string | Motion variants, space-separated — e.g. "slide-up ease-back". See the transitions guide. |
Slideshow
import { Slideshow } from '@single-studio/core/source'
A folder of pictures, playing. What a standby screen is made of.
<Slideshow group="slides" every={9} order="shuffle" />// The folder, unless the operator has picked from it
<Slideshow group="slides" name="standby.slides" every="0:12" />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
every | string | number | How long each picture holds — seconds, or "m:ss". Defaults to 8. | |
fit | 'cover' | 'contain' | How a picture fills the frame. Defaults to "cover". | |
group | string | Plays everything in the image library filed under this group — "slides" reads slides/…. | |
limit | number | Play at most this many. | |
name | string | Names a list under variables — e.g. standby.slides. Takes over from group whenever it holds anything. | |
order | 'sequence' | 'shuffle' | In order, or a fresh deal each pass. Defaults to "sequence". | |
preload | number | How many either side of the current one hold a decoded image. Defaults to 1. |
Tally
import { Tally } from '@single-studio/core/source'
A number said in icons. Three demolitions is three icons, not the word three.
<Tally name="home.demolitions" src="./icons/demo.svg" />// A best-of-five: three to win, won ones filled
<Tally name="home.games" of={3} src="./pips/won.svg" empty="./pips/empty.svg" />// The race length is the operator's
<Tally name="home.games" of="series.wins" src="./pips/won.svg" />| Prop | Type | Required | Description |
|---|---|---|---|
alt | string | Alt text for every mark. | |
className | string | Added to the component's own classes. | |
empty | string | The mark for one not yet filled. Without it an unfilled mark holds its space and shows nothing. | |
itemClassName | string | Added to each mark rather than to the row. | |
max | number | The most marks to draw without an of. Defaults to 12; 0 for no bound. | |
name | string | Yes | Names a count under variables — e.g. home.demolitions. |
of | number | string | Draw this many marks and fill the count — a number, or a path an operator sets. | |
src | string | Yes | The mark. A path, a URL, or a library entry, the same as Image takes. |
transition | string | Motion variants for a mark arriving or filling, space-separated — e.g. "zoom ease-back". See the transitions guide. |
Toggle
import { Toggle } from '@single-studio/core/source'
Shows its children while a toggle is on, and animates them in and out. This is how a whole graphic is put on and taken off air.
<Toggle name="lowerthird">
<LowerThird />
</Toggle><Toggle name="stats" transition="slide-up ease-back">
<StatsCard />
</Toggle>| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | Rendered always; visible while the toggle is on. | |
className | string | Added to the component's own classes. | |
name | string | Yes | Names a value under toggles — e.g. lowerthird. |
transition | string | Motion variants, space-separated — e.g. "slide-up ease-back". See the transitions guide. |
Timer
import { Timer } from '@single-studio/core/source'
A clock on air, reading whichever kind was stored — a countdown, a count-up, or a paused one. A finished countdown takes itself off air; nobody has to remember to clear it mid-show.
<Timer name="round" fallback="--:--" />// Red once the segment has run past two minutes
<Timer name="segment" limit="2:00" className="text-white [&[data-over]]:text-red-500" />// Do something when the clock runs out
<Timer name="break" onComplete={() => setScene("live")} />| Prop | Type | Required | Description |
|---|---|---|---|
as | string | The element to render. Defaults to "span". | |
className | string | Added to the component's own classes. | |
fallback | string | Shown when no clock is set. Defaults to "00:00". | |
limit | string | number | How long a count-up may run — "2:00", or seconds. Past it, the element gets data-over and ss-over. | |
name | string | Yes | Names a value under timers — e.g. round. |
onComplete | () => void | Called once, when a countdown reaches zero. | |
transition | string | Motion variants, space-separated — e.g. "slide-up ease-back". See the transitions guide. |
Ticker
import { Ticker } from '@single-studio/core/source'
Text scrolling across the bottom of the screen, looping continuously. Speed is in pixels per second, so a long crawl and a short one read at the same pace.
<Ticker name="headlines" /><Ticker name="headlines" speed={60} fallback="" className="text-2xl" />| Prop | Type | Required | Description |
|---|---|---|---|
className | string | Added to the component's own classes. | |
fallback | string | Shown when the value is empty. | |
name | string | Yes | Names a value under variables — e.g. home.score. |
speed | number | Pixels per second. Defaults to 100. |
Clock
import { Clock } from '@single-studio/core/source'
The time of day, from the machine the graphic is running on. Nothing replicates here — every browser source reads its own clock.
<Clock /><Clock locale="en-GB" options={{ hour: '2-digit', minute: '2-digit' }} />// Another city's time, named, for a show with a remote guest
<Clock options={{ timeZone: 'America/New_York', timeStyle: 'short', timeZoneName: 'short' }} />| Prop | Type | Required | Description |
|---|---|---|---|
as | string | The element to render. Defaults to "span". | |
className | string | Added to the component's own classes. | |
locale | string | A BCP 47 language tag, e.g. en-GB. Defaults to the browser's. | |
options | Intl.DateTimeFormatOptions | Passed straight to Intl.DateTimeFormat. |