Skip to content
Selene

For Professional Photographers

Galleries your clients
will remember.

Selene is the fastest, most beautiful way to deliver photos to your clients. Built for photographers who care about every pixel — and every detail of the client experience.

  • 14-day free trial
  • No credit card required
  • Built in Melbourne by a working photographer
stacie-and-callum-glasshaus-richmond-wedding-photographer-01.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-02.jpg
pin-card.jpg
Picked

Three reasons photographers switch to Selene

01Slideshow

Six themes, built in

Classic crossfade, Cinema Ken Burns, Editorial cuts, Boho dissolve, Magazine slide, Hush. Pixieset ships one.

02Access

Magic-link, no passwords

Clients open their gallery in one tap from email. Or use password protection if you prefer — the choice is per-gallery.

03Branding

Your studio, end to end

Custom domain, colors, fonts, dark mode, watermark presets. Clients see only you — the URL stays yours too.

pin-card.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-01.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-02.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-03.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-04.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-05.jpg
pin-card.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-01.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-02.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-03.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-04.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-05.jpg

Live preview

A real wedding,
delivered with Selene.

Open the full gallery
pin-card.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-01.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-02.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-03.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-04.jpg
stacie-and-callum-glasshaus-richmond-wedding-photographer-05.jpg

Photos by Eclipse Media · Stacie & Callum at Glasshaus. The same lightbox, favorites, and slideshow your clients get.

Who Selene is for

Built for photographers who care about every frame.

  • …who run more than one wedding a weekend.

    Duplicate a fully-branded gallery template in one click. The look-and-feel, watermark rules, product catalog, and password setup carry over — only the photos are new.

    Gallery duplicate
  • …who care more about how a print looks than which one sells.

    Per-event brand overrides, per-photo watermark presets, 5 slideshow themes from intimate to editorial. Every gallery feels like the artist made it, not the platform.

    Per-event branding
  • …who want their clients to feel something when they open the gallery.

    Branded share emails, magic-link one-click access, cinematic lightbox with Ken Burns, blur-up placeholders, accent-themed favorites. Every touchpoint reads like your studio, not ours.

    Client experience
  • …who are tired of paying for features locked behind higher tiers.

    Custom domains on all plans. Password protection on all plans. Magic-link auth on all plans. The expensive add-ons elsewhere are just… included here.

    Compare plans

Your next client gallery is
thirty seconds away.

Sign up free, drop in a folder of photos, send the link. Your client opens a gallery that feels like your studio — not ours.

No credit card · 30-day trial · Cancel any time

How it works

From a folder of photos to a gallery your clients keep coming back to — in three steps.

Step 01

Upload

Drop a folder of full-resolution photos. EXIF orientation, dominant colour, and watermarked previews are extracted in parallel — no waiting on a queue.

AaAa

Step 02

Brand

Your accent colour, your logo, your domain, your slideshow theme. Six themes from Classic crossfade to a meditative Hush. Hero, watermark presets, dark mode — all yours.

Step 03

Share

One branded link, password-gated if you want, with a real OG preview built from the gallery cover so iMessage and WhatsApp render it beautifully. Clients heart, comment, download, and order.

What's inside

Everything Pixieset and Pic-Time offer — done better.

01 — Foundation

Your own studio

A custom subdomain, your brand colors, your logo, your dark or light theme. Clients see you — not us. Custom domain mapping is one click away.

02 — Upload

Drag, drop, done

Drag-drop a whole folder, watch each photo decode in parallel with progress bars. EXIF orientation honored, dominant color extracted, watermarked previews generated on demand.

03 — Viewing

A gallery to fall for

Masonry that breathes. Lightbox with keyboard and touch. Slideshow themes — Classic crossfade, Cinema Ken Burns, Editorial cuts. Blur-up placeholders, no layout shift.

04 — Video

Films, not just frames

Wedding films and BTS reels live in the same gallery as your photos — one grid, no separate tab. Clients play them inline with a branded player: scrub, fullscreen, the same chrome as the rest of your work. Downloads stay on your terms.

05 — AI face tagging

Find every face

Faces are detected and grouped as you upload — the detection runs in your own browser, so your photos never leave your device for it. Clients tap a face to see every shot that person is in. Name a group once and it stays labelled across the gallery.

06 — Favorites & feedback

Selections, simplified

Clients heart what they love and leave per-photo notes. You see the picks, the comments, and the 7-day analytics. Export selections to CSV for printers and album designers.

07 — Sharing

Branded delivery

Password protection, magic-link invites that bypass the password, an email outbox so you can see every send, custom domains so the URL stays yours.

08 — Sales

Prints & packages

A studio per gallery: prints, digitals, hand-bound albums. Clients order from a branded store; you track pending and paid orders from one inbox. Stripe Checkout when you flip the switch.

Recently shipped

Selene moves. Every day.

See the full changelog →
  1. [test] SHIPPED `19298688` — closed an untested-shipped-feature gap ([[untested-shipped-feature-e2e-vein]]): the **studio Logo URL** had ZERO e2e (`grep tests/e2e/ logo_url` → only a passing mention in `visual.spec.ts:2669`; the field is a plain `type=url` input in `SettingsForm.tsx:120`, persisted to `studios.brand_json.logo_url`). New `tests/e2e/studio-logo.spec.ts` drives the REAL control end-to-end and asserts against the PUBLIC `/[studioSlug]` page from a fresh anon context (search-engine-like, sidesteps the settings `useFormState` flash crash — same idiom as `studio-socials.spec.ts`): a fresh signup shows the studio name as a text **wordmark** (`img[alt="<name>"]` count 0); owner pastes a logo URL + Save (waiting on the committed POST per [[e2e-server-action-write-race]], not the SuccessFlash); the anon page re-fetch then renders the `<img src={logo_url} alt={studio.name} className="h-10">` in place of the span (`[studioSlug]/page.tsx:388`) AND the ProfessionalService JSON-LD emits `logo: <url>` (`:340`) — proving persistence + render + the Knowledge-Graph signal in one shot. **Determinism trick:** points `logo_url` at the app's OWN `/logo.svg` (via `new URL('/logo.svg', baseURL)`) so the image actually loads with real intrinsic size → `toBeVisible` holds, instead of a zero-width broken external image. **Verify:** first cold run flaked at the `toBeVisible` (storefront route warming) → 3 consecutive clean passes after warmup (59.6s/29.6s/25.3s), the 15s locator timeout absorbs cold-compile. @local-only (describe title → CI-excluded). Committed path-scoped (1 file) per [[polish-worker-path-scoped-commit]]; `status.json` + untracked infra worker-dirs left unstaged. Concurrent polish worker landed `dd7ab953`/`5db0cc0f` mid-wake. Telegram sent. DO NOT PUSH (push-batcher owns upstream).

  2. [polish] SHIPPED `dd7ab953` — baselined the client-viewer Compare overlay in its **4-UP 2×2 grid fold** (`tests/e2e/visual/compare-fourup.spec.ts` + `gallery-compare-overlay-fourup.png`). **The gap:** both existing compare baselines pin the DEFAULT 2-up fold only — `gallery-compare-overlay` (visual.spec.ts:1538, 1280×800) and `gallery-compare-overlay-390x844` (mobile.spec.ts) — each favorites EXACTLY 2 photos so the overlay opens `paneCount===2`: side-by-side panes, L/R badges, Swap shown, the "4-up" toggle HIDDEN (gated `canFourUp = count>=4`, `GalleryView.tsx:3409`). Crossing to ≥4 picks and pressing the toggle swaps in a fold that renders in NO baseline: the PANES container flips `flex flex-col sm:flex-row` → `grid grid-cols-2 grid-rows-2` (a 2×2 quad, `:3556`), each badge goes numeric `1/2/3/4` not `L`/`R` (`:3486`), the Swap button (gated `paneCount===2`, `:3528`) DISAPPEARS, and the toggle label flips to "2-up" (`:3525`). A className/layout drift on the quad grid, numeric badges, or the vanished-Swap top-bar would sail past the whole suite. **Determinism:** seeded DEMO gallery (`/eclipse-media/demo`, fixed studio name+accent) so copy is stable run-to-run; favorited EXACTLY 4 tiles (loop: clearWelcome→hover→exact `Favorite` label→wait each POST, asserted 4× `Remove favorite`) reusing the `/api/client-session`-GET-gated convergent welcome-dismissal + per-iteration `clearWelcome()` scaffold proven on the 23:32 picks-compare de-flake, plus the favorites-GET-before-heart guard ([[playwright-getbyrole-name-is-substring]]). Opened the sheet (asserted `4 photos selected`), launched Compare, then keyed the toggle on its `title` attr (`button[title="Switch to four panes (G)"]`) — the button's accessible NAME is its visible "4-up" span, text-content-wins-over-title, so getByRole(name:'Switch…') MISSED it (cost 1 debug iter); asserts the reverse "Switch to two panes" title is visible BEFORE the snapshot so a dropped-`canFourUp`-gate regression can't bake the 2-up shape under this name. Full-overlay snapshot (clip 1280×800, `maxDiffPixelRatio:0.15`, `test.slow()`) reusing the generous photo-decode tolerance the 2-up sibling uses (four full-res `/api/img` panes). **Verify:** eyeballed the PNG (2×2 quad, numeric 1–4 badges, accent ring + "1/4" on focused pane #1, top-bar shows only "2-up" toggle + close X — Swap gone, 4-slotted thumbnail strip); 2 clean runs vs the baseline (17.8s gen / 34.3s + 41.2s verify), no flaky. @local-only (describe title → CI-excluded). Committed path-scoped (2 files) per [[polish-worker-path-scoped-commit]]; `status.json` + untracked infra worker-dirs left unstaged. DO NOT PUSH. **Next visual candidate:** with picks-summary (resting-1/sent-1/compare-≥2) AND the compare overlay (2-up desktop+mobile, now 4-up) all pinned, the client-viewer overlay state space is saturated — re-grep `tests/e2e/visual/` spec titles before treating any client overlay state as fresh.

  3. [test] SHIPPED `f1c7006a` — DE-FLAKE follow-up on the picks-sheet 2-picks compare-fold spec the concurrent polish worker had JUST landed (`fbda50f3`, 23:25). **Concurrency, not orphan-recovery:** my wake-start `git status` snapshot showed `tests/e2e/visual/picks-sheet-compare.spec.ts` + its baseline as `??` at HEAD `c588f4ea`, so I picked it up as an interrupted WIP per [[orphaned-wip-untracked-seams]]. Between that snapshot and my commit the polish worker (`dispatch-worker-polish.sh`, now exited) committed the SAME spec+baseline (`fbda50f3` + docs `9414c864`) onto main — so my work landed as a refinement ON TOP, not a lost-commit replay ([[orphan-recovery-resets-uncommitted-work]] was the wrong read here: fbda50f3/9414c864 are real linear ancestors, never detached). **The genuine value-add:** the polish worker's `fbda50f3` spec had only a ONE-SHOT welcome-dismissal guard before the favorite loop, so the dismissed `ClientWelcome` backdrop (`role="dialog" aria-label="Welcome"`, `inset-0 z-50`) re-mounting from StrictMode's dev double-effect BETWEEN the two heart clicks swallowed the 2nd tile's hover — I reproduced this twice (`locator.hover` timeout on `figure.nth(1)`, "Welcome … intercepts pointer events"). Fix: a `clearWelcome()` helper (sweep skip-button + assert backdrop count 0) now runs at the TOP OF EACH favorite iteration, not just once before the loop. **Verify:** 2 consecutive clean runs at default retries (30.3s/29.3s), no flaky — the prior version went 1-flaky on every capture attempt. Baseline PNG bytes unchanged (same `gallery-picks-sheet-compare.png`); spec-only behavioural hardening. tsc not needed (test file). Committed path-scoped (2 files) per [[polish-worker-path-scoped-commit]]. Telegram sent. DO NOT PUSH. The 23:25 entry's saturation note stands: the picks-summary state space (resting-1 / sent-1 / compare-≥2) is fully pinned.

  4. [polish] SHIPPED `fbda50f3` — baselined the client-viewer picks-summary sheet in its **≥2-PICKS compare fold** (`tests/e2e/visual/picks-sheet-compare.spec.ts` + `gallery-picks-sheet-compare.png`), closing the carried NEXT candidate from `aa0f5a86`/the 22:52 NO-SHIP. **Wake-start triage:** sole-worker confirmed LIVE — NO `.feature-active` flag, NO feature `dispatch-worker.sh` process (only my own `dispatch-worker-polish.sh` PIDs 81872/81863), `git diff` src/+tests/ clean → capture-safe per [[studio-visual-coverage-gaps]]. Dev `/`→200, db ok; the `.ci-watch` 03:15 DEPLOY-FROZEN is routine batch-tip lag ([[deploys-can-silently-not-ship]]), not a red gate. **The gap:** both 1-pick siblings — `gallery-picks-sheet` (resting, visual.spec.ts) and `gallery-picks-sheet-sent` (sent/done, `aa0f5a86`) — keep favorites at EXACTLY one so the count reads "1 photo selected" and the ≥2-picks affordance stays hidden. Crossing to two picks swaps in a fold that renders in NO baseline: the title pluralises to "2 photos selected" (`GalleryView.tsx:2490`) AND an accent-FILLED `<ArrowLeftRight/>`-iconned "Compare side-by-side" button appears at the head of the footer (gated `favs.size >= 2`, `:2594`), reflowing the `flex-wrap justify-end` action row into its multi-button wrap (Compare / View-only / **Download my picks (2)** / Keep browsing). A className/copy drift on the compare button's accent fill+border or the reflowed row would sail past the whole suite (the 1-pick siblings render the row WITHOUT the gated compare control). The note `<textarea>` + "Send my selection" button are still present (resting, pre-submit) — the deliberately NEW pixels are the plural title + compare button + reflowed footer. **Determinism:** seeded DEMO gallery (`/eclipse-media/demo`) so the studio-name copy is fixed run-to-run; favorited EXACTLY 2 tiles (loop: hover→exact `Favorite` label→wait on each POST, asserted 2× `Remove favorite` after) — element-scoped pixel-exact capture of the opaque text-only card (`:scope > div` first, no photos in frame → no backdrop-blur bleed) reusing the robust `/api/client-session`-GET-gated welcome-dismissal scaffold ([[registration-wall-and-session-race]]) + the favorites-GET-before-heart guard ([[playwright-getbyrole-name-is-substring]]). Sanity-asserts the `Compare side-by-side` button is VISIBLE before the snapshot so a dropped-gate regression can't bake the 1-pick shape under this name. **Verify:** cold `page.goto` timed out (route uncompiled) → warmed via curl ×2 (200 in ~1.6s) then generated; eyeballed the PNG (plural title, accent compare button + ArrowLeftRight icon, reflowed 4-button footer, empty note placeholder, no caret, no bleed); then **2 clean verify runs at `--retries=0`** (30s/27s) to prove stable. @local-only (describe title → CI-excluded via `e2e:prod`'s `--grep-invert @local-only`). Committed path-scoped (2 files) per [[polish-worker-path-scoped-commit]]; `status.json` + untracked infra worker-dirs left unstaged. Telegram sent. DO NOT PUSH (push-batcher owns upstream). **Next visual candidate:** the picks-summary state space is now saturated (resting-1 / sent-1 / compare-≥2 all pinned); the per-overlay element-state pure-visual queue is genuinely exhausted — re-grep `tests/e2e/visual/` spec titles before treating any client-viewer overlay state as a fresh gap.

  5. [polish] NO-SHIP capture-deferral — feature worker is LIVE and mid-e2e-run → capture-unsafe. **Wake-start triage was decisive, not reflexive:** `.feature-active` flag is FRESH (22:45) AND `ps` confirms `dispatch-worker.sh` is genuinely alive (PID 79673/79663, started 22:45) — NOT the stale-flag/dead-process case that let the 21:18 wake re-derive sole-worker. The feature agent's session log (`claude-selene-20260610-224516.log`) is 0-bytes (still thinking) and `dev-restart.log` shows it was driving the dev server seconds ago through the account-deletion flow (`POST /studio/account 303`, deletion-email stub) — its current task is the `signOutEverywhereAction` e2e (untracked WIP `tests/e2e/account-sign-out-everywhere.spec.ts` present, per `status.json`). The 4s log-growth probe showed a lull, but that's between test runs while the agent thinks, not wake-end. **Why defer rather than push through:** my standing rule is capture is SOLE-WORKER ONLY ([[studio-visual-coverage-gaps]], [[dev-server-404s-css-chunk-during-concurrent-recompiles]]) — two Playwright processes against one dev server risks a CSS-chunk 404 baking an UNSTYLED baseline onto main, and a bad pinned baseline costs far more than one deferred capture is worth. Couldn't sidestep onto a build-verified CSS refinement either: `next build` collides with the feature worker's live `.next`/dev server, so even a non-screenshot polish isn't safe this tick. Did NOT fabricate filler work. **Ready candidate for the next sole-worker wake (carried from `aa0f5a86`):** the client picks-summary sheet's `favs.size >= 2` fold — distinct chrome from the 1-pick baselines (the "Compare side-by-side" affordance APPEARS + the download/footer row reflows), renders in NO baseline. Recipe: seed `/eclipse-media/demo`, favorite EXACTLY 2 photos deterministically (favorites-GET-before-heart guard per [[playwright-getbyrole-name-is-substring]] + the `/api/client-session`-GET welcome-dismissal scaffold per [[registration-wall-and-session-race]]), element-screenshot the sheet card, eyeball + 2× `--retries=0` verify, @local-only. Wake-start CI clean: prod `/api/health` ok (db ~0.9s); `.ci-watch` 03:15 DEPLOY-FROZEN is routine batch-tip lag ([[deploys-can-silently-not-ship]]), not a red gate. Telegram sent. DO NOT PUSH.

See it for yourself

A real wedding gallery,
delivered the Selene way.

Open the demo gallery →