Skip to main content
The HiroLeague website lives in hiroleague-website/ at the repo root. It is a standalone project with its own package.json and its own Git repository (rendermagix/hiroleague-website) — entirely separate from the rest of the monorepo. All commands on this page are run from inside that folder.

Prerequisites

  • Node.js 22.12 or higher — required by Astro 6. Node 24 LTS works fine. Check your version:
node --version
No other global tools are required. There is no PostCSS config, no Tailwind CLI — the Vite plugin handles everything.

First-time setup

After cloning (or pulling the submodule), install dependencies:
cd hiroleague-website
npm install

Dev server

npm run dev
The site is served at http://localhost:4321. Changes to .astro files, React components, and CSS hot-reload instantly.

Production build

npm run build        # output → dist/
npm run preview      # serve the dist/ build locally
The build is fully static (output: "static"). All pages are pre-rendered to HTML at build time.

Project structure

Only the files below are owned by this project — everything else is inherited from the theme and should not be edited unless you know what you are changing.
File / folderPurpose
src/layouts/main.astroRoot HTML shell — <head>, dark-mode init script, Header, Footer
src/pages/index.astroLanding page — assembles Hero, Features, Waitlist sections
src/pages/blog/index.astroBlog listing page
src/pages/blog/why-we-are-building-hiroleague.astroFirst blog article
src/components/Header.tsxNavigation bar — logo, links, theme toggle
src/components/Hero.tsxHero section — animated headline, tagline, CTA
src/components/Features.tsxFeatures grid — four product pillars
src/components/Waitlist.tsxEmail waitlist section
src/components/Footer.tsxFooter — social links, copyright
src/components/reactbits/BlurText.tsxAnimated text reveal (ReactBits pattern)
src/styles/global.cssTailwind v4 imports, CSS tokens, dark-mode variant, custom animations
astro.config.jsAstro + Vite config — integrations and site URL
wrangler.jsoncCloudflare Workers deployment config
components.jsonshadcn/ui config

Tech stack

LayerPackageVersion
Frameworkastro6
UI runtimereact + react-dom18
Stylingtailwindcss + @tailwindcss/vite4
Componentsshadcn/ui (@radix-ui/*, lucide-react)
Animationframer-motion12
Text effectsReactBits BlurText (local copy)
Animate utilstw-animate-css
Deploymentwrangler4
No PostCSS, no tailwind.config.* file. Tailwind configuration lives entirely in src/styles/global.css inside @theme inline.

Deployment

The site is deployed to Cloudflare Workers and served at hiroleague.com. The Workers config is in wrangler.jsonc at the repo root:
{
  "name": "hiroleague-website",
  "compatibility_date": "2026-03-15",
  "assets": {
    "directory": "./dist",
    "not_found_handling": "404-page"
  }
}
wrangler is installed as a dev dependency. The deploy script in package.json builds and deploys in one step:
npm run deploy   # runs: astro build && wrangler deploy

CI/CD via Workers Builds (auto-deploy on push)

Workers Builds is the recommended path — every push to main triggers a build and deploy automatically. One-time setup:
  1. Log in to the Cloudflare dashboard and go to Workers & Pages.
  2. Click Create, then under Import a repository, connect your GitHub account and select rendermagix/hiroleague-website.
  3. Set:
    • Build command: npx astro build
    • Deploy command: npx wrangler deploy
  4. Click Save and Deploy.
Every subsequent push to main deploys automatically. The Worker is reachable at a workers.dev subdomain immediately.

Manual deploy

To deploy from your local machine without CI/CD:
cd hiroleague-website
npx wrangler login   # opens browser to authenticate with Cloudflare
npm run deploy

Custom domain

  1. In the Cloudflare dashboard, go to Workers & Pages → hiroleague-website → Custom Domains.
  2. Add hiroleague.com.
  3. Because the domain is already on Cloudflare DNS, the routing is set up automatically — no manual DNS changes needed.
  4. SSL is provisioned automatically.

Troubleshooting

This can happen when upgrading multiple packages simultaneously. Add --legacy-peer-deps to let npm resolve the conflict:
npm install --legacy-peer-deps
The dark-mode init script in src/layouts/main.astro must use is:inline so Astro does not defer or bundle it. If the script is missing or deferred, the .dark class is applied after first paint and causes a white flash. Verify the script tag reads:
<script is:inline>
  (function () {
    var stored = localStorage.getItem('theme');
    var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    if (stored === 'dark' || (!stored && prefersDark)) {
      document.documentElement.classList.add('dark');
    }
  })();
</script>
Tailwind v4 uses @theme inline for token mapping — there is no tailwind.config.* file. If you add a new CSS variable token, make sure you also map it in the @theme inline block, otherwise the generated utility class will not be available.
Astro renders React components as islands. Components that use browser APIs (localStorage, window, etc.) must use a client:* directive in the .astro page, otherwise they fail during server-side pre-rendering. Use client:load for components that need to be interactive immediately, or client:visible for below-the-fold components.