diff --git a/src/app/sections/landing/index.tsx b/src/app/sections/landing/index.tsx
new file mode 100644
index 0000000..e1bd3b1
--- /dev/null
+++ b/src/app/sections/landing/index.tsx
@@ -0,0 +1,118 @@
+import { LandingClient } from "./landing-client";
+
+const letterSegments: Record
= {
+ l: [
+ [0, 0, 2, 0],
+ [2, 0, 2, 10],
+ [2, 10, 0, 10],
+ [0, 10, 0, 0],
+ ],
+ u: [
+ [0, 3, 0, 10],
+ [0, 10, 4, 10],
+ [4, 10, 4, 3],
+ [4, 3, 0, 3],
+ [2, 3, 2, 8],
+ ],
+ i: [
+ [0, 3, 2, 3],
+ [2, 3, 2, 10],
+ [2, 10, 0, 10],
+ [0, 10, 0, 3],
+ [0, 0.5, 2, 0.5],
+ [2, 0.5, 2, 2.5],
+ [2, 2.5, 0, 2.5],
+ [0, 2.5, 0, 0.5],
+ ],
+ s: [
+ [0, 3, 5, 3],
+ [0, 10, 5, 10],
+ [0, 3, 0, 7.67],
+ [0, 7.67, 0, 10],
+ [5, 3, 5, 5.33],
+ [5, 5.33, 5, 10],
+ [2, 5.33, 5, 5.33],
+ [0, 7.67, 3, 7.67],
+ ],
+ d: [
+ [2, 0, 4, 0],
+ [4, 0, 4, 10],
+ [0, 3, 0, 10],
+ [0, 10, 4, 10],
+ [0, 3, 2, 3],
+ [2, 3, 2, 0],
+ [2, 5, 2, 8],
+ ],
+ r: [
+ [0, 3, 4, 3],
+ [2, 5.33, 2, 10],
+ [2, 10, 0, 10],
+ [0, 10, 0, 3],
+ [4, 3, 4, 5.33],
+ [2, 5.33, 4, 5.33],
+ ],
+ a: [
+ [0, 3, 0, 5.33],
+ [0, 5.33, 0, 10],
+ [0, 10, 5, 10],
+ [5, 10, 5, 3],
+ [5, 3, 0, 3],
+ [0, 5.33, 3, 5.33],
+ [2, 7.67, 3, 7.67],
+ ],
+ v: [
+ [0, 3, 1.5, 10],
+ [5, 3, 3.5, 10],
+ [1.5, 10, 3.5, 10],
+ [2, 3, 2.5, 8],
+ [3, 3, 2.5, 8],
+ [0, 3, 2, 3],
+ [3, 3, 5, 3],
+ ],
+ e: [
+ [5, 3, 5, 10],
+ [0, 3, 5, 3],
+ [0, 3, 0, 10],
+ [5, 10, 0, 10],
+ [5, 7.67, 2, 7.67],
+ [2, 5.33, 3, 5.33],
+ ],
+};
+
+const letterLayout: [string, number][] = [
+ ["l", 0],
+ ["u", 2.5],
+ ["i", 7],
+ ["s", 9.5],
+ ["d", 15],
+ ["r", 19.5],
+ ["a", 24],
+ ["l", 29.5],
+ ["v", 32],
+ ["e", 37.5],
+ ["s", 43],
+];
+
+const allPaths = letterLayout.reduce<{ d: string; key: string }[]>(
+ (paths, [letterKey, xOffset]) => {
+ const letter = letterSegments[letterKey];
+ if (letter) {
+ letter.forEach(([x1, y1, x2, y2]) => {
+ paths.push({
+ d: `M${x1 + xOffset},${y1} L${x2 + xOffset},${y2}`,
+ key: `seg-${paths.length}`,
+ });
+ });
+ }
+ return paths;
+ },
+ [],
+);
+
+export const Landing = () => {
+ return (
+
+ );
+};
diff --git a/src/app/sections/landing/landing-client.tsx b/src/app/sections/landing/landing-client.tsx
new file mode 100644
index 0000000..11de950
--- /dev/null
+++ b/src/app/sections/landing/landing-client.tsx
@@ -0,0 +1,63 @@
+"use client";
+
+import { type MotionValue, m, useScroll, useTransform } from "motion/react";
+import { useRef } from "react";
+import { springGentle } from "@/lib/motion";
+
+const STROKE_WIDTH = 0.05;
+
+const LogotypePath = ({
+ d,
+ scrollProgress,
+}: {
+ d: string;
+ scrollProgress: MotionValue;
+}) => {
+ const strokeDashoffset = useTransform(scrollProgress, [0, 0.6], [0, 1]);
+
+ return (
+
+ );
+};
+
+type Props = {
+ paths: { d: string; key: string }[];
+};
+
+export const LandingClient = ({ paths }: Props) => {
+ const containerRef = useRef(null);
+
+ const { scrollYProgress } = useScroll({
+ target: containerRef,
+ offset: ["start start", "end start"],
+ });
+
+ return (
+
+
+ {paths.map(({ d, key }) => (
+
+ ))}
+
+
+ );
+};
diff --git a/src/components/scroll-progress-indicator/radial-reveal.tsx b/src/components/scroll-progress-indicator/radial-reveal.tsx
index 5bd1a67..ded97ad 100644
--- a/src/components/scroll-progress-indicator/radial-reveal.tsx
+++ b/src/components/scroll-progress-indicator/radial-reveal.tsx
@@ -36,6 +36,21 @@ export const RadialReveal = ({ targetSection, origin, onComplete }: Props) => {
clone.style.transform = `translateY(-${clampedScrollY}px)`;
clone.style.pointerEvents = "none";
+ // Reset scroll-animated elements to their initial visual state
+ // Format: data-scroll-animated="property1:value1;property2:value2"
+ clone.querySelectorAll("[data-scroll-animated]").forEach((el) => {
+ const htmlEl = el as HTMLElement | SVGElement;
+ const resetValues = htmlEl.dataset.scrollAnimated;
+ if (resetValues) {
+ resetValues.split(";").forEach((pair) => {
+ const [property, value] = pair.split(":");
+ if (property && value !== undefined) {
+ htmlEl.style.setProperty(property, value);
+ }
+ });
+ }
+ });
+
overlayRef.current.innerHTML = "";
overlayRef.current.appendChild(clone);
setIsReady(true);