Freeframe

Documentation

Crumb

v1.0.1Updated Oct 16, 2026A charming bakery and café website with click-and-collect preorders, a live bake board and a celebration cake builder.

Overview#

Crumb is a website for a neighbourhood bakery and café with click-and-collect preorders, built for Bramble & Rye, a fictional bakery on St Benedicts Street in Norwich. It has a live "fresh out of the oven" board, a preorder catalogue with per-day availability and quantity limits, a basket drawer with a collection day, time slot and order cut-off, a demo checkout with an order number and a calendar file, a celebration cake builder with a live drawing and price, a café menu with diet filters, an about page and a visit page with a wholesale form. This is the Next.js version: Next.js 16 (App Router), React 19, TypeScript and Tailwind CSS v4, exported as a fully static site. The product cards, bake artwork and café menu are rendered at build time from typed data, so they are in the HTML. This guide covers version 1.0.0. See it live at freeframe.dev/templates/crumb.

Quick start#

Requirements: Node.js 24 or newer and pnpm (npm works too).

sh
pnpm install
pnpm dev        # http://localhost:3000

Try an order: add a croissant and a seeded rye on the preorder page, pick a collection slot in the basket and place the demo order at the checkout. Nothing is sent or charged.

The bake board, open-now badges and cut-off all follow the bakery's clock. To preview another time of day, add ?now= to any page URL, for example http://localhost:3000/?now=2026-10-17T10:15.

pnpm build writes the static site to out/; pnpm start serves it.

Pages#

Route File Purpose Notable sections and features
/ src/app/page.tsx Home Hero with the shop-window illustration, live bake board, how preordering works, this week's specials (from the product data), celebration cake teaser, café teaser, reviews, visit us with open-now badge, hours and map
/shop src/app/shop/page.tsx Preorder Shelf chips with counts (/shop?category=bread), "Collecting" day, "only that day's bakes" toggle, product cards grouped by shelf, add buttons and steppers, allergen note
/cakes src/app/cakes/page.tsx Celebration cakes Builder for size, sponge, filling, finish, colour, message and collection date; live SVG preview, price breakdown and allergens; recent cakes; cake FAQ
/cafe src/app/cafe/page.tsx Café menu Coffee, tea, brunch and sweet things with diet filters (/cafe?diet=vegan,gf), café notes
/checkout src/app/checkout/page.tsx Checkout (demo) Collection day and slot, notes, contact details, pay at collection or demo card, order summary, confirmation with order number and .ics file, empty state with the last order
/about src/app/about/page.tsx Our story Story, timeline, the 36-hour sourdough process, suppliers, team, waste figures
/visit src/app/visit/page.tsx Visit & wholesale Illustrated map, hours with today highlighted, contact, getting here, wholesale enquiry form (/visit#wholesale), FAQ
any other src/app/not-found.tsx Not found (404) Links back to home, preorder and café

Project structure#

crumb/
  src/
    app/
      layout.tsx            html shell: fonts, top bar, header, footer, basket drawer, toast, back to top
      fonts.ts              Karla, Corben and Delicious Handrawn via next/font/local
      globals.css           Tailwind v4 @theme tokens and component classes
      icon.svg              favicon
      page.tsx              home page
      shop/ cakes/ cafe/ checkout/ about/ visit/   one folder per page (page.tsx)
      not-found.tsx         404 page
    components/
      SiteHeader.tsx        header, navigation, basket button and mobile menu (client)
      SiteFooter.tsx        footer with address, hours and the bake list sign-up
      ShopClock.tsx         open-now badge, cut-off countdown and hours list (client)
      ProductCard.tsx       a bake's card, diet tags and the week strip (rendered on the server)
      Logo.tsx              the Bramble & Rye mark
      UrlParam.tsx          reads ?category= / ?diet= in the browser (client)
      Year.tsx, RevealObserver.tsx, BackToTop.tsx
      home/BakeBoard.tsx    the live bake board, its title and counts line (client)
      shop/ShopCatalogue.tsx   shelf chips, collection day, toggle and the grouped cards (client)
      basket/               BasketButton, BasketDrawer, CardAction (add / stepper on a card),
                            parts (Stepper, PickupFields, ConflictAlert), Toast
      cakes/CakeBuilder.tsx the cake builder and the earliest-date text (client)
      cafe/CafeMenu.tsx     diet chips, count and the menu (client)
      checkout/CheckoutView.tsx   the checkout form, summary, confirmation and empty state (client)
      forms/                useValidation hook, NewsletterForm (with SuccessBox), WholesaleForm
    data/
      shop.ts               SHOP, TIMEZONE, LOCALE, CURRENCY, HOURS and PICKUP rules
      bakes.ts              CATEGORIES, ALLERGENS, DIETS, PRODUCTS, BAKE_SCHEDULE and CATEGORY_TINT
      cafe.ts               CAFE_MENU
      cakes.ts              CAKE: celebration cake options, lead time and limits
    lib/
      clock.ts              the shop clock: open-now, cut-off, collection dates and slots, ?now=
      art.ts                the SVG drawing code (bakes, cakes, tier icons, the paper bag)
      bake-art.ts           bakeOf(id) / bakeInner(id) shortcuts for the page illustrations
      basket.ts             the saved basket: types, repair on read, conflicts, line info and totals
      store.tsx             shared client state: basket, drawer, toast and the basket actions
      cake.ts               cake configuration, price, summary, allergens and description
      order.ts              the last order and its .ics calendar file
      validation.ts         form field rules
      format.ts             money, lists and allergen text
      metadata.ts           per-page title, description and Open Graph tags
      asset.ts, storage.ts, use-shop-now.ts
    fonts/                  the woff2 files and their licenses
  public/img/               og-image.png and its source og-image.svg
  next.config.ts            static export and optional base path
  template.json             gallery metadata (not part of your site)

Customising#

Brand and colours#

The design tokens are in the @theme block of src/app/globals.css. Every utility such as bg-bramble or text-muted comes from them.

Token Default Used for
--color-flour #fbf5ec Page background
--color-paper #fffdf8 Cards and form fields
--color-oat #f3e7d5 Soft panels, bread tiles
--color-line #e7d6bf Hairlines and dashed rules
--color-ink #3a2620 Text, outlines, the footer
--color-muted #6c574a Secondary text
--color-bramble / --color-bramble-deep #74305a / #561f42 Brand colour: buttons, links, basket
--color-bramble-soft #f3dce7 Selected options
--color-blush / --color-blush-deep #f7dcd3 / #a33a3f Cake tiles, sold out, error text
--color-pistachio / --color-pistachio-deep #dfe8cb / #43602a Whole cake tiles, "on the shelf", vegan
--color-butter / --color-butter-deep #f9e8b2 / #7a5a06 Pastry tiles, "baking now", badges
--color-lilac, --color-sky #e5ddf0, #d9e8ee Pastel accents
--color-crust #b9733c Decoration only (steam, bread brown)

To change the brand colour, edit the tokens:

css
@theme {
  --color-bramble: #2f5d50;
  --color-bramble-deep: #1f4237;
  --color-bramble-soft: #d8ebe3;
}

The illustrations use fixed colours in src/lib/art.ts and inline SVG in the pages, so a new brand colour doesn't recolour the bakes. The shelf tile colours are CATEGORY_TINT in src/data/bakes.ts.

Typography#

Three fonts are self-hosted with next/font/local in src/app/fonts.ts, from the same woff2 files Google Fonts serves (in src/fonts/, with their SIL Open Font License files):

Token Font Used for
--font-display Corben (400, 700) Headings, prices, the wordmark
--font-sans Karla (400–800, with italics) Body text and UI
--font-hand Delicious Handrawn Hand-lettered notes (.hand), the cake message

Each localFont() call sets the real family name with declarations, so globals.css refers to "Karla", "Corben" and "Delicious Handrawn" directly. To swap a font, put its woff2 files in src/fonts/, change the paths and family names in fonts.ts and the matching token in globals.css. The SVG artwork names 'Delicious Handrawn' and Corben directly for its labels.

Content#

Page text lives in the page files under src/app/. Everything the interactive parts work from is in src/data/:

Export File What it holds
SHOP shop.ts Name, address, phone and email used in the drawer, toasts and calendar file
TIMEZONE, LOCALE, CURRENCY shop.ts Europe/London, en-GB, GBP
HOURS shop.ts Opening hours per weekday, Sunday first, ["07:30", "16:00"] or null for closed
PICKUP shop.ts cutoff ("14:00"), slotStep (30), lastSlotBeforeClose (30), daysAhead (14), notesMax (200)
CATEGORIES bakes.ts The shelves: bread, pastry, bakes, whole
ALLERGENS, DIETS bakes.ts Allergen names and diet labels (vegan, vegetarian, gf, df)
PRODUCTS bakes.ts Every bake on the preorder page
BAKE_SCHEDULE, BAKING_MINS bakes.ts When each bake comes out of the oven, and how long "baking now" shows before that
CAFE_MENU cafe.ts Café sections and items
CAKE cakes.ts Celebration cake options, the builder's default choices, lead time and limits

Add a bake by adding an object to PRODUCTS:

ts
{
  id: "rye-bun",
  name: "Caraway rye bun",
  category: "bread",
  price: 1.6,
  unit: "each",
  days: [5, 6],
  max: 12,
  blurb: "Soft rye buns with caraway, made for sandwiches.",
  allergens: ["gluten"],
  diet: ["vegan"],
  art: { kind: "boule", crust: "#8c5532", top: "#a8693d" },
},
Field Meaning
id Unique, used in the basket and in data-add buttons
category One of the CATEGORIES ids
price In pounds; whole numbers show without pence (£32)
days Weekdays it's baked (0 Sunday to 6 Saturday), or null for every day you're open
max The most one order can hold
leadDays Optional days' notice (default 1: order before the cut-off the day before)
special Optional badge text; specials also appear on the home page
allergens, diet Keys from ALLERGENS and DIETS
art How it's drawn (see Images and artwork)

TypeScript checks every field against the Product type. To show a new bake on the home page board, add it to BAKE_SCHEDULE with the time the first tray comes out and, optionally, when it usually sells out:

ts
{ id: "rye-bun", out: "09:15", soldOut: "13:00" },

Café items are { name, price, desc, diet } inside a CAFE_MENU section. The cake builder reads CAKE.sizes, CAKE.sponges, CAKE.fillings, CAKE.finishes and CAKE.colours; each option has an id, a label and a price (a size has serves, factor and tiers, the diameters in inches used for the drawing). CAKE.defaults sets the options picked when the builder opens.

The footer hours, reviews, the café teaser on the home page and the "Recently boxed up" cakes on /cakes are written in the page files: update them alongside HOURS, CAFE_MENU and CAKE.

Images and artwork#

There are no photos. All artwork is SVG:

  • Bakes are drawn by bake(art) in src/lib/art.ts from a product's art object. kind picks the drawing: boule, tin, baguette, focaccia, croissant, painchoc, bun, knot, scone, tart, cookie, brownie, loafcake or layercake. Optional colours: crust and top (breads), seeds / oats (tin), score: "leaf" (boule), almonds (croissant), dough / swirl (bun), sponge, frosting, filling and top ("berries", "walnuts", "drip", "flowers") for layercake. A seeded random generator makes the same bake look the same every time, so the drawings made at build time match the ones the browser draws in the basket.
  • Celebration cakes are drawn by cake(config) from the builder's choices; the recent cakes on /cakes and the cake on the home page use the same function with fixed choices.
  • The hero shop window, map, kitchen window, team avatars, coffee cup and 404 loaf are inline SVG in the page files (the bakes inside them come from bakeInner() in src/lib/bake-art.ts). Edit them in place, or replace them with an <img> from public/, using asset() for the path.

To use photos for the bakes, give each product an image path and replace the art <div> in ProductCard.tsx with an <img> (keep the 4:3 tile). Keep the hero image around 560×660 (portrait).

The social image is public/img/og-image.png (1200×630), rendered from og-image.svg. The favicon is src/app/icon.svg.

The header, footer, basket drawer and toast are in src/app/layout.tsx, so they're shared by every page. The main navigation is NAV in src/components/SiteHeader.tsx (the mobile menu adds "Home" in front); the footer's "Explore" links are EXPLORE in src/components/SiteFooter.tsx. The current page is marked with aria-current="page" from the route. To add a page, create src/app/<route>/page.tsx and add it to NAV.

Features#

Shop clock and opening hours#

All times use the bakery's clock (TIMEZONE) via shopNow() in src/lib/clock.ts, so a visitor abroad sees the shop's real state. useShopNow() (src/lib/use-shop-now.ts) shares one clock between every component and checks it every 30 seconds. While the page is prerendered there is no "now", so these parts show their static fallback text and switch to live text in the browser, which avoids hydration mismatches.

The components in src/components/ShopClock.tsx:

  • OpenStatus shows "Open now until 4pm", "Closing soon, at 4pm" or "Closed · opens Tuesday 7:30am" with a coloured dot (shopStatus()).
  • Cutoff shows the countdown to PICKUP.cutoff ("Order in the next 3h 40m to collect tomorrow"), or when preorders open next (cutoffText()).
  • HoursList lists the week from Tuesday with today in bold and a "Today" badge.

Add ?now=YYYY-MM-DDTHH:MM to a URL to test any time.

Bake board#

BakeBoard in src/components/home/BakeBoard.tsx shows every BAKE_SCHEDULE entry baked today. Each bake is Out at 7:30am until BAKING_MINS before its time, then Baking now (with rising steam), then Out since 7:30am, and Sold out (faded) after its optional soldOut time. Bakes on the shelf come first and sold-out ones last. BoardTitle and BoardNote show the day and a counts line ("8 on the shelf · 1 in the oven · 2 still to come"). After closing (and on closed days) the board shows the next bake day instead, so the page never looks empty. Each bake links to its shelf on the preorder page.

Preorder catalogue#

ShopCatalogue in src/components/shop/ShopCatalogue.tsx groups PRODUCTS by shelf. The prerendered page has every card; in the browser the chips filter by shelf and keep the address in step (?category=pastry), the "Collecting" select is the basket's collection day, and "Only that day's bakes" hides anything not baked then. Cards (ProductCard.tsx) show the bake days as a Monday-first week strip, diet tags and allergens, and CardAction shows:

  • Add to basket when it fits the chosen day.
  • Add for Sat 17 Oct when it doesn't: adding it moves the collection to the first day that suits the whole basket, and a toast says so.
  • A quantity stepper and "In your basket" once it's in the basket, capped at max.

Filters are buttons with aria-pressed, and the result count is a live region.

Basket drawer#

The basket button in the header opens BasketDrawer (#basket-drawer), a modal dialog with a focus trap; Esc, the close button or the backdrop close it and focus returns to the button that opened it. It lists each line with a stepper (at one, the minus becomes a bin) and a remove button, then the collection details (PickupFields and ConflictAlert in src/components/basket/parts.tsx, shared with the checkout):

  • Collection day: open days from the earliest possible (earliestDate()) up to PICKUP.daysAhead (CAKE.daysAhead when there's a celebration cake). Orders before PICKUP.cutoff can collect the next open day; after it, the day after. Whole cakes add their leadDays, celebration cakes CAKE.leadDays. Days that don't suit everything say "(2 items not baked)".
  • Time slot: half-hour slots from opening time until lastSlotBeforeClose minutes before closing.
  • Conflicts: if something isn't baked on the chosen day, the drawer says so, offers the next day that suits everything, and disables checkout until it's fixed.
  • Notes up to PICKUP.notesMax characters, saved as you type.

The basket actions (addProduct(), setQty(), removeLine(), setPickup(), setNotes()), the drawer and the toast live in src/lib/store.tsx.

Celebration cake builder#

CakeBuilder in src/components/cakes/CakeBuilder.tsx builds the radio cards from CAKE and redraws the cake and price on every change; the drawing has a text description of the cake for screen readers. The price is the size's price plus sponge, filling and finish extras multiplied by the size's factor, rounded to whole pounds (cakePrice() in src/lib/cake.ts). The colour swatches are disabled for the naked finish. The message is limited to CAKE.messageMax characters with a live counter. The date's minimum is CAKE.leadDays days ahead (one more after the cut-off) and closed days are rejected. Adding the cake puts it in the basket, sets the collection to that date and shows a toast; one order holds up to CAKE.maxPerOrder cakes. On phones a second "Add cake to basket" button with the price sits at the end of the form.

Café menu filters#

CafeMenu in src/components/cafe/CafeMenu.tsx renders CAFE_MENU. The diet chips combine (a dish must match all of them; vegan counts as vegetarian and dairy-free), keep the address in step (?diet=vegan,gf) and show an empty state with a clear button when nothing matches.

Checkout and calendar file#

CheckoutView in src/components/checkout/CheckoutView.tsx shows the collection picker, notes, contact fields, payment choice and the order summary. "Pay now by card" reveals a demo card form (Luhn-checked number in groups of four, MM / YY expiry, CVC). If something isn't baked on the chosen day, placing the order is refused until the day is fixed. On a valid submit it creates an order number (BR- and five digits), saves the order to crumb-last-order, empties the basket and shows a confirmation with an Add to calendar (.ics) link built by icsFor() in src/lib/order.ts: a 30-minute event at the collection slot with TZID=Europe/London and a VTIMEZONE block, with the items in the description. The empty checkout shows the last order and its calendar link.

Scroll reveal, motion and back to top#

Elements with the reveal class fade in as they scroll into view (RevealObserver.tsx); the steam and the "baking now" pulse are CSS animations in globals.css. All of them are off with prefers-reduced-motion. A back-to-top button (BackToTop.tsx) appears after one screen of scrolling and moves focus to the main content; remove it from layout.tsx and the .back-to-top styles in globals.css to drop it.

Forms#

All forms validate in the browser with inline messages (rules in src/lib/validation.ts, wiring in src/components/forms/useValidation.tsx) and show a success state. None of them send anything until you connect them.

Form Where Validates
Bake list sign-up (data-form="newsletter") src/components/forms/NewsletterForm.tsx, footer of every page Email
Wholesale enquiry (data-form="wholesale") src/components/forms/WholesaleForm.tsx, /visit Business, type, name, email, optional phone (10–13 digits), loaves a day (a whole number from 10 to 400), at least one interest, start date at least 7 days ahead, message up to 600 characters
Cake builder (#cake-form) src/components/cakes/CakeBuilder.tsx, /cakes Collection date (lead time, open day, up to CAKE.daysAhead), message length
Checkout (#checkout-form) src/components/checkout/CheckoutView.tsx, /checkout Time slot, name, email, phone (10–13 digits), allergen confirmation, card fields when paying now

Rules come from attributes on each field: required and data-label ("Your email is required."), the input type, data-validate (name, card, expiry, cvc, open-day), min / max, maxlength, data-min-msg and, for checkboxes, data-msg. Errors appear in <p id="<field id>-error"> after the field, linked with aria-describedby and aria-invalid, and the first problem is focused.

To connect the wholesale form to a form service such as Formspree, post the data in its onSubmit before showing the thank-you message:

tsx
onSubmit={async (e) => {
  e.preventDefault();
  const form = e.currentTarget;
  if (!v.validate(form)) return setStatus("Please check the highlighted fields.");
  const res = await fetch("https://formspree.io/f/your-id", {
    method: "POST",
    body: new FormData(form),
    headers: { Accept: "application/json" },
  });
  if (!res.ok) return setStatus("Sorry, that didn’t send. Please try again or call us.");
  const value = (name: string) => (form.elements.namedItem(name) as HTMLInputElement).value.trim();
  setSent({ first: value("name").split(/\s+/)[0], business: value("business") });
}}

The newsletter works the same way in NewsletterForm.tsx. Every field already has a name. If you remove the static export (see Building and deploying), you can post to your own Route Handler (for example src/app/api/wholesale/route.ts exporting POST) or call a Server Action instead.

For real orders, onSubmit in CheckoutView builds an order object with the lines, collection day and slot, contact details and payment choice; send it to your order system where the comment says so, take payment with your provider (Stripe Checkout, Square, SumUp…) and only show the confirmation when it succeeds. Remove the demo card form when you do, and never trust prices from the browser: recalculate them on the server from your product data.

Saved data (localStorage)#

Key Shape Notes
crumb-basket { lines, date, time, notes } lines are { id, qty } or { id: "cake", key, cake: { size, sponge, filling, finish, colour, message }, qty: 1 }; date is YYYY-MM-DD, time is HH:MM
crumb-last-order { number, placedAt, date, time, notes, name, email, phone, payment, lines, total } Written at checkout; shown on the empty checkout page

Everything is checked on every read (loadBasket() in src/lib/basket.ts, readLastOrder() in src/lib/order.ts): unknown products and cake options are dropped, quantities become whole numbers within max, duplicates merge, more than CAKE.maxPerOrder cakes are dropped, dates outside the bookable range and slots that don't exist reset, and the repaired value is written back when a page loads. Prices are never stored; they always come from PRODUCTS and CAKE. Components read the basket with useStore() (useSyncExternalStore), which has no basket while the page is prerendered and hydrated, and other open tabs update through the storage event. To reset, run localStorage.removeItem("crumb-basket") in the console, or clear the site's data. Change the key names if you run several sites on one domain.

SEO and sharing#

  • Site-wide defaults are in metadata in src/app/layout.tsx (they are also the home page's title and description).
  • Every page exports metadata = pageMetadata(title, description) from src/lib/metadata.ts, which sets the title, description, Open Graph tags (with the image asset("/img/og-image.png")) and the Twitter card.
  • metadataBase comes from NEXT_PUBLIC_SITE_URL (falling back to https://example.com). Set it when you build so social images get absolute URLs:
sh
NEXT_PUBLIC_SITE_URL=https://www.your-bakery.co.uk pnpm build

The product cards and café menu are in the exported HTML, so every search engine sees them. Consider adding src/app/sitemap.ts and src/app/robots.ts (both work with static export; leave out the checkout) and a Bakery structured data block as JSON-LD with the address, telephone and openingHours.

Accessibility#

  • Skip link, landmarks (header, nav, main, footer), one h1 per page and a logical heading order.
  • Visible focus outlines in the brand colour, including radio cards, chips and swatches; WCAG AA contrast.
  • The mobile menu button has aria-expanded and an "Open menu" / "Close menu" label, and closes on Esc.
  • The basket drawer is role="dialog" with aria-modal, a focus trap, Esc and the backdrop to close, and focus returned to the button that opened it.
  • Shelf and diet chips are toggle buttons (aria-pressed); the result counts, toasts and cake price are live regions.
  • Steppers have labelled buttons ("One more Butter croissant"), remove buttons include the item name, and the week strip has a text version ("Baked Thursdays & Saturdays.").
  • The cake drawing has a text description; decorative art is hidden from screen readers.
  • Form errors are linked with aria-describedby, fields get aria-invalid and the first error is focused.
  • Reduced motion turns off reveals, steam, the "baking now" pulse and smooth scrolling.

When editing, keep exactly one h1 per page, give every new input a <label>, and write full class names (Tailwind only finds classes it can read in the source).

Building and deploying#

pnpm build writes a fully static site to out/ (output: "export" in next.config.ts). Deploy it anywhere:

  • Vercel: import the repository; no settings needed.
  • Netlify / Cloudflare Pages: build command pnpm build, publish directory out.
  • Any static host: upload the contents of out/.

To serve the site from a sub-folder, build with a base path: DEMO_BASE_PATH=/crumb pnpm build. next.config.ts passes it to basePath and to NEXT_PUBLIC_BASE_PATH, which asset() uses. pnpm build:demo does this for the freeframe.dev demo and writes demo/, which you can delete.

Need server features (a Route Handler for orders, Server Actions, middleware)? Remove output: "export" and images: { unoptimized: true } from next.config.ts and deploy to a Node-capable host such as Vercel. Everything else keeps working.

pnpm lint runs ESLint 10 and pnpm typecheck runs TypeScript 7 (@typescript/native); the typescript package is an alias of @typescript/typescript6, because typescript-eslint still needs the TypeScript 6 API.

Troubleshooting#

  • The bake board says "Tomorrow" all day. HOURS decides when you're open; check the closing time for today and that TIMEZONE is your bakery's zone.
  • A bake never appears on the board. It needs a BAKE_SCHEDULE entry and must be baked that day (days).
  • Customers can't pick tomorrow. It's after PICKUP.cutoff, tomorrow is closed, or something in the basket needs more notice (leadDays).
  • The basket shows old items. Stored baskets are repaired against PRODUCTS; if you renamed an id, old baskets drop that line. Clear crumb-basket to start fresh.
  • A new class has no effect. Tailwind only finds full class names in the source; write bg-pistachio, not "bg-" + colour.
  • Images or links break under a sub-folder. Build with DEMO_BASE_PATH and reference public files with asset() (links made with next/link get the base path automatically).
  • Social previews point to example.com. Set NEXT_PUBLIC_SITE_URL when building.
  • The calendar file has the wrong time. Events use TIMEZONE; if you change it, update the VTIMEZONE rules in icsFor() too.

License#

MIT: the full text is in LICENSE.txt, included in the download. You can use, change and sell sites built with this template, including all artwork (bakes, cakes, map, logo and illustrations). Karla, Corben and Delicious Handrawn are licensed under the SIL Open Font License (src/fonts/OFL-karla.txt, src/fonts/OFL-corben.txt, src/fonts/OFL-delicious-handrawn.txt). Bramble & Rye, its team and its customers are fictional.

Search documentation

Search the guides and every template's documentation