6197ee7f5e
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6197ee7f5e |
feat: particle cloud (no discrete dots) + geo-IP country preselect on login
All checks were successful
Deploy to Production / deploy (push) Successful in 1m1s
Two coordinated polish moves the owner asked for.
## 1. Hero particle field — "no white dots, just a glow that follows the mouse and is always in motion"
Previous tuning (uPointSize 2.8, uBaseAlpha 0.6) gave discrete indigo
dots that additively saturated to near-white in dense clusters. The
owner wanted no granular dots visible at all — a continuous indigo
cloud that the cursor pulls toward itself.
Changes:
- **Render fragment**: replaced the anti-aliased disc SDF
(`smoothstep(0.5, 0.42, d)` — hard edge) with a Gaussian falloff
(`exp(-d * d * 6.0)` — smooth blob, no edge). Each particle is now
a soft volume that blends seamlessly with neighbours.
- **Sim fragment**: replaced the outward-gradient ring push with a
mouse-halo attraction. Particles drift toward an ideal radius
(~0.20) around the cursor, with exp-bell falloff so they don't
collapse onto the cursor or feel influenced from across the canvas.
`ringField()` helper is now unused but kept for future use.
- **JS uniforms**: `uPointSize` 2.8→14 (256-tier) / 3.6→20 (128-tier);
`uBaseAlpha` 0.6→0.055. Individual particles are below the
perception threshold for "dot" but 65k of them additively composite
into a continuous cloud. With the much lower per-particle alpha,
the cumulative brightness never saturates to white.
- **ParticleField tick loop**: asymmetric ring-active fade — `alpha
= 0.14` ramping in (fast cursor response), `0.012` decaying out
(slow glow trail after the pointer moves away). Matches the brief
"glow longer + attractive to mouse but always in motion".
- **ParticleHero index.tsx**: added an always-on indigo radial
gradient behind the WebGL canvas, so the hero never reads as
visually empty between frames — the canvas additively paints the
dynamic cloud on top. Removed the white-dot stipple from the
static fallback (it was the most likely source of the "weisse
punkte" complaint for any visitor on the fallback path).
## 2. SMS login — pre-select country picker from visitor's geo-IP
The country picker on `/login` previously defaulted to `'CH'` for
everyone. Visitors from DE / AT / US / etc. had to manually scroll
to their dial code — small friction but it sits on the highest-stakes
conversion step in the funnel.
- **New API route** `apps/api/src/routes/geo.ts` →
`GET /v1/geo/country` returns `{ country: 'CH' | 'DE' | … | null }`
by reading Cloudflare's `CF-IPCountry` header. Public, no auth —
reading a 2-letter country code from a geo-IP header isn't PII
under GDPR / DSG. `'XX'` and `'T1'` (CF's "unknown" + Tor) are
normalised to `null`. Outside CF (dev), header is missing → null.
- **Login page** picks up the result in the existing `useEffect`,
guards against codes not in our country list, and calls `setCountry`
to override the `'CH'` default. Stays at `'CH'` if the detection
fails or the visitor is on a Tor exit. Verified live: the endpoint
returns `{"country":"DE"}` from CF's German edge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
035e55f00c |
feat(web): mobile-fit hero tiles + voluminous calmer particle field + FAQ accordion
All checks were successful
Deploy to Production / deploy (push) Successful in 1m2s
Three coordinated polish items requested: 1. **Hero step-rotator tiles fit mobile without horizontal scroll.** The previous snippets contained a 50+ char `Live at https://notion-x9.mcp.buildmymcpserver.com` URL that overflowed the ~295 px text area on a 375 px viewport. Rewrote all three snippets to be naturally short — same product story, no full URLs. The <pre> drops `overflow-x-auto` and gains `whitespace-pre-wrap break-words` so any token that does exceed the column wraps gracefully instead of forcing a scrollbar. 2. **ParticleHero — more volumetric, slower, steadier at load-in.** The "stuttery / too fast" feedback came from two issues compounding: tiny dots (1.8 px on 256-tier, with 0.42 base alpha) gave the eye too few pixels to track between frames, so individual particles read as snapping rather than drifting; and the simplex-noise drift evolved at 0.08 time-scale with 0.045 velocity, fast enough that frame-to-frame deltas exceeded a tracked particle's diameter. Render uniforms tuned: - `uPointSize` 1.8 → 2.8 (256-tier), 2.4 → 3.6 (128-tier) - `uBaseAlpha` 0.42 → 0.60 Simulation shader tuned: - Drift noise time scale 0.08 → 0.045 (the most impactful single change — particles now move at half the previous speed) - Drift velocity magnitude 0.045 → 0.028 - Ring breathing noise time scale 0.35 → 0.22 - Ring polar-wave time scales 1.2 / 0.7 → 0.7 / 0.42 Net effect: same number of particles (65k) but each individually larger, brighter, and moving more slowly. The cumulative additive bloom is denser without the jitter that read as visual stutter. 3. **FAQ collapsed into a native `<details>` accordion.** Crawlers and screen readers still see every Q+A in the SSR'd HTML — `<details><summary>...</summary><p>answer</p></details>` is the standard semantic pattern for disclosure widgets. Users see one question at a time and expand on demand, which keeps the page from feeling like an endless wall of marketing text below the fold. Container narrowed `max-w-6xl` → `max-w-3xl` for accordion typography (long-form prose reads better single-column). The default WebKit disclosure-triangle marker is suppressed with `list-none` + `[&_summary::-webkit-details-marker]:hidden`, and a `lucide-react` `ChevronDown` icon rotates 180° via `group-open:rotate-180` to indicate state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
e4e437c44c |
feat(web): hero redesign — cycling step rotator + full-width video section
All checks were successful
Deploy to Production / deploy (push) Successful in 1m2s
Restructures the landing page above-the-fold into two distinct sections:
1. **Hero — left copy + cycling tile, no static stack of three blocks**
New `<HeroStepRotator>` (Framer Motion client component) shows ONE
tile centred in the column, cycling prompt.txt → build.log →
claude_desktop_config.json every 3.5s. Auto-advance pauses on hover
and exposes a 3-dot tablist so users can jump to any step. The active
dot grows wide with an accent glow.
Mouse interaction: spring-smoothed 3D tilt on rotateX/rotateY plus a
radial glow that translates toward the cursor — both driven by motion
values, so the transforms stay on the GPU compositor instead of
re-rendering on every mousemove. `useReducedMotion()` strips the
tilt + glow translation and collapses the page transition to an
instant cross-fade (the rotation itself still advances — it's content,
not decoration).
Hero padding tightened (py-12/14/16 vs py-14/20/28) so the video
section below is teased above the fold. New scroll cue ("see it run"
+ animated chevron) sits at the bottom of the hero, anchored to
#flow.
2. **Flow video — full-width edge-to-edge under the hero (new section)**
The hero.mp4 / hero.webm pair moves out of the "How it works"
section into its own #flow section. No max-w wrapper — it spans the
viewport with `w-full aspect-video`, so on a 1080p monitor the video
gets the full 1920px width. Adds a subtle radial vignette so the
black edges blend into the page chrome.
3. **"How it works" — now lean**
Video removed (it's the flow section now). Just the three textual
cards as supporting copy.
Adds `framer-motion@11.18.2` to apps/web/package.json. Build passes
typecheck + Next.js production build with no new warnings; LCP path is
untouched since the rotator is client-hydrated after first paint and
Framer Motion is tree-shaken to the components we import.
Note: visitors with `prefers-reduced-motion: reduce` will still see the
video's poster instead of autoplay — Chrome blocks the network fetch
entirely for autoplay media when reduced-motion is set. The flow video
remains visible for the rest, and the step rotator continues to cycle
its content (with instant cross-fade instead of slide+scale).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
22ba23f353 |
fix(video): make Beat 2 visible — bigger particles, parallel schematic stroke
All checks were successful
Deploy to Production / deploy (push) Successful in 52s
User report: "I only see 'Search our Notion workspace' — no video." Cause: Beat 2 (frames 55-165) was a near-empty dead moment. Particles were 1.5-2.5px on a 1080p canvas (nearly invisible), and the server schematic didn't start drawing until local frame 30 (= global 85), leaving a 30-frame gap of empty space mid-clip. The viewer's brain correctly registered "the video stops after Beat 1." Fixes: - 60 particles (was 36) at radius 6→3 with SVG Gaussian-blur glow filter, always indigo (was an indecisive two-color split). - Schematic stroke starts at local frame 8 (was 30) so the box draws IN PARALLEL with particle convergence — eye always has something to track. - Central radial-glow attractor visible the whole beat — gives the "something is forming here" cue before the schematic appears. - Server schematic enlarged 460×300 → 720×420 so it commands attention rather than feeling small. - Inner tool-row dots and port dots doubled in size with stronger drop-shadow. - Beat 3 schematic + client panel sizes scaled to match, and the wire base position adjusted (server CX moved from 960 to 760 so the wire has room to breathe before reaching the client). - Poster frame moved from 60 (mid-fade dead spot) to 180 (Beat 3 Connection layout — the most "this is a real product" shot). File sizes still well under budget: 514 KB mp4, 319 KB webm, 29 KB poster. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
fd147f9998 |
feat(web): Remotion hero video — Section 2 (prompt → server → connect)
All checks were successful
Deploy to Production / deploy (push) Successful in 1m13s
New @bmm/video workspace at remotion/. Renders an 8s 1920×1080 H.264
+ WebM + JPG poster sequence that visualises the three-step "How it
works" pitch literally:
- Beat 1 (0-2s): "Search our Notion workspace" word-by-word entrance
with spring-in from below + brief indigo under-glow + monospace
prompt.txt label. Blinking cursor bridges the loop seam.
- Beat 2 (2-5s): each prompt word detonates into ~9 particles per
word; particles drift, then magnetically converge onto target slots
along a server schematic that strokes itself on. Scan-line sweep +
corner labels (mcp-notion, OAuth 2.1, search_pages, get_page_content)
sell that this is a real artefact, not a placeholder.
- Beat 3 (5-8s): Claude Desktop client panel slides in from the right;
a Bézier wire animates between server and client; three data-packet
dots travel along the wire; 200-OK tag pops; green live-dot pulses
on the server. Last 12 frames fade to black so frame 239 ≈ frame 0
and browser <video loop> has no visible seam.
Brand palette is hard-coded in lib/colors.ts to match globals.css —
keeps the Remotion bundle self-contained (no Tailwind import needed).
springIn / softSpring / clampLerp / rand helpers in lib/easings.ts
power the motion vocabulary. Concurrency=1 + yuv420p in the config
gives a deterministic render that plays on every <video> tag.
File sizes: hero.mp4 449 KB, hero.webm 258 KB, hero-poster.jpg 33 KB —
all well under the 3 MB / 250 KB ceilings.
Section 2 ("How it works") now opens with the video in a
border-bordered aspect-video panel between the heading and the three
existing cards. autoPlay+muted+loop+playsInline satisfies every mobile
autoplay policy; motion-reduce:hidden swaps in the static poster for
prefers-reduced-motion users.
Scripts:
- pnpm --filter @bmm/video render:all (mp4 + webm + poster)
- pnpm --filter @bmm/video to-web (copy to apps/web/public/videos/)
- pnpm --filter @bmm/video build (both, end-to-end)
`to-web` is the script name because `publish` collides with pnpm's
built-in npm-publish command which refused to run with an unclean tree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|