feat: premium dark 'Signal' homepage — EN revenue content, generated assets, SEO/AEO, animated
This commit is contained in:
parent
daeb3f6cea
commit
ae0be1c48e
23 changed files with 1907 additions and 1291 deletions
67
app/components/CaseStudies.tsx
Normal file
67
app/components/CaseStudies.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CaseStudies — large film-cell cards. Each is a real <article> with the
|
||||||
|
* generated capsule visual, a problem -> result narrative, the method, and the
|
||||||
|
* headline metric. Alternating media side creates an editorial rhythm; refined
|
||||||
|
* scale-on-hover on the image. Images are explicit-sized + lazy-loaded.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Reveal from "./Reveal";
|
||||||
|
import { cases } from "../content";
|
||||||
|
|
||||||
|
export default function CaseStudies() {
|
||||||
|
return (
|
||||||
|
<section id="work" className="cases" aria-label="Case studies">
|
||||||
|
<div className="wrap">
|
||||||
|
<Reveal>
|
||||||
|
<p className="kicker">Case studies</p>
|
||||||
|
<h2 className="section__title">Proof, not promises.</h2>
|
||||||
|
<p className="section__lead">
|
||||||
|
A few of the businesses we've grown. Same approach every time:
|
||||||
|
tie the work to the revenue, then prove it.
|
||||||
|
</p>
|
||||||
|
</Reveal>
|
||||||
|
|
||||||
|
<div className="cases__list">
|
||||||
|
{cases.map((c, i) => (
|
||||||
|
<Reveal key={c.tag} y={60}>
|
||||||
|
<article className="case hoverable" data-cursor="view work">
|
||||||
|
<div className="case__media">
|
||||||
|
<span className="case__tag">{c.tag}</span>
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src={c.img}
|
||||||
|
alt={c.alt}
|
||||||
|
className="case__img"
|
||||||
|
width={900}
|
||||||
|
height={760}
|
||||||
|
loading={i === 0 ? "eager" : "lazy"}
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="case__body">
|
||||||
|
<p className="case__problem">{c.problem}</p>
|
||||||
|
<h3 className="case__result">
|
||||||
|
<em>{c.result}</em>
|
||||||
|
</h3>
|
||||||
|
<p className="case__how">{c.how}</p>
|
||||||
|
<p className="case__metric">
|
||||||
|
<span className="case__metric-num">{c.metricNum}</span>
|
||||||
|
<span className="case__metric-label">{c.metricLabel}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</Reveal>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="cases__cta">
|
||||||
|
<a className="btn btn--ghost hoverable" href="#contact">
|
||||||
|
<span>View all work →</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
74
app/components/CountUp.tsx
Normal file
74
app/components/CountUp.tsx
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CountUp — animates a number from 0 to its target when it scrolls into view.
|
||||||
|
* Uses GSAP + ScrollTrigger, formats with optional prefix/suffix/decimals and
|
||||||
|
* tabular figures. Under reduced-motion it renders the final value immediately.
|
||||||
|
* The full value is also written to the DOM on mount so it is correct even if
|
||||||
|
* JS/animation never runs (accessible + SSR-safe).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import { gsap } from "gsap";
|
||||||
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
value: number;
|
||||||
|
prefix?: string;
|
||||||
|
suffix?: string;
|
||||||
|
decimals?: number;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function CountUp({
|
||||||
|
value,
|
||||||
|
prefix = "",
|
||||||
|
suffix = "",
|
||||||
|
decimals = 0,
|
||||||
|
className = "",
|
||||||
|
}: Props) {
|
||||||
|
const ref = useRef<HTMLSpanElement>(null);
|
||||||
|
|
||||||
|
const format = (n: number) =>
|
||||||
|
`${prefix}${n.toLocaleString("en-US", {
|
||||||
|
minimumFractionDigits: decimals,
|
||||||
|
maximumFractionDigits: decimals,
|
||||||
|
})}${suffix}`;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const el = ref.current;
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
||||||
|
el.textContent = format(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj = { n: 0 };
|
||||||
|
el.textContent = format(0);
|
||||||
|
|
||||||
|
const ctx = gsap.context(() => {
|
||||||
|
gsap.to(obj, {
|
||||||
|
n: value,
|
||||||
|
duration: 2,
|
||||||
|
ease: "power2.out",
|
||||||
|
scrollTrigger: { trigger: el, start: "top 85%", once: true },
|
||||||
|
onUpdate: () => {
|
||||||
|
el.textContent = format(obj.n);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, el);
|
||||||
|
|
||||||
|
return () => ctx.revert();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [value, prefix, suffix, decimals]);
|
||||||
|
|
||||||
|
// Render full value at SSR/first paint; the effect resets to 0 then animates.
|
||||||
|
return (
|
||||||
|
<span ref={ref} className={className}>
|
||||||
|
{format(value)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
62
app/components/Faq.tsx
Normal file
62
app/components/Faq.tsx
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Faq — accessible accordion built on real <button> controls with
|
||||||
|
* aria-expanded / aria-controls and a CSS grid-rows reveal (no JS height math,
|
||||||
|
* animates cleanly, collapsible content stays in the DOM for SEO/AEO). The
|
||||||
|
* answer copy matches the FAQPage JSON-LD in layout.tsx verbatim.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import Reveal from "./Reveal";
|
||||||
|
import { faqs } from "../content";
|
||||||
|
|
||||||
|
export default function Faq() {
|
||||||
|
const [open, setOpen] = useState<number | null>(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="faq" className="faq" aria-label="Frequently asked questions">
|
||||||
|
<div className="wrap faq__inner">
|
||||||
|
<div className="faq__head">
|
||||||
|
<p className="kicker">FAQ</p>
|
||||||
|
<h2 className="section__title">
|
||||||
|
Questions about working with a digital marketing agency
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="faq__list">
|
||||||
|
{faqs.map((f, i) => {
|
||||||
|
const isOpen = open === i;
|
||||||
|
return (
|
||||||
|
<div className="faq__item" key={f.q} data-open={isOpen}>
|
||||||
|
<h3>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="faq__q hoverable"
|
||||||
|
aria-expanded={isOpen}
|
||||||
|
aria-controls={`faq-a-${i}`}
|
||||||
|
id={`faq-q-${i}`}
|
||||||
|
onClick={() => setOpen(isOpen ? null : i)}
|
||||||
|
>
|
||||||
|
{f.q}
|
||||||
|
<span className="faq__icon" aria-hidden="true" />
|
||||||
|
</button>
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
className="faq__a"
|
||||||
|
id={`faq-a-${i}`}
|
||||||
|
role="region"
|
||||||
|
aria-labelledby={`faq-q-${i}`}
|
||||||
|
>
|
||||||
|
<div className="faq__a-inner">
|
||||||
|
<p>{f.a}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,20 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hero — type IS the hero. A display headline at 8-14vw reveals line by line
|
||||||
|
* (manual masked split via KineticText), the iridescent wave asset floats as a
|
||||||
|
* tasteful accent layer, and a trust line anchors the claim. Parallax on the
|
||||||
|
* accent + headline as the hero scrolls out.
|
||||||
|
*/
|
||||||
|
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { gsap } from "gsap";
|
import { gsap } from "gsap";
|
||||||
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||||
import KineticText from "./KineticText";
|
import KineticText from "./KineticText";
|
||||||
import PillMark from "./PillMark";
|
|
||||||
import Magnetic from "./Magnetic";
|
import Magnetic from "./Magnetic";
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
export default function Hero() {
|
export default function Hero() {
|
||||||
const root = useRef<HTMLElement>(null);
|
const root = useRef<HTMLElement>(null);
|
||||||
|
|
||||||
|
|
@ -17,35 +26,22 @@ export default function Hero() {
|
||||||
const ctx = gsap.context(() => {
|
const ctx = gsap.context(() => {
|
||||||
const tl = gsap.timeline({ defaults: { ease: "power4.out" } });
|
const tl = gsap.timeline({ defaults: { ease: "power4.out" } });
|
||||||
tl.from(".hero__eyebrow", { y: 18, opacity: 0, duration: 0.9, delay: 0.15 })
|
tl.from(".hero__eyebrow", { y: 18, opacity: 0, duration: 0.9, delay: 0.15 })
|
||||||
|
.from(".hero__accent", { opacity: 0, scale: 1.06, duration: 1.4 }, 0)
|
||||||
.from(".hero__sub", { y: 22, opacity: 0, duration: 0.9 }, "-=0.2")
|
.from(".hero__sub", { y: 22, opacity: 0, duration: 0.9 }, "-=0.2")
|
||||||
.from(
|
.from(".hero__actions > *", { y: 20, opacity: 0, stagger: 0.1, duration: 0.7 }, "-=0.5")
|
||||||
".hero__actions > *",
|
.from(".hero__trust", { opacity: 0, duration: 0.8 }, "-=0.4");
|
||||||
{ y: 20, opacity: 0, stagger: 0.1, duration: 0.7 },
|
|
||||||
"-=0.5"
|
|
||||||
)
|
|
||||||
.from(".hero__meta", { opacity: 0, duration: 0.8 }, "-=0.4");
|
|
||||||
|
|
||||||
// parallax on the floating mark as you scroll the hero out
|
// parallax: accent drifts up, headline lifts + fades as hero scrolls out
|
||||||
gsap.to(".hero__mark", {
|
gsap.to(".hero__accent", {
|
||||||
yPercent: -22,
|
yPercent: -18,
|
||||||
ease: "none",
|
ease: "none",
|
||||||
scrollTrigger: {
|
scrollTrigger: { trigger: el, start: "top top", end: "bottom top", scrub: true },
|
||||||
trigger: el,
|
|
||||||
start: "top top",
|
|
||||||
end: "bottom top",
|
|
||||||
scrub: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
gsap.to(".hero__display", {
|
gsap.to(".hero__display", {
|
||||||
yPercent: 12,
|
yPercent: 14,
|
||||||
opacity: 0.25,
|
opacity: 0.18,
|
||||||
ease: "none",
|
ease: "none",
|
||||||
scrollTrigger: {
|
scrollTrigger: { trigger: el, start: "top top", end: "bottom top", scrub: true },
|
||||||
trigger: el,
|
|
||||||
start: "top top",
|
|
||||||
end: "bottom top",
|
|
||||||
scrub: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}, el);
|
}, el);
|
||||||
|
|
||||||
|
|
@ -54,68 +50,63 @@ export default function Hero() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="hero" ref={root}>
|
<section className="hero" ref={root}>
|
||||||
|
{/* iridescent wave accent — decorative texture layer */}
|
||||||
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||||
|
<img
|
||||||
|
src="/assets/hero-iridescent-1.png"
|
||||||
|
alt=""
|
||||||
|
aria-hidden="true"
|
||||||
|
className="hero__accent"
|
||||||
|
width={1344}
|
||||||
|
height={768}
|
||||||
|
fetchPriority="high"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="hero__inner wrap">
|
<div className="hero__inner wrap">
|
||||||
<p className="hero__eyebrow">
|
<p className="hero__eyebrow">
|
||||||
<span className="dot" aria-hidden="true" />
|
<span className="dot" aria-hidden="true" />
|
||||||
Agencia de marketing AI-native
|
Digital marketing agency
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h1 className="hero__display">
|
<h1 className="hero__display">
|
||||||
<KineticText as="span" className="hero__line" text="No alquilamos" immediate delay={0.25} />
|
<KineticText as="span" className="hero__line" text="Marketing that" immediate delay={0.25} />
|
||||||
<span className="hero__line hero__line--mixed">
|
<KineticText as="span" className="hero__line" text="grows your" immediate delay={0.38} />
|
||||||
<KineticText as="span" text="las" immediate delay={0.4} />
|
|
||||||
<em className="hero__serif"> herramientas.</em>
|
|
||||||
</span>
|
|
||||||
<KineticText
|
<KineticText
|
||||||
as="span"
|
as="span"
|
||||||
className="hero__line hero__line--grad"
|
className="hero__line hero__line--grad"
|
||||||
text="Construimos la máquina."
|
text="revenue."
|
||||||
immediate
|
immediate
|
||||||
delay={0.5}
|
delay={0.5}
|
||||||
highlight={[0, 2]}
|
highlight={[0, 0]}
|
||||||
/>
|
/>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div className="hero__mark" aria-hidden="true">
|
|
||||||
<PillMark animate breathe />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p className="hero__sub">
|
<p className="hero__sub">
|
||||||
Estrategia humana sobre <strong>nuestra propia plataforma de IA</strong>.
|
We're a results-driven digital marketing agency. We run paid, SEO,
|
||||||
Web, SEO, ads y contenido — más rápido, más medible y a mejor coste que
|
and content programs built around <strong>your revenue targets</strong>,
|
||||||
una agencia tradicional.
|
then show you what they returned. Every month.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="hero__actions">
|
<div className="hero__actions">
|
||||||
<Magnetic strength={0.5}>
|
<Magnetic strength={0.5}>
|
||||||
<a className="btn btn--primary hoverable" href="#contacto">
|
<a className="btn btn--primary hoverable" href="#contact" data-cursor="let's talk">
|
||||||
<span>Habla con nosotros</span>
|
<span>Get your growth audit</span>
|
||||||
</a>
|
|
||||||
</Magnetic>
|
|
||||||
<Magnetic strength={0.3}>
|
|
||||||
<a className="btn btn--ghost hoverable" href="#servicios">
|
|
||||||
<span>Ver qué hacemos</span>
|
|
||||||
</a>
|
</a>
|
||||||
</Magnetic>
|
</Magnetic>
|
||||||
|
<a className="hero__secondary hoverable" href="#results">
|
||||||
|
See the results <span aria-hidden="true">→</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<dl className="hero__meta">
|
<p className="hero__trust">
|
||||||
<div>
|
<strong>$40M+</strong> in client revenue generated
|
||||||
<dt>Entrega</dt>
|
<span className="hero__trust-sep" aria-hidden="true" />
|
||||||
<dd>en días, no semanas</dd>
|
<strong>50+</strong> brands grown
|
||||||
</div>
|
</p>
|
||||||
<div>
|
|
||||||
<dt>Reporting</dt>
|
|
||||||
<dd>cada acción medida</dd>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<dt>Infraestructura</dt>
|
|
||||||
<dd>propia, no alquilada</dd>
|
|
||||||
</div>
|
|
||||||
</dl>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a className="hero__scroll hoverable" href="#ventaja" aria-label="Bajar a la siguiente sección">
|
<a className="hero__scroll hoverable" href="#position" aria-label="Scroll to the next section">
|
||||||
<span>scroll</span>
|
<span>scroll</span>
|
||||||
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
|
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
|
||||||
<path d="M12 4v16m0 0l-6-6m6 6l6-6" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M12 4v16m0 0l-6-6m6 6l6-6" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,12 @@
|
||||||
/**
|
/**
|
||||||
* Iridescence — generative WebGL backdrop.
|
* Iridescence — generative WebGL backdrop.
|
||||||
*
|
*
|
||||||
* A living interpretation of the brand cloudscape: domain-warped fractal noise
|
* A living interpretation of the brand wave: domain-warped fractal noise mapped
|
||||||
* mapped onto an iridescent pastel palette (lavender -> blue -> rose -> mint),
|
* onto the brand spectrum (violet -> blue -> rose -> emerald) glowing out of a
|
||||||
* with a faint rainbow refraction band and animated film grain. Drifts on its
|
* near-black field, with a faint rainbow refraction band and animated film
|
||||||
* own and leans toward the cursor. Falls back to a static CSS gradient when
|
* grain. Drifts on its own and leans toward the cursor. Falls back to a static
|
||||||
* WebGL is unavailable or the user prefers reduced motion.
|
* dark CSS gradient when WebGL is unavailable or the user prefers reduced
|
||||||
|
* motion.
|
||||||
*
|
*
|
||||||
* Renders behind everything (fixed, -z) and is purely decorative (aria-hidden).
|
* Renders behind everything (fixed, -z) and is purely decorative (aria-hidden).
|
||||||
*/
|
*/
|
||||||
|
|
@ -34,8 +35,8 @@ const FRAG = /* glsl */ `
|
||||||
const vec3 VIOLET = vec3(0.545, 0.361, 0.965); // #8b5cf6
|
const vec3 VIOLET = vec3(0.545, 0.361, 0.965); // #8b5cf6
|
||||||
const vec3 BLUE = vec3(0.231, 0.510, 0.965); // #3b82f6
|
const vec3 BLUE = vec3(0.231, 0.510, 0.965); // #3b82f6
|
||||||
const vec3 ROSE = vec3(0.957, 0.475, 0.851); // soft pink
|
const vec3 ROSE = vec3(0.957, 0.475, 0.851); // soft pink
|
||||||
const vec3 MINT = vec3(0.063, 0.725, 0.506); // #10b981 softened
|
const vec3 MINT = vec3(0.204, 0.827, 0.600); // #34d399 emerald
|
||||||
const vec3 HAZE = vec3(0.945, 0.949, 0.992); // near-white lavender
|
const vec3 BASE = vec3(0.031, 0.031, 0.047); // near-black #08080c
|
||||||
|
|
||||||
// -- hash / value noise --------------------------------------------------
|
// -- hash / value noise --------------------------------------------------
|
||||||
vec2 hash22(vec2 p) {
|
vec2 hash22(vec2 p) {
|
||||||
|
|
@ -91,34 +92,34 @@ const FRAG = /* glsl */ `
|
||||||
);
|
);
|
||||||
float f = fbm(p + 2.0 * r);
|
float f = fbm(p + 2.0 * r);
|
||||||
|
|
||||||
// build the iridescent gradient from the field
|
// the brand spectrum, glowing ADDITIVELY out of a near-black base
|
||||||
vec3 col = HAZE;
|
vec3 glow = vec3(0.0);
|
||||||
col = mix(col, VIOLET, smoothstep(0.15, 0.85, f));
|
glow += VIOLET * smoothstep(0.35, 0.95, f);
|
||||||
col = mix(col, BLUE, smoothstep(0.30, 0.95, r.x));
|
glow += BLUE * smoothstep(0.45, 1.0, r.x) * 0.9;
|
||||||
col = mix(col, ROSE, smoothstep(0.55, 1.05, q.y) * 0.65);
|
glow += ROSE * smoothstep(0.62, 1.05, q.y) * 0.5;
|
||||||
col = mix(col, MINT, smoothstep(0.62, 1.0, r.y) * 0.30);
|
glow += MINT * smoothstep(0.66, 1.0, r.y) * 0.55;
|
||||||
|
|
||||||
// central radiant bloom (echoes the cloudscape light source up high)
|
// concentrate the light into a soft diagonal wave band (echoes the asset)
|
||||||
vec2 center = vec2(0.5 * aspect, 0.86);
|
float band = smoothstep(0.62, 0.0, abs((uv.x - uv.y) * 1.25 - 0.05 + 0.06 * sin(t * 2.0)));
|
||||||
float d = distance(p, center);
|
float field = smoothstep(0.2, 0.85, f);
|
||||||
float bloom = smoothstep(0.9, 0.0, d);
|
float energy = (0.35 + 0.65 * band) * field;
|
||||||
col = mix(col, HAZE, bloom * 0.55);
|
|
||||||
|
|
||||||
// faint rainbow refraction band, lower-left like the asset
|
vec3 col = BASE + glow * energy * (0.55 + 0.45 * uIntensity);
|
||||||
float band = smoothstep(0.5, 0.0, abs((uv.x - uv.y) * 1.3 - 0.15 + 0.05 * sin(t * 2.0)));
|
|
||||||
|
// faint rainbow refraction along the band
|
||||||
vec3 spectrum = 0.5 + 0.5 * cos(6.2831 * (vec3(0.0, 0.33, 0.67) + (uv.x + uv.y) * 0.7));
|
vec3 spectrum = 0.5 + 0.5 * cos(6.2831 * (vec3(0.0, 0.33, 0.67) + (uv.x + uv.y) * 0.7));
|
||||||
col += spectrum * band * 0.06 * (0.4 + uIntensity);
|
col += spectrum * band * 0.05 * (0.4 + uIntensity);
|
||||||
|
|
||||||
// lift overall to keep it airy / pastel and protect text legibility
|
// darken edges so content stays the focus
|
||||||
col = mix(col, vec3(1.0), 0.18);
|
float vig = smoothstep(1.3, 0.2, distance(uv, vec2(0.5)));
|
||||||
|
col *= 0.55 + 0.45 * vig;
|
||||||
|
|
||||||
// soft vignette to anchor content readability
|
// keep the base from washing out; clamp the glow softly
|
||||||
float vig = smoothstep(1.25, 0.25, distance(uv, vec2(0.5)));
|
col = max(col, BASE * 0.6);
|
||||||
col *= 0.82 + 0.18 * vig;
|
|
||||||
|
|
||||||
// animated grain to kill banding + add texture
|
// animated grain to kill banding + add texture
|
||||||
float g = grain(uv, floor(uTime * 12.0) * 0.5);
|
float g = grain(uv, floor(uTime * 12.0) * 0.5);
|
||||||
col += (g - 0.5) * 0.035;
|
col += (g - 0.5) * 0.03;
|
||||||
|
|
||||||
gl_FragColor = vec4(col, 1.0);
|
gl_FragColor = vec4(col, 1.0);
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +149,7 @@ export default function Iridescence() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const gl = renderer.gl;
|
const gl = renderer.gl;
|
||||||
gl.clearColor(0.95, 0.95, 0.99, 1);
|
gl.clearColor(0.031, 0.031, 0.047, 1);
|
||||||
|
|
||||||
const uniforms = {
|
const uniforms = {
|
||||||
uTime: { value: 0 },
|
uTime: { value: 0 },
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marquee — seamless looping band of disciplines, separated by the brand pill
|
* ProofBar — "trusted by" band. A labelled, seamless looping marquee of the
|
||||||
* glyph. Pure CSS animation (transform only); pauses under reduced-motion via
|
* industries we grow, separated by the brand pill glyph. Pure CSS transform
|
||||||
* the stylesheet. Decorative.
|
* animation; pauses under reduced-motion via the stylesheet. Decorative track,
|
||||||
|
* but the label and items are real text. (Swap industry labels for greyscale
|
||||||
|
* client logos before launch.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
"Web & Desarrollo",
|
"E-commerce",
|
||||||
"SEO & GEO",
|
"B2B SaaS",
|
||||||
"Paid Ads",
|
"Clinics",
|
||||||
"Contenido",
|
"Professional services",
|
||||||
"Diseño & Marca",
|
"Retail",
|
||||||
"Automatización",
|
"Hospitality",
|
||||||
];
|
];
|
||||||
|
|
||||||
function Row() {
|
function Row() {
|
||||||
|
|
@ -30,11 +32,16 @@ function Row() {
|
||||||
|
|
||||||
export default function Marquee() {
|
export default function Marquee() {
|
||||||
return (
|
return (
|
||||||
<div className="marquee" aria-hidden="true">
|
<section className="proof" aria-label="Industries we work with">
|
||||||
<div className="marquee__track">
|
<p className="proof__label">
|
||||||
<Row />
|
Trusted by teams that care about the sales number
|
||||||
<Row />
|
</p>
|
||||||
|
<div className="marquee">
|
||||||
|
<div className="marquee__track">
|
||||||
|
<Row />
|
||||||
|
<Row />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
44
app/components/Metrics.tsx
Normal file
44
app/components/Metrics.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metrics — four headline results with animated count-up on scroll-in.
|
||||||
|
* The ROAS metric is the single emerald-accented "signature" number.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Reveal from "./Reveal";
|
||||||
|
import CountUp from "./CountUp";
|
||||||
|
import { metrics } from "../content";
|
||||||
|
|
||||||
|
export default function Metrics() {
|
||||||
|
return (
|
||||||
|
<section id="results" className="metrics" aria-label="Results">
|
||||||
|
<div className="wrap">
|
||||||
|
<Reveal>
|
||||||
|
<p className="kicker">The numbers</p>
|
||||||
|
<h2 className="section__title">Results we can show you.</h2>
|
||||||
|
</Reveal>
|
||||||
|
|
||||||
|
<div className="metrics__inner">
|
||||||
|
<Reveal className="metrics__grid" stagger={0.1}>
|
||||||
|
{metrics.map((m) => (
|
||||||
|
<div
|
||||||
|
className={`metric${"accent" in m && m.accent ? " metric--accent" : ""}`}
|
||||||
|
key={m.label}
|
||||||
|
>
|
||||||
|
<p className="metric__num">
|
||||||
|
<CountUp
|
||||||
|
value={m.value}
|
||||||
|
prefix={"prefix" in m ? m.prefix : ""}
|
||||||
|
suffix={m.suffix}
|
||||||
|
decimals={"decimals" in m ? m.decimals : 0}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p className="metric__label">{m.label}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Reveal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Packages — four tiers, each named for an outcome rather than a task list.
|
|
||||||
* "Motor" is the featured tier (lifted, gradient spine). Cards reveal on scroll
|
|
||||||
* and the featured one carries a continuously-shifting gradient border.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Reveal from "./Reveal";
|
|
||||||
|
|
||||||
type Pkg = {
|
|
||||||
n: string;
|
|
||||||
who: string;
|
|
||||||
price: string;
|
|
||||||
f: string[];
|
|
||||||
featured?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const packages: Pkg[] = [
|
|
||||||
{
|
|
||||||
n: "Sitio AI-native",
|
|
||||||
who: "Necesitas web, ya",
|
|
||||||
price: "Proyecto",
|
|
||||||
f: ["Web en código, editable", "SEO base + tracking", "Entregada en tiempo récord"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: "Base",
|
|
||||||
who: "Estás arrancando",
|
|
||||||
price: "Mensual",
|
|
||||||
f: ["Fundamentos SEO", "Contenido inicial", "Analítica conectada"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: "Motor",
|
|
||||||
who: "Quieres crecer en serio",
|
|
||||||
price: "Mensual",
|
|
||||||
f: ["Ads + SEO + contenido", "Dashboard de resultados", "Optimización mensual", "Plataforma de IA incluida"],
|
|
||||||
featured: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: "Partner",
|
|
||||||
who: "Quieres escalar",
|
|
||||||
price: "Retainer",
|
|
||||||
f: ["Full-stack de crecimiento", "Automatización a medida", "Prioridad y roadmap", "Acceso directo al equipo"],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Packages() {
|
|
||||||
return (
|
|
||||||
<section id="paquetes" className="packages">
|
|
||||||
<div className="wrap">
|
|
||||||
<Reveal>
|
|
||||||
<p className="kicker">04 — Paquetes</p>
|
|
||||||
<h2 className="packages__title">
|
|
||||||
Cada uno con un resultado. <span className="serif-em">No listas de tareas.</span>
|
|
||||||
</h2>
|
|
||||||
</Reveal>
|
|
||||||
|
|
||||||
<Reveal className="packages__grid" stagger={0.1}>
|
|
||||||
{packages.map((p) => (
|
|
||||||
<article
|
|
||||||
className={`pkg hoverable${p.featured ? " pkg--featured" : ""}`}
|
|
||||||
key={p.n}
|
|
||||||
data-cursor={p.featured ? "el más elegido" : "ver"}
|
|
||||||
>
|
|
||||||
{p.featured && <span className="pkg__tag">Más elegido</span>}
|
|
||||||
<header className="pkg__head">
|
|
||||||
<span className="pkg__price">{p.price}</span>
|
|
||||||
<h3 className="pkg__name">{p.n}</h3>
|
|
||||||
<p className="pkg__who">{p.who}</p>
|
|
||||||
</header>
|
|
||||||
<ul className="pkg__features">
|
|
||||||
{p.f.map((x) => (
|
|
||||||
<li key={x}>
|
|
||||||
<svg viewBox="0 0 20 20" width="18" height="18" aria-hidden="true">
|
|
||||||
<path
|
|
||||||
d="M4 10.5l3.5 3.5L16 6"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth="2"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>{x}</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<a className="pkg__cta hoverable" href="#contacto">
|
|
||||||
Empezar con {p.n}
|
|
||||||
<span aria-hidden="true">→</span>
|
|
||||||
</a>
|
|
||||||
</article>
|
|
||||||
))}
|
|
||||||
</Reveal>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
81
app/components/Process.tsx
Normal file
81
app/components/Process.tsx
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process — "The Feedback Loop". The intro column pins (sticky) while the four
|
||||||
|
* steps scroll past; each step lights up as it reaches the viewport center, and
|
||||||
|
* a serif count in the sticky column advances with it. This is the
|
||||||
|
* scrollytelling beat. Degrades to a plain stacked list under reduced-motion
|
||||||
|
* (all steps shown active, no pin behaviour) and on narrow screens.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { gsap } from "gsap";
|
||||||
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||||
|
import { processSteps } from "../content";
|
||||||
|
|
||||||
|
gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
|
export default function Process() {
|
||||||
|
const root = useRef<HTMLElement>(null);
|
||||||
|
const [active, setActive] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const el = root.current;
|
||||||
|
if (!el) return;
|
||||||
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
||||||
|
setActive(processSteps.length - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = gsap.context(() => {
|
||||||
|
gsap.utils.toArray<HTMLElement>(".pstep").forEach((step, i) => {
|
||||||
|
ScrollTrigger.create({
|
||||||
|
trigger: step,
|
||||||
|
start: "top 60%",
|
||||||
|
end: "bottom 60%",
|
||||||
|
onToggle: (self) => {
|
||||||
|
if (self.isActive) setActive(i);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, el);
|
||||||
|
|
||||||
|
return () => ctx.revert();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section id="process" className="process" ref={root} aria-label="How it works">
|
||||||
|
<div className="wrap process__inner">
|
||||||
|
<div className="process__sticky">
|
||||||
|
<p className="kicker">How it works</p>
|
||||||
|
<h2 className="section__title">
|
||||||
|
The <span className="serif-em">Feedback Loop.</span>
|
||||||
|
</h2>
|
||||||
|
<p
|
||||||
|
className="process__count"
|
||||||
|
aria-hidden="true"
|
||||||
|
key={active}
|
||||||
|
>
|
||||||
|
0{active + 1}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ol className="process__steps">
|
||||||
|
{processSteps.map((p, i) => (
|
||||||
|
<li
|
||||||
|
className={`pstep${i <= active ? " is-active" : ""}`}
|
||||||
|
key={p.n}
|
||||||
|
aria-current={i === active ? "step" : undefined}
|
||||||
|
>
|
||||||
|
<div className="pstep__top">
|
||||||
|
<span className="pstep__n">{p.n}</span>
|
||||||
|
<h3 className="pstep__name">{p.name}</h3>
|
||||||
|
</div>
|
||||||
|
<p className="pstep__desc">{p.desc}</p>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
37
app/components/Services.tsx
Normal file
37
app/components/Services.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Services — deliberately broken editorial grid. Six services on a 6-column
|
||||||
|
* grid; the first two cards span 3 (breaking the safe 2-col-per-card rhythm),
|
||||||
|
* the rest span 2. Serif index numerals, spectrum top-line on hover.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Reveal from "./Reveal";
|
||||||
|
import { services } from "../content";
|
||||||
|
|
||||||
|
export default function Services() {
|
||||||
|
return (
|
||||||
|
<section id="services" className="services" aria-label="Services">
|
||||||
|
<div className="wrap">
|
||||||
|
<Reveal>
|
||||||
|
<p className="kicker">What we do</p>
|
||||||
|
<h2 className="section__title">How we grow your business.</h2>
|
||||||
|
</Reveal>
|
||||||
|
|
||||||
|
<Reveal className="services__grid" stagger={0.08}>
|
||||||
|
{services.map((s, i) => (
|
||||||
|
<article
|
||||||
|
className={`service hoverable${i < 2 ? " service--wide" : ""}`}
|
||||||
|
key={s.id}
|
||||||
|
data-cursor="more"
|
||||||
|
>
|
||||||
|
<span className="service__index">0{i + 1}</span>
|
||||||
|
<h3 className="service__name">{s.name}</h3>
|
||||||
|
<p className="service__desc">{s.desc}</p>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
</Reveal>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,163 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ServicesJourney — pinned horizontal-scroll track of services.
|
|
||||||
*
|
|
||||||
* On desktop the section pins and the panels scroll sideways as you scroll
|
|
||||||
* down (GSAP ScrollTrigger pin + scrub), with a progress bar. On mobile / when
|
|
||||||
* the pin would be awkward, and under reduced-motion, it degrades to a normal
|
|
||||||
* vertical stack (no pin, panels just stack and reveal). Each panel is a real
|
|
||||||
* <article> so the content is accessible regardless of layout.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { useEffect, useRef } from "react";
|
|
||||||
import { gsap } from "gsap";
|
|
||||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
||||||
|
|
||||||
gsap.registerPlugin(ScrollTrigger);
|
|
||||||
|
|
||||||
const services = [
|
|
||||||
{
|
|
||||||
n: "01",
|
|
||||||
t: "Web & Desarrollo",
|
|
||||||
d: "Sitios construidos en código, veloces y 100% editables. Sin plantillas, sin atajos: arquitectura que escala contigo.",
|
|
||||||
tags: ["Next.js", "Headless", "Core Web Vitals"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: "02",
|
|
||||||
t: "SEO & GEO",
|
|
||||||
d: "Posicionamiento técnico y de contenido — para Google y para los motores de IA. Reporting real, no humo.",
|
|
||||||
tags: ["Técnico", "Contenido", "Answer Engines"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: "03",
|
|
||||||
t: "Paid Ads",
|
|
||||||
d: "Google, Meta, TikTok y LinkedIn. Creatividad asistida por IA y pujas optimizadas hacia el resultado, no el clic.",
|
|
||||||
tags: ["Performance", "Creatividad IA", "Atribución"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: "04",
|
|
||||||
t: "Contenido",
|
|
||||||
d: "Piezas pensadas para rankear y para convertir. Producción a escala sin perder la voz de tu marca.",
|
|
||||||
tags: ["Editorial", "Vídeo", "Social"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: "05",
|
|
||||||
t: "Diseño & Marca",
|
|
||||||
d: "Identidad y dirección de arte con criterio. Sistemas de diseño que viven en producto, no en un PDF.",
|
|
||||||
tags: ["Identidad", "Design System", "Motion"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
n: "06",
|
|
||||||
t: "Automatización",
|
|
||||||
d: "Flujos que devuelven horas: captación de leads, reporting automático y operativa conectada de punta a punta.",
|
|
||||||
tags: ["Leads", "Reporting", "Ops"],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function ServicesJourney() {
|
|
||||||
const section = useRef<HTMLElement>(null);
|
|
||||||
const track = useRef<HTMLDivElement>(null);
|
|
||||||
const bar = useRef<HTMLSpanElement>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const sec = section.current;
|
|
||||||
const trk = track.current;
|
|
||||||
if (!sec || !trk) return;
|
|
||||||
|
|
||||||
const mm = gsap.matchMedia();
|
|
||||||
|
|
||||||
// Desktop with motion allowed: pin + horizontal scroll.
|
|
||||||
mm.add(
|
|
||||||
"(min-width: 900px) and (prefers-reduced-motion: no-preference)",
|
|
||||||
() => {
|
|
||||||
const distance = () => trk.scrollWidth - window.innerWidth;
|
|
||||||
|
|
||||||
const tween = gsap.to(trk, {
|
|
||||||
x: () => -distance(),
|
|
||||||
ease: "none",
|
|
||||||
scrollTrigger: {
|
|
||||||
trigger: sec,
|
|
||||||
start: "top top",
|
|
||||||
end: () => "+=" + distance(),
|
|
||||||
scrub: 0.6,
|
|
||||||
pin: true,
|
|
||||||
invalidateOnRefresh: true,
|
|
||||||
onUpdate: (self) => {
|
|
||||||
if (bar.current) {
|
|
||||||
bar.current.style.transform = `scaleX(${self.progress})`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Per-panel inner reveal as it slides into center.
|
|
||||||
gsap.utils.toArray<HTMLElement>(".sjourney__panel").forEach((panel) => {
|
|
||||||
gsap.from(panel.querySelectorAll(".sjourney__reveal"), {
|
|
||||||
y: 40,
|
|
||||||
opacity: 0,
|
|
||||||
duration: 0.6,
|
|
||||||
stagger: 0.06,
|
|
||||||
ease: "power3.out",
|
|
||||||
scrollTrigger: {
|
|
||||||
trigger: panel,
|
|
||||||
containerAnimation: tween,
|
|
||||||
start: "left 80%",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (bar.current) bar.current.style.transform = "scaleX(0)";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Mobile / reduced-motion: simple stacked reveals.
|
|
||||||
mm.add("(max-width: 899px)", () => {
|
|
||||||
gsap.utils.toArray<HTMLElement>(".sjourney__panel").forEach((panel) => {
|
|
||||||
gsap.from(panel, {
|
|
||||||
y: 36,
|
|
||||||
opacity: 0,
|
|
||||||
duration: 0.7,
|
|
||||||
ease: "power3.out",
|
|
||||||
scrollTrigger: { trigger: panel, start: "top 88%" },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => mm.revert();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section id="servicios" className="sjourney" ref={section} aria-label="Servicios">
|
|
||||||
<div className="sjourney__head wrap">
|
|
||||||
<p className="kicker">02 — Qué hacemos</p>
|
|
||||||
<h2 className="sjourney__title">
|
|
||||||
Todo tu crecimiento, <span className="serif-em">un mismo sistema.</span>
|
|
||||||
</h2>
|
|
||||||
<div className="sjourney__progress" aria-hidden="true">
|
|
||||||
<span ref={bar} className="sjourney__progress-bar" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="sjourney__viewport">
|
|
||||||
<div className="sjourney__track" ref={track}>
|
|
||||||
{services.map((s) => (
|
|
||||||
<article className="sjourney__panel hoverable" key={s.t} data-cursor="explorar">
|
|
||||||
<span className="sjourney__n sjourney__reveal">{s.n}</span>
|
|
||||||
<h3 className="sjourney__panel-title sjourney__reveal">{s.t}</h3>
|
|
||||||
<p className="sjourney__panel-desc sjourney__reveal">{s.d}</p>
|
|
||||||
<ul className="sjourney__tags sjourney__reveal">
|
|
||||||
{s.tags.map((tag) => (
|
|
||||||
<li key={tag}>{tag}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<span className="sjourney__pill" aria-hidden="true" />
|
|
||||||
</article>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -10,10 +10,10 @@ import { useEffect, useRef, useState } from "react";
|
||||||
import PillMark from "./PillMark";
|
import PillMark from "./PillMark";
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
{ href: "#ventaja", label: "Ventaja" },
|
{ href: "#services", label: "Services" },
|
||||||
{ href: "#servicios", label: "Servicios" },
|
{ href: "#work", label: "Work" },
|
||||||
{ href: "#sectores", label: "Sectores" },
|
{ href: "#process", label: "About" },
|
||||||
{ href: "#paquetes", label: "Paquetes" },
|
{ href: "#faq", label: "FAQ" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function SiteHeader() {
|
export default function SiteHeader() {
|
||||||
|
|
@ -44,14 +44,14 @@ export default function SiteHeader() {
|
||||||
className={`site-header${scrolled ? " is-scrolled" : ""}${open ? " is-open" : ""}`}
|
className={`site-header${scrolled ? " is-scrolled" : ""}${open ? " is-open" : ""}`}
|
||||||
>
|
>
|
||||||
<div className="site-header__inner">
|
<div className="site-header__inner">
|
||||||
<a className="brand hoverable" href="#top" aria-label="Feedback Studios, inicio">
|
<a className="brand hoverable" href="#top" aria-label="Feedback Studios, home">
|
||||||
<PillMark className="brand__mark" title="Feedback Studios" />
|
<PillMark className="brand__mark" title="Feedback Studios" />
|
||||||
<span className="brand__word">
|
<span className="brand__word">
|
||||||
feedback<span className="brand__word-2">studios</span>
|
feedback<span className="brand__word-2">studios</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<nav className="site-nav" aria-label="Principal">
|
<nav className="site-nav" aria-label="Primary">
|
||||||
<ul>
|
<ul>
|
||||||
{links.map((l) => (
|
{links.map((l) => (
|
||||||
<li key={l.href}>
|
<li key={l.href}>
|
||||||
|
|
@ -61,8 +61,8 @@ export default function SiteHeader() {
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<a className="btn btn--sm btn--primary hoverable" href="#contacto" onClick={() => setOpen(false)}>
|
<a className="btn btn--sm btn--primary hoverable" href="#contact" onClick={() => setOpen(false)}>
|
||||||
<span>Hablemos</span>
|
<span>Get a growth audit</span>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ export default function SiteHeader() {
|
||||||
type="button"
|
type="button"
|
||||||
className="site-header__toggle hoverable"
|
className="site-header__toggle hoverable"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
aria-label={open ? "Cerrar menú" : "Abrir menú"}
|
aria-label={open ? "Close menu" : "Open menu"}
|
||||||
onClick={() => setOpen((v) => !v)}
|
onClick={() => setOpen((v) => !v)}
|
||||||
>
|
>
|
||||||
<span />
|
<span />
|
||||||
|
|
|
||||||
137
app/content.ts
Normal file
137
app/content.ts
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
/**
|
||||||
|
* Single source of truth for on-page copy + structured data.
|
||||||
|
* Mirrors content/home-content.md (EN, revenue-focused marketing).
|
||||||
|
* NOTE: metrics, cases and testimonials are illustrative SAMPLES for the
|
||||||
|
* prototype — swap for real, verifiable data before launch.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const SITE = {
|
||||||
|
name: "Feedback Studios",
|
||||||
|
url: "https://studiosfeedback.com",
|
||||||
|
tagline: "Marketing that grows your revenue.",
|
||||||
|
email: "hello@feedbackstudios.com",
|
||||||
|
contactEmail: "feedback.studios.design@gmail.com",
|
||||||
|
booking: "https://cal.feedback-studios.com",
|
||||||
|
description:
|
||||||
|
"Most agencies sell activity. Feedback Studios builds paid, SEO and content programs around one number: your revenue. And we report on it every month.",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const services = [
|
||||||
|
{
|
||||||
|
id: "seo",
|
||||||
|
name: "SEO that compounds",
|
||||||
|
desc: "Rank for the searches your buyers make, and keep ranking long after the invoice clears.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "paid",
|
||||||
|
name: "Paid ads that pay back",
|
||||||
|
desc: "Google, Meta, TikTok, and LinkedIn, managed to ROAS and pipeline. Not vanity clicks.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "content",
|
||||||
|
name: "Content that converts",
|
||||||
|
desc: "Articles, landing pages, and assets that pull in qualified traffic and turn it into customers.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "social",
|
||||||
|
name: "Social that builds demand",
|
||||||
|
desc: "Feeds and creative that make people remember you before they're ready to buy.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "web",
|
||||||
|
name: "Web & landing pages",
|
||||||
|
desc: "Fast, on-brand pages built for one job: conversion.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "creative",
|
||||||
|
name: "Creative & brand",
|
||||||
|
desc: "Scroll-stopping creative that still sells.",
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const metrics = [
|
||||||
|
{ value: 40, prefix: "$", suffix: "M+", label: "client revenue generated" },
|
||||||
|
{ value: 3.8, suffix: "×", decimals: 1, label: "average return on ad spend", accent: true },
|
||||||
|
{ value: 183, prefix: "+", suffix: "%", label: "average organic traffic in 6 months" },
|
||||||
|
{ value: 92, suffix: "%", label: "client retention" },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const cases = [
|
||||||
|
{
|
||||||
|
img: "/assets/case-1.png",
|
||||||
|
alt: "Glossy 3D capsule cluster in brand violet, blue and emerald, representing the e-commerce fashion case study",
|
||||||
|
tag: "E-commerce · Fashion",
|
||||||
|
problem: "Rising ad costs were eating the margin.",
|
||||||
|
result: "−34% CPA and +52% ROAS in 90 days",
|
||||||
|
how: "Meta + Google Shopping restructure.",
|
||||||
|
metricNum: "+52%",
|
||||||
|
metricLabel: "ROAS in 90 days",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: "/assets/case-2.png",
|
||||||
|
alt: "Suspended glossy capsules in brand colors, representing the B2B SaaS case study",
|
||||||
|
tag: "B2B SaaS",
|
||||||
|
problem: "Plenty of traffic, no pipeline.",
|
||||||
|
result: "+217% qualified demo requests in 6 months",
|
||||||
|
how: "SEO + content + LinkedIn.",
|
||||||
|
metricNum: "+217%",
|
||||||
|
metricLabel: "demo requests",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: "/assets/case-3.png",
|
||||||
|
alt: "Cascade of glossy capsules in brand colors, representing the aesthetic clinic case study",
|
||||||
|
tag: "Aesthetic clinic",
|
||||||
|
problem: "Empty calendar despite the ad spend.",
|
||||||
|
result: "+128 booked consultations a month",
|
||||||
|
how: "Paid + landing-page rebuild.",
|
||||||
|
metricNum: "+128",
|
||||||
|
metricLabel: "consultations / month",
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const processSteps = [
|
||||||
|
{ n: "01", name: "Audit", desc: "We find where your revenue is leaking." },
|
||||||
|
{ n: "02", name: "Plan", desc: "A channel mix and targets tied to your numbers, not guesswork." },
|
||||||
|
{ n: "03", name: "Execute", desc: "We build, launch, and optimize. Fast." },
|
||||||
|
{ n: "04", name: "Report", desc: "Every month: marketing tied straight to pipeline and sales." },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const testimonials = [
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
"We were spending $20k a month on ads with nothing to show. Six months later, marketing is our most predictable growth channel.",
|
||||||
|
by: "Name, Role, Company",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quote:
|
||||||
|
"They talk in revenue, not impressions. First agency that moved our pipeline.",
|
||||||
|
by: "Name, Role, Company",
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const faqs = [
|
||||||
|
{
|
||||||
|
q: "What does a digital marketing agency do?",
|
||||||
|
a: "A digital marketing agency plans and runs campaigns across search, paid media, social, and content to grow a business. Feedback Studios focuses on revenue, not vanity metrics, and puts your budget into the channels that convert.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "How much does a digital marketing agency cost?",
|
||||||
|
a: "Most retainers run from about $2,000 to $20,000+ a month, depending on scope, channels, and competition. Feedback Studios scopes the work to your growth goals, and we also offer one-time audits and project work if a full retainer isn't the right fit yet.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "How long until I see results?",
|
||||||
|
a: "Paid campaigns can bring in leads within 2 to 4 weeks. SEO and content usually show real organic growth in 3 to 6 months. We set clear 30, 60, and 90-day milestones so you always know what to expect, and when.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "What makes Feedback Studios different?",
|
||||||
|
a: "We measure success by revenue, not impressions or followers. Every campaign is built around your bottom line, with monthly reporting that ties what we do straight to pipeline and sales. If it doesn't grow the business, we stop doing it.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "Which businesses do you work with?",
|
||||||
|
a: "We work with e-commerce brands, B2B SaaS, clinics, and professional-service firms that want to grow revenue through digital channels. Clients range from scaling startups to established companies that have outgrown their current marketing.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
q: "What should I look for in a marketing agency?",
|
||||||
|
a: "Look for transparent reporting, real case studies with hard numbers, a clear process for your channels, and a team that talks in revenue, not reach. Ask to see work in your industry before you sign anything.",
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
1348
app/globals.css
1348
app/globals.css
File diff suppressed because it is too large
Load diff
|
|
@ -2,12 +2,14 @@ import type { Metadata } from "next";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import SmoothScroll from "./components/SmoothScroll";
|
import SmoothScroll from "./components/SmoothScroll";
|
||||||
import Cursor from "./components/Cursor";
|
import Cursor from "./components/Cursor";
|
||||||
|
import { SITE, services, faqs } from "./content";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Feedback Studios — La agencia de marketing AI-native",
|
title: "Results-driven digital marketing agency | Feedback Studios",
|
||||||
description:
|
description: SITE.description,
|
||||||
"Estrategia humana, ejecución sobre nuestra propia plataforma de IA. Web, SEO, ads y contenido: más rápido, más medible y a mejor coste.",
|
|
||||||
// Test environment — keep everything out of search engines.
|
// Test environment — keep everything out of search engines.
|
||||||
|
// Remove these robots directives (here + app/robots.ts + next.config.mjs
|
||||||
|
// X-Robots-Tag header) to flip the site to index when it goes live.
|
||||||
robots: {
|
robots: {
|
||||||
index: false,
|
index: false,
|
||||||
follow: false,
|
follow: false,
|
||||||
|
|
@ -16,15 +18,81 @@ export const metadata: Metadata = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* JSON-LD: Organization + WebSite (+SearchAction) + Service (per core
|
||||||
|
service) + FAQPage. Structure is launch-ready; the page stays noindex
|
||||||
|
in this test env via the robots directives above. */
|
||||||
|
function StructuredData() {
|
||||||
|
const graph = [
|
||||||
|
{
|
||||||
|
"@type": "Organization",
|
||||||
|
"@id": `${SITE.url}/#organization`,
|
||||||
|
name: SITE.name,
|
||||||
|
url: SITE.url,
|
||||||
|
description: SITE.description,
|
||||||
|
email: SITE.email,
|
||||||
|
slogan: SITE.tagline,
|
||||||
|
knowsAbout: [
|
||||||
|
"digital marketing",
|
||||||
|
"search engine optimization",
|
||||||
|
"paid advertising",
|
||||||
|
"content marketing",
|
||||||
|
"social media marketing",
|
||||||
|
"conversion rate optimization",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@type": "WebSite",
|
||||||
|
"@id": `${SITE.url}/#website`,
|
||||||
|
url: SITE.url,
|
||||||
|
name: SITE.name,
|
||||||
|
publisher: { "@id": `${SITE.url}/#organization` },
|
||||||
|
potentialAction: {
|
||||||
|
"@type": "SearchAction",
|
||||||
|
target: {
|
||||||
|
"@type": "EntryPoint",
|
||||||
|
urlTemplate: `${SITE.url}/?s={search_term_string}`,
|
||||||
|
},
|
||||||
|
"query-input": "required name=search_term_string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...services.map((s) => ({
|
||||||
|
"@type": "Service",
|
||||||
|
name: s.name,
|
||||||
|
description: s.desc,
|
||||||
|
serviceType: s.name,
|
||||||
|
provider: { "@id": `${SITE.url}/#organization` },
|
||||||
|
areaServed: "Worldwide",
|
||||||
|
})),
|
||||||
|
{
|
||||||
|
"@type": "FAQPage",
|
||||||
|
"@id": `${SITE.url}/#faq`,
|
||||||
|
mainEntity: faqs.map((f) => ({
|
||||||
|
"@type": "Question",
|
||||||
|
name: f.q,
|
||||||
|
acceptedAnswer: { "@type": "Answer", text: f.a },
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: JSON.stringify({ "@context": "https://schema.org", "@graph": graph }),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<html lang="es">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
{/* Satoshi (brand) + Instrument Serif (editorial accent) */}
|
{/* Satoshi (workhorse) + Instrument Serif (editorial accent) */}
|
||||||
<link rel="preconnect" href="https://api.fontshare.com" crossOrigin="" />
|
<link rel="preconnect" href="https://api.fontshare.com" crossOrigin="" />
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
|
|
@ -37,12 +105,14 @@ export default function RootLayout({
|
||||||
href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&display=swap"
|
||||||
/>
|
/>
|
||||||
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet" />
|
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet" />
|
||||||
<meta name="theme-color" content="#0a0a12" />
|
<meta name="theme-color" content="#08080c" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<StructuredData />
|
||||||
<a href="#main" className="skip-link">
|
<a href="#main" className="skip-link">
|
||||||
Saltar al contenido
|
Skip to content
|
||||||
</a>
|
</a>
|
||||||
|
<div className="grain" aria-hidden="true" />
|
||||||
<SmoothScroll />
|
<SmoothScroll />
|
||||||
<Cursor />
|
<Cursor />
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
225
app/page.tsx
225
app/page.tsx
|
|
@ -4,37 +4,14 @@ import Hero from "./components/Hero";
|
||||||
import Marquee from "./components/Marquee";
|
import Marquee from "./components/Marquee";
|
||||||
import Reveal from "./components/Reveal";
|
import Reveal from "./components/Reveal";
|
||||||
import KineticText from "./components/KineticText";
|
import KineticText from "./components/KineticText";
|
||||||
import ServicesJourney from "./components/ServicesJourney";
|
import Services from "./components/Services";
|
||||||
import Packages from "./components/Packages";
|
import Metrics from "./components/Metrics";
|
||||||
|
import CaseStudies from "./components/CaseStudies";
|
||||||
|
import Process from "./components/Process";
|
||||||
|
import Faq from "./components/Faq";
|
||||||
import PillMark from "./components/PillMark";
|
import PillMark from "./components/PillMark";
|
||||||
|
import Magnetic from "./components/Magnetic";
|
||||||
const advantages = [
|
import { testimonials } from "./content";
|
||||||
{
|
|
||||||
k: "Más rápido",
|
|
||||||
metric: "días",
|
|
||||||
sub: "no semanas",
|
|
||||||
d: "Nuestra plataforma hace el trabajo pesado. Entregamos en días lo que una agencia tradicional tarda en arrancar.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
k: "Más medible",
|
|
||||||
metric: "100%",
|
|
||||||
sub: "trazable",
|
|
||||||
d: "Cada acción tiene su dashboard y su resultado. Sabes qué funciona y qué no — sin humo ni informes de relleno.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
k: "Mejor coste",
|
|
||||||
metric: "0",
|
|
||||||
sub: "horas vacías",
|
|
||||||
d: "No pagas por horas: pagas por resultado. La IA absorbe lo repetitivo, el equipo se concentra en la estrategia.",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const sectors = [
|
|
||||||
{ t: "Clínicas estéticas", d: "Captación de pacientes, reputación y agenda llena." },
|
|
||||||
{ t: "Servicios profesionales", d: "Autoridad, leads cualificados y cierre." },
|
|
||||||
{ t: "E-commerce", d: "ROAS sostenible y catálogo que convierte." },
|
|
||||||
{ t: "SaaS & Tech", d: "Activación, retención y growth medible." },
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -46,110 +23,107 @@ export default function Home() {
|
||||||
<span id="top" />
|
<span id="top" />
|
||||||
<Hero />
|
<Hero />
|
||||||
|
|
||||||
|
{/* SOCIAL PROOF BAR */}
|
||||||
<Marquee />
|
<Marquee />
|
||||||
|
|
||||||
{/* VENTAJA INJUSTA — dark chapter */}
|
{/* POSITIONING / PROBLEM — big editorial statement */}
|
||||||
<section id="ventaja" className="band band--ink advantage">
|
<section id="position" className="positioning" aria-label="Our positioning">
|
||||||
|
<div className="wrap positioning__grid">
|
||||||
|
<Reveal>
|
||||||
|
<p className="kicker">Why we exist</p>
|
||||||
|
<p className="positioning__statement">
|
||||||
|
Most marketing budgets buy{" "}
|
||||||
|
<span className="muted">activity</span>, not{" "}
|
||||||
|
<span className="serif-em">outcomes.</span>
|
||||||
|
</p>
|
||||||
|
</Reveal>
|
||||||
|
<Reveal className="positioning__aside" y={40}>
|
||||||
|
<span className="serif-em">We started to fix that.</span>
|
||||||
|
Dashboards fill up with impressions and “engagement”
|
||||||
|
while the sales number sits still. Every campaign we run is built
|
||||||
|
to move revenue, and we report on it the way your CFO would.
|
||||||
|
</Reveal>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* SERVICES — broken grid */}
|
||||||
|
<Services />
|
||||||
|
|
||||||
|
{/* RESULTS — animated count-up */}
|
||||||
|
<Metrics />
|
||||||
|
|
||||||
|
{/* CASE STUDIES — large film-cell cards */}
|
||||||
|
<CaseStudies />
|
||||||
|
|
||||||
|
{/* PROCESS — pinned scrollytelling */}
|
||||||
|
<Process />
|
||||||
|
|
||||||
|
{/* TESTIMONIALS + PARTNERS */}
|
||||||
|
<section id="voices" className="tmonials" aria-label="What clients say">
|
||||||
<div className="wrap">
|
<div className="wrap">
|
||||||
<Reveal>
|
<Reveal>
|
||||||
<p className="kicker kicker--light">01 — Ventaja injusta</p>
|
<p className="kicker">In their words</p>
|
||||||
<h2 className="band__title">
|
<h2 className="section__title">
|
||||||
<KineticText as="span" text="No alquilamos herramientas." />{" "}
|
The number is the <span className="serif-em">whole point.</span>
|
||||||
<KineticText
|
|
||||||
as="span"
|
|
||||||
className="band__title-grad"
|
|
||||||
text="Construimos la máquina."
|
|
||||||
highlight={[0, 2]}
|
|
||||||
/>
|
|
||||||
</h2>
|
</h2>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
||||||
<div className="advantage__grid">
|
<Reveal className="tmonials__grid" stagger={0.12}>
|
||||||
{advantages.map((a, i) => (
|
{testimonials.map((t) => (
|
||||||
<Reveal className="advantage__item" key={a.k} y={56}>
|
<figure className="tmonial" key={t.by}>
|
||||||
<span className="advantage__index">0{i + 1}</span>
|
<span className="tmonial__mark" aria-hidden="true">
|
||||||
<p className="advantage__metric">
|
“
|
||||||
{a.metric}
|
</span>
|
||||||
<span className="advantage__metric-sub">{a.sub}</span>
|
<blockquote>
|
||||||
</p>
|
<p className="tmonial__quote">{t.quote}</p>
|
||||||
<h3 className="advantage__k">{a.k}</h3>
|
</blockquote>
|
||||||
<p className="advantage__d">{a.d}</p>
|
<figcaption className="tmonial__by">{t.by}</figcaption>
|
||||||
</Reveal>
|
</figure>
|
||||||
))}
|
))}
|
||||||
</div>
|
</Reveal>
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* SERVICIOS — horizontal journey */}
|
<Reveal className="partners">
|
||||||
<ServicesJourney />
|
<span className="partners__label">Partners</span>
|
||||||
|
<span className="partner">Google Partner</span>
|
||||||
{/* SECTORES — deep dive */}
|
<span className="partner">Meta Business Partner</span>
|
||||||
<section id="sectores" className="band sectors">
|
|
||||||
<div className="wrap sectors__wrap">
|
|
||||||
<div className="sectors__intro">
|
|
||||||
<Reveal>
|
|
||||||
<p className="kicker">03 — Profundidad por sector</p>
|
|
||||||
<h2 className="sectors__title">
|
|
||||||
No hacemos marketing genérico.{" "}
|
|
||||||
<span className="serif-em">Hablamos tu negocio.</span>
|
|
||||||
</h2>
|
|
||||||
<p className="sectors__lead">
|
|
||||||
Construimos soluciones a medida de cada sector: el mismo motor de
|
|
||||||
IA, afinado con el contexto, el vocabulario y los KPIs que de verdad
|
|
||||||
importan en tu mercado.
|
|
||||||
</p>
|
|
||||||
<a className="link-arrow hoverable" href="#contacto">
|
|
||||||
¿Tu sector no está? Cuéntanoslo
|
|
||||||
<span aria-hidden="true">→</span>
|
|
||||||
</a>
|
|
||||||
</Reveal>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Reveal className="sectors__list" stagger={0.1}>
|
|
||||||
{sectors.map((s) => (
|
|
||||||
<div className="sector hoverable" key={s.t} data-cursor="ver">
|
|
||||||
<PillMark className="sector__mark" />
|
|
||||||
<div>
|
|
||||||
<h3 className="sector__t">{s.t}</h3>
|
|
||||||
<p className="sector__d">{s.d}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</Reveal>
|
</Reveal>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* PAQUETES */}
|
{/* FAQ */}
|
||||||
<Packages />
|
<Faq />
|
||||||
|
|
||||||
{/* CTA — light iridescent close */}
|
{/* FINAL CTA */}
|
||||||
<section id="contacto" className="cta">
|
<section id="contact" className="cta" aria-label="Get in touch">
|
||||||
|
<span className="cta__glow" aria-hidden="true" />
|
||||||
<Reveal className="wrap cta__wrap">
|
<Reveal className="wrap cta__wrap">
|
||||||
<PillMark className="cta__mark" animate breathe />
|
<PillMark className="cta__mark" animate breathe />
|
||||||
<h2 className="cta__title">
|
<h2 className="cta__title">
|
||||||
<KineticText as="span" text="¿Hablamos de tu" />{" "}
|
<KineticText as="span" text="Ready to" />{" "}
|
||||||
<KineticText
|
<KineticText
|
||||||
as="span"
|
as="span"
|
||||||
className="cta__title-grad"
|
className="cta__title-grad"
|
||||||
text="crecimiento?"
|
text="grow?"
|
||||||
highlight={[0, 0]}
|
highlight={[0, 0]}
|
||||||
/>
|
/>
|
||||||
</h2>
|
</h2>
|
||||||
<p className="cta__lead">
|
<p className="cta__lead">
|
||||||
Cuéntanos dónde estás y te enseñamos, con datos, cómo llegar al
|
No long contracts. No vanity reports. Marketing you can measure in
|
||||||
siguiente nivel. Respuesta en menos de 24h.
|
sales.
|
||||||
</p>
|
</p>
|
||||||
<a
|
<Magnetic strength={0.4}>
|
||||||
className="btn btn--primary btn--lg hoverable"
|
<a
|
||||||
href="mailto:feedback.studios.design@gmail.com"
|
className="btn btn--primary btn--lg hoverable"
|
||||||
data-cursor="escríbenos"
|
href="https://cal.feedback-studios.com"
|
||||||
>
|
data-cursor="book a call"
|
||||||
<span>Habla con nosotros</span>
|
>
|
||||||
</a>
|
<span>Book a call</span>
|
||||||
|
</a>
|
||||||
|
</Magnetic>
|
||||||
<p className="cta__mail">
|
<p className="cta__mail">
|
||||||
o escríbenos a{" "}
|
or email{" "}
|
||||||
<a className="hoverable" href="mailto:feedback.studios.design@gmail.com">
|
<a className="hoverable" href="mailto:hello@feedbackstudios.com">
|
||||||
feedback.studios.design@gmail.com
|
hello@feedbackstudios.com
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
|
|
@ -163,18 +137,35 @@ export default function Home() {
|
||||||
feedback<span className="brand__word-2">studios</span>
|
feedback<span className="brand__word-2">studios</span>
|
||||||
</span>
|
</span>
|
||||||
<p className="site-footer__tag">
|
<p className="site-footer__tag">
|
||||||
La agencia de marketing AI-native. Estrategia humana,
|
A results-driven digital marketing agency. We build paid, SEO and
|
||||||
infraestructura propia.
|
content programs around your revenue.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<nav className="site-footer__nav" aria-label="Pie">
|
|
||||||
<a className="hoverable" href="#servicios">Servicios</a>
|
<div className="site-footer__col">
|
||||||
<a className="hoverable" href="#paquetes">Paquetes</a>
|
<h2>Sitemap</h2>
|
||||||
<a className="hoverable" href="#sectores">Sectores</a>
|
<nav aria-label="Footer">
|
||||||
<a className="hoverable" href="mailto:feedback.studios.design@gmail.com">Contacto</a>
|
<a className="hoverable" href="#services">Services</a>
|
||||||
</nav>
|
<a className="hoverable" href="#work">Work</a>
|
||||||
|
<a className="hoverable" href="#process">About</a>
|
||||||
|
<a className="hoverable" href="#faq">FAQ</a>
|
||||||
|
<a className="hoverable" href="#contact">Contact</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="site-footer__col">
|
||||||
|
<h2>Connect</h2>
|
||||||
|
<nav aria-label="Social and legal">
|
||||||
|
<a className="hoverable" href="https://www.linkedin.com" rel="noopener">LinkedIn</a>
|
||||||
|
<a className="hoverable" href="mailto:hello@feedbackstudios.com">Email</a>
|
||||||
|
<a className="hoverable" href="#">Privacy</a>
|
||||||
|
<a className="hoverable" href="#">Terms</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p className="site-footer__legal">
|
<p className="site-footer__legal">
|
||||||
© 2026 Feedback Studios · Marketing AI-native con infraestructura propia
|
<span>© 2026 Feedback Studios</span>
|
||||||
|
<span>Marketing that grows your revenue.</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
83
content/home-content.md
Normal file
83
content/home-content.md
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
# Feedback Studios — Homepage Content (EN, humanized)
|
||||||
|
|
||||||
|
> Voice: direct, human, a bit opinionated. Short sentences mixed with longer ones. Contractions. No em dashes, no AI vocabulary, no "full-service" slop. Focus: marketing that grows revenue.
|
||||||
|
> ⚠️ Metrics, case studies, testimonials and logos are illustrative SAMPLES for the prototype. Swap for real, verifiable client data before launch (E-E-A-T / honesty).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SEO / META
|
||||||
|
- **Title (≤60):** `Results-driven digital marketing agency | Feedback Studios`
|
||||||
|
- **Meta description (~150):** `Most agencies sell activity. Feedback Studios builds paid, SEO and content programs around one number: your revenue. And we report on it every month.`
|
||||||
|
- **Primary keyword:** digital marketing agency · results-driven marketing · revenue
|
||||||
|
- **Schema (JSON-LD):** Organization, WebSite (+SearchAction), Service (per core service), FAQPage, AggregateRating (only with real reviews).
|
||||||
|
- **Note:** test env stays noindex. When live: index, allow AI crawlers (GPTBot, OAI-SearchBot, PerplexityBot, ClaudeBot, Googlebot, Bingbot), add llms.txt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. NAV
|
||||||
|
Logo · Services · Work · About · FAQ · **button: "Get a growth audit"**
|
||||||
|
|
||||||
|
## 2. HERO
|
||||||
|
- **Eyebrow:** Digital marketing agency
|
||||||
|
- **H1:** Marketing that grows your revenue.
|
||||||
|
- **Sub:** We're a results-driven digital marketing agency. We run paid, SEO, and content programs built around your revenue targets, then show you what they returned. Every month.
|
||||||
|
- **Primary CTA:** Get your growth audit
|
||||||
|
- **Secondary:** See the results →
|
||||||
|
- **Trust line:** $40M+ in client revenue generated · 50+ brands grown
|
||||||
|
- **Visual:** custom WebGL / motion signature moment. No stock.
|
||||||
|
|
||||||
|
## 3. SOCIAL PROOF BAR
|
||||||
|
Label: "Trusted by teams that care about the sales number" · 6–8 greyscale client logos (or industry labels: E-commerce · B2B SaaS · Clinics · Professional services).
|
||||||
|
|
||||||
|
## 4. POSITIONING / PROBLEM
|
||||||
|
Most marketing budgets buy activity, not outcomes. Dashboards fill up with impressions and "engagement" while the sales number sits still. We started Feedback Studios to fix that. Every campaign we run is built to move revenue, and we report on it the way your CFO would.
|
||||||
|
|
||||||
|
## 5. SERVICES — H2: "How we grow your business"
|
||||||
|
- **SEO that compounds** — Rank for the searches your buyers make, and keep ranking long after the invoice clears.
|
||||||
|
- **Paid ads that pay back** — Google, Meta, TikTok, and LinkedIn, managed to ROAS and pipeline. Not vanity clicks.
|
||||||
|
- **Content that converts** — Articles, landing pages, and assets that pull in qualified traffic and turn it into customers.
|
||||||
|
- **Social that builds demand** — Feeds and creative that make people remember you before they're ready to buy.
|
||||||
|
- **Web & landing pages** — Fast, on-brand pages built for one job: conversion.
|
||||||
|
- **Creative & brand** — Scroll-stopping creative that still sells.
|
||||||
|
|
||||||
|
## 6. RESULTS / METRICS (animated count-up — SAMPLE)
|
||||||
|
- $40M+ — client revenue generated
|
||||||
|
- 3.8× — average return on ad spend
|
||||||
|
- +183% — average organic traffic in 6 months
|
||||||
|
- 92% — client retention
|
||||||
|
|
||||||
|
## 7. CASE STUDIES — H2: "Proof, not promises" (SAMPLE, 3)
|
||||||
|
1. **E-commerce, fashion.** Rising ad costs were eating the margin. → **−34% CPA and +52% ROAS in 90 days** (Meta + Google Shopping restructure).
|
||||||
|
2. **B2B SaaS.** Plenty of traffic, no pipeline. → **+217% qualified demo requests in 6 months** (SEO + content + LinkedIn).
|
||||||
|
3. **Aesthetic clinic.** Empty calendar despite the ad spend. → **+128 booked consultations a month** (paid + landing-page rebuild).
|
||||||
|
CTA: View all work →
|
||||||
|
|
||||||
|
## 8. PROCESS — H2: "How it works" · Framework: **The Feedback Loop**
|
||||||
|
1. **Audit** — We find where your revenue is leaking.
|
||||||
|
2. **Plan** — A channel mix and targets tied to your numbers, not guesswork.
|
||||||
|
3. **Execute** — We build, launch, and optimize. Fast.
|
||||||
|
4. **Report** — Every month: marketing tied straight to pipeline and sales.
|
||||||
|
|
||||||
|
## 9. TESTIMONIALS (SAMPLE)
|
||||||
|
- "We were spending $20k a month on ads with nothing to show. Six months later, marketing is our most predictable growth channel." — *Name, Role, Company*
|
||||||
|
- "They talk in revenue, not impressions. First agency that moved our pipeline." — *Name, Role, Company*
|
||||||
|
|
||||||
|
## 10. AWARDS / PARTNERS
|
||||||
|
Google Partner · Meta Business Partner · (+ real awards/press when available).
|
||||||
|
|
||||||
|
## 11. FAQ — H2: "Questions about working with a digital marketing agency" (AEO answer capsules, 40–60 words)
|
||||||
|
1. **What does a digital marketing agency do?** A digital marketing agency plans and runs campaigns across search, paid media, social, and content to grow a business. Feedback Studios focuses on revenue, not vanity metrics, and puts your budget into the channels that convert.
|
||||||
|
2. **How much does a digital marketing agency cost?** Most retainers run from about $2,000 to $20,000+ a month, depending on scope, channels, and competition. Feedback Studios scopes the work to your growth goals, and we also offer one-time audits and project work if a full retainer isn't the right fit yet.
|
||||||
|
3. **How long until I see results?** Paid campaigns can bring in leads within 2 to 4 weeks. SEO and content usually show real organic growth in 3 to 6 months. We set clear 30, 60, and 90-day milestones so you always know what to expect, and when.
|
||||||
|
4. **What makes Feedback Studios different?** We measure success by revenue, not impressions or followers. Every campaign is built around your bottom line, with monthly reporting that ties what we do straight to pipeline and sales. If it doesn't grow the business, we stop doing it.
|
||||||
|
5. **Which businesses do you work with?** We work with e-commerce brands, B2B SaaS, clinics, and professional-service firms that want to grow revenue through digital channels. Clients range from scaling startups to established companies that have outgrown their current marketing.
|
||||||
|
6. **What should I look for in a marketing agency?** Look for transparent reporting, real case studies with hard numbers, a clear process for your channels, and a team that talks in revenue, not reach. Ask to see work in your industry before you sign anything.
|
||||||
|
|
||||||
|
## 12. FINAL CTA
|
||||||
|
- **H2:** Ready to grow?
|
||||||
|
- **Sub:** No long contracts. No vanity reports. Marketing you can measure in sales.
|
||||||
|
- **CTA:** Book a call (→ cal.feedback-studios.com)
|
||||||
|
- Secondary: or email hello@feedbackstudios.com
|
||||||
|
|
||||||
|
## 13. FOOTER
|
||||||
|
Logo + one-line positioning · Sitemap (Services, Work, About, FAQ, Contact) · LinkedIn · Privacy · Terms · © 2026 · NAP (city/country) when available.
|
||||||
466
package-lock.json
generated
466
package-lock.json
generated
|
|
@ -10,7 +10,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"gsap": "^3.12.5",
|
"gsap": "^3.12.5",
|
||||||
"lenis": "^1.1.14",
|
"lenis": "^1.1.14",
|
||||||
"next": "15.1.6",
|
"next": "^15.5.19",
|
||||||
"ogl": "^1.0.11",
|
"ogl": "^1.0.11",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
|
|
@ -36,10 +36,20 @@
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@img/colour": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@img/sharp-darwin-arm64": {
|
"node_modules/@img/sharp-darwin-arm64": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
|
||||||
"integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
|
"integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -55,13 +65,13 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-darwin-arm64": "1.0.4"
|
"@img/sharp-libvips-darwin-arm64": "1.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-darwin-x64": {
|
"node_modules/@img/sharp-darwin-x64": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
|
||||||
"integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
|
"integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -77,13 +87,13 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-darwin-x64": "1.0.4"
|
"@img/sharp-libvips-darwin-x64": "1.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||||
"version": "1.0.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
|
||||||
"integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
|
"integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -97,9 +107,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-libvips-darwin-x64": {
|
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||||
"version": "1.0.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
|
||||||
"integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
|
"integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -113,9 +123,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-libvips-linux-arm": {
|
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||||
"version": "1.0.5",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
|
||||||
"integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
|
"integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
|
@ -129,9 +139,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-libvips-linux-arm64": {
|
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||||
"version": "1.0.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
|
||||||
"integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
|
"integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -144,10 +154,42 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-ppc64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-riscv64": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@img/sharp-libvips-linux-s390x": {
|
"node_modules/@img/sharp-libvips-linux-s390x": {
|
||||||
"version": "1.0.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
|
||||||
"integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
|
"integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
|
|
@ -161,9 +203,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-libvips-linux-x64": {
|
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||||
"version": "1.0.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
|
||||||
"integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
|
"integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -177,9 +219,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
||||||
"version": "1.0.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
|
||||||
"integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
|
"integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -193,9 +235,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
||||||
"version": "1.0.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
|
||||||
"integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
|
"integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -209,9 +251,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-linux-arm": {
|
"node_modules/@img/sharp-linux-arm": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
|
||||||
"integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
|
"integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
|
@ -227,13 +269,13 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-arm": "1.0.5"
|
"@img/sharp-libvips-linux-arm": "1.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-linux-arm64": {
|
"node_modules/@img/sharp-linux-arm64": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
|
||||||
"integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
|
"integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -249,13 +291,57 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-arm64": "1.0.4"
|
"@img/sharp-libvips-linux-arm64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-ppc64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-ppc64": "1.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-riscv64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
|
||||||
|
"cpu": [
|
||||||
|
"riscv64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-riscv64": "1.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-linux-s390x": {
|
"node_modules/@img/sharp-linux-s390x": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
|
||||||
"integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
|
"integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
|
|
@ -271,13 +357,13 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-s390x": "1.0.4"
|
"@img/sharp-libvips-linux-s390x": "1.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-linux-x64": {
|
"node_modules/@img/sharp-linux-x64": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
|
||||||
"integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
|
"integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -293,13 +379,13 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linux-x64": "1.0.4"
|
"@img/sharp-libvips-linux-x64": "1.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-linuxmusl-arm64": {
|
"node_modules/@img/sharp-linuxmusl-arm64": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
|
||||||
"integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
|
"integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -315,13 +401,13 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
|
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-linuxmusl-x64": {
|
"node_modules/@img/sharp-linuxmusl-x64": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
|
||||||
"integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
|
"integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -337,20 +423,20 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.4"
|
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-wasm32": {
|
"node_modules/@img/sharp-wasm32": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
|
||||||
"integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
|
"integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"wasm32"
|
"wasm32"
|
||||||
],
|
],
|
||||||
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/runtime": "^1.2.0"
|
"@emnapi/runtime": "^1.7.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
|
@ -359,10 +445,29 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@img/sharp-win32-arm64": {
|
||||||
|
"version": "0.34.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
|
||||||
|
"integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@img/sharp-win32-ia32": {
|
"node_modules/@img/sharp-win32-ia32": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
|
||||||
"integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
|
"integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
|
@ -379,9 +484,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@img/sharp-win32-x64": {
|
"node_modules/@img/sharp-win32-x64": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
|
||||||
"integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
|
"integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -398,15 +503,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/env": {
|
"node_modules/@next/env": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.19.tgz",
|
||||||
"integrity": "sha512-d9AFQVPEYNr+aqokIiPLNK/MTyt3DWa/dpKveiAaVccUadFbhFEvY6FXYX2LJO2Hv7PHnLBu2oWwB4uBuHjr/w==",
|
"integrity": "sha512-sWWluFvcv5v3Fxznmf2ZfjyoVQt/64oCnYqS90inQWGzMPK1VjvekPiz3OPHKmFT30EnHrjlbyaHLt3M0vWabw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-arm64": {
|
"node_modules/@next/swc-darwin-arm64": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.19.tgz",
|
||||||
"integrity": "sha512-u7lg4Mpl9qWpKgy6NzEkz/w0/keEHtOybmIl0ykgItBxEM5mYotS5PmqTpo+Rhg8FiOiWgwr8USxmKQkqLBCrw==",
|
"integrity": "sha512-jx9wWlTKueHKPvVOndyr7WuaevWCkuYqsQ8gC0TMPKAVWG3MhcdMrjfo9tvIZNXd0QOUYXXvAcZ325y8Uq7uzg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -420,9 +525,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-darwin-x64": {
|
"node_modules/@next/swc-darwin-x64": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.19.tgz",
|
||||||
"integrity": "sha512-x1jGpbHbZoZ69nRuogGL2MYPLqohlhnT9OCU6E6QFewwup+z+M6r8oU47BTeJcWsF2sdBahp5cKiAcDbwwK/lg==",
|
"integrity": "sha512-291KFcsIQ3OenRdiUDFOR6W3wezzH4auENXm1gbm1Bjd4ANMMRgxPrWTUztQN43BnVoVuMnHCrLeECIMwgFKbA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -436,9 +541,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.19.tgz",
|
||||||
"integrity": "sha512-jar9sFw0XewXsBzPf9runGzoivajeWJUc/JkfbLTC4it9EhU8v7tCRLH7l5Y1ReTMN6zKJO0kKAGqDk8YSO2bg==",
|
"integrity": "sha512-WeH+nelQyyMeE2f8FxBRZNrGipya5zHZV2vjzfCOAYyiI6am+NbnWAAldOBFQBB2w0DjJcsvrKqoFT2b7+5YoA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -452,9 +557,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-arm64-musl": {
|
"node_modules/@next/swc-linux-arm64-musl": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.19.tgz",
|
||||||
"integrity": "sha512-+n3u//bfsrIaZch4cgOJ3tXCTbSxz0s6brJtU3SzLOvkJlPQMJ+eHVRi6qM2kKKKLuMY+tcau8XD9CJ1OjeSQQ==",
|
"integrity": "sha512-5xTOE0lDlDCSSfp+BAif7j17VRRCjWp//ZPZy6NI0QpdrhxtQnsZguSx0xAAZ0c9XZLrLLwCe/XVe5YPrRilKw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -468,9 +573,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-gnu": {
|
"node_modules/@next/swc-linux-x64-gnu": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.19.tgz",
|
||||||
"integrity": "sha512-SpuDEXixM3PycniL4iVCLyUyvcl6Lt0mtv3am08sucskpG0tYkW1KlRhTgj4LI5ehyxriVVcfdoxuuP8csi3kQ==",
|
"integrity": "sha512-LTxRmMgqqMv05Had879W00Fm53quiJd3Zuz8h1JSNJ3nGSlbZ/7Tjs1tKyScgN3Au3t3MyPsjPlq60fMmSHLsg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -484,9 +589,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-linux-x64-musl": {
|
"node_modules/@next/swc-linux-x64-musl": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.19.tgz",
|
||||||
"integrity": "sha512-L4druWmdFSZIIRhF+G60API5sFB7suTbDRhYWSjiw0RbE+15igQvE2g2+S973pMGvwN3guw7cJUjA/TmbPWTHQ==",
|
"integrity": "sha512-eoNQSpA5PQfB9wBO4RA47MTDXWz1fizy9Y3Z6e4DetYIF3dvjuu8sj7aIGn/bFCU6lnFzTK34NtCaffP4NsQ7Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -500,9 +605,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.19.tgz",
|
||||||
"integrity": "sha512-s8w6EeqNmi6gdvM19tqKKWbCyOBvXFbndkGHl+c9YrzsLARRdCHsD9S1fMj8gsXm9v8vhC8s3N8rjuC/XrtkEg==",
|
"integrity": "sha512-6UNt2dFuCHOe446sm/Kp69nUe8/wIhnh9bm6Xcqw4qEWCOppLMOvhTBVgvM7invVUNr4SPpP6NOQsACtn2IN9Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -516,9 +621,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@next/swc-win32-x64-msvc": {
|
"node_modules/@next/swc-win32-x64-msvc": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.19.tgz",
|
||||||
"integrity": "sha512-6xomMuu54FAFxttYr5PJbEfu96godcxBTRk1OhAvJq0/EnmFU/Ybiax30Snis4vdWZ9LGpf7Roy5fSs7v/5ROQ==",
|
"integrity": "sha512-PhmojAHyqMne56HBLGu9dhDnHPuFmEjrXSQMM/nW0J6j849lk3ESrVtqNJcCk8CKOV7brpTTbaYAjwKPzKM69w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -531,12 +636,6 @@
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@swc/counter": {
|
|
||||||
"version": "0.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
|
||||||
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
|
|
||||||
"license": "Apache-2.0"
|
|
||||||
},
|
|
||||||
"node_modules/@swc/helpers": {
|
"node_modules/@swc/helpers": {
|
||||||
"version": "0.5.15",
|
"version": "0.5.15",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
|
||||||
|
|
@ -576,17 +675,6 @@
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/busboy": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
|
||||||
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
|
||||||
"dependencies": {
|
|
||||||
"streamsearch": "^1.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.16.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001799",
|
"version": "1.0.30001799",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz",
|
||||||
|
|
@ -613,51 +701,6 @@
|
||||||
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
|
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/color": {
|
|
||||||
"version": "4.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
|
||||||
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"color-convert": "^2.0.1",
|
|
||||||
"color-string": "^1.9.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/color-convert": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"color-name": "~1.1.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=7.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/color-name": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"node_modules/color-string": {
|
|
||||||
"version": "1.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
|
||||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"color-name": "^1.0.0",
|
|
||||||
"simple-swizzle": "^0.2.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.2.3",
|
"version": "3.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||||
|
|
@ -681,13 +724,6 @@
|
||||||
"integrity": "sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==",
|
"integrity": "sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==",
|
||||||
"license": "Standard 'no charge' license: https://gsap.com/standard-license."
|
"license": "Standard 'no charge' license: https://gsap.com/standard-license."
|
||||||
},
|
},
|
||||||
"node_modules/is-arrayish": {
|
|
||||||
"version": "0.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
|
|
||||||
"integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"node_modules/lenis": {
|
"node_modules/lenis": {
|
||||||
"version": "1.3.23",
|
"version": "1.3.23",
|
||||||
"resolved": "https://registry.npmjs.org/lenis/-/lenis-1.3.23.tgz",
|
"resolved": "https://registry.npmjs.org/lenis/-/lenis-1.3.23.tgz",
|
||||||
|
|
@ -738,16 +774,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/next": {
|
"node_modules/next": {
|
||||||
"version": "15.1.6",
|
"version": "15.5.19",
|
||||||
"resolved": "https://registry.npmjs.org/next/-/next-15.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/next/-/next-15.5.19.tgz",
|
||||||
"integrity": "sha512-Hch4wzbaX0vKQtalpXvUiw5sYivBy4cm5rzUKrBnUB/y436LGrvOUqYvlSeNVCWFO/770gDlltR9gqZH62ct4Q==",
|
"integrity": "sha512-xNOW6tYshGX1/Oi3F8uuk4gpDeWsSUE/1Z0G5uUMekIxaQ0xc03UXd9II0VQHYMWviMeA0OHpJFAKsHf8bTYVg==",
|
||||||
"deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details.",
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/env": "15.1.6",
|
"@next/env": "15.5.19",
|
||||||
"@swc/counter": "0.1.3",
|
|
||||||
"@swc/helpers": "0.5.15",
|
"@swc/helpers": "0.5.15",
|
||||||
"busboy": "1.6.0",
|
|
||||||
"caniuse-lite": "^1.0.30001579",
|
"caniuse-lite": "^1.0.30001579",
|
||||||
"postcss": "8.4.31",
|
"postcss": "8.4.31",
|
||||||
"styled-jsx": "5.1.6"
|
"styled-jsx": "5.1.6"
|
||||||
|
|
@ -759,19 +792,19 @@
|
||||||
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
|
"node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@next/swc-darwin-arm64": "15.1.6",
|
"@next/swc-darwin-arm64": "15.5.19",
|
||||||
"@next/swc-darwin-x64": "15.1.6",
|
"@next/swc-darwin-x64": "15.5.19",
|
||||||
"@next/swc-linux-arm64-gnu": "15.1.6",
|
"@next/swc-linux-arm64-gnu": "15.5.19",
|
||||||
"@next/swc-linux-arm64-musl": "15.1.6",
|
"@next/swc-linux-arm64-musl": "15.5.19",
|
||||||
"@next/swc-linux-x64-gnu": "15.1.6",
|
"@next/swc-linux-x64-gnu": "15.5.19",
|
||||||
"@next/swc-linux-x64-musl": "15.1.6",
|
"@next/swc-linux-x64-musl": "15.5.19",
|
||||||
"@next/swc-win32-arm64-msvc": "15.1.6",
|
"@next/swc-win32-arm64-msvc": "15.5.19",
|
||||||
"@next/swc-win32-x64-msvc": "15.1.6",
|
"@next/swc-win32-x64-msvc": "15.5.19",
|
||||||
"sharp": "^0.33.5"
|
"sharp": "^0.34.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@opentelemetry/api": "^1.1.0",
|
"@opentelemetry/api": "^1.1.0",
|
||||||
"@playwright/test": "^1.41.2",
|
"@playwright/test": "^1.51.1",
|
||||||
"babel-plugin-react-compiler": "*",
|
"babel-plugin-react-compiler": "*",
|
||||||
"react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
|
"react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
|
||||||
"react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
|
"react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
|
||||||
|
|
@ -873,16 +906,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sharp": {
|
"node_modules/sharp": {
|
||||||
"version": "0.33.5",
|
"version": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
|
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
|
||||||
"integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
|
"integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color": "^4.2.3",
|
"@img/colour": "^1.0.0",
|
||||||
"detect-libc": "^2.0.3",
|
"detect-libc": "^2.1.2",
|
||||||
"semver": "^7.6.3"
|
"semver": "^7.7.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
|
@ -891,35 +924,30 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@img/sharp-darwin-arm64": "0.33.5",
|
"@img/sharp-darwin-arm64": "0.34.5",
|
||||||
"@img/sharp-darwin-x64": "0.33.5",
|
"@img/sharp-darwin-x64": "0.34.5",
|
||||||
"@img/sharp-libvips-darwin-arm64": "1.0.4",
|
"@img/sharp-libvips-darwin-arm64": "1.2.4",
|
||||||
"@img/sharp-libvips-darwin-x64": "1.0.4",
|
"@img/sharp-libvips-darwin-x64": "1.2.4",
|
||||||
"@img/sharp-libvips-linux-arm": "1.0.5",
|
"@img/sharp-libvips-linux-arm": "1.2.4",
|
||||||
"@img/sharp-libvips-linux-arm64": "1.0.4",
|
"@img/sharp-libvips-linux-arm64": "1.2.4",
|
||||||
"@img/sharp-libvips-linux-s390x": "1.0.4",
|
"@img/sharp-libvips-linux-ppc64": "1.2.4",
|
||||||
"@img/sharp-libvips-linux-x64": "1.0.4",
|
"@img/sharp-libvips-linux-riscv64": "1.2.4",
|
||||||
"@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
|
"@img/sharp-libvips-linux-s390x": "1.2.4",
|
||||||
"@img/sharp-libvips-linuxmusl-x64": "1.0.4",
|
"@img/sharp-libvips-linux-x64": "1.2.4",
|
||||||
"@img/sharp-linux-arm": "0.33.5",
|
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
|
||||||
"@img/sharp-linux-arm64": "0.33.5",
|
"@img/sharp-libvips-linuxmusl-x64": "1.2.4",
|
||||||
"@img/sharp-linux-s390x": "0.33.5",
|
"@img/sharp-linux-arm": "0.34.5",
|
||||||
"@img/sharp-linux-x64": "0.33.5",
|
"@img/sharp-linux-arm64": "0.34.5",
|
||||||
"@img/sharp-linuxmusl-arm64": "0.33.5",
|
"@img/sharp-linux-ppc64": "0.34.5",
|
||||||
"@img/sharp-linuxmusl-x64": "0.33.5",
|
"@img/sharp-linux-riscv64": "0.34.5",
|
||||||
"@img/sharp-wasm32": "0.33.5",
|
"@img/sharp-linux-s390x": "0.34.5",
|
||||||
"@img/sharp-win32-ia32": "0.33.5",
|
"@img/sharp-linux-x64": "0.34.5",
|
||||||
"@img/sharp-win32-x64": "0.33.5"
|
"@img/sharp-linuxmusl-arm64": "0.34.5",
|
||||||
}
|
"@img/sharp-linuxmusl-x64": "0.34.5",
|
||||||
},
|
"@img/sharp-wasm32": "0.34.5",
|
||||||
"node_modules/simple-swizzle": {
|
"@img/sharp-win32-arm64": "0.34.5",
|
||||||
"version": "0.2.4",
|
"@img/sharp-win32-ia32": "0.34.5",
|
||||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
|
"@img/sharp-win32-x64": "0.34.5"
|
||||||
"integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"is-arrayish": "^0.3.1"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
|
|
@ -937,14 +965,6 @@
|
||||||
"integrity": "sha512-otEk9vnD8qwfLsk3Lx0gz+qRkNIJCx0mlyL47ImP/DjMuV39d75Lpfwjn9fHteDRz0aoOblSzQjSNT9+Sswxcg==",
|
"integrity": "sha512-otEk9vnD8qwfLsk3Lx0gz+qRkNIJCx0mlyL47ImP/DjMuV39d75Lpfwjn9fHteDRz0aoOblSzQjSNT9+Sswxcg==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/streamsearch": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/styled-jsx": {
|
"node_modules/styled-jsx": {
|
||||||
"version": "5.1.6",
|
"version": "5.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,16 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"gsap": "^3.12.5",
|
"gsap": "^3.12.5",
|
||||||
"lenis": "^1.1.14",
|
"lenis": "^1.1.14",
|
||||||
"next": "15.1.6",
|
"next": "^15.5.19",
|
||||||
"ogl": "^1.0.11",
|
"ogl": "^1.0.11",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"split-type": "^0.3.4"
|
"split-type": "^0.3.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.7.3",
|
|
||||||
"@types/node": "^22.10.7",
|
"@types/node": "^22.10.7",
|
||||||
"@types/react": "^19.0.7",
|
"@types/react": "^19.0.7",
|
||||||
"@types/react-dom": "^19.0.3"
|
"@types/react-dom": "^19.0.3",
|
||||||
|
"typescript": "^5.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
public/assets/case-1.png
Normal file
BIN
public/assets/case-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
BIN
public/assets/case-2.png
Normal file
BIN
public/assets/case-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
public/assets/case-3.png
Normal file
BIN
public/assets/case-3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/hero-iridescent-1.png
Normal file
BIN
public/assets/hero-iridescent-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2 MiB |
Loading…
Reference in a new issue