21a5cf5762
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
21a5cf5762 |
@
All checks were successful
Deploy to Production / deploy (push) Successful in 1m25s
feat(web): subtle hover/tap video controls (seek + play/pause) Add a discreet bottom control bar to the hero video — play/pause, elapsed time, a seek slider, and mute — that reveals on hover (desktop) or tap (touch) and auto-hides ~2.8s after the last interaction while playing; it stays visible while paused so the scrubber is reachable. The seek slider is a real <input type=range> (keyboard/drag/touch, accessible) laid invisibly over a custom rail+fill so the look matches the page. Autoplay/muted/loop, the centre play overlay, the play-failed fallback link and poster are unchanged; the always-on mute button is now folded into the bar. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @ |
||
|
|
3a05766f88 |
fix(oauth): allow generic RFC 7591 DCR + expand install snippets
All checks were successful
Deploy to Production / deploy (push) Successful in 1m28s
- /oauth/register: drop resource_required check, accept generic registrations (Claude Desktop omits resource in DCR body per spec). serverId stored as NULL; /authorize still enforces org-ownership + access-token aud claim still pinned to resource. Fixes Claude Desktop DCR failure (ofid_d7e39530c109fa7f). - /oauth/authorize: skip strict server.id check when client.serverId is NULL (generic client); org check remains the security boundary. - schema: oauth_clients.server_id no longer NOT NULL. - migration 0002: ALTER COLUMN server_id DROP NOT NULL (already applied on prod). - install-snippets: add Claude Code (CLI), VS Code, Codex, raw URL tabs. Claude Desktop now shows form-field values (Name / Remote MCP Server URL / OAuth Client ID / Secret) matching the new Custom Connector UI instead of the obsolete JSON config. - types: InstallTarget enum extended. - hero-video: clicking the audio toggle restarts the video from frame 0 so unmute aligns with the spoken opening. - marketing: drop em-dashes from rendered copy. |
||
|
|
05746e13e6 |
fix(video): drop WebM source + load()-before-play() + open-in-tab fallback
All checks were successful
Deploy to Production / deploy (push) Successful in 59s
Owner: "wird nicht richtig gestream hab browser daten gelöscht aber kann [nicht]" — clearing the cache didn't help. Three things changed: 1. **Single MP4 source.** Chrome listed the WebM source first because we offered it first; on the owner's setup the VP9 decode appears to stall silently and Chrome does NOT fall back to MP4 — it parks the element at networkState=2/readyState=0 forever. Removing the WebM source forces Chrome onto the MP4 (Main profile / yuv420p / TV-range / faststart, 2.6 MB) which we've already verified plays correctly. 2. **.load() before .play() in togglePlay.** When the original autoplay was blocked before the source ever fetched, some Chrome builds leave the element in a "stuck unloaded" state where subsequent .play() calls inside a user gesture also no-op. Calling .load() first resets the resource-selection algorithm, then .play() fetches and plays. 3. **playFailed escape hatch.** If .play() still rejects even after .load() + user gesture (extension sandbox, hardware decoder failure), surface a small "your browser blocked playback — open the video directly" link to the raw MP4. The visitor isn't trapped staring at a poster. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
b464b5640f |
feat(video): play-overlay for blocked autoplay + click-to-play
All checks were successful
Deploy to Production / deploy (push) Successful in 1m0s
Owner reported "video läuft nicht, sehe nur foto" — classic blocked- autoplay on browsers with prefers-reduced-motion / data-saver / strict autoplay policies. The poster sat there forever and the visitor thought the page was broken because the only control was a tiny mute pill they didn't realise would also start playback. Fixes: - Tracks `playing` state via the video element's own play/pause events so React knows whether the browser actually granted autoplay. - Renders a large centre PLAY button overlay whenever the video is paused. The button covers the full frame (universal YouTube / Vimeo pattern: click anywhere on the video to play); the inner indigo circle with the triangle is the visual affordance, with hover scale for tactile feedback. - Wires onClick directly on the <video> element too so the click- anywhere-to-play works whether or not the overlay happens to be up. - Mute toggle now calls e.stopPropagation so tapping it doesn't accidentally trigger play/pause via the video's onClick handler. - Best-effort .play() call in the mount effect, with the rejection silently swallowed — failure just means the user has to click play themselves, which the overlay already affords. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
438ce3cfbc |
feat(video): v10 hero video with mute toggle — voice + bg music
All checks were successful
Deploy to Production / deploy (push) Successful in 1m6s
Ships the long-form (71.5 s) hero video to the marketing /flow section
along with the iteration trail of architectural visual fixes the owner
worked through over the last sprint.
## Video composition (remotion/)
Eight phases driven by the 71.47 s voice-over in `audio.mp3` plus the
`Sub-bass Lullaby.wav` background music (ducked to 0.16 with fade in /
fade out). Every scene was rebuilt for v10 with concrete fixes:
- **HookScene** (12 s) — adds FloatingChaos overlay: a docker-compose
excerpt, an oauth_callback.ts snippet, an .env file with a yellow
squiggle warning ("in git history since v0.3.1"), and a live-ticking
502 retry toast. Tangle now reads as a developer's desktop right
before they give up, not as four icons drifting.
- **PromptScene** (12.2 s) — 6.5 s post-typing dead-zone replaced with
the parse beat: three sequential highlights on the prompt text
(MCP server / searches / Notion workspace), three chips below the
input (intent / tool / secret → vault), three-stat summary panel
(tools · 2, secrets · 1, targets · 3). At local frame 250 (≈ 21 s
global, on the voice line "the prompt path and the secret path
never cross") a mini two-rail diagram with an explicit X-marker
ring lands, visualising the architectural promise the moment it's
spoken.
- **SecretsScene** (15.2 s) — kept the arrow-fork + AES-256 stamp +
env-var injection beats; added the lock-snap flash at frame 66,
pinned the vault at full opacity throughout, and added a dashed
vault → container connector so the secret's provenance is visible.
The "what the AI sees" panel is now 680 px wide with an eye icon,
four corner viewfinder brackets around the prompt text, and three
explicit denied lines (no secrets / no environment variables / no
tokens).
- **BuildScene** (7.2 s) — unchanged beats: streaming log, server
card emerges with code + 🔒 NOTION_API_KEY slot pills, isolated-
container caption, <60s countdown.
- **IsolationScene** (14 s) — completely restructured. Orbit-and-dock
chips that collided with the card and with the tokens-only badge
are replaced by a clean vertical chip column at x=760: read-only
filesystem · dropped capabilities · no new privileges · 512 MB
memory cap · 0.5 CPU limit · ✓ your token only (last in green).
A vault graphic now sits below the server card with a dashed arrow
up into its env slot so the architecture story is complete in one
frame. PKCE jargon removed: "OAuth 2.1 · PKCE" → "only your token
gets in" with a small "oauth 2.1 · proof-key flow" subtitle for
the curious. Handshake stages simplified to your client → verified
→ scoped token. Final settlement arrow in success-green curves
from the scoped-token pill back into the card.
- **LibraryScene** (7 s) — cards enlarged from 340×180 to 400×220
with 36 px gaps. The "templates carry code, not credentials"
sub-caption was pulled (felt on-the-nose; the detached lock and
empty NOTION_API_KEY=? slot carry the story visually).
- **DiscoveryScene** (3 s) — the most-iterated scene. Earlier
versions had a fake "1,200+ developers building" fork counter
(pulled — solo-founder, hadn't earned). Replaced with a two-lane
architecture diagram that visualises "no paths cross" literally:
top lane prompt → AI → code, bottom lane vault → encrypted →
env, both converging at the server box on the right. v10
refinements: all seven boxes visible from frame 0 (no late
server arrival), a parallel glow tour walks across both lanes
simultaneously, a dashed vertical divider with a "no shared
node" chip pinned in the middle, and the closing line "One
sentence in. Live server out." slides down from above and lands
centred while the diagram fades to 0.12 opacity behind it —
no overlap.
- **LogoLockup** (1.7 s) — wordmark + fade-to-black for a clean
loop seam.
The Subtitle / CAPTIONS layer added in v7 was pulled wholesale —
owner found the kinetic-typography overlay aggressive and noted
that technical terms (PKCE etc.) created friction with no payoff.
Scene visuals and voice now carry the whole story; the Subtitle
component file is retained for possible future use.
Render pipeline (`render:mp4` / `render:webm` / `render:poster` in
remotion/package.json) is unchanged. The MP4 is post-processed to
H.264 Main / yuv420p / TV-range with faststart + AAC audio. The
WebM is re-encoded at VP9 CRF 38 / Opus 64k to stay under the 3 MB
budget. Final artefacts in apps/web/public/videos/: 2.59 MB mp4,
2.99 MB webm, 62 KB poster.
## Web integration (apps/web/components/hero-video.tsx)
New client component wraps the <video> element and pins a frosted-
glass mute toggle bottom-right of the player. Why not native
`controls`: the browser chrome fights the section's design vocabulary
and we only need one affordance — unmute — so we render exactly
that. The toggle's icon flips between VolumeX (currently muted) and
Volume2 (currently unmuted), accent colour switches indigo when sound
is on. Initial state is muted so autoplay still fires; on unmute we
call .play() defensively because mobile Safari pauses on
muted-property changes mid-playback.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|