44 * Layout: Flexbox "podium" — 3 phones side-by-side, center elevated.
55 * Anim: Asymmetric bottom-to-center push with:
66 * • center-first stagger (manual timeline offsets)
7- * • per-phone randomised duration & ease
8- * • trigger-once auto-play (NOT scrub-bound)
7+ * • per-phone randomised ease
8+ * • scroll-scrubbed ( scrub: 1) — phones follow scroll
99 *
10- * Trigger: when the section scrolls into view (~60% of viewport),
11- * the timeline plays automatically in ~1 s.
12- * Scrolling back up reverses it.
10+ * Trigger: tight scroll interval from "top 80%" to "center 45%"
11+ * on #phones-wrap. No pin, no sticky — pure scrub.
1312 *
1413 * Relies on window.gsap & window.ScrollTrigger loaded via CDN.
1514 * Called by router.js after the home view is injected into the DOM.
@@ -79,33 +78,29 @@ export function initShowcase() {
7978 /* ─────────────────────────────────────────────────────
8079 * PER-PHONE RANDOMISED CONFIGS
8180 *
82- * 【改动】duration 区间从 0.48-0.70 提升到 0.8-1.2 秒,
83- * 因为去掉 scrub 后时长由真实秒数决定,需要稍长一些
84- * 才能看起来干脆利落而非一闪而过 。
81+ * scrub 模式下 duration 只决定时间轴内各 tween 的
82+ * 相对权重,不再对应真实秒数。统一用 0.5 保持均匀,
83+ * 差异化靠 ease 和 stagger offset 体现 。
8584 * ───────────────────────────────────────────────────── */
86- const cfgC = { dur : rand ( 0.80 , 0.95 ) , ease : randomEase ( ) } ; // center (fastest)
87- const cfgL = { dur : rand ( 0.95 , 1.15 ) , ease : randomEase ( ) } ; // left
88- const cfgR = { dur : rand ( 0.95 , 1.15 ) , ease : randomEase ( ) } ; // right
85+ const cfgC = { dur : 0.5 , ease : randomEase ( ) } ; // center
86+ const cfgL = { dur : 0.5 , ease : randomEase ( ) } ; // left
87+ const cfgR = { dur : 0.5 , ease : randomEase ( ) } ; // right
8988
9089 /* ─────────────────────────────────────────────────────
91- * SCROLL-TRIGGERED AUTO-PLAY TIMELINE
90+ * SCROLL-SCRUBBED TIMELINE
9291 *
93- * 【核心改动】
94- * ① 移除 scrub — 不再绑定滚轮进度
95- * ② 移除 end / markers
96- * ③ 添加 toggleActions — 滚入自动播放,滚回自动倒放
97- * ④ trigger 指向手机容器 — 确保标题已可见后才触发
98- * ⑤ start: "top 65%" — 容器顶部到达视口 65% 处触发
99- * (用户刚好看完标题和副标题)
92+ * ① scrub: 1 — 手机跟随滚轮进度,1s 平滑缓冲
93+ * ② start: "top 80%" — 容器顶部到达视口 80% 时开始
94+ * ③ end: "center 45%" — 容器中点到达视口 45% 时完成
95+ * → 紧凑触发区间,不拖沓
96+ * ④ 无 pin / toggleActions — 不会产生粘滞或空白
10097 * ───────────────────────────────────────────────────── */
10198 const tl = gsap . timeline ( {
10299 scrollTrigger : {
103- trigger : '#phones-wrap' , // 手机容器,而非整个 section
104- start : 'top 65%' , // 容器顶部到达视口 65% 处
105- toggleActions : 'play none none reverse' ,
106- // ↑ ↑ ↑ ↑
107- // onEnter onLeave onEnterBack onLeaveBack
108- // 播放 不动 不动 倒放回去
100+ trigger : '#phones-wrap' ,
101+ start : 'top 80%' ,
102+ end : 'center 45%' ,
103+ scrub : 1 ,
109104 } ,
110105 } ) ;
111106
@@ -121,28 +116,26 @@ export function initShowcase() {
121116 } , 0 ) ;
122117
123118 /*
124- * LEFT PHONE — 0.12s after center
125- * 【改动】stagger 间隔从 0.08 增大到 0.12,
126- * 配合更长的 duration 保持节奏感。
119+ * LEFT PHONE — offset 0.10 after center in timeline units
127120 */
128121 tl . to ( pL , {
129122 y : podium . sideY ,
130123 opacity : 1 ,
131124 scale : 1 ,
132125 duration : cfgL . dur ,
133126 ease : cfgL . ease ,
134- } , 0.12 ) ;
127+ } , 0.10 ) ;
135128
136129 /*
137- * RIGHT PHONE — same 0.12s stagger as left
130+ * RIGHT PHONE — same offset as left
138131 */
139132 tl . to ( pR , {
140133 y : podium . sideY ,
141134 opacity : 1 ,
142135 scale : 1 ,
143136 duration : cfgR . dur ,
144137 ease : cfgR . ease ,
145- } , 0.12 ) ;
138+ } , 0.10 ) ;
146139
147140 /*
148141 * Labels now live inside each .ag-iphone container,
0 commit comments