mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
examples: add 3D creator portfolio and Velar luxury real-estate templates (#3817)
* examples: add 3D creator portfolio and Velar luxury real-estate templates Two first-party motionsites.ai template seeds under plugins/_official/examples/, each shipping the manifest + locked SKILL.md spec + a self-contained rendered example.html fidelity anchor. - example-3d-creator-portfolio: dark gradient-text hero with a magnetic 3D portrait, scroll marquee, char-reveal About, and sticky-stacking project cards. - example-velar-luxury-real-estate: typewriter preloader, scroll-driven building that scales up while pinning to a dark stats band, count-up stats, and a hover-expand video gallery. Fixed decoration/portrait images are inlined as compressed WebP data URIs so the card and detail previews never break in the sandbox; large GIFs/videos and stable -CDN backgrounds stay as remote URLs. Both manifests validate against PluginManifestSchema (od.kind=scenario). * examples: use first-party metadata for motionsites templates Align the 3D creator portfolio and Velar manifests with the first-party metadata contract used by the rest of plugins/_official/examples/** (MIT, author Open Design, repo homepage) instead of CC-BY-4.0 / third-party motionsites provenance. Generated-By: looper 0.8.1 (runner=fixer, agent=claude-code) * examples: point all inlined-asset references in the locked query at example.html The per-section spec in od.useCase.query.en still named the original remote hosts (figma.site portrait/decorations, cloudinary HOUSE_IMG) as the asset source, while only the trailing note said to reuse the inlined data URIs. Since the query is the authoritative generation brief injected on Use, a port could copy the deprecated remote URLs and regress to sandbox-403 / broken images. Rewrote those references to instruct reusing the inlined data:image/webp URIs from example.html. Genuinely-remote assets on stable CDNs (the 21 motionsites marquee GIFs, 9 higgs project images, 5 cloudfront gallery videos, the higgs hero background) are unchanged. * examples: align Velar nav dark-section refs in the locked query with the seed The Fixed Navigation bullet in od.useCase.query.en said the nav-color logic watches "Section 4 and Section 5", but the seed and SKILL.md define the dark sections as Section 5 (dark statement band) and Section 6 (gallery). Since the query is injected as the generation brief, the stale ref could make a port watch the wrong sections and leave the nav dark over the gallery. Updated the string to match the seed/skill wording. * examples: give the 3D portfolio nav links real anchor targets The hero nav shipped #price and #contact links with no matching ids in the seed, so half the navbar did nothing in the preview (and ports would inherit the dead links). Added id="price" to the Services section and a minimal contact footer (id="contact") so all four nav anchors resolve to real targets. The four-link names stay as the prompt specifies; only the seed gains anchors. * examples: document the 3D portfolio contact footer in the locked query and skill The previous fix added a #contact footer to example.html but left the injected query and SKILL.md describing only five sections (no contact target), so a port could still recreate a dead #contact anchor. Added the Contact footer section to the SECTION ORDER, a nav→anchor mapping (every link must resolve), and a Contact Section spec in both od.useCase.query.en and SKILL.md so the prompt, skill, and seed all agree. --------- Co-authored-by: qiongyu1999 <2694684348@qq.com>
This commit is contained in:
co-authored by
qiongyu1999
parent
e2dc6423cd
commit
df9ec8f40d
@@ -0,0 +1,119 @@
|
||||
---
|
||||
name: 3d-creator-portfolio
|
||||
description: "Use this plugin when the user wants a dark, premium 3D-creator / designer portfolio landing page: a full-viewport hero with a gradient-text headline and a mouse-following magnetic 3D portrait, a scroll-driven horizontal image marquee, an About section with corner 3D decorations and character-by-character scroll-reveal text, a white Services list, and sticky-stacking project cards. Invoke for '3D creator portfolio', 'designer landing page', 'creative portfolio with magnetic hero', or when the user references the Jack 3D Creator template."
|
||||
version: 0.1.0
|
||||
od:
|
||||
mode: prototype
|
||||
surface: web
|
||||
scenario: design
|
||||
preview:
|
||||
type: html
|
||||
entry: example.html
|
||||
design_system:
|
||||
requires: false
|
||||
---
|
||||
|
||||
# Jack — 3D Creator Portfolio
|
||||
|
||||
Produce a dark, premium **3D-creator portfolio landing page**. A complete, rendered reference implementation ships beside this skill at `example.html` — **start from it**. Copy `example.html`, then adjust copy and data; do not rewrite the CSS or invent a new visual language. The seed already encodes the exact tokens, gradient text, magnetic-hover portrait, scroll marquee, char-reveal text, sticky-stacking cards, and responsive behavior described below.
|
||||
|
||||
This is the authoritative build brief. Follow it exactly — the named colors, gradients, fonts, sizes, image URLs, and animations are locked.
|
||||
|
||||
**Inlined images (critical):** `example.html` ships the hero portrait and the four About-section 3D decorations as **inlined `data:image/webp;base64,…` URIs** — keep those exactly as they are. Do **not** swap them back for the original `shrug-person-78902957.figma.site/...` URLs: that host rate-limits / 403s inside the preview sandbox and renders as broken images. When you copy the seed, the inlined images come with it; only replace one if the user supplies their own asset, and prefer a data URI over a remote URL. The 21 motionsites marquee GIFs and the 9 higgs/cloudfront project images stay as remote URLs (large stable CDNs).
|
||||
|
||||
## Stack
|
||||
|
||||
- Default output: a single self-contained HTML file (the `example.html` seed) using vanilla CSS + JS. It already includes everything inline.
|
||||
- If the user explicitly asks for the React project: port the seed faithfully to **React 18 + TypeScript + Vite + Tailwind CSS + Framer Motion + lucide-react**. Same tokens, same markup structure, same animations. Section order: `HeroSection → MarqueeSection → AboutSection → ServicesSection → ProjectsSection → ContactSection (footer)`. Do not change the design while porting.
|
||||
|
||||
## Global styles — locked
|
||||
|
||||
- Background `#0C0C0C` on `html, body, #root`, and the main wrapper.
|
||||
- Font: **Kanit** (Google Fonts, weights 300–900), `'Kanit', sans-serif`.
|
||||
- Page title: `Jack — 3D Creator`.
|
||||
- Global reset: `box-sizing: border-box; margin: 0; padding: 0`.
|
||||
- Main wrapper: `overflow-x: clip`.
|
||||
- `.hero-heading` gradient text: `background: linear-gradient(180deg, #646973 0%, #BBCCD7 100%)` with `-webkit-background-clip: text` and `-webkit-text-fill-color: transparent`.
|
||||
|
||||
## 1. Hero Section (`h-screen`, flex column, `overflow-x: clip`)
|
||||
|
||||
- **Navbar:** flex `justify-between`, 4 links — "About", "Price", "Projects", "Contact". Color `#D7E2EA`, font-medium, uppercase, `tracking-wider`. Sizes `text-sm md:text-lg lg:text-[1.4rem]`. Padding `px-6 md:px-10 pt-6 md:pt-8`. Hover: opacity 70%, 200ms. The four links map to anchors that must ALL resolve: "About" → `#about`, "Price" → the Services section (`id="price"`), "Projects" → `#projects`, "Contact" → the Contact footer (`id="contact"`). No dead anchors.
|
||||
- **Hero heading:** massive `<h1>` "Hi, i'm jack" (lowercase "i", curly apostrophe `'`). `.hero-heading` gradient, font-black, uppercase, tracking-tight, leading-none, whitespace-nowrap, `w-full`. Sizes `text-[14vw] sm:text-[15vw] md:text-[16vw] lg:text-[17.5vw]`. Margin top `mt-6 sm:mt-4 md:-mt-5`. Wrapped in an `overflow-hidden` container.
|
||||
- **Bottom bar:** flex `justify-between items-end`, `pb-7 sm:pb-8 md:pb-10`.
|
||||
- Left: paragraph "a 3d creator driven by crafting striking and unforgettable projects", color `#D7E2EA`, font-light, uppercase, tracking-wide, leading-snug, `font-size: clamp(0.75rem, 1.4vw, 1.5rem)`, `max-w-[160px] sm:max-w-[220px] md:max-w-[260px]`.
|
||||
- Right: **ContactButton** (see Reusable components).
|
||||
- **Hero portrait:** centered, wrapped in a **Magnet** component (mouse-following). Image is the inlined portrait `data:` URI (originally `Rectangle_40443.81459862.png`). Magnet: `padding 150, strength 3, activeTransition "transform 0.3s ease-out", inactiveTransition "transform 0.6s ease-in-out"`. Positioning `absolute left-1/2 -translate-x-1/2 z-10`. Width `w-[280px] sm:w-[360px] md:w-[440px] lg:w-[520px]`. On mobile: `top-1/2 -translate-y-1/2`; on `sm+`: `sm:top-auto sm:translate-y-0 sm:bottom-0`.
|
||||
- **FadeIn delays:** Navbar `delay 0, y -20`. Heading `delay 0.15, y 40`. Left text `delay 0.35, y 20`. Contact button `delay 0.5, y 20`. Portrait `delay 0.6, y 30`.
|
||||
|
||||
## 2. Marquee Section
|
||||
|
||||
Two rows of images that scroll horizontally based on page scroll position. Background `#0C0C0C`. Padding `pt-24 sm:pt-32 md:pt-40 pb-10`.
|
||||
|
||||
- 21 GIFs from `motionsites.ai/assets/...` (exact URLs in the seed — keep them).
|
||||
- **Row 1:** first 11 images, tripled for seamless scroll. Moves RIGHT: `translateX(offset - 200)`.
|
||||
- **Row 2:** remaining 10 images, tripled. Moves LEFT: `translateX(-(offset - 200))`.
|
||||
- Scroll offset: `(window.scrollY - sectionTop + window.innerHeight) * 0.3`.
|
||||
- Each tile: 420×270px, `rounded-2xl`, `object-cover`, lazy-loaded. Gap `gap-3` between tiles and between rows.
|
||||
- `will-change: transform`; scroll listener is **passive**.
|
||||
|
||||
## 3. About Section (`min-h-screen`, centered, `px-5 sm:px-8 md:px-10 py-20`)
|
||||
|
||||
Four decorative 3D images positioned absolutely in corners (all inlined `data:` URIs in the seed):
|
||||
|
||||
- **Top-left** — moon icon (`moon_icon.11395d36.png`): `w-[120px] sm:w-[160px] md:w-[210px]`, `top-[4%] left-[1%] sm:left-[2%] md:left-[4%]`. FadeIn `delay 0.1, x -80, dur 0.9`.
|
||||
- **Bottom-left** — 3D object (`p59_1.4659672e.png`): `w-[100px] sm:w-[140px] md:w-[180px]`, `bottom-[8%] left-[3%] sm:left-[6%] md:left-[10%]`. FadeIn `delay 0.25, x -80, dur 0.9`.
|
||||
- **Top-right** — lego icon (`lego_icon-1.703bb594.png`): `w-[120px] sm:w-[160px] md:w-[210px]`, `top-[4%] right-[1%] sm:right-[2%] md:right-[4%]`. FadeIn `delay 0.15, x 80, dur 0.9`.
|
||||
- **Bottom-right** — 3D group (`Group_134-1.2e04f3ce.png`): `w-[130px] sm:w-[170px] md:w-[220px]`, `bottom-[8%] right-[3%] sm:right-[6%] md:right-[10%]`. FadeIn `delay 0.3, x 80, dur 0.9`.
|
||||
|
||||
- **Heading:** "About me", `.hero-heading` gradient, font-black, uppercase, leading-none, tracking-tight, centered, `font-size: clamp(3rem, 12vw, 160px)`. FadeIn `delay 0, y 40`.
|
||||
- **Animated paragraph (AnimatedText):** char-by-char scroll-driven opacity (0.2 → 1) based on scroll progress, offset `['start 0.8', 'end 0.2']`. Text: "With more than five years of experience in design, i focus on branding, web design, and user experience, i truly enjoy working with businesses that aim to stand out and present their best image. Let's build something incredible together!" Color `#D7E2EA`, font-medium, centered, leading-relaxed, `max-w-[560px]`, `font-size: clamp(1rem, 2vw, 1.35rem)`.
|
||||
- **ContactButton** below the text. Gap heading→text `gap-10 sm:gap-14 md:gap-16`; gap text→button `gap-16 sm:gap-20 md:gap-24`.
|
||||
|
||||
## 4. Services Section (white `#FFFFFF`, `rounded-t-[40px] sm:rounded-t-[50px] md:rounded-t-[60px]`)
|
||||
|
||||
Padding `px-5 sm:px-8 md:px-10 py-20 sm:py-24 md:py-32`.
|
||||
|
||||
- **Heading:** "Services" in `#0C0C0C`, font-black, uppercase, centered, `font-size: clamp(3rem, 12vw, 160px)`, `mb-16 sm:mb-20 md:mb-28`.
|
||||
- 5 items, vertical list, `max-w-5xl`, centered. Each: number (font-black, `clamp(3rem, 10vw, 140px)`, `#0C0C0C`) on the left + name & description stacked on the right. Name: font-medium, uppercase, `clamp(1rem, 2.2vw, 2.1rem)`. Description: font-light, leading-relaxed, `max-w-2xl`, `clamp(0.85rem, 1.6vw, 1.25rem)`, opacity 0.6. 1px borders `rgba(12,12,12,0.15)`. Padding `py-8 sm:py-10 md:py-12`. Staggered FadeIn: each item `delay = i * 0.1`.
|
||||
- `01 — 3D Modeling`: "Creation of detailed objects, characters, or environments tailored to specific client needs, ideal for games, products, and visualizations."
|
||||
- `02 — Rendering`: "High-quality, photorealistic renders that showcase designs with custom lighting, textures, and materials to bring concepts to life."
|
||||
- `03 — Motion Design`: "Dynamic animations and motion graphics that add energy and storytelling to brands, products, and digital experiences."
|
||||
- `04 — Branding`: "Crafting cohesive visual identities — from logos to full brand systems — that communicate a clear and memorable presence."
|
||||
- `05 — Web Design`: "Designing clean, modern, and conversion-focused websites with attention to layout, typography, and user experience."
|
||||
|
||||
## 5. Projects Section (dark `#0C0C0C`, `rounded-t-[40px] sm:rounded-t-[50px] md:rounded-t-[60px]`, `-mt-10 sm:-mt-12 md:-mt-14`, `z-10`)
|
||||
|
||||
- **Heading:** "Project" (singular), `.hero-heading` gradient, same styling as other headings.
|
||||
- **3 sticky-stacking project cards** that scale down as you scroll past them (Framer Motion `useScroll` + `useTransform`). Each card is `sticky top-24 md:top-32` inside an `h-[85vh]` container.
|
||||
- Scale: `targetScale = 1 - (totalCards - 1 - index) * 0.03`. Each card offset `top: ${index * 28}px`.
|
||||
- Card: `rounded-[40px] sm:rounded-[50px] md:rounded-[60px]`, `border-2 border-[#D7E2EA]`, background `#0C0C0C`, padding `p-4 sm:p-6 md:p-8`.
|
||||
- **Top row:** number (huge, same style as services), category label, project name, and a **LiveProjectButton** ("Live Project" ghost pill).
|
||||
- **Bottom row:** two-column image grid — left column (40%) has 2 stacked images, right column (60%) has 1 tall image. All `rounded-[40px] sm:rounded-[50px] md:rounded-[60px]`. Left-top height `clamp(130px, 16vw, 230px)`; left-bottom height `clamp(160px, 22vw, 340px)`.
|
||||
- Project data (higgs/cloudfront URLs are in the seed — keep them):
|
||||
- `01 — Nextlevel Studio` (Client)
|
||||
- `02 — Aura Brand Identity` (Personal)
|
||||
- `03 — Solaris Digital` (Client)
|
||||
|
||||
## 6. Contact Section (footer)
|
||||
|
||||
A closing `<footer id="contact">` so the navbar's **Contact** link resolves to a real target. Dark background `#0C0C0C`, centered column, generous padding (e.g. `80px 24px 120px`, `gap` ~32px). Contains a large gradient headline using `.hero-heading` (e.g. "Let's talk") and a **ContactButton** ("Contact Me"). Keep it minimal — its job is to be a real, scrollable anchor target consistent with the bundled `example.html`.
|
||||
|
||||
## Reusable Components
|
||||
|
||||
- **ContactButton:** rounded-full pill. Background `linear-gradient(123deg, #18011F 7%, #B600A8 37%, #7621B0 72%, #BE4C00 100%)`. Box-shadow `0px 4px 4px rgba(181,1,167,0.25), 4px 4px 12px #7721B1 inset`. White 2px outline with `-3px` offset. Text: white, font-medium, uppercase, tracking-widest. Sizes `px-8 py-3 sm:px-10 sm:py-3.5 md:px-12 md:py-4`, `text-xs sm:text-sm md:text-base`. Label "Contact Me".
|
||||
- **LiveProjectButton:** ghost/outline pill. Rounded-full, `border-2 border-[#D7E2EA]`, text `#D7E2EA`, font-medium, uppercase, tracking-widest. Sizes `px-8 py-3 sm:px-10 sm:py-3.5`, `text-sm sm:text-base`. Hover `bg-[#D7E2EA]/10`. Label "Live Project".
|
||||
- **FadeIn:** Framer Motion wrapper, `whileInView` with `viewport={{ once: true, margin: "50px", amount: 0 }}`. Props: `delay`, `duration` (default 0.7), `x` (default 0), `y` (default 30). Easing `[0.25, 0.1, 0.25, 1]`. Use `motion.create()` for dynamic element types. (In the vanilla seed this is an `IntersectionObserver` + CSS transition.)
|
||||
- **Magnet:** mouse-following magnetic hover. Track mouse position relative to element center; apply `translate3d` divided by `strength`. Activates when cursor is within `padding` distance of the element edge. Transition-in `0.3s ease-out`, out `0.6s ease-in-out`. `will-change: transform`.
|
||||
- **AnimatedText:** char-by-char scroll reveal. Each character goes opacity 0.2 → 1 based on its position relative to scroll progress. Framer Motion `useScroll` on the paragraph, offset `['start 0.8', 'end 0.2']`. Each char uses an invisible placeholder + an absolutely-positioned animated span. (In the seed, a scroll listener lights up character spans progressively.)
|
||||
|
||||
## Key Dependencies (React port)
|
||||
|
||||
`react`, `react-dom` (^18.3.1), `framer-motion` (^12.38.0), `lucide-react` (^0.344.0), `tailwindcss` (^3.4.1), `vite`, `typescript`.
|
||||
|
||||
## Responsive
|
||||
|
||||
Tailwind default breakpoints (sm 640, md 768, lg 1024), mobile-first. Heavy use of `clamp()` for fluid typography. The design must scale gracefully from mobile to ultra-wide.
|
||||
|
||||
## Color Rules — hard
|
||||
|
||||
Dark theme anchored on `#0C0C0C` background and `#D7E2EA` foreground text. Hero/heading gradient `#646973 → #BBCCD7` is locked. ContactButton multi-stop gradient (`#18011F → #B600A8 → #7621B0 → #BE4C00`) is locked — do not flatten it to a single color. Services section is the only light (`#FFFFFF`) block.
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,99 @@
|
||||
---
|
||||
name: velar-luxury-real-estate
|
||||
description: "Use this plugin when the user wants a high-end luxury real-estate / architecture landing page with cinematic scroll choreography: a typewriter preloader that lifts away, a scroll-driven house image that rises from below and scales up while pinning to a dark statement section, a sticky dark stats band with count-up numbers, and a hover-expand video gallery that slides up over the dark section. Invoke for 'luxury real estate landing page', 'architecture brand site', 'scroll-driven hero with rising building', or when the user references the Velar template."
|
||||
version: 0.1.0
|
||||
od:
|
||||
mode: prototype
|
||||
surface: web
|
||||
scenario: design
|
||||
preview:
|
||||
type: html
|
||||
entry: example.html
|
||||
design_system:
|
||||
requires: false
|
||||
---
|
||||
|
||||
# Velar. — Luxury Real Estate Landing Page
|
||||
|
||||
Produce a single-page, cinematic luxury real-estate landing page. A complete, rendered reference implementation ships beside this skill at `example.html` — **start from it**. Copy `example.html`, then adjust copy and data; do not rewrite the choreography or invent a new visual language. The seed already encodes the exact tokens, preloader typewriter, scroll-driven house animation, sticky dark stats band, count-up, and hover-expand gallery described below.
|
||||
|
||||
This is the authoritative build brief. Follow it exactly — the named colors, fonts, timings, image URLs, and the scroll-math are locked.
|
||||
|
||||
**Inlined image (critical):** `example.html` ships the building/house silhouette (`HOUSE_IMG`, originally `res.cloudinary.com/.../building_bzziky.png`) as an inlined `data:image/webp;base64,…` URI — keep it exactly as-is. The 5 cloudfront gallery `.mp4` videos and the `BG_IMG` higgs.ai hero background stay as remote URLs (large stable CDNs); the cloudinary host is the one to inline because it is the load-bearing, repeatedly-scaled centerpiece asset.
|
||||
|
||||
## Stack
|
||||
|
||||
- Default output: a single self-contained HTML file (the `example.html` seed) using vanilla CSS + JS. It already includes everything inline.
|
||||
- If the user explicitly asks for the React project: port the seed faithfully to **React 18 + TypeScript + Vite + Tailwind CSS** with **only** `lucide-react` for icons (the hamburger→`X`). All animation logic lives in a single `src/App.tsx` using `useState`, `useEffect`, `useRef`, `useCallback`, and `IntersectionObserver`. No other libraries. Do not change the design while porting.
|
||||
|
||||
## Global setup — locked
|
||||
|
||||
- Page background `#f5f0ea` (warm off-white). Body wrapper `overflow-x: clip`.
|
||||
- Fonts via `@import` in an inline `<style>`: **Syne** (400, 700, 800, 900) + **Inter** (300, 400, 500, 600) from Google Fonts.
|
||||
- Constants: `GRASS_GREEN = '#213138'` (preloader bg + default logo color), `FULL_TEXT = 'Velar.'`, `HOUSE_IMG` (inlined data URI in the seed), `BG_IMG` (higgs.ai hero bg), and the 5 cloudfront gallery videos (in order — keep them).
|
||||
|
||||
## Section 1 — Preloader / intro overlay
|
||||
|
||||
Fixed full-viewport overlay (`z-index:100`, bg `#213138`, centered flex). Typewriter of `Velar.` in Syne `2.6rem`, white, `letter-spacing:-0.02em`; letters weight 700 except `.` weight 900. Blinking white cursor (3px × 1.1em rounded bar, `blink 0.7s step-end infinite`, opacity 0↔1) follows the last typed letter.
|
||||
|
||||
Timings (`setTimeout`): `CHAR_INTERVAL=140ms`, `TYPE_START=600ms`. Reveal letter `i` at `TYPE_START + i*CHAR_INTERVAL`. `LIFT_AT = TYPE_START + 6*CHAR_INTERVAL + 700`. Hide cursor at `LIFT_AT-150`. At `LIFT_AT`, lift overlay `translateY(-100%)` with `transform 1.5s cubic-bezier(0.45,0,0.15,1)` AND trigger the house rise. At `LIFT_AT+1300`, fade in hero text (`opacity 0→1`, `translateY(-28px)→0`, `0.7s cubic-bezier(0.22,1,0.36,1) 0.1s`). At `LIFT_AT+2100`, set `liftDone`, disable overlay transition (parked off-screen), and hand house control to the scroll handler.
|
||||
|
||||
## Section 2 — Fixed nav
|
||||
|
||||
Fixed top nav `z-50`, padding `px-6 md:px-10 lg:px-16`, `py-5 md:py-6`, flex justify-between. Left: `Velar.` in Syne `text-xl`, weight 700 letters / 900 dot, color = `navColor`. Right: hamburger — two stacked 28px×1px lines, top shrinks to `w-5` on hover; when open swaps to Lucide `X` (size 24).
|
||||
|
||||
Scroll behavior: if any **dark section** (Section 5 dark band + Section 6 gallery) overlaps the viewport top (`rect.top <= 0 && rect.bottom > 0`), `navColor = '#ffffff'`, else `'#213138'`. Transition `color 0.35s ease`.
|
||||
|
||||
Mobile menu: full-screen `#f5f0ea` overlay (`z-40`), centered, 4 stacked links — `Residences`, `Story`, `Listings`, `Inquire` — Syne `text-4xl`, font-light, tracking-widest, uppercase, black, hover `text-gray-500`. Click closes.
|
||||
|
||||
## Section 3 — Hero
|
||||
|
||||
`<section>` `position:relative; min-height:100vh; overflow:visible`, `BG_IMG` as cover/center background. Hero text block `z-index:10`, hidden initially, fades+slides in per preloader timing.
|
||||
|
||||
- Top row `.hero-heading-top` (`px-6 md:px-10 lg:px-16`, flex `items-end justify-between`, `margin-bottom:-0.04em`): left `LIVE IN` (`.hero-own-the`, Syne 800, uppercase, black, `letter-spacing:-0.03em`, `line-height:1`); right desktop-only `.hero-subtitle-desktop` (Syne 700, `clamp(10px,0.95vw,14px)`, max-width 300, opacity 0.7, right-aligned): "Stately homes built with vision, / scope, and architectural finesse."
|
||||
- Headline row (wrapped in `overflow:hidden`): `IRREPLACEABLE` (`.hero-extraordinary`, Syne 800, uppercase, black, `letter-spacing:-0.03em`, `px-6 md:px-10 lg:px-16`).
|
||||
- `.hero-subtitle-mobile` (`px-6`, Syne 600, `clamp(12px,3vw,15px)`, opacity 0.65, `margin-top:0.9em`): "Premium real estate with vision, / depth, and architectural clarity."
|
||||
|
||||
Responsive type sizes are locked — copy the three `@media` blocks verbatim from the seed (`<=639`, `640–1023`, `>=1024`); they swap desktop/mobile subtitles, set `padding-top`, and size `.hero-own-the` / `.hero-extraordinary`.
|
||||
|
||||
## Section 4 — Scroll-driven house animation (centerpiece)
|
||||
|
||||
`position:fixed` wrapper `z-index:22`, `pointer-events:none`, `will-change:transform`, default `bottom:0; left:50%; transform:translateX(-50%); width:100%; min-width:1400px`. Inner div entrance: starts `translateY(102vh)`, transitions to `translateY(0)` via `transform 1.5s cubic-bezier(0.45,0,0.15,1) 0.4s` when `lifting` becomes true; once `liftDone` the transition is removed so the scroll handler takes over. Renders `HOUSE_IMG` at `width:100%`, aria-hidden.
|
||||
|
||||
After `liftDone`, `updateHousePosition` (scroll+resize) computes — **locked math**:
|
||||
- `baseW = max(innerWidth, 1400)`.
|
||||
- `triggerPoint = -(heroH * 0.30)`; `endPoint = heroRect.top - (darkRect.bottom - vh)`; `progress = clamp((heroRect.top - triggerPoint)/(endPoint - triggerPoint), 0, 1)`.
|
||||
- `t = smoothstep(smoothstep(progress))`, `smoothstep(x)=x*x*(3-2x)` applied twice.
|
||||
- `startX=(vw-baseW)/2`, `startY=vh-imgH`; `finalScale=1.45`, `finalX=(vw-baseW*finalScale)/2`, `mobileOffset = vw<1024 ? -250 : 4`, `finalY = darkRect.bottom - imgH*finalScale + 500 + mobileOffset`.
|
||||
- Interpolate `currentX/Y/Scale` linearly via `t`.
|
||||
- `progress <= 0` → reset to resting (bottom-centered, scale 1). Else `top:0; left:0; transform: translate(currentX,currentY) scale(currentScale); transform-origin: top left`.
|
||||
|
||||
## Section 5 — Dark statement + stats (sticky)
|
||||
|
||||
Outer `position:relative; height:200vh; z-index:20`. A `4vh` `#1a1a1a` spacer, then inner `.s2-section` `position:sticky; top:0; height:100vh; background:#1a1a1a; overflow:hidden`. Content `.s2-content` flex column, `px-6 md:px-10 lg:px-16`, `padding-top:clamp(30px,4vw,60px)`, `padding-bottom:clamp(60px,8vw,120px)`.
|
||||
|
||||
- `.s2-statement` (Inter 300, `#e8e4df`, `letter-spacing:-0.02em`, `line-height:1.35`, `white-space:nowrap`, `clamp(22px,2.6vw,42px)`); wrapper `max-width:1200px`, centered, `padding-left:25%`. Four hard-broken lines: "Every estate we present is hand-chosen / through a frame of permanence, refinement, / and timeless detail. Standards are not / a flourish. It is our discipline."
|
||||
- `.s2-stats-row` (same max-width/centered/`padding-left:25%`, `margin-top:clamp(48px,6vw,80px)`): 3 flex columns, `flex:1`, left border `1px solid rgba(255,255,255,0.2)` between items, `padding-left:clamp(20px,2.5vw,40px)` on items 2–3:
|
||||
1. `120+` — Portfolio Holdings
|
||||
2. `12` — Global Locations
|
||||
3. `98%` — Patron Loyalty Rate
|
||||
- Numbers: Inter 300, white, `clamp(36px,4.5vw,72px)`, `line-height:1.1`. **CountUp**: when the element first crosses 30% into viewport (IntersectionObserver), animate 0→`end` over 2000ms, easing `1-(1-t)^3`, render `Math.round(eased*end)+suffix`.
|
||||
- Labels: Inter 400, `rgba(255,255,255,0.6)`, `clamp(12px,1.1vw,16px)`, `margin-top:clamp(4px,0.5vw,8px)`, `letter-spacing:0.01em`.
|
||||
- `<=767px`: drop the 25% left padding to 0. `768–1023px`: padding-left 15%, `min-height:70vh`.
|
||||
|
||||
## Section 6 — Hover-expand gallery (slides over Section 5)
|
||||
|
||||
`.s3-gallery-section` `position:relative; z-index:25; margin-top:-100vh; background:#1a1a1a; height:100vh; overflow:hidden` — the negative margin + higher z slides it up over the sticky dark section. Background ticker `.s3-ticker-wrap` (`inset:0`, flex center, `overflow:hidden`, `z-index:0`, `pointer-events:none`) with `.ticker-track` of two copies of a giant repeating `Velar.` word-mark; each span Syne 800, `clamp(100px,14vw,220px)`, white, low opacity, `white-space:nowrap`, `letter-spacing:-0.02em`, `user-select:none`, `padding-right:0.3em`.
|
||||
|
||||
Gallery content `.s3-gallery-content` (`z-index:1`, flex center, full height, `clamp(24px,4vw,60px)`). Row `.gallery-expand-row` (flex, `gap:6px`, height 70%, max-width 1200px). Each `.gallery-expand-item` (`flex:1 1 0%`, full height, `border-radius:12px`, `overflow:hidden`, `cursor:pointer`, `transition: flex 0.5s cubic-bezier(0.4,0,0.2,1)`) holds its video (autoplay, loop, muted, playsInline, `object-fit:cover`). On hover the hovered item grows to `flex:4`, others shrink (accordion expand).
|
||||
|
||||
`<=1023px`: copy the mobile grid rules verbatim from the seed — `s3-gallery-section` becomes `height:auto; min-height:100vh; overflow:visible`; ticker becomes sticky; row becomes a `1fr 1fr` grid with `aspect-ratio:4/5` items and a centered full-width last-odd item; `<=479px` tightens padding/gap.
|
||||
|
||||
## Tech notes
|
||||
|
||||
- Only `react`, `react-dom`, `lucide-react`, Tailwind, Vite. No other libraries.
|
||||
- All animation logic in a single `App.tsx`. Use Supabase only if persistence is later needed; this page has no data layer.
|
||||
|
||||
## Color Rules — hard
|
||||
|
||||
Warm off-white `#f5f0ea` page; deep teal `#213138` for preloader + default logo; dark `#1a1a1a` for the statement/gallery sections; statement text `#e8e4df`; hero text black. Do not introduce other accent hues — the palette is intentionally monochromatic-luxury.
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user