// ===== Mark.jsx =====
// Veradoma viewfinder mark — copied from v1, unchanged glyph.
const Mark = ({ size = 24, inverse = false, accent = "#B68A4E", stroke = "#2B2A28", strokeWidth }) => {
const sw = strokeWidth ?? (size <= 20 ? 8 : size <= 32 ? 6 : size <= 64 ? 4.5 : 3.5);
const fillColor = inverse ? "#D4B07A" : accent;
const strokeColor = inverse ? "#F7F4EE" : stroke;
return (
);
};
// Tiny outline icon set used across the kit. 1.5px stroke, currentColor.
const Icon = ({ name, size = 18 }) => {
const common = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true };
switch (name) {
case "arrow-right":
return ;
case "arrow-down":
return ;
case "camera":
return ;
case "video":
return ;
case "drone":
return ;
case "floor-plan":
return ;
case "globe":
return ;
case "social":
return ;
case "clock":
return ;
case "check":
return ;
case "instagram":
return ;
case "phone":
return ;
case "mail":
return ;
case "pin":
return ;
case "menu":
return ;
case "close":
return ;
case "facebook":
return ;
case "linkedin":
return ;
case "vimeo":
return ;
default: return null;
}
};
Object.assign(window, { Mark, Icon });
// ===== Reveal hooks =====
function useReveal() {
const ref = React.useRef(null);
React.useEffect(() => {
const el = ref.current;
if (!el) return;
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (reduce) { el.classList.add("is-revealed"); return; }
const io = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
el.classList.add("is-revealed");
io.disconnect();
}
}, { threshold: 0.15, rootMargin: "-10% 0px -10% 0px" });
io.observe(el);
return () => io.disconnect();
}, []);
return ref;
}
function useRevealOnMount(delayMs = 0) {
const ref = React.useRef(null);
React.useEffect(() => {
const el = ref.current;
if (!el) return;
const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (reduce) { el.classList.add("is-revealed"); return; }
const id = window.setTimeout(() => {
window.requestAnimationFrame(() => el.classList.add("is-revealed"));
}, delayMs);
return () => window.clearTimeout(id);
}, [delayMs]);
return ref;
}
// Smooth-scroll to a same-page anchor while respecting modifier clicks
// (Cmd/Ctrl/Shift → open in new tab; middle-click → open in new tab).
const smoothNav = (e, id) => {
if (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) return;
e.preventDefault();
const el = document.getElementById(id);
if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
};
Object.assign(window, { useReveal, useRevealOnMount, smoothNav });
// ===== Spiro booking =====
// bundleIDs verified against the live Spiro order page on 2026-05-18.
// To refresh: GET https://order-api.spiro.media/api/bundle/GetBundles?tenantShortCode=veradoma&orderPageCode=veradoma-order-page
const SPIRO = {
base: "https://book.veradoma.com/order/veradoma/veradoma-order-page",
essential: "30c8a7c5-0ded-473f-9d91-9028647b3712",
premium: "d79f1eda-9c33-4366-ad2b-b3eb8ab57dab",
luxury: "1025fe9b-91df-4f98-8f5a-612b7e32e3c0",
};
const spiroLink = (id) => (id ? `${SPIRO.base}/${id}` : SPIRO.base);
// ===== Header.jsx =====
const Header = ({ active = "home" }) => {
const [scrolled, setScrolled] = React.useState(false);
const [menuOpen, setMenuOpen] = React.useState(false);
React.useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 80);
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
const items = [
{ id: "work", label: "Work" },
{ id: "services", label: "Services" },
{ id: "packages", label: "Packages" },
{ id: "book", label: "Book" },
];
const go = (e, id) => {
if (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) return;
setMenuOpen(false);
smoothNav(e, id);
};
return (
);
};
Object.assign(window, { Header });
// ===== Hero.jsx =====
const Hero = () => {
const eyebrowRef = useRevealOnMount(0);
const titleRef = useRevealOnMount(60);
const leadRef = useRevealOnMount(120);
const ctaRef = useRevealOnMount(180);
const statsRef = useRevealOnMount(240);
const reduce = React.useMemo(
() => typeof window !== "undefined"
&& window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true,
[]);
// Phones get a muted autoplay loop; desktop scroll-scrubs the timeline.
const isMobile = React.useMemo(
() => typeof window !== "undefined"
&& window.matchMedia?.("(max-width: 767px)").matches === true,
[]);
const sectionRef = React.useRef(null);
const videoRef = React.useRef(null);
// Force muted at attach time. React's `muted` JSX prop doesn't reliably set
// the DOM property, and iOS blocks autoplay unless the element is truly muted.
const setVideoEl = React.useCallback((el) => {
videoRef.current = el;
if (el) { el.muted = true; el.defaultMuted = true; }
}, []);
React.useEffect(() => {
if (reduce) return;
const video = videoRef.current;
const section = sectionRef.current;
if (!video || !section) return;
// Scrub the day→evening timeline from the scroll position — on mobile too.
// The mobile clip (hero-scrub-mobile.mp4) is encoded with every frame as a
// keyframe, so iOS can seek it instantly; a normal sparse-keyframe clip
// freezes while scrubbing on iOS. Prime first: a muted play()/pause()
// unlocks programmatic currentTime updates on iOS.
const prime = () => { video.play().then(() => video.pause()).catch(() => {}); };
if (video.readyState >= 1) prime(); else video.addEventListener('loadedmetadata', prime, { once: true });
let rafId = null;
let lastT = -1;
const update = () => {
rafId = null;
const rect = section.getBoundingClientRect();
const scrubRange = Math.max(1, rect.height - window.innerHeight);
const progress = Math.max(0, Math.min(1, -rect.top / scrubRange));
const dur = video.duration;
if (!dur || !isFinite(dur)) return;
const t = progress * dur;
if (Math.abs(t - lastT) < 0.03) return;
lastT = t;
video.currentTime = t;
};
const onScroll = () => { if (rafId == null) rafId = requestAnimationFrame(update); };
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
return () => {
window.removeEventListener('scroll', onScroll);
if (rafId != null) cancelAnimationFrame(rafId);
};
}, [reduce]);
return (
{reduce ? (

) : (
)}
Real estate media · Orange County
Cinematic listings,
delivered next morning.
Photo, drone, video, and floor plans. Polished work, predictable turnaround, easy to book.
{[
{ v: "24 hr", l: "Gallery turnaround" },
{ v: "500+", l: "Listings shot" },
{ v: "OC", l: "Orange County" },
].map(s => (
))}
);
};
Object.assign(window, { Hero });
// ===== FeaturedWork.jsx =====
const WORK = [
{ id: 1, title: "Bayside Twilight", loc: "Newport Beach", tag: "Twilight", deliverables: "32 photos · drone", turn: "Delivered 24 hr", src: "assets/photos/portfolio-bayside-twilight.png", alt: "Newport Beach waterfront home at twilight" },
{ id: 2, title: "Linden Cottage", loc: "Costa Mesa", tag: "Photography", deliverables: "28 photos", turn: "Delivered 24 hr", src: "assets/photos/portfolio-linden-cottage.png", alt: "Costa Mesa cottage at golden hour" },
{ id: 3, title: "Ridgeline", loc: "Laguna Beach", tag: "Drone", deliverables: "Aerial stills + 30s clip", turn: "Delivered 24 hr", src: "assets/photos/portfolio-ridgeline-aerial.png", alt: "Aerial view of a Laguna Beach hillside home" },
{ id: 4, title: "The Crescent", loc: "Corona del Mar", tag: "Photography", deliverables: "35 photos · floor plan", turn: "Delivered 24 hr", src: "assets/photos/portfolio-the-crescent.png", alt: "Corona del Mar exterior in late-afternoon light" },
{ id: 5, title: "Whitewater House", loc: "Laguna Niguel", tag: "Video", deliverables: "60s walkthrough · 30 photos", turn: "Delivered 24 hr", src: "assets/photos/portfolio-whitewater-house.png", alt: "Modern kitchen interior in Laguna Niguel" },
{ id: 6, title: "Magnolia Estate", loc: "Newport Coast", tag: "Twilight", deliverables: "50 photos · drone · 3D plan", turn: "Same-day rush", src: "assets/photos/portfolio-magnolia-estate.png", alt: "Newport Coast estate at dusk" },
];
const WorkCard = ({ work, index }) => {
const ref = useReveal();
return (
{work.tag}
{work.loc}
{work.title}
{work.deliverables}
{work.turn}
);
};
const FeaturedWork = () => {
const headRef = useReveal();
return (
Recent work
From the last few weeks.
{WORK.map((w, i) => )}
);
};
Object.assign(window, { FeaturedWork });
// ===== Services.jsx =====
const SERVICES = [
{ icon: "camera", name: "Photography", desc: "Interior and exterior, MLS-ready, color-corrected, next morning." },
{ icon: "drone", name: "Drone", desc: "FAA-licensed aerial stills and short clips of home + lot." },
{ icon: "video", name: "Video", desc: "Gimbal walkthroughs and twilight cinematic edits." },
{ icon: "floor-plan", name: "Floor plans", desc: "Accurate 2D and 3D floor plans with room dimensions." },
{ icon: "globe", name: "Property site",desc: "Single-property site with your branding and full gallery." },
{ icon: "social", name: "Reels", desc: "Vertical reels and square highlights for Instagram." },
];
const ServiceTile = ({ s, index }) => {
const ref = useReveal();
return (
);
};
const Services = () => {
const headRef = useReveal();
return (
What we shoot
Everything a listing needs.
Book one service or the whole set. Most agents pair photography with a floor plan and a short walkthrough — three deliverables, one shoot.
{SERVICES.map((s, i) => )}
);
};
Object.assign(window, { Services });
// ===== WhyPickUs.jsx =====
const REASONS = [
{ icon: "clock", name: "Always on time", desc: "We arrive at the scheduled minute, with the crew and gear the brief calls for." },
{ icon: "check", name: "24-hour gallery", desc: "Standard 24-hour turnaround. Twilight and same-day available for a small uplift." },
{ icon: "camera", name: "Consistent edit", desc: "Warm white-balance, vertical lines, no over-cooked HDR. Every shoot looks like the last." },
{ icon: "arrow-right", name: "Easy to book", desc: "One link, three fields. Confirmation in the hour, calendar invite the same day." },
];
const ReasonTile = ({ r, index }) => {
const ref = useReveal();
return (
);
};
const WhyPickUs = () => {
const headRef = useReveal();
return (
Why agents pick us
The boring parts, done right.
Most of what makes media work for a listing is consistency, not flash. Punctual crews, predictable color, files where you expect them.
{REASONS.map((r, i) => )}
);
};
Object.assign(window, { WhyPickUs });
// ===== Packages.jsx =====
const PACKAGES = [
{
name: "Essential", price: "from $225", featured: false,
desc: "For standard listings. Photo, drone, and the basics that make a clean gallery.",
features: [
"MLS-ready listing photos",
"Drone photos (all standard angles)",
"Basic 2D floor plan",
"TV screens replaced",
"Single-property website",
],
bundleId: SPIRO.essential,
},
{
name: "Premium", price: "from $299", featured: true,
desc: "What most agents book. Adds 3D tour and a twilight image.",
features: [
"MLS-ready listing photos",
"Drone photos",
"Zillow 3D Tour",
"Virtual twilight image",
"TV screens replaced",
"2D floor plan with measurements",
"Single-property website",
],
bundleId: SPIRO.premium,
},
{
name: "Luxury", price: "from $650", featured: false,
desc: "For homes that need a marketing campaign. Adds cinematic video and four twilight images.",
features: [
"MLS-ready listing photos",
"Drone photos",
"Cinematic video (incl. drone video)",
"30s social-media reel",
"Zillow 3D Tour",
"4 virtual twilight photos",
"TV screens replaced",
"2D floor plan with measurements",
"Single-property website",
],
bundleId: SPIRO.luxury,
},
];
const PackageCard = ({ pkg, index }) => {
const ref = useReveal();
return (
);
};
const Packages = () => {
const headRef = useReveal();
const live = useSpiroBundles();
const cards = PACKAGES.map(p => {
const liveData = live?.get(p.bundleId);
if (!liveData) return p;
return {
...p,
price: liveData.price || p.price,
features: liveData.features.length ? liveData.features : p.features,
};
});
return (
Simple packages
Pick the one that fits the listing.
Final price depends on square footage and add-ons; the exact quote appears in the booking flow.
);
};
Object.assign(window, { Packages });
// ===== BookCTA.jsx =====
const BookCTA = () => {
const eyebrowRef = useReveal();
const titleRef = useReveal();
const contactRef = useReveal();
const ctaRef = useReveal();
const contacts = [
{ icon: "phone", label: "747-243-8969", href: "tel:7472438969", external: false },
{ icon: "mail", label: "vlad@veradoma.com", href: "mailto:vlad@veradoma.com", external: false },
{ icon: "instagram", label: "@veradoma_media", href: "https://instagram.com/veradoma_media", external: true },
];
return (
Ready when you are
Book a shoot.
{contacts.map(c => (
{c.label}
))}
Orange County · CA
Start booking
Or pick a specific package above — each opens the booking flow preselected.
);
};
Object.assign(window, { BookCTA });
// ===== Footer.jsx =====
const FOOTER_COLS = {
Services: ["Photography", "Drone", "Video", "Floor plans", "Property sites", "Reels"],
"Get in touch": [
{ label: "747-243-8969", href: "tel:7472438969" },
{ label: "vlad@veradoma.com", href: "mailto:vlad@veradoma.com" },
{ label: "@veradoma_media", href: "https://instagram.com/veradoma_media" },
{ label: "book.veradoma.com", href: "https://book.veradoma.com" },
],
Locations: ["Newport Beach", "Costa Mesa", "Laguna Beach", "Irvine", "Corona del Mar", "Newport Coast"],
};
const Footer = () => {
const brandRef = useReveal();
return (
);
};
Object.assign(window, { Footer });
// ===== App entry =====
const App = () => {
return (
);
};
ReactDOM.createRoot(document.getElementById("app")).render();