motionsites中文站 / BuildShield
BuildShield
aadmin2026-09-22 发布Site模板0 阅读

BuildShield

类型:Site模板 · 分类:Business · 源码:会员可见

BuildShield
[hidecontent type="vip1"]
# BuildShield — Exact Recreation Prompt



> Paste everything below the line into a fresh AI builder (Bolt / v0 / Claude / Cursor) to regenerate this page byte-for-byte.



---



Build a single-page React + TypeScript + Vite + Tailwind CSS landing page for a construction-insurance brand called **BuildShield**. It is a **two-section full-screen scroll-hijacked experience**: a gold Hero and a white Features section that cross-fade into each other on wheel/touch scroll. Follow every specification below **exactly** — colors, pixel values, animation delays, class names, and URLs are all literal and must not be substituted or "improved."



---



## 1. Stack & Tooling



- **Vite 5** + `@vitejs/plugin-react`, React **18.3**, TypeScript **5.5**

- **Tailwind CSS 3.4** + `postcss` + `autoprefixer`

- **lucide-react ^0.446.0** (only `Menu` and `X` icons are used)

- `package.json` has `"type": "module"`, scripts: `dev`, `build`, `lint`, `preview`, `typecheck` (`tsc --noEmit -p tsconfig.app.json`)



**`vite.config.ts`** — must define the `@` alias and exclude lucide from prebundling:



```ts

import { defineConfig } from 'vite';

import react from '@vitejs/plugin-react';

import { fileURLToPath, URL } from 'node:url';



export default defineConfig({

  plugins: [react()],

  resolve: {

    alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) },

  },

  optimizeDeps: { exclude: ['lucide-react'] },

});

```



Add the matching `"baseUrl": "."` / `"paths": { "@/*": ["./src/*"] }` to `tsconfig.app.json` so the `@/components/...` imports typecheck.



---



## 2. `index.html`



Exactly this — including both font `<link>` tags and the title:



```html

<!doctype html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <link rel="icon" type="image/svg+xml" href="/vite.svg" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>BuildShield - Eliminating the Friction of Risk</title>

    <link href="https://db.onlinewebfonts.com/c/08ae108e7fb1d31fd1311943f98055fe?family=TT+Octosquares+Trl+Cnd" rel="stylesheet">

    <link href="https://fonts.googleapis.com/css2?family=Inter+Tight:wght@400;500;600;700&display=swap" rel="stylesheet">

    <meta property="og:image" content="https://bolt.new/static/og_default.png">

    <meta name="twitter:card" content="summary_large_image">

    <meta name="twitter:image" content="https://bolt.new/static/og_default.png">

</head>

  <body>

    <div id="root"></div>

    <script type="module" src="/src/main.tsx"></script>

  </body>

</html>

```



### Fonts (critical)

- **Display font:** `"TT Octosquares Trl Cnd"` — a condensed geometric square-ish display face, loaded from the OnlineWebFonts CDN URL above. Used for the logo wordmark, H1, H2, and card titles.

- **Body font:** `"Inter Tight"` from Google Fonts, weights **400, 500, 600, 700**. Used for everything else.



---



## 3. `tailwind.config.js`



```js

/** @type {import('tailwindcss').Config} */

export default {

  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],

  theme: {

    extend: {

      fontFamily: {

        octosquares: ['"TT Octosquares Trl Cnd"', 'sans-serif'],

        inter: ['"Inter Tight"', 'sans-serif'],

      },

      colors: {

        gold: {

          DEFAULT: '#F3AF42',

          dark: '#C68C2F',

        },

        dark: '#080808',

      },

    },

  },

  plugins: [],

};

```



**Color tokens used throughout:**



| Token | Hex | Where |

|---|---|---|

| `bg-gold` | `#F3AF42` | Hero background, mobile menu overlay |

| `border-gold-dark` | `#C68C2F` | Hero solid + dashed frames, column divider |

| `bg-dark` / `text-dark` | `#080808` | Buttons, corner dots, logo fill, `<body>` bg |

| `text-gold` | `#F3AF42` | Hero button label text |

| `neutral-200` | Tailwind default | Features frames + dashed borders |

| Card surface | `#F7F7F7` | Inline `style={{ backgroundColor: '#F7F7F7' }}` |

| Card logo fill | `#f59e0b` | The small amber `CardLogo` SVG |



---



## 4. `src/index.css` — exact contents



```css

@tailwind base;

@tailwind components;

@tailwind utilities;



@layer base {

  html {

    scroll-behavior: smooth;

    -webkit-font-smoothing: antialiased;

    -moz-osx-font-smoothing: grayscale;

  }



  html::-webkit-scrollbar {

    display: none;

  }



  html {

    -ms-overflow-style: none;

    scrollbar-width: none;

  }



  body {

    font-family: 'Inter Tight', sans-serif;

    background-color: #080808;

  }

}



@layer utilities {

  @keyframes fade-up {

    from {

      opacity: 0;

      transform: translateY(18px);

    }

    to {

      opacity: 1;

      transform: translateY(0);

    }

  }



  @keyframes fade-in {

    from { opacity: 0; }

    to { opacity: 1; }

  }



  @keyframes scale-in {

    from {

      opacity: 0;

      transform: scale(0.96);

    }

    to {

      opacity: 1;

      transform: scale(1);

    }

  }



  @keyframes border-draw {

    from {

      opacity: 0;

      clip-path: inset(0 100% 100% 0);

    }

    to {

      opacity: 1;

      clip-path: inset(0 0 0 0);

    }

  }



  .scrollbar-hide {

    -ms-overflow-style: none;

    scrollbar-width: none;

  }



  .scrollbar-hide::-webkit-scrollbar {

    display: none;

  }



  .animate-fade-up {

    animation: fade-up 0.7s cubic-bezier(0.16, 1, 0.3, 1) both;

  }



  .animate-fade-in {

    animation: fade-in 0.6s ease both;

  }



  .animate-scale-in {

    animation: scale-in 0.8s cubic-bezier(0.16, 1, 0.3, 1) both;

  }



  .animate-border-draw {

    animation: border-draw 0.9s cubic-bezier(0.16, 1, 0.3, 1) both;

  }

}

```



**Animation summary** — the whole page uses exactly four keyframes and one easing curve, `cubic-bezier(0.16, 1, 0.3, 1)` (a fast-out, long-settle "expo out"):



- `fade-up` — 0.7s, translateY **18px → 0** + fade. Fill mode `both`.

- `fade-in` — 0.6s, `ease`, pure opacity.

- `scale-in` — 0.8s, scale **0.96 → 1** + fade.

- `border-draw` — 0.9s, `clip-path: inset(0 100% 100% 0) → inset(0 0 0 0)`, which wipes the frame in diagonally from the top-left. This is the signature effect.



Every animated element gets its timing via an inline `style={{ animationDelay: 'Nms' }}`.



---



## 5. `src/main.tsx`



```tsx

import { StrictMode } from 'react';

import { createRoot } from 'react-dom/client';

import App from './App.tsx';

import './index.css';



createRoot(document.getElementById('root')!).render(

  <StrictMode>

    <App />

  </StrictMode>

);

```



---



## 6. `src/App.tsx` — the scroll orchestrator



A fixed, non-scrolling `<main className="relative h-screen w-full overflow-hidden">` holding two absolutely-positioned, stacked layers that cross-fade.



**State:** `activeSection` (`0` = Hero, `1` = Features), `transitioning` (boolean lock), and `featuresRef` (a `useRef<HTMLDivElement>` on the Features layer).



**Wheel handler** (`useCallback`, deps `[activeSection, transitioning]`):

- Bail immediately if `transitioning`.

- `deltaY > 0` while on section 0 → lock, go to section 1, unlock after **1000ms** via `setTimeout`.

- `deltaY < 0` while on section 1 → **only** go back to section 0 if `featuresRef.current.scrollTop <= 0` (so the user must scroll Features to the very top before the hero returns). Same 1000ms lock.



**Touch handlers** (inside the `useEffect`): record `touchStartY` on `touchstart`, and on `touchend` compute `deltaY = touchStartY - e.changedTouches[0].clientY`. Threshold is **50px**: `deltaY > 50` advances to Features, `deltaY < -50` returns to Hero (again gated on `scrollTop <= 0`).



All three listeners (`wheel`, `touchstart`, `touchend`) are attached to `window` with `{ passive: true }` and removed on cleanup. Effect deps: `[handleScroll, activeSection, transitioning]`.



**Layer 1 — Hero:**

```

className="absolute inset-0 transition-all duration-700 ease-[cubic-bezier(0.16,1,0.3,1)]"

style: opacity 1→0, transform scale(1)→scale(0.97), pointerEvents 'auto'→'none'

```

(It shrinks slightly as it leaves.)



**Layer 2 — Features:**

```

className="absolute inset-0 overflow-y-auto bg-white transition-all duration-700 ease-[cubic-bezier(0.16,1,0.3,1)] scrollbar-hide"

ref={featuresRef}

style: opacity 0→1, transform scale(1.02)→scale(1), pointerEvents 'none'→'auto'

```

(It settles down from slightly oversized.) Renders `<Features active={activeSection === 1} />`.



Imports use the alias: `import Hero from '@/components/Hero';` and `import Features from '@/components/Features';`.



---



## 7. `src/components/Hero.tsx`



`const NAV_LINKS = ['Product', 'Industries', 'Resources', 'Careers'];` and local `menuOpen` state.



### Root

`<section className="relative min-h-screen w-full bg-gold font-inter overflow-hidden">`



### The nested-frame motif

1. **Outer solid border** — `absolute inset-2 sm:inset-3 border border-gold-dark rounded-sm pointer-events-none animate-border-draw`, delay **100ms**.

2. **Four corner dots** — `w-1 h-1 bg-dark animate-fade-in`, positioned `top-2 left-2 sm:top-3 sm:left-3` and the three mirrored variants. Delays **600 / 700 / 800 / 900ms** (TL, TR, BL, BR).

3. **Inner dashed frame** — `absolute inset-3 sm:inset-4 border border-dashed border-gold-dark rounded-sm flex flex-col overflow-hidden min-h-0 animate-border-draw`, delay **250ms**. **All page content lives inside this frame.**



### Navbar (`<nav>`, inside the dashed frame)

`relative z-30 flex items-center justify-between px-5 sm:px-8 lg:px-12 border-b border-dashed border-gold-dark min-h-[4rem] sm:min-h-[5.5rem]`



- **Logo group** — `flex items-center gap-2 sm:gap-3 animate-fade-up`, delay **400ms**. Contains `<LogoMark />` then the wordmark: `font-octosquares font-medium text-lg sm:text-[22px] text-black tracking-tight` → `BuildShield`.

- **Desktop nav links** — wrapper `hidden md:flex items-center gap-1`. Each link: `px-5 py-2.5 bg-black/5 rounded-sm text-[13px] font-medium uppercase tracking-[0.07em] text-black hover:bg-black/10 transition-colors animate-fade-up` with delay `500 + i * 80` → **500, 580, 660, 740ms**.

- **Desktop CTA** — `hidden md:inline-flex px-6 py-3.5 bg-dark rounded-sm text-gold text-[13px] font-medium uppercase tracking-[0.07em] hover:bg-black transition-colors animate-fade-up`, delay **820ms**, label `Get a Quote`.

- **Mobile hamburger** — `md:hidden flex items-center justify-center w-10 h-10 rounded-sm bg-black/5 hover:bg-black/10 transition-colors animate-fade-in`, delay **500ms**, `aria-label="Toggle menu"`. Inside is a `relative w-5 h-5` box holding **both** lucide `<Menu size={20} />` and `<X size={20} />` absolutely stacked at `inset-0`, cross-fading with `transition-all duration-300`:

  - `Menu`: open → `opacity-0 rotate-90 scale-75`, closed → `opacity-100 rotate-0 scale-100`

  - `X`: open → `opacity-100 rotate-0 scale-100`, closed → `opacity-0 -rotate-90 scale-75`



### Mobile menu overlay

`md:hidden absolute inset-0 top-[4rem] sm:top-[5.5rem] z-20 bg-gold flex flex-col transition-all duration-500 ease-[cubic-bezier(0.16,1,0.3,1)]`, toggling between `opacity-100 translate-y-0 pointer-events-auto` and `opacity-0 -translate-y-4 pointer-events-none`.



- Links container: `flex flex-col px-5 sm:px-8 pt-8 gap-2`. Each link `px-5 py-4 bg-black/5 rounded-sm text-[14px] font-medium uppercase tracking-[0.07em] text-black hover:bg-black/10 transition-all duration-400`, animating `opacity-100 translate-y-0` ↔ `opacity-0 translate-y-3`, with **`transitionDelay`** (not animationDelay) of `80 + i * 50` ms when open, `0ms` when closed → **80, 130, 180, 230ms**.

- CTA below: wrapper `px-5 sm:px-8 mt-6`; button `inline-flex px-6 py-4 bg-dark rounded-sm text-gold text-[13px] font-medium uppercase tracking-[0.07em] hover:bg-black transition-all duration-400`, transitionDelay `80 + NAV_LINKS.length * 50` = **280ms**.



### Content area

`relative z-10 flex-1 grid grid-cols-1 lg:grid-cols-2 min-h-0` — single column on mobile/tablet, **two columns at `lg`**.



**Left column** — `flex flex-col justify-between px-5 sm:px-8 lg:px-12 pt-6 sm:pt-10 lg:pt-14 pb-6 sm:pb-12`



- **H1** — `font-octosquares font-bold text-black uppercase leading-[0.9] select-none`, three `<span className="block">` lines each sized `text-[clamp(1.8rem,7vw,5.5rem)]`, lines 2 and 3 get `mt-2 sm:mt-3`. Each `animate-fade-up` at **500 / 620 / 740ms**:

  1. `Eliminating`

  2. `the friction`

  3. `of risk`

- **Bottom block** — `mt-6 lg:mt-0`:

  - Paragraph: `max-w-[26rem] text-black text-[14px] sm:text-[15px] font-medium uppercase leading-[1.4] tracking-[0.04em] animate-fade-up`, delay **900ms**, text: `Next-generation insurance for the creators and developers building infrastructure.`

  - CTA: `inline-flex mt-5 sm:mt-6 px-6 py-3.5 bg-dark rounded-sm text-gold text-[13px] font-medium uppercase tracking-[0.07em] hover:bg-black transition-colors animate-fade-up`, delay **1050ms**, label `Get a Quote`.



**Right column — video** (visible at every breakpoint)



`flex border-t lg:border-t-0 lg:border-l border-dashed border-gold-dark p-2 animate-scale-in`, delay **600ms**. Note the divider flips from a top border (stacked layout) to a left border at `lg`.



```html

<video autoPlay muted loop playsInline class="w-full h-full object-cover rounded-sm">

  <source

    src="https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260813_100342_9f090e9e-aab8-4f6d-828d-1ace18862aff.mp4"

    type="video/mp4"

  />

</video>

```



> ⚠️ **Use this CloudFront URL verbatim** — do not swap in a placeholder or stock video.



### `LogoMark()` — local component at the bottom of the file



A 32×32 SVG of two overlapping rotated rounded squares (a stylized shield/chevron), both filled `#080808`:



```html

<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" class="flex-shrink-0">

  <rect x="16" y="2" width="18" height="15" rx="1" transform="rotate(45 16 2)" fill="#080808" />

  <rect x="10" y="8" width="12" height="15" rx="1" transform="rotate(45 10 8)" fill="#080808" />

</svg>

```



---



## 8. `src/components/Features.tsx`



Signature: `export default function Features({ active }: { active: boolean })`.



**Gating helper — this is essential.** Because the section is mounted but invisible until scrolled to, its entrance animations must not run early:



```tsx

const anim = (cls: string) => (active ? cls : 'opacity-0');

```



Every animated element uses `` className={`... ${anim('animate-fade-up')}`} `` so it sits at `opacity-0` until `active` flips true, at which point the real animation class is applied and plays from the start.



### Data array (module scope, above the component)



```tsx

const CARDS = [

  {

    title: 'Lightning-FastnQuotes',

    image: 'https://images.unsplash.com/photo-1504307651254-35680f356dfd?w=200&h=200&fit=crop',

    description:

      'Streamlined digital processes designed to deliver instant policy pricing and eliminate administrative bottlenecks.',

  },

  {

    title: 'Precision-CraftednPolicies',

    image: 'https://images.unsplash.com/photo-1541888946425-d81bb19240f5?w=200&h=200&fit=crop',

    description:

      'Bespoke coverage terms engineered specifically around the unique complexities of modern construction sites.',

  },

  {

    title: 'ActivenRisk Mitigation',

    image: 'https://images.unsplash.com/photo-1503387762-592deb58ef4e?w=200&h=200&fit=crop',

    description:

      'Dedicated partnerships focused on identifying hazards and preventing costly claims before they ever happen.',

  },

];

```



The `n` in each title is intentional — titles render with `whitespace-pre-line` so they break onto exactly two lines. Use these three Unsplash photo IDs exactly.



### Structure — same nested-frame motif, but neutral instead of gold



- **Root:** `relative min-h-screen w-full bg-white font-inter p-2 sm:p-3`

- **Outer border:** `relative border border-neutral-200 rounded-sm p-1 sm:p-1 min-h-[calc(100vh-1rem)] sm:min-h-[calc(100vh-1.5rem)]` + `anim('animate-border-draw')`, delay **100ms**

- **Corner dots:** `absolute -top-0.5 -left-0.5 w-1 h-1 bg-dark` (+ three mirrored) with `anim('animate-fade-in')`, delays **500 / 600 / 700 / 800ms**

- **Inner dashed frame:** `border border-dashed border-neutral-200 rounded-sm flex flex-col min-h-[calc(100vh-2rem)] sm:min-h-[calc(100vh-2.5rem)]` + `anim('animate-border-draw')`, delay **200ms**



### Navbar

`relative z-30 flex items-center justify-between px-5 sm:px-8 lg:px-12 border-b border-dashed border-neutral-200 min-h-[4rem] sm:min-h-[5.5rem]`



- Logo group `anim('animate-fade-up')`, delay **350ms**, same `LogoMark` + `BuildShield` wordmark as the Hero.

- Nav links (inline literal array `['Product', 'Industries', 'Resources', 'Careers']`), same classes as Hero, delays `450 + i * 70` → **450, 520, 590, 660ms**.

- CTA — identical to Hero's **except the label is `text-white`, not `text-gold`**: `hidden md:inline-flex px-6 py-3.5 bg-dark rounded-sm text-white text-[13px] font-medium uppercase tracking-[0.07em] hover:bg-black transition-colors`, delay **750ms**.

- **There is no hamburger and no mobile menu in this section** — the nav links and CTA simply stay hidden below `md`.



### Content

`flex-1 flex flex-col px-5 sm:px-8 lg:px-12 py-8 sm:py-10 lg:py-14`



**H2** — `font-octosquares font-bold text-black uppercase leading-[1.05] text-center text-[clamp(1.4rem,4.5vw,3.2rem)] max-w-[48rem] mx-auto`, `anim('animate-fade-up')`, delay **500ms**:



> Adaptive Coverage Designed for an Evolving Industry



**Card grid** — `grid grid-cols-1 md:grid-cols-3 gap-4 sm:gap-5 mt-8 sm:mt-12 lg:mt-14 md:flex-1 md:min-h-0`



Each card: `flex flex-col justify-between items-center rounded-sm p-5 sm:p-6 lg:p-7 min-h-[240px] sm:min-h-[280px] md:min-h-0 md:h-full` + `anim('animate-scale-in')`, with `style={{ backgroundColor: '#F7F7F7', animationDelay: `${700 + i * 120}ms` }}` → **700, 820, 940ms**.



Three stacked children, spread apart by `justify-between`:

1. **Top row** — `flex items-start justify-between w-full`, containing the title `h3` (`font-octosquares font-bold text-black text-[13px] sm:text-[14px] uppercase leading-[1.3] tracking-[0.02em] whitespace-pre-line`) and `<CardLogo />` on the right.

2. **Square thumbnail** — `w-20 h-20 sm:w-24 sm:h-24 rounded-sm overflow-hidden flex-shrink-0` wrapping `<img className="w-full h-full object-cover" alt={card.title} />`.

3. **Description** — `text-black/70 text-[10px] sm:text-[11px] uppercase leading-[1.5] tracking-[0.03em] text-center max-w-[80%]`.



**Bottom text** — `mt-8 sm:mt-10 lg:mt-12 text-center text-black text-[10px] sm:text-[11px] font-semibold uppercase leading-[1.6] tracking-[0.05em] max-w-[26rem] mx-auto pb-4` + `anim('animate-fade-up')`, delay **1100ms**:



> We offer dependable assurance that allows operators to make confident decisions and scale without hesitation.



### `CardLogo()` — the same mark at 20×20, filled amber



```html

<svg width="20" height="20" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" class="flex-shrink-0 mt-0.5">

  <rect x="16" y="2" width="18" height="15" rx="1" transform="rotate(45 16 2)" fill="#f59e0b" />

  <rect x="10" y="8" width="12" height="15" rx="1" transform="rotate(45 10 8)" fill="#f59e0b" />

</svg>

```



`Features.tsx` also declares its **own local copy** of `LogoMark()` (identical to the Hero's, `#080808` fill) — the two components do not share an import.



---



## 9. Responsive behavior (mobile-first, Tailwind defaults: `sm` 640px, `md` 768px, `lg` 1024px)



| Breakpoint | Hero | Features |

|---|---|---|

| **< 640px** | Frames at `inset-2` / `inset-3`; padding `px-5`; navbar `min-h-[4rem]`; hamburger visible, desktop nav + CTA hidden; H1 at clamp floor `1.8rem`; content stacks with video **below** the text, separated by a dashed **top** border | Root `p-2`; cards stack in **one column**, each `min-h-[240px]`; nav links + CTA hidden entirely; H2 at clamp floor `1.4rem` |

| **≥ 640px (`sm`)** | Frames widen to `inset-3` / `inset-4`; padding `px-8`; navbar `min-h-[5.5rem]`; wordmark `text-[22px]`; larger vertical padding | Root `p-3`; cards `min-h-[280px]`, padding `p-6`; thumbnails `w-24 h-24` |

| **≥ 768px (`md`)** | Hamburger + mobile overlay disappear; desktop nav links and CTA appear | Cards become a **3-column grid**, `md:flex-1 md:min-h-0 md:h-full` so they stretch to fill remaining height; nav links + CTA appear |

| **≥ 1024px (`lg`)** | Content becomes **2-column grid**; video divider flips from `border-t` to `border-l`; padding `px-12`; H1 scales up to the `5.5rem` clamp ceiling; left column's bottom block loses its `mt-6` (`lg:mt-0`) so `justify-between` spreads heading and CTA to the extremes | Padding `px-12 py-14`; card padding `p-7`; H2 up to `3.2rem` |



Fluid type is handled entirely by `clamp()` — H1 `clamp(1.8rem, 7vw, 5.5rem)`, H2 `clamp(1.4rem, 4.5vw, 3.2rem)` — so there are no font-size breakpoints for the headings.



Touch users get the same section transition via the 50px swipe threshold. Scrollbars are hidden globally on `html` and on the Features layer via `.scrollbar-hide`.



---



## 10. Design language summary



Editorial/technical "blueprint" aesthetic: a **double frame** (solid outer + dashed inner) with **1×1px dark corner dots**, everything set in **uppercase** with wide letter-spacing (`0.02em`–`0.07em`), `rounded-sm` on every surface, and near-flat color — no shadows, no gradients. Buttons are solid `#080808` pills with `rounded-sm` corners. The dashed borders double as layout dividers (under the navbar, between the text and video columns). The single `expo-out` easing curve and the diagonal `border-draw` clip-path wipe give the whole page one coherent motion signature.
[/hidecontent]
← 返回首页