@sushindustries/ui

0.1.0

The components this site is made of. Every one of them is installable on its own - nothing here is site-specific.

pnpm add @sushindustries/ui
2 min read
View as Markdown

The components this site is made of. Every element you can see on sushindustries.com is in here, and nothing in here is site-specific - the site is just the first thing that imports it.

Install

pnpm add @sushindustries/ui @sushindustries/atoms
shell

The components carry no styles of their own. They emit class names from @sushindustries/atoms@sushindustries/atomsThe design tokens and the atomic utilities built on them. One stylesheet, no build step, no framework.package, so import that stylesheet once at the root:

import "@sushindustries/atoms/atoms.css";
ts

Components

ComponentWhat it does
SmoothScrollMounts Lenis for the page. Renders nothing.
RevealRevealFades and rises its children the first time they reach the viewport. Never un-reveals.@sushindustries/ui · motionFades and rises its children the first time they reach the viewport.
ScrollSpinRotates its children with the page scroll.
SectionSectionKicker, heading and body, revealing top-down with an 80ms offset.@sushindustries/ui · layoutKicker, heading and body, revealing top-down.
CardCardTitle, optional meta, arbitrary body. Heading level is a prop so the outline stays correct.@sushindustries/ui · layoutTitle, optional meta, whatever you put inside.
MarkdownViewRenders Markdown with syntax-highlighted code fences.

Use

import { Reveal, ScrollSpin, Section, SmoothScroll } from "@sushindustries/ui";

export function Page() {
	return (
		<>
			<SmoothScroll />

			<ScrollSpin revolutions={2} tilt={8}>
				<img src="/mark.svg" alt="" />
			</ScrollSpin>

			<Section id="work" label="Work" title="What I build">
				<Reveal delay={80}>
					<p>Anything you like.</p>
				</Reveal>
			</Section>
		</>
	);
}
tsx

Everything degrades

Every component here checks prefers-reduced-motion and stops moving if it is set. RevealRevealFades and rises its children the first time they reach the viewport. Never un-reveals.@sushindustries/ui · motion shows its children immediately rather than leaving them invisible

  • a reveal that never fires is a blank page, which is the worst possible failure for an accessibility preference.

ScrollSpin and SmoothScroll need a browser, so they do their work in an effect. The first server render and the first client render are identical, which is what keeps them safe under SSR.

Optional peers

MarkdownView needs @tanstack/markdown and @tanstack/highlight; SmoothScroll needs lenis. All three are optional peer dependencies - if you only want CardCardTitle, optional meta, arbitrary body. Heading level is a prop so the outline stays correct.@sushindustries/ui · layout and SectionSectionKicker, heading and body, revealing top-down with an 80ms offset.@sushindustries/ui · layout, you do not install any of them.