Instruction
How to Update Design Tokens
Every color, font, radius, and shadow value in this template is a Tailwind v4 theme token declared in the @theme block of src/styles/tokens.css. Change a token once and it updates everywhere its matching utility class is used.
- Open
src/styles/tokens.cssand scroll to the@themeblock. - Update the color tokens you want to change, for example:
--color-signal-400through--color-signal-700— the accent color used by buttons, links, and highlighted text.--color-ink-950,--color-ink-900,--color-ink-850— the dark background layers.--color-paper-50,--color-paper-400— heading and muted body text.
- Change the typography. Headings use Satoshi (self-hosted from
public/fonts/via@font-faceintokens.css) and body text uses Inter (loaded from Google Fonts insrc/layouts/BaseLayout.astro). To swap a family, drop the new font files intopublic/fonts/, update the@font-facerules, then update--font-display/--font-body. - Adjust the radius and shadow scale using the
--radius-*and--shadow-*tokens. - Save the file. The dev server hot-reloads instantly — no build step required.
Prefer a live reference? Open the Style Guide page to see every token rendered on screen.
How to Update Text and Images
Updating Text
All repeating content lives in typed data files under src/data/, so you can edit copy without touching markup.
- Pick the right data file for the section you want to change:
nav.ts— header and navigation linksfeatures.ts— feature cardshowItWorks.ts— the step-by-step sectionpricing.ts— plan names, prices, and feature listsuseCases.ts— use-case tabstestimonials.ts— quotes and authorsfaqs.ts— question and answer pairs
- Edit the values in the exported array. TypeScript will flag a typo in a field name straight away.
- For one-off headings and paragraphs, edit the section component directly in
src/components/sections/.
Updating Images
Content images live in src/assets/images/ and are rendered with Astro's <Image /> component. Astro processes them at build time — converting to WebP, adding width and height so the page never jumps, and giving each file a hashed name browsers can cache forever.
- Drop your new file into
src/assets/images/. - Import it at the top of the component:
import photo from '@/assets/images/your-file.webp';then render<Image src={photo} alt="…" />. Reusing the original filename means no code change at all. - Update the
alttext to describe the new image. Leave it empty (alt="") only when the image is purely decorative. You do not need to setwidth/height— Astro reads them from the file. - Supply images at roughly twice their display size. Astro will shrink and re-encode, but it never upscales, so a small source file stays soft on high-resolution screens.
- Prefer WebP or JPG for photography and SVG for logos and icons.
The exception: favicons, the web-clip icon, and the social share image live in public/images/ and are referenced by plain URL, because their addresses must stay fixed and unhashed for browsers and social crawlers. Videos and fonts work the same way, in public/videos/ and public/fonts/.
Product Mockups Are Code, Not Images
The app-screenshot visuals — feature cards, the three "How it Works" steps, the use-case tabs, and the 404/401 illustrations — are built in markup, not bitmap files. They stay crisp at any screen size and pick up your accent color automatically when you change the design tokens.
- To change what a mockup shows, edit the matching component in
src/components/ui/:FeatureMockup.astro,WorkMockup.astro,UseCaseMockup.astro, orUtilityIllustration.astro. - To swap which mockup a card uses, change the
mockupfield in the matching data file (for examplefeatures.ts) — TypeScript lists the valid variant names. - To use a real screenshot instead, replace the component call with a normal
<img>tag in the section component.
How to Replace an Icon (SVG)
Icons are inlined as raw <svg> markup rather than loaded as image files, so they inherit color from CSS and add no extra network requests.
- Find the icon in the component you want to change — look for an
<svg>element, usually wrapped in adivwith a class likebutton-iconorsocial-icon. - Replace the markup from
<svg>to</svg>with your own icon. - Keep
fill="currentColor"(orstroke="currentColor") on the paths. This is what lets the icon pick up the surrounding text color and animate on hover. - Match the
width,height, andviewBoxto the original so the layout stays intact. - Note the casing: in Astro use
viewBox, not the lowercaseviewboxthat some exporters produce. - Reusing an icon in several places? Move it into its own component under
src/components/ui/and import it where needed.
How to Adjust Animations and Interactions
Motion is Tailwind utility classes (transition, duration-*, ease-*) plus the shared timing tokens in tokens.css (--dur-fast, --dur-base, --dur-slow, --ease-out), backed by a small amount of vanilla JavaScript. There is no animation library and no framework runtime to configure.
CSS Transitions
- Tune a timing token in
src/styles/tokens.cssto change duration or easing everywhere it's referenced, or override a single element'sduration-[var(--dur-base)]class directly in its component. - Hover states use Tailwind's
hover:variant right on the element, e.g.hover:border-signal-500/60.
Interactive Components
Each interactive piece keeps its script in a <script> block at the bottom of its own component file:
- Pricing toggle —
PricingSection.astrotoggles anis-activeclass between the monthly and yearly tabs and shows the matching prices. - Use-case tabs —
UseCasesSection.astroswaps the active tab panel. - FAQ accordion —
FAQSection.astrotogglesaria-expandedand animates the answer panel height. - Mobile navigation —
Header.astroopens and closes the menu.
Astro scopes and bundles these scripts automatically. To disable an effect, remove or comment out its <script> block — the markup stays fully usable without it.
Respecting Reduced Motion
To honour a visitor's system preference, wrap your motion in a media query:
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }
How to Update Page SEO
Meta tags, Open Graph tags, and Twitter card tags are all generated by src/layouts/BaseLayout.astro from the props each page passes in.
- Open the page you want to edit in
src/pages/. - Update the props on the
<BaseLayout>tag:title— the browser tab title and search result headline.description— the meta description, also reused for the OG and Twitter descriptions.
- Replace the share image at
public/images/og-image.webp, keeping the filename so no code change is needed. Recommended size is 1200 × 630 pixels. - Set your production domain in the
sitefield ofastro.config.mjs. The@astrojs/sitemapintegration uses it to generatesitemap-index.xmlat build time, and it makes the canonical and OG URLs absolute. - Swap the favicon by replacing
public/images/favicon.pngandwebclip.png. - Run
npm run buildand check the generateddist/HTML to confirm the tags render as expected.
How to Work with Video
Background videos use native HTML <video> elements with two sources, so browsers pick whichever format they support best.
- Add your files to
public/videos/in both formats — an.mp4(H.264) and a.webm. - Update the two
<source>tags in the section component to point at your files. - Keep the playback attributes.
autoplay,loop,muted, andplaysinlineare all required together — withoutmutedandplaysinline, mobile browsers refuse to autoplay. - Set a
posterimage so a still frame appears while the video loads. - Keep files small. Aim for a few megabytes per background loop; compress before you commit, since these files ship as-is from
public/.
Adding a Third-Party Embed
For YouTube or Vimeo, paste the provider's <iframe> snippet directly into the component and add loading="lazy" so it does not block the initial page render.
Using a Section in Another Project
Every section is self-contained — none of them reach into a layout or depend on global class names. What they do depend on is the design tokens, because they are styled with tokens rather than hard-coded colors. Copy a section into a project without those tokens and it renders unstyled. Three things have to travel with it.
- Tailwind CSS v4. Install
tailwindcssand@tailwindcss/vite, then register the plugin inastro.config.mjsundervite.plugins. - The
@themeblock fromsrc/styles/tokens.css. Sections use utilities likebg-ink-950,text-paper-400,border-line,shadow-glow, andfont-display— none of which exist in stock Tailwind. The README lists a trimmed-down copy-paste version. - The
@/path alias. Sections import from@/components/…and@/data/…. Add the alias to yourtsconfig.jsonor rewrite those imports as relative paths.
For the Satoshi headings, also copy public/fonts/ and the three @font-face rules at the top of tokens.css. Skip it and headings simply fall back to your own font.
What Else a Section Might Need
- A data file. Most sections read their content from
src/data/—features.ts,pricing.ts,faqs.ts, and so on. Copy that file too, or replace the import with a local array.HeroSection,CTASection,BreadcrumbSection, andAuthShowcaseneed no data file. - A UI component. Sections may pull in
Button.astro,SectionHeading.astro, or one of the SVG mockup components fromsrc/components/ui/. - An image.
HeroSectionandAuthShowcaseimport fromsrc/assets/images/. - Nothing for the JavaScript. The pricing toggle, FAQ accordion, and use-case tabs are plain
<script>blocks inside their own section file, so they travel with it automatically.
Two Things That Catch People Out
- Cascade layers. If your project has unlayered CSS — even something as ordinary as
ul { padding-left: 40px }— it will silently override every Tailwind utility, no matter the specificity, because layered rules always win over unlayered ones. Import older stylesheets into a layer:@import './legacy.css' layer(reset); - Breakpoints. Section-level card grids switch at
lg(1024px) rather thanmd, because three or four columns are too cramped on a 768px tablet; two-column splits still switch atsmormdwhere they comfortably fit. Keep that in mind when mixing these sections with components that go multi-column atmd.
Build and Deployment
Local Development
- Install dependencies:
npm install— requires Node.js 22.12 or newer. - Start the dev server:
npm run dev, then openhttp://localhost:4321. Edits hot-reload as you save. - Build for production:
npm run build. Output goes todist/, and the build surfaces any TypeScript error in your data files. - Preview the build:
npm run previewservesdist/exactly as it will be deployed.
Deploying
This is a fully static site, so any static host works. Point your host at:
- Build command:
npm run build - Output directory:
dist
Netlify, Vercel, Cloudflare Pages, and GitHub Pages all detect Astro automatically. Before your first deploy, set the site value in astro.config.mjs to your real domain so the sitemap and canonical URLs are correct.
Adding a New Page
Create a .astro file in src/pages/ — the filename becomes the route. Import BaseLayout, Header, and Footer, then compose the sections you need. Follow an existing page such as contact.astro as your starting point.
Troubleshooting
- Missing image? Content images are imported from
src/assets/images/, not linked by URL — check theimportpath at the top of the component. For favicons, videos, and fonts, confirm the URL matches the folder underpublic/(/images/…,/videos/…,/fonts/…). - Style not applying? Remember that styles inside a component's
<style>block are scoped. Shared rules belong insrc/styles/tokens.css— and any element-level defaults you add there must go inside its@layer baseblock. An unlayered rule such ash2 { color: … }would beat every Tailwind text-colour utility, no matter how specific the class. - Build failing? Read the error path — it almost always points at a mistyped field in a
src/data/file.