improve view buttons and home animation
All checks were successful
Deploy / Deploy to Production (push) Successful in 6s

This commit is contained in:
isUnknown 2026-06-24 16:02:13 +02:00
parent 8996e3e194
commit 2ec9354266
7 changed files with 125 additions and 39 deletions

View file

@ -39,6 +39,8 @@
li.characters {
flex: 0 0 200px;
justify-content: center;
margin-right: 4vw;
margin-left: 2vw;
svg {
width: var(--char-size);

View file

@ -14,11 +14,10 @@
padding: 0.3rem 0.7rem;
border-radius: 0.5rem;
border: var(--border);
box-shadow: inset 0 0 0px 0 0 var(--color-green);
transition: box-shadow 0.2s ease-in-out;
&.active {
box-shadow: inset 0 0 3px 1px var(--color-green);
background-color: #000;
color: #fff;
}
}
}

View file

@ -236,11 +236,10 @@ main {
padding: 0.3rem 0.7rem;
border-radius: 0.5rem;
border: var(--border);
box-shadow: inset 0 0 0px 0 0 var(--color-green);
transition: box-shadow 0.2s ease-in-out;
}
.view-buttons li button.active {
box-shadow: inset 0 0 3px 1px var(--color-green);
background-color: #000;
color: #fff;
}
.main-header {
@ -281,6 +280,8 @@ main {
.main-header nav ul li.characters {
flex: 0 0 200px;
justify-content: center;
margin-right: 4vw;
margin-left: 2vw;
}
.main-header nav ul li.characters svg {
width: var(--char-size);

File diff suppressed because one or more lines are too long

View file

@ -76,16 +76,18 @@
<path id="rc-eye-r-iris" d="M508.39,605.19C506.93,605.19 505.54,605.52 504.22,606.1C503.58,604.82 503.23,603.26 503.29,601.58C503.35,600.09 503.73,598.71 504.33,597.56C502.65,598.82 501.47,601.17 501.36,603.92C501.31,605.2 501.5,606.42 501.88,607.49C501.49,607.79 501.11,608.11 500.75,608.46C499.82,607.31 499.14,605.79 498.87,604.07C498.64,602.59 498.75,601.17 499.12,599.93C497.72,601.49 497.01,604.03 497.43,606.74C497.66,608.2 498.19,609.52 498.91,610.58C498.73,610.84 498.55,611.1 498.38,611.37C496.86,610.45 495.53,608.84 494.77,606.78C494.26,605.38 494.08,603.96 494.2,602.67C493.13,604.47 492.93,607.1 493.87,609.68C494.54,611.52 495.68,613 497,613.95C495.83,616.6 495.15,619.69 495.15,623C495.15,632.84 501.08,640.82 508.39,640.82C515.7,640.82 521.63,632.84 521.63,623C521.63,613.16 515.7,605.18 508.39,605.18L508.39,605.19ZM508.39,608.47C511.95,608.47 514.83,611.05 514.83,614.23C514.83,617.41 511.95,619.99 508.39,619.99C504.83,619.99 501.95,617.41 501.95,614.23C501.95,611.05 504.83,608.47 508.39,608.47ZM508.39,639C502.32,639 497.2,631.68 497.2,623.01C497.2,618.29 498.73,613.97 501.09,611.02C499.19,614.33 498.45,618.99 499.41,623.82C501,631.79 506.76,637.9 512.38,637.89C511.13,638.6 509.78,639.01 508.38,639.01L508.39,639ZM513.13,635.43C511.22,635.43 509.67,634.04 509.67,632.33C509.67,630.62 511.22,629.23 513.13,629.23C515.04,629.23 516.59,630.62 516.59,632.33C516.59,634.04 515.04,635.43 513.13,635.43Z" style="fill-rule:nonzero;"/>
</g>
<!-- Overlays no-outfit : paupières + sourcils, masqués par défaut, révélés par GSAP -->
<g id="eye-overlays" opacity="0" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:2.76px;">
<!-- Overlays no-outfit : paupières, sourcils, nez — masqués par défaut, révélés par GSAP -->
<g id="face-overlays" opacity="0" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:2.76px;">
<path id="lc-eye-l-brow" d="M413.54,625.91C413.54,625.91 419.70,620.30 426.70,622.13C431.92,623.49 432.28,624.02 435.97,624.53"/>
<path id="lc-eye-l-lid" d="M414.99,632.79C418.98,629.42 425.04,625.28 434.52,632.16"/>
<path id="lc-eye-r-brow" d="M465.62,625.91C465.62,625.91 459.46,620.30 452.46,622.13C447.24,623.49 446.88,624.02 443.19,624.53"/>
<path id="lc-eye-r-lid" d="M464.17,632.79C460.18,629.42 454.12,625.28 444.64,632.16"/>
<path id="lc-nose" d="M439.84,631.04C439.84,631.04 438.55,635.06 441.02,639.44C443.33,643.55 447.25,643.68 447.29,647.19C447.32,650.12 443.22,652.22 441.11,652.53"/>
<path id="rc-eye-l-brow" d="M526.71,616.03C526.71,616.03 531.57,614.79 535.25,612.98C538.67,611.31 542.43,609.03 542.43,609.03C542.43,609.03 546.80,614.47 549.07,615.46"/>
<path id="rc-eye-l-lid" d="M530.00,624.44C533.64,621.21 539.31,616.47 547.18,624.97"/>
<path id="rc-eye-r-brow" d="M519.62,615.61C519.62,615.61 514.76,614.37 511.08,612.56C507.66,610.89 503.90,608.61 503.90,608.61C503.90,608.61 499.53,614.05 497.26,615.04"/>
<path id="rc-eye-r-lid" d="M516.33,624.02C514.22,622.14 511.42,619.76 507.91,619.75C505.37,619.75 502.45,620.98 499.15,624.54"/>
<path id="rc-nose" d="M524.29,625.53C524.29,625.53 522.13,632.35 526.52,635.55C530.67,638.57 531.58,640.87 531.23,642.96C530.52,647.16 525.37,647.66 523.48,647.70"/>
</g>
</g>

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

View file

@ -4,21 +4,31 @@ export function initMorphEyes() {
gsap.registerPlugin(MorphSVGPlugin);
const DURATION = 0.5;
const EASE = "power2.inOut";
const DURATION = 0.7;
const EASE_IN = "elastic.out(1.3, 0.35)";
const EASE_OUT = "elastic.out(1.3, 0.35)";
// lc-eye-l : composé de plusieurs éléments superposés
const lcEyeLIris = svg.querySelector("#lc-eye-l-iris");
const lcEyeLBase = svg.querySelector("#lc-eye-l-base");
const lcEyeLOverlays = svg.querySelectorAll("#lc-eye-l-sclera, #lc-eye-l-shadow, #lc-eye-l-sparkle");
const lcEyeLIris = svg.querySelector("#lc-eye-l-iris");
const lcEyeLBase = svg.querySelector("#lc-eye-l-base");
const lcEyeLOverlays = svg.querySelectorAll(
"#lc-eye-l-sclera, #lc-eye-l-shadow, #lc-eye-l-sparkle"
);
// Les trois autres yeux : un seul compound path chacun
const lcEyeRIris = svg.querySelector("#lc-eye-r-iris");
const rcEyeLIris = svg.querySelector("#rc-eye-l-iris");
const rcEyeRIris = svg.querySelector("#rc-eye-r-iris");
// Paupières + sourcils : révélés en fondu lors du passage en no-outfit
const eyeOverlays = svg.querySelector("#eye-overlays");
// Groupes d'yeux pour le blink
const eyeGroupLcL = svg.querySelector("#lc-eye-l");
const eyeGroupLcR = svg.querySelector("#lc-eye-r");
const eyeGroupRcL = svg.querySelector("#rc-eye-l");
const eyeGroupRcR = svg.querySelector("#rc-eye-r");
const eyeGroups = [eyeGroupLcL, eyeGroupLcR, eyeGroupRcL, eyeGroupRcR];
// Paupières, sourcils, nez : révélés en fondu lors du passage en no-outfit
const faceOverlays = svg.querySelector("#face-overlays");
if (!lcEyeLIris || !lcEyeRIris || !rcEyeLIris || !rcEyeRIris) return;
@ -30,31 +40,102 @@ export function initMorphEyes() {
rcEyeRIris: rcEyeRIris.getAttribute("d"),
};
let blinkTl = null;
function blink() {
blinkTl = gsap.timeline({ delay: DURATION + 0.1 });
blinkTl
.to(eyeGroups, { scaleY: 0, duration: 0.07, ease: "power2.in", transformOrigin: "center center" })
.to(eyeGroups, { scaleY: 1, duration: 0.1, ease: "power2.out" })
.to(eyeGroups, { scaleY: 0, duration: 0.07, ease: "power2.in", delay: 0.06 })
.to(eyeGroups, { scaleY: 1, duration: 0.1, ease: "power2.out" })
.to(eyeGroups, { scaleY: 0, duration: 0.07, ease: "power2.in", delay: 0.1 })
.to(eyeGroups, { scaleY: 1, duration: 0.12, ease: "power2.out" });
}
function morphToNoOutfit() {
// lc-eye-l : iris + base → ovale, overlays blancs → opacity 0
gsap.to(lcEyeLIris, { morphSVG: "#lc-eye-l-target", duration: DURATION, ease: EASE });
gsap.to(lcEyeLBase, { morphSVG: "#lc-eye-l-target", duration: DURATION, ease: EASE });
gsap.to(lcEyeLOverlays, { opacity: 0, duration: DURATION * 0.4, ease: "power1.in" });
if (blinkTl) blinkTl.kill();
gsap.set(eyeGroups, { scaleY: 1 });
gsap.to(lcEyeRIris, { morphSVG: "#lc-eye-r-target", duration: DURATION, delay: 0.04, ease: EASE });
gsap.to(rcEyeLIris, { morphSVG: "#rc-eye-l-target", duration: DURATION, delay: 0.02, ease: EASE });
gsap.to(rcEyeRIris, { morphSVG: "#rc-eye-r-target", duration: DURATION, delay: 0.06, ease: EASE });
gsap.to(lcEyeLIris, {
morphSVG: "#lc-eye-l-target",
duration: DURATION,
ease: EASE_IN,
});
// base + overlays disparaissent vite pour ne pas masquer le morph de l'iris
gsap.to([lcEyeLBase, ...lcEyeLOverlays], {
opacity: 0,
duration: 0.08,
ease: "power1.in",
});
// Paupières + sourcils : apparition en fondu
gsap.to(eyeOverlays, { opacity: 1, duration: DURATION * 0.8, delay: DURATION * 0.3, ease: "power1.out" });
gsap.to(lcEyeRIris, {
morphSVG: "#lc-eye-r-target",
duration: DURATION,
delay: 0.04,
ease: EASE_IN,
});
gsap.to(rcEyeLIris, {
morphSVG: "#rc-eye-l-target",
duration: DURATION,
delay: 0.02,
ease: EASE_IN,
});
gsap.to(rcEyeRIris, {
morphSVG: "#rc-eye-r-target",
duration: DURATION,
delay: 0.06,
ease: EASE_IN,
});
gsap.to(faceOverlays, {
opacity: 1,
duration: DURATION * 0.8,
delay: DURATION * 0.25,
ease: "power1.out",
});
}
function morphToKawai() {
gsap.to(lcEyeLIris, { morphSVG: origins.lcEyeLIris, duration: DURATION, ease: EASE });
gsap.to(lcEyeLBase, { morphSVG: origins.lcEyeLBase, duration: DURATION, ease: EASE });
gsap.to(lcEyeLOverlays, { opacity: 1, duration: DURATION * 0.6, delay: DURATION * 0.5, ease: "power1.out" });
gsap.to(lcEyeLIris, {
morphSVG: origins.lcEyeLIris,
duration: DURATION,
ease: EASE_OUT,
});
// base + overlays réapparaissent seulement après que l'iris ait fini de morphier
gsap.to([lcEyeLBase, ...lcEyeLOverlays], {
opacity: 1,
duration: 0.1,
delay: DURATION,
ease: "power1.out",
});
gsap.to(lcEyeRIris, { morphSVG: origins.lcEyeRIris, duration: DURATION, delay: 0.04, ease: EASE });
gsap.to(rcEyeLIris, { morphSVG: origins.rcEyeLIris, duration: DURATION, delay: 0.02, ease: EASE });
gsap.to(rcEyeRIris, { morphSVG: origins.rcEyeRIris, duration: DURATION, delay: 0.06, ease: EASE });
gsap.to(lcEyeRIris, {
morphSVG: origins.lcEyeRIris,
duration: DURATION,
delay: 0.04,
ease: EASE_OUT,
});
gsap.to(rcEyeLIris, {
morphSVG: origins.rcEyeLIris,
duration: DURATION,
delay: 0.02,
ease: EASE_OUT,
});
gsap.to(rcEyeRIris, {
morphSVG: origins.rcEyeRIris,
duration: DURATION,
delay: 0.06,
ease: EASE_OUT,
});
// Paupières + sourcils : disparition immédiate
gsap.to(eyeOverlays, { opacity: 0, duration: DURATION * 0.4, ease: "power1.in" });
gsap.to(faceOverlays, {
opacity: 0,
duration: DURATION * 0.35,
ease: "power2.in",
});
blink();
}
const identity = document.querySelector(".identity");

View file

@ -12,8 +12,9 @@ export function initMorphMouth() {
const rcMouthOrigin = rcMouth.getAttribute("d");
const DURATION = 0.3;
const EASE = "power2.inOut";
const STAGGER = 0.06;
const EASE_IN = "elastic.out(1.3, 0.35)";
const EASE_OUT = "elastic.out(1.3, 0.35)";
const STAGGER = 0.06;
function morphToNoOutfit() {
gsap.to(lcMouth, {
@ -21,7 +22,7 @@ export function initMorphMouth() {
fill: "black",
stroke: "transparent",
duration: DURATION,
ease: EASE,
ease: EASE_IN,
});
gsap.to(rcMouth, {
morphSVG: "#rc-mouth-target",
@ -29,7 +30,7 @@ export function initMorphMouth() {
stroke: "transparent",
duration: DURATION,
delay: STAGGER,
ease: EASE,
ease: EASE_IN,
});
}
@ -39,7 +40,7 @@ export function initMorphMouth() {
fill: "none",
stroke: "black",
duration: DURATION,
ease: EASE,
ease: EASE_OUT,
});
gsap.to(rcMouth, {
morphSVG: rcMouthOrigin,
@ -47,7 +48,7 @@ export function initMorphMouth() {
stroke: "black",
duration: DURATION,
delay: STAGGER,
ease: EASE,
ease: EASE_OUT,
});
}