Client Project | Live

Client Project | Live

San Motif

San Motif

A portfolio site that turns WhatsApp outreach into enquiries for a UAE product-film studio

A portfolio site that turns WhatsApp outreach into enquiries for a UAE product-film studio

Astro, TypeScript, Sanity CMS, ffmpeg, Firebase Hosting

Astro, TypeScript, Sanity CMS, ffmpeg, Firebase Hosting

San Motif makes short cinematic films for fragrance and watch brands. I'm the sole web developer: I designed, built, deployed and now maintain their site with the founder, so a brand opening a link on their phone is watching finished films within seconds and one tap away from a WhatsApp enquiry.

San Motif makes short cinematic films for fragrance and watch brands. I'm the sole web developer: I designed, built, deployed and now maintain their site with the founder, so a brand opening a link on their phone is watching finished films within seconds and one tap away from a WhatsApp enquiry.

Live | client project, built and maintained by me

The 30-second version
Client projectAstro | TypeScript | SanityLive
ProblemBrands discover San Motif from a WhatsApp link opened on a phone. If a film doesn’t play within seconds, the enquiry is gone.
What I didAs the sole developer, designed, built and deployed the site with the founder: Astro with a Sanity CMS he edits himself, an ffmpeg video pipeline, and a Reels-style film viewer on phones.
ResultLive at sanmotif.com and maintained by me. Images cut from about 47 MB to 2 MB, and hover previews kept to roughly 1 MB each.
01 / The visit that matters

Built for one moment: a link opened on a phone.

San Motif makes short cinematic films for fragrance and watch brands, and finds clients through WhatsApp outreach. So the typical visitor is a brand manager tapping a link between messages. Everything on the site serves that moment: films playing within seconds, and a WhatsApp enquiry one tap away.

~1 MBsilent hover preview per film, cut automatically from the master
47 → 2 MBtotal image weight after the media pipeline
No black flashbetween films, thanks to automatic opening-frame detection
02 / On desktop

Work first, with colour that follows the film.

The grid follows the order the founder sets in the CMS. Hovering a film previews it silently, tints the whole page to that film’s colour with a soft glow, and dims the others to spotlight it.

The film grid with category filters, in the order set in the CMS
Hovering a film tints the page to its colour and dims the rest
Desktop viewer: arrows and the call to action stay put whatever the title length
1 / 3 | The film grid with category filters, in the order set in the CMS
03 / Design decision

On phones, it behaves like Reels, on purpose.

San Motif’s clients will post these films on Instagram and TikTok. So instead of a gallery, the phone viewer is a full-screen vertical feed: a brand sees its product the way its own customers will, between other posts, before it has even commissioned a film.

Phone home: films autoplay as they scroll into view
The page takes on the colour of the film in the middle of the screen
Full-screen viewer: swipe up for the next film
Every film ends one tap from a WhatsApp enquiry
1 / 4 | Phone home: films autoplay as they scroll into view
Swipe up or downNext or previous film. The content follows your finger and the next film’s frame slides in underneath.
Swipe left or rightSwitch between the film and the product photo it was made from.
TapPause or play, with the text overlaid on a soft scrim so it stays legible on bright footage.
The next film is already loading before you swipe, so the feed never makes you wait.

Previews load just before cards scroll into view, and inside the viewer the next film and neighbouring frames are preloaded. All of it is skipped on Data Saver and 2G connections, so preloading never costs a visitor on a weak signal.

04 / Decisions

Built so the client never needs a developer for content.

05 / Video pipeline

From camera file to a film that plays everywhere.

1
HEVC inSource films often arrive as HEVC, which Chrome and Firefox can’t play.
2
H.264 outNode.js + ffmpeg scripts produce web-safe MP4s with fast-start for streaming, on macOS and Windows.
3
Hover previewsFirst 6 seconds, 720px, silent, at each film’s native 24 or 30 fps, around 0.4–1.5 MB each.
4
Opening frameA luminance scan finds the first non-black frame and saves it as the poster and start time.
5
Prune + shipUnused media is removed from the build (about 50 MB in one pass), then deployed to Firebase with cache headers per asset type.
06 / Hard bugs

Bugs worth talking about.

Safari wouldn’t playVideos needed byte-range (206) responses. Fixed by tuning Firebase cache headers per asset type.
Black flickerFilms flashed black between swipes on phones. Fixed with detected opening frames used as posters and start times.
Frozen pagesChrome without hardware acceleration froze on heavy effects. The site now detects it and switches to a lighter mode.
iOS lock screenMuted films showed up in Now Playing. Media Session now runs only with sound on, and the video unloads when the viewer closes.
Windows buildsShell scripts didn’t run on Windows, so the pipeline was ported to Node and works on both.
07 / Handover

Documented, tested, and easy to hand over.

Docs
  • ✓AGENTS.md for future developers and AI agents
  • ✓HANDOVER.md + README
  • ✓CMS editing guide for the client
Testing
  • ✓Headless Chrome scripts simulating swipes, trackpad and hover
  • ✓Checked at 390px and 1440px
  • ✓Type-checked builds before every release
Accessibility
  • ✓Keyboard-operable viewer with managed focus
  • ✓44–48px touch targets and safe areas
  • ✓Respects reduced motion
How I worked

Built with Claude Code (Opus 5.5) to speed up implementation. The product, design and UX decisions were mine, and I reviewed and tested everything that shipped.

Open to new opportunities.

View CV