This commit is contained in:
Your Name committed 2026-10-17 08:11:33 +07:00
1 parent 34be2599fa
commit 3f9db48df4
8 files changed
+2037 -4

No files matched your search

+449
View File
@@ -0,0 +1,449 @@
<!doctype html>
<html lang="th">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>TOBAKI Story Scroll Mockup</title>
<style>
:root{
--bg:#f6f3ea;
--ink:#111;
--muted:#6d6a62;
--blue:#1267ff;
--gold:#d8b35a;
--dark:#0c1320;
--panel:#ffffff;
--line:#d8d3c8;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
margin:0;
font-family:Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color:var(--ink);
background:var(--bg);
}
/* ---------- top product block ---------- */
.product-top{
min-height:92vh;
display:grid;
grid-template-columns:1.05fr 1fr;
gap:4vw;
align-items:center;
padding:8vh 8vw;
background:#f7f4ec;
border-bottom:1px solid #e5e0d6;
}
.gallery{
display:grid;
grid-template-columns:72px 1fr;
gap:20px;
align-items:center;
}
.thumbs{display:flex;flex-direction:column;gap:12px}
.thumb{
aspect-ratio:1;
border:1px solid #ddd5c9;
background:#fff;
border-radius:14px;
display:grid;
place-items:center;
color:#8c877e;
font-size:11px;
}
.thumb.active{border:2px solid #d8b35a}
.product-stage{
min-height:520px;
border-radius:28px;
background:#fff;
border:1px solid #e5dfd4;
display:grid;
place-items:center;
box-shadow:0 24px 60px rgba(0,0,0,.05);
position:relative;
overflow:hidden;
}
.fake-pack{
width:44%;
height:64%;
background:linear-gradient(180deg,#151515 0 18%,#d9b35a 18% 100%);
border-radius:18px;
box-shadow:0 30px 50px rgba(0,0,0,.14);
position:absolute;
left:18%;
}
.fake-pad{
width:28%;
height:14%;
background:#c79b43;
border-radius:50px 26px 26px 50px;
position:absolute;
right:14%;
top:44%;
transform:rotate(-18deg);
box-shadow:0 16px 24px rgba(0,0,0,.12);
}
.product-info h1{font-size:clamp(36px,4vw,64px);line-height:.98;margin:0 0 18px}
.eyebrow{font-size:12px;letter-spacing:.18em;font-weight:800}
.desc{color:var(--muted);font-size:17px;line-height:1.7;max-width:620px}
.price{font-size:52px;font-weight:900;margin:34px 0 10px}
.selector,.buyrow{
display:flex;gap:14px;align-items:center;margin-top:18px
}
.selectbox{
flex:1;padding:18px 20px;border-radius:16px;background:#fff;border:1px solid #e0dbd1
}
.qty{padding:18px 22px;border-radius:16px;background:#fff;border:1px solid #e0dbd1}
.cart{
flex:1;padding:19px 26px;border-radius:16px;background:#171a18;color:#fff;text-align:center;font-weight:800
}
/* ---------- story ---------- */
.story-wrap{
position:relative;
background:var(--dark);
color:#fff;
}
.story-progress{
position:fixed;
right:24px;
top:50%;
transform:translateY(-50%);
z-index:50;
display:flex;
flex-direction:column;
gap:10px;
opacity:0;
pointer-events:none;
transition:.25s ease;
}
.story-progress.show{opacity:1}
.dot{width:8px;height:8px;border-radius:99px;background:rgba(255,255,255,.28)}
.dot.active{height:26px;background:#fff}
.story{
position:relative;
}
.sticky-stage{
position:sticky;
top:0;
height:100vh;
overflow:hidden;
display:grid;
place-items:center;
background:
radial-gradient(circle at 34% 50%, rgba(20,103,255,.23), transparent 32%),
linear-gradient(180deg,#0c1320 0%, #0a0f18 100%);
}
.product-core{
position:absolute;
left:11vw;
top:50%;
transform:translateY(-50%);
width:min(42vw,640px);
aspect-ratio:1;
border-radius:50%;
border:28px solid #1467ff;
box-shadow:
inset -30px -15px 0 #050a10,
0 0 60px rgba(18,103,255,.32);
transition:all .5s ease;
}
.product-core:after{
content:"";
position:absolute;
inset:12%;
border-radius:50%;
border:22px solid #16181b;
}
.product-core:before{
content:"";
position:absolute;
left:-14%; right:-14%; bottom:-12%;
height:18%;
filter:blur(18px);
background:rgba(0,0,0,.45);
border-radius:50%;
}
.scene-copy{
position:absolute;
left:56vw;
top:50%;
transform:translateY(-50%);
width:35vw;
max-width:650px;
opacity:0;
transition:opacity .35s ease, transform .35s ease;
}
.scene-copy.active{opacity:1;transform:translateY(-50%)}
.scene-copy .kicker{
color:#9fbfff;font-size:13px;letter-spacing:.18em;font-weight:800;margin-bottom:16px
}
.scene-copy h2{
font-size:clamp(44px,5vw,88px);
line-height:.92;
margin:0 0 18px;
letter-spacing:-.03em;
}
.scene-copy p{font-size:18px;line-height:1.65;color:#cdd4df;max-width:560px}
.metric{
font-size:clamp(64px,8vw,120px);
font-weight:900;
color:#fff;
letter-spacing:-.05em;
margin-top:20px;
}
.feature-row{display:flex;flex-wrap:wrap;gap:10px;margin-top:24px}
.chip{
padding:10px 14px;border:1px solid rgba(255,255,255,.18);
border-radius:999px;background:rgba(255,255,255,.05);
color:#e9edf4;font-size:13px
}
.trigger{
height:100vh;
position:relative;
}
/* visual states */
.story-wrap[data-scene="material"] .sticky-stage{
background:
radial-gradient(circle at 34% 50%, rgba(44,119,255,.26), transparent 30%),
linear-gradient(180deg,#0e1728 0%,#09101a 100%);
}
.story-wrap[data-scene="material"] .product-core{
transform:translateY(-50%) scale(1.18);
border-width:34px;
}
.story-wrap[data-scene="heat"] .sticky-stage{
background:
radial-gradient(circle at 30% 50%, rgba(255,94,0,.42), transparent 35%),
linear-gradient(110deg,#160c08,#111522 70%);
}
.story-wrap[data-scene="heat"] .product-core{
border-color:#ff7a00;
box-shadow:inset -30px -15px 0 #050a10,0 0 80px rgba(255,122,0,.55);
}
.story-wrap[data-scene="friction"] .sticky-stage{
background:
linear-gradient(rgba(255,255,255,.04) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,.04) 1px, transparent 1px),
linear-gradient(180deg,#0b1018,#080c13);
background-size:40px 40px,40px 40px,auto;
}
.story-wrap[data-scene="control"] .product-core{
transform:translateY(-50%) rotate(-18deg) scale(.93);
}
.story-wrap[data-scene="durability"] .sticky-stage{
background:
radial-gradient(circle at 75% 70%, rgba(216,179,90,.2), transparent 28%),
linear-gradient(120deg,#101722,#0a0e15);
}
.story-wrap[data-scene="fitment"] .sticky-stage{
background:linear-gradient(180deg,#f6f3ea,#ece7dc);
color:#111;
}
.story-wrap[data-scene="fitment"] .scene-copy p{color:#5d5a54}
.story-wrap[data-scene="fitment"] .product-core{
left:8vw;
transform:translateY(-50%) scale(.82);
}
.fit-grid{
display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-top:26px
}
.fit-grid span{
padding:13px 14px;border-radius:12px;background:#fff;color:#111;text-align:center;
border:1px solid #d7d1c6;font-size:13px;font-weight:700
}
.end-cta{
min-height:65vh;
display:grid;
place-items:center;
text-align:center;
padding:10vh 8vw;
background:#f6f3ea;
}
.end-cta h3{font-size:clamp(44px,5vw,80px);margin:0}
.end-cta p{color:#6f6a61;font-size:18px}
.end-cta .btn{
display:inline-block;margin-top:20px;background:#171a18;color:#fff;
padding:16px 26px;border-radius:14px;font-weight:800
}
.note{
position:fixed;left:20px;bottom:20px;z-index:60;
background:rgba(255,255,255,.9);backdrop-filter:blur(10px);
color:#111;padding:10px 13px;border-radius:12px;font-size:12px;
box-shadow:0 12px 30px rgba(0,0,0,.12)
}
@media(max-width:900px){
.product-top{grid-template-columns:1fr;padding:6vh 5vw}
.gallery{grid-template-columns:1fr}
.thumbs{flex-direction:row}
.thumb{width:64px}
.product-stage{min-height:390px}
.product-core{left:50%;top:31%;transform:translate(-50%,-50%);width:70vw}
.scene-copy{left:8vw;top:auto;bottom:8vh;transform:none;width:84vw}
.scene-copy.active{transform:none}
.scene-copy h2{font-size:48px}
.story-wrap[data-scene="material"] .product-core,
.story-wrap[data-scene="control"] .product-core,
.story-wrap[data-scene="fitment"] .product-core{left:50%;transform:translate(-50%,-50%) scale(.9)}
}
</style>
</head>
<body>
<section class="product-top">
<div class="gallery">
<div class="thumbs">
<div class="thumb active">IMG 01</div>
<div class="thumb">IMG 02</div>
<div class="thumb">IMG 03</div>
<div class="thumb">DETAIL</div>
<div class="thumb">TEXTURE</div>
</div>
<div class="product-stage">
<div class="fake-pack"></div>
<div class="fake-pad"></div>
</div>
</div>
<div class="product-info">
<div class="eyebrow">TOBAKI / BRAKING SYSTEM</div>
<h1>X Ceramic Brake Pad</h1>
<p class="desc">ช่วงแรกของหน้าเป็น Product Detail แบบปกติ — ดูภาพ, เลือกรุ่น, ราคา, สต๊อก และสั่งซื้อได้ทันที</p>
<div class="price">฿3</div>
<div class="selector">
<div class="selectbox">SELECT MODEL: <b>ADV150 / ADV160 (F)</b></div>
</div>
<div class="buyrow">
<div class="qty">− &nbsp; 1 &nbsp; +</div>
<div class="cart">Add to Cart</div>
</div>
</div>
</section>
<section class="story-wrap" id="story" data-scene="hero">
<div class="story-progress" id="progress">
<div class="dot active"></div><div class="dot"></div><div class="dot"></div>
<div class="dot"></div><div class="dot"></div><div class="dot"></div><div class="dot"></div>
</div>
<div class="story">
<div class="sticky-stage">
<div class="product-core" aria-hidden="true"></div>
<div class="scene-copy active" data-copy="hero">
<div class="kicker">01 / PRODUCT STORY</div>
<h2>STOP WITH<br>CONFIDENCE.</h2>
<p>เริ่ม Story แบบภาพใหญ่เต็มจอ ให้สินค้ากลายเป็นพระเอก ก่อนจะพาคนดูลงลึกไปทีละประเด็น</p>
</div>
<div class="scene-copy" data-copy="material">
<div class="kicker">02 / MATERIAL</div>
<h2>CERAMIC<br>COMPOUND.</h2>
<p>ซูมเข้าเนื้อผ้าเบรก แล้วอธิบายเรื่อง Low Noise, Low Vibration และ Brake Dust ต่ำลง</p>
<div class="feature-row">
<span class="chip">Low Noise</span><span class="chip">Low Vibration</span><span class="chip">Cleaner Braking</span>
</div>
</div>
<div class="scene-copy" data-copy="heat">
<div class="kicker">03 / HEAT CONTROL</div>
<h2>HIGH-HEAT<br>CONTROL.</h2>
<div class="metric">300°C</div>
<p>ฉากเปลี่ยนจาก Blue → Orange/Heat เพื่อสื่อ Brake Fade Resistance แบบเห็นความต่างทันที</p>
</div>
<div class="scene-copy" data-copy="friction">
<div class="kicker">04 / PERFORMANCE</div>
<h2>STABLE<br>FRICTION.</h2>
<p>พื้นหลังเปลี่ยนเป็น Technical Grid / Data Scene เพื่อเล่าเรื่องแรงเสียดทานคงที่ โดยไม่ต้องทำ Dashboard หนัก ๆ</p>
</div>
<div class="scene-copy" data-copy="control">
<div class="kicker">05 / CONTROL</div>
<h2>SMOOTH<br>ENGAGEMENT.</h2>
<p>สินค้าเริ่มหมุน/เปลี่ยนมุม มองเห็นโครงสร้างและสปริง สื่อถึง Predictable Modulation และการควบคุมที่นุ่มนวล</p>
</div>
<div class="scene-copy" data-copy="durability">
<div class="kicker">06 / DURABILITY</div>
<h2>BUILT<br>TO LAST.</h2>
<p>เปลี่ยน mood เป็นการใช้งานระยะยาว และเล่าจุดขายเรื่อง Durable Lifespan, Rotor Friendly และ Everyday Confidence</p>
<div class="feature-row">
<span class="chip">Durable</span><span class="chip">Rotor Friendly</span><span class="chip">Everyday Use</span>
</div>
</div>
<div class="scene-copy" data-copy="fitment">
<div class="kicker">07 / FITMENT</div>
<h2>MADE FOR<br>YOUR BIKE.</h2>
<p>Story ปิดท้ายด้วยรุ่นรถที่รองรับ ก่อนส่งผู้ใช้กลับเข้าสู่ flow การเลือก Model และซื้อสินค้า</p>
<div class="fit-grid">
<span>NVX155</span><span>LC135</span><span>Vario125</span>
<span>Vario150</span><span>PCX150</span><span>Beat110 FI</span>
</div>
</div>
</div>
<div class="trigger" data-scene="hero"></div>
<div class="trigger" data-scene="material"></div>
<div class="trigger" data-scene="heat"></div>
<div class="trigger" data-scene="friction"></div>
<div class="trigger" data-scene="control"></div>
<div class="trigger" data-scene="durability"></div>
<div class="trigger" data-scene="fitment"></div>
</div>
</section>
<section class="end-cta">
<div>
<div class="eyebrow">END OF PRODUCT STORY</div>
<h3>SELECT YOUR MODEL.</h3>
<p>หลังจบ Story ค่อยพากลับมาที่ Conversion อีกครั้ง ไม่ต้องให้ animation แย่งกับการซื้อสินค้า</p>
<div class="btn">Choose Your Bike</div>
</div>
</section>
<div class="note">Scroll ลงเพื่อดู Story UX Mockup</div>
<script>
const story = document.getElementById('story');
const progress = document.getElementById('progress');
const triggers = [...document.querySelectorAll('.trigger')];
const copies = [...document.querySelectorAll('.scene-copy')];
const dots = [...document.querySelectorAll('.dot')];
const observer = new IntersectionObserver((entries)=>{
entries.forEach(entry=>{
if(entry.isIntersecting){
const scene = entry.target.dataset.scene;
story.dataset.scene = scene;
copies.forEach(c=>c.classList.toggle('active', c.dataset.copy === scene));
const i = triggers.indexOf(entry.target);
dots.forEach((d,idx)=>d.classList.toggle('active',idx===i));
}
});
},{threshold:.55});
triggers.forEach(t=>observer.observe(t));
const visibilityObserver = new IntersectionObserver((entries)=>{
entries.forEach(e=>progress.classList.toggle('show', e.isIntersecting));
},{threshold:.1});
visibilityObserver.observe(story);
</script>
</body>
</html>