Free
🚀 Startup

Marketeam

Marketing-talent hero on a gradient mesh: a typewriter headline that switches from black to white mid-sentence, four counter-rotating avatar orbits around a counting 20k+, and conic-gradient borders that spin via @property.

536 views 395 copies 2.0k palavras

O prompt

# Marketeam — Orbiting Talent Hero

Build a single-page React + Vite landing page for **Marketeam**, a marketing talent platform. The whole page is one full-viewport hero: a header, a left content column, a right orbit visualization, and a logo ticker strip along the bottom.

Reproduce this exactly — same copy, same hex values, same numbers, same timings. No extra sections. No animation libraries: pure CSS animations plus JS for the typewriter and the counter.

## Stack

- **React** (`useState`, `useEffect`, `useRef`) + **Vite**
- **Inter** (400, 500, 600, 700) and **Urbanist** (600, 700) from Google Fonts
- CSS `@property --border-angle` for the animated gradient border
- Custom `useCountUp` hook and a `TypewriterHeading` component

## Background

Full-page background covering the viewport, applied to the root `.app`:

```css
background: url("https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260624_111401_56af5012-2263-45d3-849a-8688084d7c2a.png&w=1280&q=85") center center / cover no-repeat;
```

It is a soft gradient mesh: a warm cream bloom in the upper left, violet through the middle, falling to near-black at the right edge and along the bottom.

## Key colours

| Role | Hex |
|------|-----|
| Primary accent | `#A068FF` |
| Background dark | `#060218` / `#070319` |
| Text dark | `#000000` |
| Text light | `#ffffff` |
| Body bg fallback | `#0a0a0a` |

## Header

Flex row, `justify-content: space-between`, padding `24px 64px`, `max-width: 1920px`, centred.

**Left** — logo `<img>` at `height: 32px` from `https://polo-pecan-73837341.figma.site/_assets/v11/17ae538989a509947a8de3892c644664895e69b1.png`, then nav links **Your Team**, **Solutions**, **Blog**, **Pricing** — colour `#000000`, 15px, weight 400, each with an underline that animates `scaleX` 0 → 1 from `transform-origin: left` over `0.3s ease` on hover.

**Right** — **Log In** (`#ffffff`, 15px, weight 500, same underline hover in white), then **Join Now**: a pill (`border-radius: 50px`), background `#000000`, white text, padding `12px 26px`, 15px, weight 500. On hover a `#A068FF` fill slides in from the left via `::after`, `translateX(-100%)` → `translateX(0)`, `cubic-bezier(0.22, 1, 0.36, 1)`, `0.4s`; the button sets `overflow: hidden`.

The button sits inside a `.btn-border-wrap` carrying a rotating conic-gradient border, drawn with `::before` at `inset: -3px`, `padding: 3px`, and the mask technique for a border-only fill:

```css
background: conic-gradient(from var(--border-angle), #A068FF, #070319, #A068FF, #070319, #A068FF);
```

`@property --border-angle` is registered as an `<angle>` and animated `0deg → 360deg` over `3s linear infinite`.

## Hero left

`flex: 0 1 600px`, `padding-top: 40px`.

**Heading** — typewriter, Urbanist, 64px, weight 600, `line-height: 64px`, `letter-spacing: -1.5px`:

> Unlock Top Marketing Talent You Thought Was Out of Reach — Now Just One Click Away!

The first 67 characters render `#000000` and the rest `#ffffff`. A blinking `#A068FF` cursor shows while typing. 35ms per character, starting after a 400ms delay.

**Start Project button** — the same pill treatment, slightly larger: padding `14px 28px`, 16px, background `#060218`, with an 18×18 right-chevron SVG. The hover fill slides in from the *right* (`translateX(100%)` → `translateX(0)`). Also wrapped in `.btn-border-wrap`. Appears after the typing finishes, via `animation-delay: 3.2s`.

**Cursor element** — a purple pointer-arrow SVG filled `#A068FF` next to a **David** pill badge (background `#A068FF`, white, 16px, weight 500, padding `8px 16px`, `border-radius: 20px`). Positioned `margin-left: 290px`, `margin-top: 40px`, `animation-delay: 3.6s`.

## Hero right — orbits

Container `720 × 720px`, centred. Four concentric circles, each rotating:

| Orbit | Diameter | Direction | Duration |
|-------|----------|-----------|----------|
| 1 (inner) | 353px | left | 30s |
| 2 | 501px | right | 40s |
| 3 | 649px | right | 50s |
| 4 (outer) | 797px | left | 60s |

Each circle gets a 1px gradient border via the mask technique:

```css
linear-gradient(180deg, rgba(217,161,255,0) 0%, rgba(217,161,255,1) 43%, rgba(217,161,255,0) 100%)
```

**Centre (orbit 1)** — an animated count-up reading **20k+** (Urbanist 64px, weight 500) over a **Specialists** label (Urbanist 16px, weight 600). It counter-rotates so it stays upright.

**Avatars** are placed with `transform: translate(-50%, -50%) rotate(Xdeg) translate(radius) rotate(-Xdeg)`, 58px unless noted:

| Asset | Orbit | Angle | Radius | Size / shape | Glow | Delay |
|---|---|---|---|---|---|---|
| `aa51718fb3af3637e6d666b6543fc27a175fada6.png` | 1 | 270° | 177px | square, radius 20 | purple | 0.6s |
| `ca755f7f93c1126fb8bdbf99ab364a33aa9ab272.png` | 2 | 60° | 251px | round | yellow | 0.8s |
| `dc01064c7093dcc32674876ee3cf5e41c4a485c6.png` | 2 | 180° | 251px | 78px | pink | 1.0s |
| `d5470a58b02388336141575048720f19a50de832.png` | 2 | 300° | 251px | square, radius 20 | blue | 1.2s |
| `018736aa5d0275c4ce56cfebaf2ae3007d81ca1e.png` | 3 | 130° | 325px | 88px | pink | 1.4s |
| `c76d8a0b99676de31c014344bfaf75bad090758d.png` | 4 | 30° | 399px | round | purple | 1.7s |
| `7b1b5f039de7b54cc9913e96c1923c3b15a157fa.png` | 4 | 95° | 399px | 88px square, radius 24 | orange | 1.9s |
| `9ae171d8895199349755c43fbff00e122221a027.png` | 4 | 220° | 399px | 88px square, radius 24 | pink | 2.1s |
| `926c9eb7b4bc1df846fa0e39f0b0dc3fefd80671.png` | 4 | 320° | 399px | round | purple | 2.3s |

All under `https://polo-pecan-73837341.figma.site/_assets/v11/`. Each flies in from scale 0.3 + `rotate(-180deg)` + blur to its resting transform.

## Logo ticker

A horizontally scrolling strip, `gap: 64px`, 20s linear loop, with linear-gradient fade masks on both edges. Five SVGs from the same `_assets/v11/` path — `1e7b0e6f…`, `3eac03c1…`, `17705a4c…`, `0e5f442b…`, `63f99030…` — repeated 4× for a seamless loop. Each is `width: 137px`, `height: 40px`, `object-fit: contain`.

## Entrance animations

All on `cubic-bezier(0.22, 1, 0.36, 1)`:

- Header — fade-down, `translateY(-20px)` → 0, 0.8s
- Hero left — fade-up, `translateY(40px)` → 0, 1s
- Orbits — scale-in, `scale(0.85)` → 1 with opacity, 1.2s, delay 0.3s
- Logos — fade-up, delay 0.6s

## Responsive

- **1280px** — circles `scale(0.85)`
- **1024px** — stack to a column, heading 48px, circles `scale(0.7)`, nav gap shrinks
- **768px** — hide the nav, heading 36px, circles `scale(0.5)`
- **480px** — heading 28px, circles `scale(0.4)`, smaller buttons and logos

## Quality Bar

- **The 67-character split only lands on a word boundary if the dash is an em dash.** Written with `--`, the heading is 84 characters and `slice(0, 67)` ends at `…Now Jus`, leaving `t One Click Away!` to start the white run — the word `Just` is cut in half, one letter into a colour change. With a real `—` the string is 83 characters and index 67 falls cleanly after `Now Just`. The index is the tell: use `—`, or the split number is wrong.
- **The black-to-white handoff is one line too late.** Measured against the actual background at 1440×900, the black text degrades as it descends the gradient: line 1 **5.91:1**, line 2 **3.70:1**, line 3 **3.29:1**, line 4 **3.03:1**, and line 5 — which begins `Now Just`, still black under the 67 split — **2.70:1, with 17.0% of its pixels below the 3:1 large-text threshold**. Line 5 starts at character **59**. Splitting there instead of 67 puts every black glyph on lines 1–4 at 3.03:1 or better, and hands the whole of `Now Just One Click Away!` to white, which measures **5.67:1** at its worst. Everything else on the page is already comfortable — nav links in black sit in the cream bloom at **6.20–7.68:1**, `Log In` in white at **9.61:1**, the `20k+` at **10.36:1**, `Specialists` at **11.75:1**. This is a one-line fix, not a palette problem.
- **The Start Project button arrives before the sentence it is waiting for.** The typewriter runs `400ms + 83 × 35ms = 3.30s`, and the button's `animation-delay` is `3.2s` — it fades in roughly 100ms before the final character. The spec says it "appears after typing finishes"; either delay it to 3.4s or derive it from the typing state instead of hard-coding a guess.
- **In a background tab that gap becomes 80 seconds.** Chained `setTimeout(35ms)` is clamped to a 1s minimum while the document is hidden, so the headline takes **~83s** to type — while the button (3.2s) and the David cursor (3.6s) are CSS-driven and arrive on schedule regardless. Observed directly: the CTA and the cursor sit fully rendered beside a headline that reads `Unlock Top Ma`. Drive the typewriter off `requestAnimationFrame` with a timestamp, or gate it on `visibilitychange`.
- **Orbit 4 is larger than the box that holds it.** The container is `720 × 720` and the outermost orbit is `797px` — measured overflow of **39px on every side**, which at a 900px-tall viewport pushes the orbit-4 avatars down into the logo ticker. Size the container to at least 800px, or bring the orbit under 720.
- **The font request does not match what the page renders.** Inter is loaded at 400/500/600/700 but the design only ever sets 400 (nav) and 500 (Log In, the two pill buttons, the David badge) — 600 and 700 are downloaded and never drawn. Urbanist is loaded at 600/700, but the count-up is specified at **weight 500**, which is never requested, so it falls back to a synthesised or nearest weight; 700 is never used. Google's latin slices come to 48,432 + 27,812 = **76,244 bytes**; self-hosted and subset to the characters this page actually sets, with the variable axes pinned to the weights it actually uses, the same rendering is 4,312 + 4,748 = **9,060 bytes (11.9%)**.
- **Fifteen assets hotlink somebody else's Figma Sites deployment.** `polo-pecan-73837341.figma.site` is a published Figma site, not a CDN under your control: it can be renamed, unpublished or re-exported at any time and every avatar, the wordmark and all five partner logos vanish at once. Among them are five identifiable human portraits and five third-party brand marks, with no licence stated for either. Host your own copies of assets you have the right to use.
- **The background comes through a third-party image proxy, capped at 1280px.** `images.higgs.ai` returns a 1280×720 WebP of **11,234 bytes** from an **8,513,544-byte** source PNG — a genuine 0.13% saving, and the right instinct. But `cover` on a 1440×900 viewport already scales that up **1.25×** to 1600×900, and a 2× display asks for four times the pixels it has. Raise `w`, or accept the softness knowingly. It also puts a third party on the critical path of the only thing behind the whole page.
- **No image in the spec has alt text** — not the nine avatars, not the five ticker logos, and not the wordmark, which is the only place the brand name is written. The avatars and partner marks are decorative and want `alt=""`; the logo wants a real name.
- **The typewriter rewrites an `<h1>`'s accessible name 83 times.** Assistive technology sees a heading whose text changes on every tick, and may announce fragments or re-announce the whole thing repeatedly. Render the full string in the DOM and reveal it visually, or give the heading a stable `aria-label` and mark the animating text `aria-hidden`.
- **The `::after` fill will cover the button label unless the label is lifted.** The spec sets `overflow: hidden` and a positioned `::after`, but says nothing about stacking. A positioned pseudo-element with the default `z-index` paints *above* the button's inline text, so a bare text node ends up behind the purple wash on hover. Wrap the label in its own element with `position: relative; z-index: 1`. Do not reach for `z-index: -1` on the `::after` instead — the button is `position: relative` with `z-index: auto` and so creates no stacking context, which sends the fill behind the button's own background and makes it invisible.
- **Every control has a hover state and none has a focus state.** Eight focusable controls sit on a gradient with no `:focus-visible` rule anywhere in the spec.
- **There is no `prefers-reduced-motion` branch, and this page owes a large one.** Four orbits rotating forever, a ticker looping forever, a border gradient spinning every 3s forever, plus a typewriter, a count-up and six entrance animations. Land the entrances on their end state, give the counter its final value, print the headline in full, and stop the loops.
- **`@property` is what makes the border move at all.** Without it `--border-angle` is an unregistered custom property, which cannot be interpolated — the conic gradient renders once at `0deg` and simply never rotates. That is an acceptable degradation, but it is worth knowing that the animation, not the border, is the part that disappears.
- **None of the four nav links has a destination**, on a page that is only a hero.

Você também pode gostar

Verified DR - Verified Domain Rating for buildpromptkit.comBuildPromptKit - AI prompts that ship real UI — every one has a live demo | Product HuntBuildPromptKit — AI Website & App Prompts - Featured on YizhanFeatured on saasfame.comFeatured on Twelve Tools