Files
homaroma/story-line/tobaki_story_scroll_mockup.html
T
2026-10-17 08:11:33 +07:00

450 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>