Beeesign is a dark, spring-loaded UI kit extracted from the Beeer beer-collecting app: ink-black grounds, pill controls, one rare red accent, a single typeface and one spring that moves everything you can touch. It ships one theme, Dark.
безалк. (or 0,0 % when the ABV is exactly zero). Unknown fields stay empty, never invented.%.background, raise content onto surface, nest wells on surface-secondary. Body text is text-primary, captions text-secondary. The primary button is light ink (action-primary with text-on-action-primary), not the accent. The accent is rare: switch track on, selected marks. Accent text is text-accent, never accent (3.7:1 on background).focus-ring, 2px, offset 2px.section-title for screen titles (38/38), headline for rows, body for reading, button for actions, footnote for captions. Group labels are 11px, uppercase, tracked +1.32px.screen-x 18, card padding card-pad 18, stack gap stack 10.separator lines, not shadows. The one place depth is allowed is glass: floating bars use glass-fill, a blur and a specular edge over content (see TabBar).size-touch (44px). Disabled controls drop to opacity-disabled.spring-mass, spring-stiffness, spring-damping) for press, switch, sliding indicators, glass lens, tickers and entrances; timed curves only for scene transitions. Reduced motion jumps to the end value. See the Motion section.camera-void.24px grid, 1.75 stroke, round caps and joins, single colour from currentColor (size-icon-stroke). The TabBar ships four icons (shelf, rank, me, add); anything else comes from the host app on the same grid and stroke.
Load tokens.css, bundle.css, React 18 and bundle.js; everything is on window.Beeesign. Set data-theme="dark" on <html>. Components read tokens as CSS variables and never branch on the theme.
#000000Page and screen ground. Text roles text-primary and text-secondary are checked against it.#141414Cards, sheets, dialogs, tab bar and fields. Holds text-primary, text-secondary and text-accent.#232323Ghost buttons, nested wells and the second layer inside a card.#F2F2F2Body copy and headings on background, surface and surface-secondary.#A6A6A6Captions, labels, field borders and secondary icons on background and surface.#2B2B2BHairlines between rows, header dividers, card edges. Decorative, not a text colour.#D7261EBrand fill: switch track on, selected marks. Never body text; it is about 3.7:1 on background, so accent text uses text-accent.#FF5A52Accent-coloured text and invalid-field borders on background and surface.#FFFFFFText and icons drawn on an accent fill.#F2F2F22px focus outline offset 2px, 3:1 or better on background and surface in every theme.#1C1C1CLoading placeholders on background and surface.rgba(0,0,0,0.62)Dimmer behind dialogs and sheets.#F2F2F2Toast background; the opposite end of the theme from surface.#000000Text on inverse-surface (toasts).#F2F2F2Primary button fill. Ink-coloured in every theme, so the accent stays rare.#000000Primary button label on action-primary.#3A3A3ASwitch track when off.#141414Segmented control track.#F2F2F2Selected segment fill.#000000Label on segment-selected-bg.#F2F2F2Switch thumb.#2A2A2ALeaderboard row that belongs to the viewer.#2FBF71Non-alcoholic badge fill. Always paired with the word, never colour alone.#06210FBadge text on signal-green.#15171ACamera viewfinder ground; identical in all themes.#F2F2F2Chart series 1: the lead segment.#D7261EChart series 2.#8C8C8CChart series 3.#555555Chart series 4.#333333Chart series 5. Segments are separated by a gap, not by hue alone.rgba(22,22,22,0.8)Liquid-glass surface (tab bar) over content, with a 28px blur. text-secondary and text-accent hold 4.5:1 on it over backdrops up to #808080; over lighter content add a scrim.rgba(255,255,255,0.16)The moving lens under the selected glass tab.rgba(255,255,255,0.22)Hairline edge of glass surfaces; a mark, 3:1 against background.rgba(255,255,255,0.38)Specular top edge of glass surfaces and the lens.Medeo Sans, веса 400, 600, 700.
section-title · 38px/38px · 700Screen titles.accent-number · 34px/44px · 600Big stat numbers, tabular.wordmark · 15px/20px · 700The wordmark in headers, tracked +2.4px.dialog-title · 19px/24px · 600Dialog titles.headline · 17px/22px · 600Row and card headlines.body · 15px/20px · 400Reading text.body-strong · 15px/20px · 600Emphasis inside body copy.button · 15px/20px · 600Primary button label.button-secondary · 15px/20px · 400Ghost button label.list-row · 15px/20px · 400List rows.list-row-selected · 15px/20px · 600Selected list row.input · 16px/20px · 400Field text; 16px keeps iOS from zooming on focus.unit · 17px/20px · 400Units next to big numbers.control · 14px/20px · 400Segments, chips, toast copy.control-strong · 14px/20px · 600Selected segment, toast action.dialog-body · 14px/19px · 400Dialog paragraphs.subhead · 13px/18px · 400Sub-headings, helper text.body-small · 13px/20px · 400Dense paragraphs.footnote · 12px/16px · 400Footnotes and timestamps.footnote-strong · 12px/16px · 600Emphasised footnotes, avatar initials (small).tab-label · 12px/14px · 400Tab labels.tab-label-selected · 12px/14px · 600Selected tab label.badge · 11px/18px · 600Badge text.group-label · 11px/16px · 400Group labels over lists; set uppercase in components.field-label · 13px/16px · 400Labels above fields.| Токен | Значение | Назначение |
|---|---|---|
space-2 | 2px | Gap and padding step from the Beeer scale (2,4,6,8,10,12,14,16,18,20). |
space-4 | 4px | Gap and padding step from the Beeer scale (2,4,6,8,10,12,14,16,18,20). |
space-6 | 6px | Gap and padding step from the Beeer scale (2,4,6,8,10,12,14,16,18,20). |
space-8 | 8px | Gap and padding step from the Beeer scale (2,4,6,8,10,12,14,16,18,20). |
space-10 | 10px | Gap and padding step from the Beeer scale (2,4,6,8,10,12,14,16,18,20). |
space-12 | 12px | Gap and padding step from the Beeer scale (2,4,6,8,10,12,14,16,18,20). |
space-14 | 14px | Gap and padding step from the Beeer scale (2,4,6,8,10,12,14,16,18,20). |
space-16 | 16px | Gap and padding step from the Beeer scale (2,4,6,8,10,12,14,16,18,20). |
space-18 | 18px | Gap and padding step from the Beeer scale (2,4,6,8,10,12,14,16,18,20). |
space-20 | 20px | Largest scale step; also the default screen gutter. |
screen-x | 18px | Horizontal screen gutter. |
card-pad | 18px | Card padding. |
stack | 10px | Vertical gap between stacked cards. |
| Токен | Значение | Назначение |
|---|---|---|
radius-card | 22px | Cards. |
radius-control | 999px | Buttons and fields: pill. |
radius-row | 999px | List rows: pill. |
radius-overlay | 22px | Dialogs and sheets. |
radius-segment | 996px | Selected segment pill. |
radius-chip | 999px | Chips and tags. |
radius-pill | 999px | Pills, badges, avatars. |
radius-track | 999px | Switch track. |
radius-thumb | 999px | Switch thumb. |
| Токен | Значение | Назначение |
|---|---|---|
size-touch | 44px | Minimum touch target and default button/field height. |
size-touch-large | 48px | Dialog actions, large targets. |
size-row | 52px | Standard list row. |
size-row-large | 56px | Large row and action-bar button. |
size-row-switch | 72px | Row that carries a switch and a description. |
size-icon-sm | 18px | Small icon. |
size-icon-md | 20px | Standard icon. |
size-icon-tab | 22px | Tab icon. |
size-icon-lg | 24px | Large icon. |
size-icon-stroke | 1.75 | Icon stroke width; 2 for emphasis. |
size-focus-width | 2px | Focus ring width. |
size-focus-offset | 2px | Focus ring offset. |
size-switch-w | 46px | Switch track width. |
size-switch-h | 28px | Switch track height. |
size-switch-thumb | 22px | Switch thumb diameter; inset 3px, travel 18px. |
size-segment-h | 40px | Segment item height; track padding 3px, gap 4px. |
size-avatar | 52px | Avatar; small is 32px. |
size-badge-h | 18px | Badge height. |
size-toast-h | 44px | Toast minimum height; sits 88px above the bottom. |
size-bar-h | 12px | Stacked chart bar height; segment gap 3px. |
size-glass-blur | 28px | Backdrop blur radius of glass surfaces. |
size-tabbar-h | 64px | Glass tab bar height (4px inset, 56px tabs). |
Dark separates surfaces with 1px lines, not shadows: the card shadow is none.
| Токен | Значение | Назначение |
|---|---|---|
shadow-card | none | Cards: none; Dark separates with lines. |
shadow-toast | 0px 6px 20px 0px rgba(0,0,0,0.18) | Toasts floating over content. |
shadow-overlay | 0px 10px 30px 0px rgba(0,0,0,0.25) | Dialogs and sheets. |
shadow-segment | none | Selected segment: none. |
shadow-thumb | 0px 1px 2px 0px rgba(0,0,0,0.25) | Switch thumb. |
shadow-glass | 0px 8px 32px 0px rgba(0,0,0,0.5) | Floating glass tab bar. |
| Токен | Значение | Назначение |
|---|---|---|
opacity-disabled | 0.45 | Disabled controls. |
opacity-press | 0.78 | Pressed controls, together with scale 0.98. |
| Токен | Значение | Назначение |
|---|---|---|
layer-content | 0 | Scrolling content. |
layer-sticky | 1 | Sticky rows. |
layer-bar | 2 | Bottom bar. |
layer-toast | 3 | Toasts. |
layer-overlay | 4 | Dialogs, sheets, scrims. |
Everything that responds to a finger is a spring. Everything that stages a scene is a curve. Spring numbers are tokens (spring-), curves are ease-, durations duration-*; the JS helpers on window.Beeesign.motion implement all of this.
mass 1 · stiffness 350 · damping 30 (Reanimated withSpring). Damping ratio ζ = c / (2√(k·m)) = 0.80, so it starts fast, overshoots 1–3 % and rests in about 300 ms. It is the only spring in the interface: press, switch, indicator, ticker, entrances, layout. Interruptible: a new target starts from the current position and velocity.
Beeesign.motion.spring({ from: 0, to: 1, onUpdate: v => el.style.opacity = v });
| Behaviour | Recipe | Used by | ||
|---|---|---|---|---|
| Press | Spring a down value 0→1 on press-in, 1→0 on press-out; scale = 1 − 0.02·down (spring-press-scale 0.98), opacity = 1 − 0.22·down (opacity-press 0.78). Reduced motion: scale stays 1. Add a light haptic on release. | SpringPressable, Button | ||
| Sliding indicator | The selection pill springs to the new slot. In the glass TabBar it is a lens: it lifts (scale up to spring-lens-lift 1.12) while pressed, follows the finger, and on release springs to the nearest tab carrying the release velocity. Distance travelled `k = min(1.5, | goal − x | / slot); while it moves it stretches scaleX = 1 + 0.22·k and squeezes scaleY = 1 − 0.1·k`, so it reads as a drop of liquid. | SegmentedControl, TabBar |
| Ticker | When a value changes, the old one rolls out and the new one rolls in, one line height, spring-driven. A larger number rolls up, a smaller one rolls down; text always rolls up. | Ticker, StatCard | ||
| Layout spring | A container changes width or height continuously (Reanimated LinearTransition.springify() with the same mass/stiffness/damping), no unmount. | lists, chips | ||
| Switch | Thumb travels 18px on the Beeesign spring; track colour changes in duration-state. | Switch | ||
| Entrance (addition of this system, not yet in the app) | Toast rises 16px on the Beeesign spring while fading in over duration-fade; dialogs scale 0.96→1 the same way. | Toast, Dialog |
| Scene | Timing |
|---|---|
| Bottom sheet peek ⇄ expanded | duration-sheet 420 ms, ease-sheet |
| Curtain in / out | duration-curtain-in 700 ms, duration-curtain-out 600 ms, ease-curtain; content scale-in 1100 ms after a 120 ms delay |
| XP count-up | duration-count 1200 ms, ease-out-cubic |
| Scan overlay intensity | duration-scan-fade 300 ms; the scan line loops linear |
| Card lift on drag | 150 ms, translateY −18 |
| Camera flight between slots | ease-flight |
Free-moving 3D objects use the physics form x'' = −k(x − target) − c·x', integrated each frame with dt clamped to 1–64 ms.
| Object | k | c |
|---|---|---|
| Fridge door, open | 34 | 12 |
| Fridge door, close (overshoot −0.8°) | 48 | 13.5 |
| Door, reduced motion | 400 | 40 |
A bottle cap is thrown from below, spins an integer number of turns, and lands face-on, then bursts and can be spun by finger.
REVEAL = { turns 7, kick 2.6, rise 0.8 s, stop 0.36, burst 1.2, scale 0.85 }. Rise follows y = y0 + (yA − y0)·(1 − (1 − t/rise)^kick); after the apex it falls under gravity g = 2(yA − y0)/rise² until it reaches the stop line capY = hh·(1 − 2·stop). Rotation is ω·t with ω = 2π·round(turns)/T, so it lands on a whole number of turns. A selection haptic ticks on every full revolution; none on landing.1 + 0.16·k·e^(−7b)·sin(22b + 0.6) (b = seconds since landing, k = burst). A medium haptic fires on the first frame.v = 0.6·v + 0.4·(dx·0.012 / dt) and clamped to ±9 rad/s; on release the cap coasts and settles to the nearest face, round(rotY/π)·π.selection (revolution tick), light (button press, release), medium (burst), heavy, success (card saved). A failing haptic motor must never break an animation.
If the user prefers reduced motion: springs jump to their target, press scale is 1, the reveal shows its end pose, door springs use the reduced pair. Information must never depend on motion.
linear, ease-in-out or a duration for a pressed, dragged or toggled control.mass / stiffness / damping as in Reanimated withSpring. Spring-driven properties never use timing curves.
| Токен | Значение | Назначение |
|---|---|---|
spring-mass | 1 | Beeesign spring: mass. |
spring-stiffness | 350 | Beeesign spring: stiffness. Settles in about 300ms with 1-3% overshoot. |
spring-damping | 30 | Beeesign spring: damping (damping ratio about 0.80). |
spring-press-scale | 0.98 | Pressed scale target. |
spring-stretch-x | 0.22 | Sliding indicator: extra scaleX per slot travelled (clamped at 1.5 slots). |
spring-stretch-y | 0.1 | Sliding indicator: scaleY squeeze per slot travelled. |
spring-door-open-k | 34 | Fridge door, opening: spring constant k (physics form, see Motion). |
spring-door-open-c | 12 | Fridge door, opening: damping c. |
spring-door-close-k | 48 | Fridge door, closing: k. |
spring-door-close-c | 13.5 | Fridge door, closing: c. |
spring-reduced-k | 400 | Reduced-motion door: k (near-instant). |
spring-reduced-c | 40 | Reduced-motion door: c. |
spring-lens-lift | 1.12 | Glass lens scale while pressed or dragged. |
Timed animations. Interactive motion uses springs instead (see Motion).
| Токен | Значение | Назначение |
|---|---|---|
duration-press | 80ms | Legacy press fade; the live press is a spring. |
duration-state | 150ms | State colour changes, card lift on drag. |
duration-fade | 200ms | Fades. |
duration-overlay-exit | 150ms | Overlay dismissal. |
duration-scan-fade | 300ms | Scan overlay intensity fade. |
duration-sheet | 420ms | Bottom sheet between peek and expanded, ease-sheet. |
duration-curtain-out | 600ms | Curtain leaving, ease-curtain. |
duration-curtain-in | 700ms | Curtain arriving, ease-curtain. |
duration-curtain-zoom | 1100ms | Curtain content scale-in. |
duration-count | 1200ms | XP count-up, ease-out-cubic. |
duration-toast | 5000ms | Toast lifetime; 10000ms with a screen reader. |
| Токен | Значение | Назначение |
|---|---|---|
ease-curtain | cubic-bezier(0.22, 1, 0.36, 1) | Curtain and reveal entrances: quick, long settle. |
ease-sheet | cubic-bezier(0.2, 0.9, 0.3, 1) | Bottom sheet travel. |
ease-flight | cubic-bezier(0.65, 0, 0.35, 1) | Camera fly-between-slots. |
ease-out-cubic | cubic-bezier(0.33, 1, 0.68, 1) | Count-ups. |
ease-out-quad | cubic-bezier(0.5, 1, 0.89, 1) | Fades. |
Beeesign has one theme, Dark (data-theme="dark"), the Nothing theme of the Beeer app renamed and moved to Medeo Sans throughout.
| Dark | |
|---|---|
| Scheme | dark (OLED black ground) |
| Cards | 22px, flat, no border |
| Controls and rows | pill |
| Gutter / card padding / stack | 18 / 18 / 10 |
| Type | Medeo Sans 400, 600, 700; group labels 11px uppercase +1.32 |
| Segment | light pill on a surface track |
| Tab bar | liquid glass capsule with a lens |
| Chart palette | white, red, then greys |
color.themes and a value for every colour token (a missing one inherits Dark).[data-theme="<id>"] block to bundle.css for structural overrides (radius, gutter, card border, label style) declaring every variable the Dark block declares.The Beeer app wordmark (beeer-logo-smooth.svg), a single-ink mark drawn in #1B120B (warm near-black). <img> cannot inherit colour, so on Dark grounds place it on a light plate. Keep clear space of one letter height; do not recolour or redraw it.