// Group VIDA'S Digital Studios — landing components (v2: purple/black, modern sans)
const { useState, useEffect, useRef } = React;
// ---------- Primitives ----------
// Realistic Lisbon scene placeholder — SVG-composed skyline/landmark illustrations
// No photos available; we compose stylised scene illustrations with purple duotone.
const LisbonScene = ({ kind = "tejo", label, ratio = "16/9" }) => {
const scenes = {
// River Tejo + 25 de Abril bridge silhouette
tejo: (
{/* sun */}
{/* far hills */}
{/* bridge towers */}
{/* bridge cables */}
{/* bridge deck */}
{/* water */}
{/* water reflections */}
{[150, 160, 170, 180, 190, 200, 210].map((y, i) => (
))}
),
// Alfama rooftops
alfama: (
{/* rooftops layered */}
{[...Array(30)].map((_, i) => {
const x = i * 14;
const h = 40 + (i % 7) * 12;
const y = 225 - h;
return (
{/* roof triangle */}
{/* windows */}
{h > 60 && }
{h > 80 && }
);
})}
{/* church spire */}
),
// Eléctrico 28 tram on cobbled street
tram: (
{/* buildings left */}
{/* buildings right */}
{/* windows glow */}
{[[20,70],[20,110],[60,90],[60,140],[120,100],[120,150],[240,90],[240,140],[320,80],[320,130],[360,100]].map(([x,y],i)=>(
))}
{/* street */}
{/* tram rails */}
{/* tram body */}
{/* tram number */}
28
{/* pole */}
),
// Aerial / drone shot over Baixa
aerial: (
{/* grid streets */}
{[0,1,2,3,4,5,6,7].map(i => (
))}
{[0,1,2,3,4,5,6,7,8,9,10].map(i => (
))}
{/* blocks */}
{[...Array(40)].map((_, i) => {
const x = 22 + (i % 10) * 36;
const y = 32 + Math.floor(i / 10) * 26;
return ;
})}
{/* drone reticle */}
),
// Praça do Comércio arch
praca: (
{/* arch */}
{/* columns */}
{/* top statue */}
{/* ground */}
{/* wings */}
{[...Array(8)].map((_,i)=> )}
{[...Array(8)].map((_,i)=> )}
),
// Cais (dock) with boats
cais: (
{/* far skyline */}
{/* water */}
{[...Array(12)].map((_,i) => (
))}
{/* boat silhouettes */}
),
};
return (
{scenes[kind] || scenes.tejo}
{label && (
{label}
)}
{/* corner ticks */}
{[["top","left"],["top","right"],["bottom","right"]].map(([v,h],i)=>(
))}
);
};
// Logo mark — real brand logo
const Logo = ({ size = 36 }) => (
);
const MonoLabel = ({ children, color }) => (
{children}
);
// ---------- Nav ----------
const Nav = ({ onCta }) => {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 40);
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
const links = [["serviços","services"],["trabalho","work"],["consultoria","consultoria"],["2026","stats"],["contacto","contact"]];
return (
Group VIDA'S
DIGITAL STUDIOS
);
};
// ---------- Hero ----------
// Animated purple orb + particles
const HeroVisual = () => {
const canvasRef = useRef(null);
useEffect(() => {
const canvas = canvasRef.current; if (!canvas) return;
const ctx = canvas.getContext("2d");
let w, h, raf;
const resize = () => {
const r = canvas.getBoundingClientRect();
canvas.width = r.width * devicePixelRatio;
canvas.height = r.height * devicePixelRatio;
w = r.width; h = r.height;
ctx.setTransform(devicePixelRatio,0,0,devicePixelRatio,0,0);
};
resize();
window.addEventListener("resize", resize);
const particles = Array.from({length: 60}, () => ({
x: Math.random()*1, y: Math.random()*1,
vx: (Math.random()-0.5)*0.0004, vy: (Math.random()-0.5)*0.0004,
r: Math.random()*1.6+0.4,
}));
let t = 0;
const draw = () => {
t += 0.005;
ctx.clearRect(0,0,w,h);
// orb glow
const cx = w*0.55, cy = h*0.5;
const grad = ctx.createRadialGradient(cx, cy, 0, cx, cy, Math.min(w,h)*0.55);
grad.addColorStop(0, "rgba(138, 58, 208, 0.55)");
grad.addColorStop(0.4, "rgba(92, 30, 160, 0.25)");
grad.addColorStop(1, "rgba(10, 4, 21, 0)");
ctx.fillStyle = grad;
ctx.fillRect(0,0,w,h);
// concentric rings
for (let i=0; i<6; i++) {
const r = 40 + i*28 + Math.sin(t+i)*4;
ctx.beginPath();
ctx.arc(cx, cy, r, 0, Math.PI*2);
ctx.strokeStyle = `rgba(198, 240, 60, ${0.22 - i*0.03})`;
ctx.lineWidth = 0.6;
ctx.stroke();
}
// rotating dashed ring
ctx.save();
ctx.translate(cx, cy); ctx.rotate(t*2);
ctx.beginPath();
ctx.arc(0,0, 110, 0, Math.PI*2);
ctx.setLineDash([4, 10]);
ctx.strokeStyle = "rgba(198,240,60,0.6)";
ctx.lineWidth = 1;
ctx.stroke();
ctx.restore();
ctx.save();
ctx.translate(cx, cy); ctx.rotate(-t*1.3);
ctx.beginPath();
ctx.arc(0,0, 170, 0, Math.PI*2);
ctx.setLineDash([2, 18]);
ctx.strokeStyle = "rgba(138,58,208,0.7)";
ctx.lineWidth = 1;
ctx.stroke();
ctx.restore();
// particles
particles.forEach(p => {
p.x += p.vx; p.y += p.vy;
if (p.x < 0 || p.x > 1) p.vx *= -1;
if (p.y < 0 || p.y > 1) p.vy *= -1;
ctx.beginPath();
ctx.arc(p.x*w, p.y*h, p.r, 0, Math.PI*2);
ctx.fillStyle = `rgba(198,240,60,${0.2 + p.r*0.2})`;
ctx.fill();
});
raf = requestAnimationFrame(draw);
};
draw();
return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", resize); };
}, []);
return (
);
};
const Hero = () => {
const words = ["visíveis", "desejadas", "rentáveis"];
const [w, setW] = useState(0);
useEffect(() => {
const id = setInterval(() => setW(x => (x+1) % words.length), 2200);
return () => clearInterval(id);
}, []);
return (
Estúdio · Portugal Continental · 2024 — 2026
Negócios locais
tornam-se marcas
{words[w]}.
Produção audiovisual, captação aérea com drone e gestão de presença digital
para empresas locais e mediadores imobiliários em Portugal.
Um estúdio. Três operações: Produção · Distribuição · Visibilidade.
{/* scroll indicator */}
↓ SCROLL
001 / 006
);
};
// ---------- Marquee ----------
const Marquee = () => {
const items = ["VÍDEO INSTITUCIONAL", "DRONE 4K", "GOOGLE BUSINESS", "LANDING PAGES", "META ADS", "VÍDEO TOUR IMOBILIÁRIO", "FOTOGRAFIA AÉREA", "STORYTELLING", "RETAINERS MENSAIS", "CONSULTORIA DIGITAL"];
return (
{[...items, ...items, ...items].map((it, i) => (
{it}
✦
))}
);
};
// ---------- Services ----------
const services = [
{
num: "01", title: "Audiovisual Comercial", scene: "alfama", sceneLabel: "Alfama, Lisboa",
short: "Vídeos que vendem percepção.",
detail: "Institucionais, promocionais, storytelling de marca e conteúdo nativo para redes sociais. Direção criativa própria — do briefing ao entregável final.",
items: ["Vídeos institucionais", "Promocionais", "Storytelling", "Reels & Shorts"],
},
{
num: "02", title: "Drone & Captação Aérea", scene: "aerial", sceneLabel: "Baixa · vista aérea",
short: "Perspectiva que o concorrente não tem.",
detail: "Fotografia e vídeo aéreo comercial, vídeos imobiliários, inspeções visuais e mapeamento. Equipamento certificado ANAC, operação com seguro.",
items: ["Fotografia aérea 4K", "Vídeo imobiliário", "Inspeções visuais", "Mapeamento"],
},
{
num: "03", title: "Presença Digital Local", scene: "tram", sceneLabel: "Chiado · eléctrico 28",
short: "Visibilidade onde o cliente procura.",
detail: "Google Business otimizado, landing pages que convertem, funis simples de aquisição e conteúdo estratégico pensado para mercado local.",
items: ["Google Business", "Landing pages", "Funis de aquisição", "Conteúdo SEO local"],
},
{
num: "04", title: "Imobiliário", scene: "tejo", sceneLabel: "Tejo · 25 de Abril",
short: "Anúncios que fecham visitas.",
detail: "Vídeo tour de imóveis, fotografia profissional, vídeos de impacto para anúncios e branding visual para mediadores. Vendemos o imóvel antes da visita.",
items: ["Vídeo tour", "Fotografia profissional", "Anúncios de impacto", "Branding mediadores"],
},
];
const ServiceRow = ({ s, open, onToggle }) => (
{s.num}
{s.title}
{s.short}
{s.detail}
{s.items.map(it => (
{it}
))}
);
const Services = () => {
const [openIdx, setOpenIdx] = useState(0);
return (
§ 01
Quatro pilares. Uma operação.
O mercado separa videomaker, marketing e drone em silos. Nós juntamos os três — produção, distribuição e visibilidade — num só estúdio.
{services.map((s, i) => (
setOpenIdx(openIdx === i ? -1 : i)}/>
))}
);
};
// ---------- Consultoria (phased roadmap) ----------
const phases = [
{
n: "FASE 01", dur: "30 MIN · GRATUITO", t: "Diagnóstico digital",
d: "Sessão inicial por videochamada. Mapeamos a presença atual — Google Business, redes sociais, website, concorrência local. Saem um relatório visual e três hipóteses de ganho imediato.",
bullets: ["Auditoria de visibilidade", "Análise de concorrentes locais", "Identificação de 3 oportunidades prioritárias"],
scene: "praca", sceneLabel: "Praça do Comércio",
},
{
n: "FASE 02", dur: "SEMANA 1", t: "Plano editorial & estratégia",
d: "Desenhamos um calendário de produção mensal alinhado ao funil do negócio: atração, autoridade e conversão. Definimos formatos, tom e pilares de conteúdo específicos para o segmento.",
bullets: ["Calendário editorial 90 dias", "Pilares de conteúdo & narrativa", "Métricas de sucesso acordadas"],
scene: "alfama", sceneLabel: "Alfama",
},
{
n: "FASE 03", dur: "2 – 3 DIAS", t: "Produção no terreno",
d: "Dias de captação com equipa completa: vídeo, drone e fotografia na mesma sessão. Optimizamos deslocações e logística para extrair volume útil de conteúdo para 30 a 60 dias.",
bullets: ["Vídeo multicâmara", "Captação aérea ANAC", "Fotografia editorial & still"],
scene: "tram", sceneLabel: "Chiado",
},
{
n: "FASE 04", dur: "CONTÍNUO", t: "Distribuição & tráfego",
d: "Publicação calendarizada, optimização do perfil Google Business, SEO local, e — quando o plano inclui — gestão de anúncios Meta e Google para o bairro ou cidade onde o negócio está.",
bullets: ["Publicação multicanal", "Google Business contínuo", "Meta Ads geolocalizado"],
scene: "aerial", sceneLabel: "Vista aérea · Baixa",
},
{
n: "FASE 05", dur: "MENSAL", t: "Relatório & iteração",
d: "Revisão mensal: alcance, contactos gerados, custo por lead, evolução face ao mês anterior. Iteramos sobre dados, nunca sobre achismo. Ajustamos formatos, horários e foco geográfico.",
bullets: ["Painel de métricas", "Revisão estratégica mensal", "Iteração com base em dados"],
scene: "cais", sceneLabel: "Cais do Sodré",
},
];
const Consultoria = () => {
const [active, setActive] = useState(0);
return (
§ 02
Consultoria fase a fase.
Um processo claro, executado mês a mês. Começa com um diagnóstico gratuito e evolui até um sistema recorrente de aquisição — sem projeto único, sem surpresas.
{/* phase list */}
{phases.map((p, i) => (
setActive(i)} style={{
width: "100%", textAlign: "left", cursor: "pointer",
background: active === i ? "rgba(198,240,60,0.06)" : "transparent",
border: "none", borderLeft: `2px solid ${active === i ? "var(--accent)" : "rgba(198,240,60,0.15)"}`,
padding: "22px 24px", color: "var(--fg)",
display: "flex", flexDirection: "column", gap: 8,
transition: "all 220ms",
}}>
{p.n}
{p.dur}
{p.t}
))}
{/* active detail */}
{phases[active].n}
{phases[active].t}
{phases[active].d}
{phases[active].bullets.map(b => (
{b}
))}
{/* CTA within consultoria */}
PRÓXIMO PASSO
Fase 01 — diagnóstico gratuito, 30 minutos.
Marcar agora
);
};
// ---------- Portfolio ----------
const portfolio = [
{ title: "Restaurante à beira-rio", segment: "local", scene: "tejo", meta: "VÍDEO + STILLS · 00:48", location: "Doca de Santo Amaro" },
{ title: "Empreendimento residencial", segment: "imobiliário", scene: "aerial", meta: "DRONE + TOUR · 02:04", location: "Parque das Nações" },
{ title: "Clínica boutique", segment: "local", scene: "alfama", meta: "BRANDING + FOTOGRAFIA", location: "Príncipe Real" },
{ title: "Apartamento de charme", segment: "imobiliário", scene: "tram", meta: "VÍDEO TOUR · 01:12", location: "Bairro Alto" },
{ title: "Ginásio urbano", segment: "local", scene: "praca", meta: "REEL MENSAL + ADS", location: "Baixa-Chiado" },
{ title: "Villa com vista", segment: "imobiliário", scene: "cais", meta: "AERIAL + CAMPANHA", location: "Cascais" },
];
const Portfolio = () => {
const [filter, setFilter] = useState("tudo");
const filters = ["tudo", "imobiliário", "local"];
const shown = portfolio.filter(p => filter === "tudo" || p.segment === filter);
return (
§ 03
Trabalho selecionado
{filters.map(f => (
setFilter(f)} style={{
background: filter === f ? "var(--accent)" : "transparent",
color: filter === f ? "#0a0415" : "var(--fg)",
border: "none", padding: "8px 18px", cursor: "pointer", borderRadius: 999,
fontFamily: "'Geist', sans-serif", fontSize: 12, fontWeight: 500,
transition: "all 200ms",
}}>{f}
))}
{shown.map((p, i) => {
const span = i % 5 === 0 ? 4 : i % 5 === 1 ? 2 : i % 5 === 2 ? 3 : i % 5 === 3 ? 3 : 2;
return (
{ const img = e.currentTarget.querySelector(".ph"); if (img) img.style.transform = "scale(1.02)"; }}
onMouseLeave={e => { const img = e.currentTarget.querySelector(".ph"); if (img) img.style.transform = "scale(1)"; }}
>
= 4 ? "21/9" : span === 3 ? "4/3" : "3/4"}/>
);
})}
);
};
// ---------- Stats 2026 ----------
const Stats2026 = () => {
const stats = [
{ big: "87%", label: "dos portugueses pesquisam um negócio online antes de o visitar", src: "Marktest Digital" },
{ big: "6h 42m", label: "tempo médio diário de utilização de internet em Portugal em 2026", src: "We Are Social PT" },
{ big: "72%", label: "dos consumidores locais confiam mais em empresas com vídeo", src: "Wyzowl 2026" },
{ big: "+184%", label: "crescimento do consumo de vídeo vertical em Portugal (2024 → 2026)", src: "Meta for Business" },
{ big: "3.2×", label: "mais pedidos de contacto em perfis Google Business com fotos profissionais", src: "Google Business Insights" },
{ big: "8 seg", label: "é o tempo médio de atenção de um visitante num anúncio imobiliário", src: "Idealista Labs" },
];
// animated bars
return (
{/* faint grid bg */}
§ 04
Portugal digital 2026.
LIVE · ATUALIZADO Q1 2026
{/* main chart strip */}
Consumo de vídeo em Portugal · 2022 → 2026 (índice)
{/* grid */}
{[0,1,2,3,4].map(i => (
))}
{/* bars */}
{[
["2022", 45], ["2023", 62], ["2024", 84], ["2025", 118], ["2026", 160],
].map(([y, v], i) => {
const x = 40 + i * 155;
const h = (v/180) * 140;
return (
+{v}%
{y}
);
})}
{/* trend line */}
{[75,230,385,540,695].map((x, i) => )}
{/* stat tiles */}
{stats.map((s, i) => (
{s.big}
{s.label}
Fonte · {s.src}
))}
);
};
// ---------- Contact ----------
const Contact = () => {
const [form, setForm] = useState({ nome: "", empresa: "", email: "", segmento: "local", mensagem: "" });
const [sent, setSent] = useState(false);
const [errors, setErrors] = useState({});
const submit = (e) => {
e.preventDefault();
const errs = {};
if (!form.nome.trim()) errs.nome = "obrigatório";
if (!form.email.includes("@")) errs.email = "email inválido";
if (!form.mensagem.trim()) errs.mensagem = "obrigatório";
setErrors(errs);
if (Object.keys(errs).length === 0) setSent(true);
};
const field = (key, label, type = "text") => (
{label} {errors[key] && — {errors[key]} }
setForm({ ...form, [key]: e.target.value })} style={{
background: "transparent", border: "none", borderBottom: "1px solid rgba(242,238,232,0.2)",
padding: "10px 0", color: "var(--fg)", fontFamily: "'Geist', sans-serif", fontSize: 16, outline: "none",
}} onFocus={e => e.target.style.borderBottomColor = "var(--accent)"}
onBlur={e => e.target.style.borderBottomColor = "rgba(242,238,232,0.2)"} />
);
return (
);
};
// ---------- Footer ----------
const Footer = () => (
);
// ---------- WhatsApp float ----------
const WhatsFloat = () => (
e.currentTarget.style.transform="scale(1.08)"}
onMouseLeave={e=>e.currentTarget.style.transform="scale(1)"}>
);
// expose
Object.assign(window, {
Nav, Hero, Marquee, Services, Consultoria, Portfolio, Stats2026, Contact, Footer, WhatsFloat,
});