Skip to content
BrandCloud

Getting started

Pick your setup. Every route uses the same tokens, so a brand file made in the builder works in all of them.

Get the packages

npm packages are coming soon. Until then, install from the GitHub repository: clone it, run one command to pack the packages, then add the packed files to your project.

Terminal

git clone https://github.com/Zammi1/brandcloud.git
cd brandcloud
pnpm install
pnpm packs        # builds every package and packs it into ./packs

The commands below assume your project folder sits next to the cloned repository. Change the paths if it does not.

Astro

The Astro components ship as .astro source. They render to HTML and CSS and send no JavaScript, except the small scripts in the navbar menu and the enquiry form.

Terminal

pnpm add ../brandcloud/packs/brandcloud-astro-0.9.0.tgz ../brandcloud/packs/brandcloud-tokens-0.9.0.tgz ../brandcloud/packs/brandcloud-motion-0.9.0.tgz astro

src/layouts/Layout.astro

---
import "@brandcloud/tokens/css";
import "@brandcloud/tokens/themes.css";      // every brand and mode, or one brand file
import "@brandcloud/motion/motion.css";      // optional: motion tokens and utilities
---
<html lang="en-GB" data-brand="harbour" data-theme="light" data-button-appearance="depth">
  <body><slot /></body>
</html>

src/pages/index.astro

---
import Layout from "../layouts/Layout.astro";
import Hero from "@brandcloud/astro/components/Hero.astro";
import Button from "@brandcloud/astro/components/Button.astro";
---
<Layout>
  <Hero variant="editorial" copy={{ heading: "Your headline", primary: { label: "Book a visit", href: "/book/" } }} />
  <Button href="/prices/" tone="ink">See prices</Button>
</Layout>
  • Import components one by one from @brandcloud/astro/components/Name.astro, so only their CSS reaches the page.
  • Component styles sit in @layer components. Keep your own element rules (h1, a) in @layer base, and declare the layer order once before any stylesheet: @layer tokens, theme, base, components, brand-motion, utilities;
  • data-button-appearance="depth" on <html> makes the depth button the default. Without it buttons are solid.
  • Fonts are not bundled. Load them yourself (this site self-hosts Bricolage Grotesque and Hanken Grotesk from Fontsource) and keep their licence.

React and Next

The React primitives are built on Base UI, styled only with the tokens. Include the stylesheet once near the root.

Terminal

pnpm add ../brandcloud/packs/brandcloud-ui-0.9.0.tgz ../brandcloud/packs/brandcloud-tokens-0.9.0.tgz react react-dom

main.tsx (Vite)

import "@brandcloud/tokens/css";
import "@brandcloud/tokens/themes.css";
import "@brandcloud/ui/styles.css";
import { Button } from "@brandcloud/ui/button";

export function Save() {
  return <Button loading={false}>Save changes</Button>;
}

app/layout.tsx (Next App Router)

import "@brandcloud/tokens/css";
import "@brandcloud/tokens/themes.css";
import "@brandcloud/ui/styles.css";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en-GB" data-brand="harbour" data-theme="light">
      <body>{children}</body>
    </html>
  );
}
  • Interactive components (dialog, drawer, menu, popover, tooltip and the rest) carry "use client" in the build, so you can import them from a Server Component page.Card also has a react-server entry.
  • Import leaf paths such as @brandcloud/ui/button to keep bundles small, or the root for everything.
  • For motion in React, wrap the app in BrandMotionConfig from @brandcloud/motion/react. It follows the OS reduced-motion setting and <html data-motion="reduce">.

Tailwind v4

The Tailwind layer is @theme inline, so utilities read the tokens where they are used and re-theme with data-brand or data-theme on any element.

app.css

@import "tailwindcss";
@import "@brandcloud/tokens/css";
@import "@brandcloud/tokens/themes.css";
@import "@brandcloud/tokens/tailwind.css";
@import "@brandcloud/motion/tokens.css";
@import "@brandcloud/motion/tailwind.css";
Tailwind utilities from the tokens
TokensUtilities
Colour rolesbg-canvas, text-text-muted, border-border, bg-action-ink,bg-whatsapp
Shadowsshadow-action-depth, hover:shadow-action-depth-hover, shadow-popover
Typefont-display, font-body, text-display, text-h1, text-lead
Layoutpy-section, h-action-md, max-w-content-max, rounded-control
Gradientsbg-action-depth, bg-level-sky to bg-level-obsidian
Motionease-brand-enter, duration-brand-fast, transition-spring-snappy,animate-brand-enter

The shadcn bridge

Already using shadcn/ui? Import the bridge last and stock components take on the brand without edits.

app.css

@import "tailwindcss";
@import "@brandcloud/tokens/css";
@import "@brandcloud/tokens/themes.css";
@import "@brandcloud/tokens/tailwind.css";
@import "@brandcloud/tokens/shadcn.css"; /* last */

--background becomes canvas, --primary becomes accent, --muted becomes surface-muted,--destructive becomes danger, --ring becomes focus and --radius becomes radius-control, along with the card, popover, chart and sidebar variables. They are re-declared on every [data-brand] and [data-theme] element, so nested brands work too.

With the bridge loaded, Tailwind's bg-accent follows shadcn's meaning (the hover surface). Use bg-primary for the brand colour.

Add your brand

Export the JSON from the brand builder, or make one from the command line in a clone of the repository:

Terminal

node packages/tokens/scripts/make-brand.mjs --name acme --label "Acme Roofing" \
  --accent "#0f766e" --ink "#111827" --paper "#fbfaf7" \
  --font-body "'Hanken Grotesk Variable', Arial, sans-serif" \
  --font-display "'Fraunces Variable', Georgia, serif"
# or: --input brief.json (same keys), --dry-run, --report report.json, --appearance solid|depth

It prints a pass or fail line for every required contrast pair and refuses to write a brand that fails. More in Theming.