hugo-music
v0.6.0
Published
Frosted-glass UI kit with droplet motion for React Native and Expo — native and web
Maintainers
Readme
Hugo Music
Frosted-glass UI kit with droplet motion for React Native and Expo. One codebase for native apps and the web: translucent glass surfaces that blur what scrolls behind them, controls that squash and spring back like drops of water, and a calm layout system built on large titles, grouped lists and generous touch targets.
Install
npx expo install hugo-music @expo/vector-icons expo-blur expo-glass-effect expo-linear-gradient react-native-safe-area-contextThe peer packages provide icons, blur, the native glass material, gradients and safe-area insets. Live web refraction is provided by the liquid-glass-web-react dependency. Import icons and gradients from the kit too (Icon, Gradient) so your app depends on a single UI package.
Copy the source instead
Prefer to own the code? The kit is also a component registry in the shadcn format (registry.json in this package, served by the Hugo Music API at /api/registry). One command copies a component, every library file it imports and its npm packages into your project:
npx shadcn@latest add https://<api-host>/api/registry/select-field.json
npx shadcn@latest add https://<api-host>/api/registry/hugo-music.json # the whole kitOr register the namespace once and add items by name:
npx shadcn@latest registry add @hugo-music=https://<api-host>/api/registry/{name}.json
npx shadcn@latest add @hugo-music/glass @hugo-music/action-buttonFiles land in components/hugo-music/ with the library's own folders, so their relative imports keep working. Every component page in the docs also has a Copy the source tab with the same files. A copy no longer receives library updates, so copy only the components you want to change and install the rest. registry.json is generated from the source — never edit it by hand.
Live refraction
LiquidGlass uses liquid-glass-web-react (MIT, Pallav Agarwal) directly on the web. Its SVG displacement map bends live content rather than blurring a screenshot. The demo at /developer/components/LiquidGlass supports dragging, keyboard movement and shape controls. Native platforms keep the content with a native/fallback Glass overlay; the SVG effect is web-only.
<LiquidGlass draggable width={190} height={130} radius={40} strength={0.12}
chromaticAberration={0.3} accessibilityLabel="Move the glass lens">
<View style={{ height: 320 }}><Backdrop variant="mosaic" dim={0} /></View>
</LiquidGlass>Lens width/height are independent of content height. Keep the filtered region small, test on target browsers and leave essential reading outside it. Reduced transparency disables refraction. Web consumers need matching versions of react and react-dom; the scanner also needs expo-camera.
Quick start
import { HugoProvider, LargeTitle, InsetGroup, ListRow, Toggle, ActionButton } from 'hugo-music';
export default function Settings() {
const [soundCheck, setSoundCheck] = useState(true);
return (
<HugoProvider scheme="system">
<LargeTitle title="Settings" />
<InsetGroup header="Playback" footer="Sound Check plays every song at the same volume.">
<ListRow icon="volume-high-outline" title="Sound Check"
right={<Toggle value={soundCheck} onValueChange={setSoundCheck} accessibilityLabel="Sound Check" />} />
</InsetGroup>
<ActionButton title="Done" size="lg" onPress={close} />
</HugoProvider>
);
}HugoProvider is optional. Without it every component follows the device appearance with the default green accent.
Frosted glass
Glass is the material under every floating control. It blurs and saturates what is behind it, adds a soft sheen on the upper half and a bright rim along the edge.
- regular — the default, for bars, toolbars and buttons.
- clear — thinner and more see-through, for controls floating over artwork or video.
- thick — nearly opaque, for side panels and sheets that hold text.
- tint — colours the glass for prominent actions (a primary button, a selected state).
- interactive — the surface reacts to touch where the platform supports it.
When the system asks for reduced transparency, every variant turns into an opaque surface of the same shape — on phones and in browsers.
Content laid over artwork or dark media (a full-screen player, lyrics) uses the onMedia colours — white at fixed strengths for text, fills and borders — instead of one-off values.
Use glass for the layer that floats above content. Keep reading material — long text, lists, forms — on solid surfaces so it stays legible.
Design principles
The kit follows one order of priority: function → content → hierarchy → accessibility → interaction → material → decoration. Glass is a material for one layer, never a decoration for everything.
Three layers.
| Layer | What lives there | Material | Kit components |
|---|---|---|---|
| Content | artwork, text, lists, charts, forms | solid surfaces | Card, InsetGroup, ListRow, MediaTile, Shelf, BarChart, TextField |
| Functional | navigation and controls floating above content | glass | GlassTabBar, NavigationSidebar, BackButton, GlassButton, GlassCapsule, SearchField glass, ContextMenu, Sheet header |
| Interaction | feedback when pressed, focused, opened | motion | droplet press, sliding selection lens, sheets that rise from their control |
Material rules.
regularfor bars, toolbars and controls;clearonly over rich media (artwork, video) where the content must show through;thickfor menus and side panels that hold text. Do not mix them inside one group.- One glass layer over content: no glass inside glass. Several glass shapes that belong together go in one
GlassGroup. - Cards and forms are not glass: content keeps solid, readable surfaces.
- Shadows stay soft (separation, not 3D); blur is the material itself, not an effect added to every component.
- Tint means something — the main action, a state, a destructive action. One accent per screen; never one colour per button.
Hierarchy comes from position, spacing, grouping, size and type first; tint and material come last. No thick borders, heavy gradients or dark backgrounds to make something stand out.
Tokens (use them instead of raw numbers):
| Token | Values |
|---|---|
| space | 2 · 4 · 8 · 12 · 16 · 20 · 24 · 32 — a 4-point rhythm |
| radius | 6 · 10 · 14 · 20 · 28 · pill; nested shapes stay concentric (inner radius = outer radius − padding) |
| type | Large Title 34 → Caption 12, line heights 1.2–1.4; one font family (the system font) |
| motion | fast 140 ms · normal 220 ms · complex 320 ms · morph 420 ms — never a one-second transition for a small change |
| TOUCH | 44-point minimum hit area; a small-looking icon still gets the full target |
| GUTTER | 18-point side margin on phones; wider layouts use 24–32 |
Buttons come in three heights (sm 32, md 44, lg 50), are capsules by default, and have every state: default, hover (web), focus ring (keyboard), pressed (droplet squash), disabled (dimmed but readable) and loading (spinner, presses blocked so an action is never sent twice).
Layout by screen size. Phones: content with a floating tab bar. Tablets and desktops: sidebar + content (+ toolbar) — the layout changes with the space instead of scaling the phone up.
Accessibility is part of the material:
- Reduce Transparency → every glass surface becomes opaque (phones and browsers).
- Reduce Motion → controls stop squashing and bouncing; only a short highlight remains.
- Keyboard → every control shows a 2-point focus ring.
- Contrast → text on its background and white on the accent stay at 4.5:1; screen readers get roles, names and states from every component.
Do: content first · glass for navigation and key controls · subtle, meaningful tint · consistent spacing and concentric corners · motion that connects a control to what it opens · accessible contrast. Don't: glass everywhere · glass on glass · heavy shadows, thick borders, strong gradients · many colours · animation for decoration · tiny buttons · low-contrast text.
Droplet motion
Pressing a glass control squashes it (a little wider, a little shorter); releasing bounces it back on an under-damped spring, so it overshoots and wobbles before settling — like a drop landing on glass. Selection lenses in SegmentedControl and GlassTabBar slide on a spring and stretch while they move. useDroplet() exposes the same physics for your own components.
Theming and colours
useHugoTheme() returns { isDark, colors, radii }: semantic colours (background, surface, text, textSecondary, border, accent…), glass fills and the active corner tokens. Every component reads these values from there, so changing one token updates the whole kit.
1. Build a theme on the docs page. The component library page in the Hugo Music app has a Theme builder: choose colours and rounded or square corners, watch real components update, then copy the generated HugoProvider into your app.
2. Set them in code. Wrap the app once; list only the colours you change, per appearance — the others keep their defaults:
import { HugoProvider } from 'hugo-music';
<HugoProvider scheme="system" radii={{ sm: 0, md: 0, lg: 0, xl: 0, xxl: 0, pill: 0 }} colors={{
light: { accent: '#5E5CE6', background: '#F7F5FF' },
dark: { accent: '#7D7AFF', glass: 'rgba(30,26,60,0.6)' },
}}>
<App />
</HugoProvider>schemeforces"light"or"dark", or follows the device with"system".accent={{ light, dark }}is a shortcut when only the brand colour changes.radiichanges corners across the kit. Override a single token, or set all six to0for a square theme. Components with aradiusprop can override it locally.- Glass colours are translucent on purpose: keep an alpha below 1 (
rgba(…, 0.6)), or the blur behind disappears. - Keep text readable:
textonbackgroundand white onaccentshould stay at 4.5:1 contrast or more. - Nested providers override outer ones — preview one section in another palette by wrapping only that section.
3. Change the source. After copying the source (below), the defaults are the two objects lightColors and darkColors in theme.tsx; edit them directly and every copied component follows. For one component only, pass a colour prop where it has one (tint, tintOpacity on Glass, tint on ActionButton…) — each component page has a Playground to try them and copy the result.
renderArtwork replaces how every cover is drawn — one place to route images through a CDN or a cache.
Layout and spacing
Tokens replace magic numbers: space (a 4-point grid), radius, type (Large Title 34 down to Caption 12), TOUCH (44-point minimum target) and GUTTER (content margin). LargeTitle, Shelf, InsetGroup and ListRow already apply them, so screens built from them line up without extra styling.
Accessibility
- Icon-only controls take a required
labelthat screen readers announce. - Roles and states are set for you: tabs, selected items, adjustable date wheels, menus.
- Touch targets are at least 44 points.
- When the user asks for reduced transparency, glass becomes an opaque surface.
Platform behaviour
| Where | Glass | Date picker | Context menu | |---|---|---|---| | Native, newest system glass | native glass material, interactive | wheels | glass menu | | Native, other versions | system blur material | wheels | glass menu | | Browsers | CSS backdrop blur with sheen and rim | browser date input | glass menu (long-press) | | Native without blur | opaque fill | wheels | glass menu |
Components
| Group | Exports |
|---|---|
| Theme, tokens and primitives | HugoProvider, useHugoTheme, lightColors, darkColors, space, radius, type, motion, TOUCH, GUTTER, gradientFor, GRADIENTS, onMedia, useTone, Icon, Gradient |
| Frosted glass | LiquidGlass, Glass, GlassGroup, useDroplet, useSwipeDismiss, useRipple, useShimmer, reduceMotionOn, Appear, RippleMark, mixColors, withAlpha, isHexColor, shade, isLight |
| Controls | SeekBar, GlassButton, CapsuleButton, GlassCapsule, DropletPressable, ActionButton, Spinner, Chips, FormField, SegmentedControl, Toggle, TextField, SearchField, DatePicker, SelectField, flagEmoji, OptionSheet, SelectRow, ActionTile, BackdropPicker, ContextMenu, CodeField, QrScanner |
| Navigation | SwipeBack, GlassTabBar, BackButton, Sheet, DropSheet, NavigationSidebar |
| Layout | LargeTitle, Shelf, SectionHeader, ListRow, InsetGroup, MediaTile, GradientTile, PinnedRow, ProfileHeader, Backdrop, BACKDROP_VARIANTS, GlassArt, Artwork |
| Data display | Avatar, CoverImage, Badge, Card, StatCard, BarChart, EmptyState, Pager, ErrorText, QrCode |
Every component has its own page with props, usage notes, accessibility notes, examples, a live demo and its source to copy at /developer/components in the Hugo Music app. This table is generated from src/index.ts.
License
MIT
