Premium, horizontal-first React landing page based on Figma design 8:426.
- React 19 + TypeScript + Vite
- Feature-based folders:
src/sections/— Page sections (feature-based)src/components/— Shared UI componentssrc/hooks/— Custom React hookssrc/data/— Static content/datasrc/theme/tokens.css— Design tokens (colors, spacing, typography)
- CSS Modules: All components use local CSS modules for styling
- Design Tokens: All colors, spacing, and typography use CSS custom properties from
tokens.css - Framer Motion: For reveal and premium interaction animation
- Install dependencies:
npm install
- Configure Environment:
Create a
.env.localfile for local development (see .env.example):cp .env.example .env.local
- Run development server:
npm run dev
The application uses Vite's environment variable system. For local development, use .env.local.
| Variable | Description | Default |
|---|---|---|
VITE_API_BASE_URL |
The target backend for the dev proxy (e.g., https://dev.capyrpi.org) |
undefined |
VITE_API_VERSION |
The API version prefix | /api/v1 |
Note
If VITE_API_BASE_URL is set, Vite will automatically proxy all /api requests to that target. This avoids CORS issues and allows for testing against remote backends.
Production build:
npm run buildBuild and run the production image locally:
docker build -t capy-lander:local .
docker run --rm -p 8080:80 capy-lander:localOpen http://localhost:8080.
This repo supports both Compose modes:
image:mode for reproducible runs (default indocker-compose.yml)build:mode for local development iteration (indocker-compose.override.yml)
By default, Docker Compose loads docker-compose.override.yml, so a local run builds from source:
docker compose up --buildTo run a published registry image instead, disable overrides and set the image tag:
CAPY_IMAGE=ghcr.io/<owner>/<repo>:latest docker compose -f docker-compose.yml upSee CONTRIBUTING.md for full guidelines.
- Feature-based folders: Place new features/sections in their own folder under
src/sections/orsrc/components/. - CSS Modules: Use local CSS modules for all new components.
- Design Tokens: Reference all colors, spacing, and typography via
src/theme/tokens.css. - JSDoc Comments: Add clear JSDoc comments to all hooks and complex logic blocks, explaining why the logic exists.
Workflow: .github/workflows/docker-image.yml
- PRs to
main: lint, build, and container build validation (no push) - Push to
main: lint, build, build and push image to GHCR - Version tags (
v*): lint, build, build and push versioned image tags
For questions, open an issue or start a discussion.
Published image name:
ghcr.io/<owner>/<repo>
Tags include branch/PR refs, commit SHA, semver (for v* tags), and latest on the default branch.
src/App.tsx: app shell + panel composition + horizontal scroll containersrc/hooks/useHorizontalWheelScroll.ts: maps vertical wheel intent to horizontal scrollingsrc/components/*: reusable primitives (GlassCard,TopNav,AspectImage)src/sections/*: page-level sections matching Figma panel structuresrc/data/content.ts: static content and asset URLssrc/theme/tokens.css: global design tokens (colors, spacing, radii, fonts, glass effects)
Core tokens live in src/theme/tokens.css and are consumed by all sections:
- Global colors (
--c-bg,--c-surface,--c-accent, text tones) - Glassmorphism (
--glass-blur,--glass-highlight,--glass-shadow) - Type system (
--font-display,--font-body) - Spacing/radius system (
--space-*,--radius-*)
This keeps visual updates centralized and safe.
- Vertical page scroll is disabled at document level.
- Main scroller (
.horizontalScroller) has x-overflow only. - Wheel events are intercepted and converted to horizontal movement.
- Touchpad/mouse wheel deltas both work by choosing dominant intent (
deltaYordeltaX).
- All logo/icon/illustration image nodes use
AspectImage. AspectImageenforcesobject-fit: containand centered positioning.- Containers define the intended dimensions; image content is never stretched.
When iterating:
- Verify panel widths/heights against Figma track
- Verify card padding and inter-card gaps
- Verify font sizes: 16, 18, 20, 24, 36, 40, 96, 160
- Verify CTA dimensions and corner radii
- Verify no vertical scrolling on desktop
- Verify all SVGs/icons remain non-distorted
public/assets/brand: logo and brand markspublic/assets/illustrations: larger decorative illustrationspublic/assets/ui: UI chrome shapes (pills and controls)public/assets/social: social platform icons
Canonical brand filenames:
public/assets/brand/capy-full-white.svgpublic/assets/brand/capy-full-primary.svg
Asset mapping is centralized in src/data/content.ts.