// sections.jsx — "The Reel" landing page, in six chapters // ──────────────────── Chapter marker ──────────────────── function Slate({ n, total = '06', title }) { return (
{n} / {total} {title}
); } // ──────────────────── Nav ──────────────────── function Nav() { const [scrolled, setScrolled] = React.useState(false); React.useEffect(() => { const on = () => setScrolled(window.scrollY > 40); window.addEventListener('scroll', on, { passive: true }); on(); return () => window.removeEventListener('scroll', on); }, []); return ( ); } // ──────────────────── Hero — Title Card with key art ──────────────────── function Hero({ layout }) { return (
Wedding Photography & Cinema / New Jersey · Since 2013

The days
that matter most.

Photography, cinema and livestreaming for weddings and the gatherings you'll come back to forever.

); } // ──────────────────── Chapter 02 — Disciplines ──────────────────── const DISCIPLINES = [ { n: '01', title: 'Photography', spec: 'Documentary + portrait coverage' }, { n: '02', title: 'Videography', spec: 'Multi cam wedding films' }, { n: '03', title: 'Livestream', spec: 'Broadcast to anywhere' }, { n: '04', title: 'Aerial / Drone', spec: 'FAA Part 107 certified' }, { n: '05', title: 'Same Day Edit', spec: '60–90 sec highlight reel' }, ]; function Services() { return (

Five disciplines.
One crew on the day.

Every event is staffed by a single tight team so the photograph, the film and the livestream tell one story, not three. Mix what you need.

    {DISCIPLINES.map((d) => (
  1. /{d.n}

    {d.title}

    {d.spec}
  2. ))}
); } // ──────────────────── Chapter 03 — The Reel (collage) ──────────────────── // Columns of photos — varied single / stacked arrangements, scrolls sideways const COLLAGE_COLS = [ ['w1'], ['e1', 'p1'], ['n1'], ['n3', 'n2'], ['w2'], ['e2', 'p2'], ['n5'], ['n4', 'n7'], ['w3', 'p3'], ['e3'], ['n6'], ['n8'], ['n12'], ['n9'], ['n10'], ['n11'], ['n13'], ['w5', 'p4'], ['w4', 'p5'], ]; const COLLAGE = COLLAGE_COLS.flat().map((k) => `assets/portfolio/${k}.jpg`); function Portfolio() { const [open, setOpen] = React.useState(null); // index into COLLAGE or null const stripRef = React.useRef(null); const close = () => setOpen(null); const go = (dir) => setOpen((i) => (i + dir + COLLAGE.length) % COLLAGE.length); React.useEffect(() => { if (open === null) return; const onKey = (e) => { if (e.key === 'Escape') close(); else if (e.key === 'ArrowRight') go(1); else if (e.key === 'ArrowLeft') go(-1); }; window.addEventListener('keydown', onKey); document.body.style.overflow = 'hidden'; return () => { window.removeEventListener('keydown', onKey); document.body.style.overflow = ''; }; }, [open]); // drag-to-scroll React.useEffect(() => { const el = stripRef.current; if (!el) return; let down = false, startX = 0, startScroll = 0, moved = 0; const onDown = (e) => { down = true; moved = 0; startX = e.pageX; startScroll = el.scrollLeft; el.classList.add('dragging'); }; const onMove = (e) => { if (!down) return; const dx = e.pageX - startX; moved = Math.max(moved, Math.abs(dx)); el.scrollLeft = startScroll - dx; }; const onUp = () => { down = false; el.classList.remove('dragging'); }; el.addEventListener('pointerdown', onDown); window.addEventListener('pointermove', onMove); window.addEventListener('pointerup', onUp); el._getMoved = () => moved; return () => { el.removeEventListener('pointerdown', onDown); window.removeEventListener('pointermove', onMove); window.removeEventListener('pointerup', onUp); }; }, []); const openIfNotDragged = (idx) => () => { const el = stripRef.current; if (el && el._getMoved && el._getMoved() > 6) return; // was a drag setOpen(idx); }; let flatIdx = -1; return (

240+ events.
A few favorites.

A working contact sheet of moments from weddings, ceremonies, and the quiet in between. Drag to scroll, click any frame to enlarge.

Drag or scroll sideways
{COLLAGE_COLS.map((col, ci) => (
1 ? 'stack' : 'single'}`} key={ci}> {col.map((key) => { flatIdx += 1; const idx = flatIdx; return ( ); })}
))}
240+ events shot 13 years working NJ · NY · PA · and beyond
{open !== null && (
e.stopPropagation()} />
{String(open + 1).padStart(2, '0')} / {String(COLLAGE.length).padStart(2, '0')}
)}
); } // ──────────────────── Chapter 04 — Voices ──────────────────── const VOICES = [ { q: 'Very professional media company with great quality work and excellent customer service. I highly recommend them to anyone in New Jersey and New Milford. Reliable, respectful, and easy to work with.', by: 'Luis Guaman', meta: 'Google Review · New Milford NJ', stars: 5 }, { q: 'Professional, good quality, excellent photographic skills, unique capture of moments, highly recommend.', by: 'Lexy Maria Alappat', meta: 'Google Review', stars: 5 }, { q: 'They made my grandfather\'s memorial feel like a love letter, not a funeral. We will watch the film they made for our family for the rest of our lives.', by: 'Marisol Reyes', meta: 'Memorial · Princeton NJ', stars: 5 }, ]; function Testimonials() { return (

What couples
say after.

A handful of the things we hear most often — drawn from the cards and emails and the messages people send us months later, on their anniversaries.

{VOICES.map((v, i) => (
/0{i + 1} {Array.from({ length: v.stars }).map((_, k) => )}
"{v.q}"
{v.by} {v.meta}
))}
); } // ──────────────────── Chapter 06 — Reserve ──────────────────── // ⬇⬇⬇ PASTE YOUR WEB3FORMS ACCESS KEY HERE ⬇⬇⬇ // Get a free key in 30 seconds at https://web3forms.com (enter twilightmediausa@gmail.com, // they email you a key). Submissions then arrive in that inbox automatically. const WEB3FORMS_ACCESS_KEY = '9c5ad4ca-b1e1-4644-acc7-60b913e141f8'; function Booking() { const [form, setForm] = React.useState({ name: '', email: '', phone: '', date: '', eventType: 'Wedding', guests: '', notes: '', services: ['Photography'], }); const [sent, setSent] = React.useState(false); const [sending, setSending] = React.useState(false); const [error, setError] = React.useState(''); const update = (k) => (e) => setForm({ ...form, [k]: e.target.value }); const toggleSvc = (s) => () => { setForm(f => ({ ...f, services: f.services.includes(s) ? f.services.filter(x => x !== s) : [...f.services, s] })); }; const submit = async (e) => { e.preventDefault(); setError(''); setSending(true); try { const res = await fetch('https://api.web3forms.com/submit', { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, body: JSON.stringify({ access_key: WEB3FORMS_ACCESS_KEY, subject: `New booking request — ${form.name || 'Website'}`, from_name: 'Twilight Media Website', name: form.name, email: form.email, phone: form.phone, event_date: form.date, event_type: form.eventType, approx_guests: form.guests, services: form.services.join(', '), message: form.notes, }), }); const data = await res.json(); if (data.success) { setSent(true); } else { setError(data.message || 'Something went wrong. Please email us directly.'); } } catch (err) { setError('Network error. Please email us directly at twilightmediausa@gmail.com.'); } finally { setSending(false); } }; return (
{sent ? (

Thank you, {form.name || 'friend'}.

We've received your request and will be in touch within 24 hours at {form.email || 'the email you provided'}.

) : (
{['Photography', 'Videography', 'Livestream', 'Drone', 'Same Day Edit'].map(s => ( ))}