שורות טקסט מודבקות על גליל שמסתובב סביב ציר אופקי עם הגלילה. השורה הקדמית קריאה ומלאה, האחרות מתעקלות למעלה ולמטה ודוהות. רולודקס של שירותים.
מתי משתמשים: רשימת שירותים, ערכים, ענפים שעובדים איתם. חמש עד תשע שורות קצרות.
הדמו כאן עיצובי-ניטרלי בכוונה. כשהמהלך נכנס לפרויקט, מיובאת רק ההתנהגות: הצבעים, הרדיוסים, הפונטים והצללים יורשים את העיצוב של אותו פרויקט.
הקוד כאן עומד בפני עצמו. כל טוקן עיצוב נושא ברירת מחדל, מחלקות העזר של המאגר מוטמעות בו, ותגי הסקריפט מסודרים לפי הסדר הנכון. פרויקט שמגדיר --accent או --line משלו יורש אותם אוטומטית. הרכיב הזה מסתמך על dir="rtl".
/* G99 · גליל טקסט תלת-ממדי */
.cyl{position:relative;height:260vh}
.cyl-pin{position:sticky;top:0;height:100vh;display:grid;place-items:center;perspective:1100px;overflow:hidden}
.cyl-drum{position:relative;width:min(900px,92vw);height:1.2em;font-size:clamp(26px,4.6vw,64px);font-weight:800;transform-style:preserve-3d;will-change:transform}
.cyl-line{position:absolute;inset:0;display:flex;align-items:baseline;justify-content:center;gap:.5em;white-space:nowrap;backface-visibility:hidden;color:var(--ink, #16182b)}
.cyl-line small{font-size:.38em;font-weight:500;color:var(--accent, #4a3aff);margin-inline-start:.6em;letter-spacing:.1em}
.cyl-fade{position:absolute;inset:0;pointer-events:none;background:linear-gradient(180deg,var(--bg, #f7f7fa) 0%,transparent 30%,transparent 70%,var(--bg, #f7f7fa) 100%)}
@media(max-width:767px){.cyl{height:200vh}.cyl-pin{perspective:700px}}
<div class="cyl">
<div class="cyl-pin"><div class="cyl-drum">
<div class="cyl-line">אתרי תדמית<small>01</small></div><div class="cyl-line">דפי נחיתה<small>02</small></div><div class="cyl-line">חנויות אונליין<small>03</small></div>
<div class="cyl-line">מערכות ניהול<small>04</small></div><div class="cyl-line">אוטומציות<small>05</small></div><div class="cyl-line">קופי ואסטרטגיה<small>06</small></div><div class="cyl-line">ליווי שוטף<small>07</small></div>
</div><div class="cyl-fade"></div></div>
</div>
gsap.registerPlugin(ScrollTrigger);
(function(){
const drum=document.querySelector(".cyl-drum"),lines=gsap.utils.toArray(".cyl-line"),n=lines.length;
// לא גליל מלא של 360: קשת של 30 מעלות לשורה, כך שרואים רק שלוש מעל ושלוש מתחת והן לא נערמות.
// הרדיוס נגזר מגובה השורה כדי ששורות סמוכות לא יחפפו.
const step=matchMedia("(max-width:767px)").matches?26:30;
// לא דרך gsap.set: GSAP מסדר תמיד הזזה לפני סיבוב, ואז השורה רק מסתובבת במקום ב-z קבוע.
// כאן חייבים rotateX ואז translateZ, כלומר מחרוזת transform ידנית.
function place(){const h=drum.offsetHeight,r=(h*1.15)/(2*Math.tan(step*Math.PI/360));lines.forEach((l,i)=>{l.style.transform="rotateX("+(i*step)+"deg) translateZ("+r+"px)";});gsap.set(drum,{z:-r});}
place();addEventListener("resize",place);
if(matchMedia("(prefers-reduced-motion: reduce)").matches)return;
// כל שורה עוצרת רגע בחזית: ease לכל צעד במקום סיבוב ליניארי
const tl=gsap.timeline({scrollTrigger:{trigger:".cyl",start:"top top",end:"bottom bottom",scrub:.6}});
for(let i=1;i<n;i++)tl.to(drum,{rotateX:-i*step,duration:1,ease:"power2.inOut"},i-1+.15);
})();