Magnetic Field hero, Thai eyebrows, black text-stroke, service pages fixes
- Hero: Magnetic Field design (ripple rings, field curves, attract animations) - H1: เปลี่ยนเป็น 'เป้าหมายของเราคือการเพิ่มกำไรให้ลูกค้า', กำไร เน้นขอบดำ - Site: ทุก eyebrow แปลเป็นไทย - Buttons: text สีดำทุกหน้าแม้ใน dark section - Yellow text: เพิ่ม -webkit-text-stroke ขอบดำทุก element - Service pages: light/light/dark pattern, process-grid แถวเดียว - Logo: อัพเดทใหม่ - Demos: เพิ่ม 5 hero design concepts (orbital, energy flow, holographic, constellation, magnetic)
This commit is contained in:
182
public/demos/a-orbital.html
Normal file
182
public/demos/a-orbital.html
Normal file
@@ -0,0 +1,182 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>A: Orbital — ระบบดาวเคราะห์</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #0a0f1a;
|
||||
color: #fff;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
min-height: 100vh; overflow: hidden;
|
||||
}
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
|
||||
.demo { position: relative; width: 650px; height: 580px; }
|
||||
|
||||
/* Canvas for orbital rings */
|
||||
canvas#orbitalCanvas {
|
||||
position: absolute; inset: 0; pointer-events: none; z-index: 1;
|
||||
}
|
||||
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d;
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute; border-radius: 50%;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center;
|
||||
text-align: center; backface-visibility: hidden;
|
||||
}
|
||||
|
||||
/* Center Sun */
|
||||
.sun {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 170px; height: 170px;
|
||||
background: radial-gradient(circle at 40% 35%, #fff7cc, #fed400 40%, #d4a000 100%);
|
||||
box-shadow: 0 0 60px rgba(254,212,0,0.6), 0 0 120px rgba(254,212,0,0.3), 0 0 200px rgba(254,180,0,0.15);
|
||||
z-index: 10; animation: sunPulse 3s ease-in-out infinite;
|
||||
}
|
||||
@keyframes sunPulse {
|
||||
0%, 100% { box-shadow: 0 0 60px rgba(254,212,0,0.6), 0 0 120px rgba(254,212,0,0.3), 0 0 200px rgba(254,180,0,0.15); }
|
||||
50% { box-shadow: 0 0 80px rgba(254,212,0,0.8), 0 0 150px rgba(254,212,0,0.4), 0 0 230px rgba(254,180,0,0.2); }
|
||||
}
|
||||
.sun .label { font-size: 2.8rem; font-weight: 900; color: #3a2e00; }
|
||||
.sun .sub { font-size: 0.75rem; color: #6b5500; margin-top: 4px; font-weight: 600; }
|
||||
|
||||
/* Orbiting planets */
|
||||
.planet {
|
||||
width: 110px; height: 110px;
|
||||
background: rgba(255,255,255,0.06);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1.5px solid rgba(255,255,255,0.2);
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.15);
|
||||
left: 50%; top: 50%;
|
||||
animation: orbit var(--orbit-dur) linear infinite;
|
||||
z-index: 5;
|
||||
}
|
||||
.planet:nth-child(2) { --orbit-dur: 12s; --radius: 230px; --angle: 0deg; --z: -40px; }
|
||||
.planet:nth-child(3) { --orbit-dur: 15s; --radius: 280px; --angle: 120deg; --z: -70px; }
|
||||
.planet:nth-child(4) { --orbit-dur: 18s; --radius: 330px; --angle: 240deg; --z: -100px; }
|
||||
|
||||
@keyframes orbit {
|
||||
0% { transform: translate(-50%, -50%) rotate(0deg) translateX(var(--radius)) rotate(0deg); }
|
||||
100% { transform: translate(-50%, -50%) rotate(360deg) translateX(var(--radius)) rotate(-360deg); }
|
||||
}
|
||||
|
||||
.planet .tag { font-size: 1rem; font-weight: 800; color: #fff; text-transform: uppercase; }
|
||||
.planet .desc { font-size: 0.7rem; color: rgba(255,255,255,0.6); margin-top: 4px; }
|
||||
|
||||
/* Connecting lines (drawn on canvas) */
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(255,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">A. Orbital — ระบบดาวเคราะห์โคจร</span>
|
||||
<div class="demo">
|
||||
<canvas id="orbitalCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node sun" data-node="center">
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node planet" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node planet" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุนและเวลา</span>
|
||||
</div>
|
||||
<div class="node planet" data-node="biz">
|
||||
<span class="tag">Business<br>Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('orbitalCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
function draw() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const sun = document.querySelector('[data-node="center"]');
|
||||
const planets = document.querySelectorAll('.planet');
|
||||
if (!sun) return;
|
||||
|
||||
const sunRect = sun.getBoundingClientRect();
|
||||
const sx = sunRect.left + sunRect.width/2 - rect.left;
|
||||
const sy = sunRect.top + sunRect.height/2 - rect.top;
|
||||
|
||||
// Draw orbital rings
|
||||
const sr = 85; // sun radius
|
||||
const radii = [230, 280, 330];
|
||||
radii.forEach((r, i) => {
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(sx, sy, r, r * 0.45, 0, 0, Math.PI * 2);
|
||||
ctx.strokeStyle = `rgba(254,212,0,${0.15 - i * 0.03})`;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.setLineDash([8, 14]);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
});
|
||||
|
||||
// Draw connection lines
|
||||
planets.forEach(p => {
|
||||
const pRect = p.getBoundingClientRect();
|
||||
const px = pRect.left + pRect.width/2 - rect.left;
|
||||
const py = pRect.top + pRect.height/2 - rect.top;
|
||||
|
||||
const dx = px - sx, dy = py - sy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
const r = 85;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(sx + (dx/dist)*r, sy + (dy/dist)*r);
|
||||
ctx.lineTo(px - (dx/dist)*55, py - (dy/dist)*55);
|
||||
const grad = ctx.createLinearGradient(sx, sy, px, py);
|
||||
grad.addColorStop(0, 'rgba(254,212,0,0.7)');
|
||||
grad.addColorStop(1, 'rgba(254,212,0,0.15)');
|
||||
ctx.strokeStyle = grad;
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.stroke();
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
// Mouse parallax
|
||||
document.addEventListener('mousemove', e => {
|
||||
const x = (e.clientX / window.innerWidth - 0.5) * 8;
|
||||
const y = (e.clientY / window.innerHeight - 0.5) * -8;
|
||||
scene.style.transform = `rotateX(${y}deg) rotateY(${x}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
180
public/demos/b-energyflow.html
Normal file
180
public/demos/b-energyflow.html
Normal file
@@ -0,0 +1,180 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>B: Energy Flow — กระแสพลังงาน</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #080d14;
|
||||
color: #fff; overflow: hidden;
|
||||
display: flex; align-items: center; justify-content: center; min-height: 100vh;
|
||||
}
|
||||
.demo { position: relative; width: 650px; height: 580px; }
|
||||
canvas#flowCanvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d;
|
||||
transition: transform 0.3s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; text-align: center;
|
||||
}
|
||||
|
||||
/* Core */
|
||||
.core {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 160px; height: 160px; border-radius: 50%;
|
||||
background: radial-gradient(circle at 35% 30%, #2a1a00, #100800);
|
||||
border: 2px solid rgba(254,212,0,0.8);
|
||||
box-shadow: 0 0 40px rgba(254,212,0,0.3), 0 0 80px rgba(254,180,0,0.1), inset 0 0 40px rgba(254,212,0,0.08);
|
||||
z-index: 10;
|
||||
animation: coreBeat 2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes coreBeat {
|
||||
0%, 100% { box-shadow: 0 0 40px rgba(254,212,0,0.3), 0 0 80px rgba(254,180,0,0.1), inset 0 0 40px rgba(254,212,0,0.08); }
|
||||
50% { box-shadow: 0 0 60px rgba(254,212,0,0.5), 0 0 100px rgba(254,180,0,0.2), inset 0 0 50px rgba(254,212,0,0.12); }
|
||||
}
|
||||
.core .label { font-size: 2.6rem; font-weight: 900; color: #fed400; }
|
||||
.core .sub { font-size: 0.7rem; color: rgba(254,212,0,0.5); margin-top: 4px; font-weight: 600; }
|
||||
|
||||
/* Satellites */
|
||||
.satellite {
|
||||
border-radius: 50%;
|
||||
background: rgba(255,255,255,0.04);
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(254,212,0,0.25);
|
||||
width: 120px; height: 120px;
|
||||
z-index: 5;
|
||||
left: 50%; top: 50%;
|
||||
}
|
||||
.satellite:nth-child(2) { transform: translate(-50%, -50%) translateY(-230px); animation: float1 4s ease-in-out infinite; }
|
||||
.satellite:nth-child(3) { transform: translate(-50%, -50%) translateX(220px) translateY(10px); animation: float2 4.5s ease-in-out infinite; }
|
||||
.satellite:nth-child(4) { transform: translate(-50%, -50%) translateX(-160px) translateY(190px); animation: float3 5s ease-in-out infinite; }
|
||||
@keyframes float1 { 0%,100%{ transform: translate(-50%,-50%) translateY(-230px); } 50%{ transform: translate(-50%,-50%) translateY(-245px); } }
|
||||
@keyframes float2 { 0%,100%{ transform: translate(-50%,-50%) translateX(220px) translateY(10px); } 50%{ transform: translate(-50%,-50%) translateX(235px) translateY(0px); } }
|
||||
@keyframes float3 { 0%,100%{ transform: translate(-50%,-50%) translateX(-160px) translateY(190px); } 50%{ transform: translate(-50%,-50%) translateX(-175px) translateY(205px); } }
|
||||
|
||||
.satellite .tag { font-size: 0.9rem; font-weight: 800; color: #fff; }
|
||||
.satellite .desc { font-size: 0.65rem; color: rgba(255,255,255,0.5); margin-top: 3px; }
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(255,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">B. Energy Flow — กระแสพลังงาน พร้อม particles</span>
|
||||
<div class="demo">
|
||||
<canvas id="flowCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node core" data-node="center">
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node satellite" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node satellite" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุนและเวลา</span>
|
||||
</div>
|
||||
<div class="node satellite" data-node="biz">
|
||||
<span class="tag">Business<br>Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('flowCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
// Particle system per connection
|
||||
const connections = [];
|
||||
let t = 0;
|
||||
|
||||
function draw() {
|
||||
t++;
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const sun = document.querySelector('[data-node="center"]');
|
||||
const sats = document.querySelectorAll('.satellite');
|
||||
if (!sun) { requestAnimationFrame(draw); return; }
|
||||
|
||||
const sr = sun.getBoundingClientRect();
|
||||
const sx = sr.left + sr.width/2 - rect.left;
|
||||
const sy = sr.top + sr.height/2 - rect.top;
|
||||
|
||||
sats.forEach((sat, i) => {
|
||||
const pr = sat.getBoundingClientRect();
|
||||
const px = pr.left + pr.width/2 - rect.left;
|
||||
const py = pr.top + pr.height/2 - rect.top;
|
||||
|
||||
const dx = px - sx, dy = py - sy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
// Draw stream line
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(sx + (dx/dist)*80, sy + (dy/dist)*80);
|
||||
ctx.lineTo(px - (dx/dist)*60, py - (dy/dist)*60);
|
||||
const grad = ctx.createLinearGradient(sx, sy, px, py);
|
||||
grad.addColorStop(0, 'rgba(254,212,0,0.6)');
|
||||
grad.addColorStop(0.5, 'rgba(254,212,0,0.3)');
|
||||
grad.addColorStop(1, 'rgba(254,212,0,0.1)');
|
||||
ctx.strokeStyle = grad;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Animated particles along the line
|
||||
const count = 12;
|
||||
for (let j = 0; j < count; j++) {
|
||||
const phase = (t * 0.03 + j / count + i * 0.33) % 1;
|
||||
const pp = phase < 0.5 ? phase * 2 : 2 - phase * 2;
|
||||
const x = sx + (dx/dist)*80 + dx * (1 - 80/dist - 60/dist) * phase;
|
||||
const y = sy + (dy/dist)*80 + dy * (1 - 80/dist - 60/dist) * phase;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 2.5, 0, Math.PI*2);
|
||||
ctx.fillStyle = `rgba(254,230,100,${0.8 * pp})`;
|
||||
ctx.fill();
|
||||
// Glow
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 5, 0, Math.PI*2);
|
||||
ctx.fillStyle = `rgba(254,212,0,${0.25 * pp})`;
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', e => {
|
||||
const x = (e.clientX / window.innerWidth - 0.5) * 6;
|
||||
const y = (e.clientY / window.innerHeight - 0.5) * -6;
|
||||
scene.style.transform = `rotateX(${y}deg) rotateY(${x}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
179
public/demos/c-holographic.html
Normal file
179
public/demos/c-holographic.html
Normal file
@@ -0,0 +1,179 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>C: Holographic 3D — Hologram Sci-Fi</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #020810;
|
||||
color: #fff; overflow: hidden;
|
||||
display: flex; align-items: center; justify-content: center; min-height: 100vh;
|
||||
}
|
||||
|
||||
.demo { position: relative; width: 700px; height: 600px; }
|
||||
canvas#holoCanvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d; perspective: 1200px;
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; text-align: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Center hologram */
|
||||
.holo-core {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 170px; height: 170px;
|
||||
background: radial-gradient(circle at 40% 35%, rgba(0,255,255,0.15), rgba(0,200,255,0.05));
|
||||
border: 2px solid rgba(0,255,255,0.5);
|
||||
box-shadow: 0 0 50px rgba(0,255,255,0.2), 0 0 100px rgba(0,200,255,0.08), inset 0 0 30px rgba(0,255,255,0.05);
|
||||
z-index: 10;
|
||||
animation: holoPulse 2.5s ease-in-out infinite;
|
||||
}
|
||||
@keyframes holoPulse {
|
||||
0%, 100% { border-color: rgba(0,255,255,0.5); box-shadow: 0 0 50px rgba(0,255,255,0.2), 0 0 100px rgba(0,200,255,0.08); }
|
||||
50% { border-color: rgba(0,255,255,0.8); box-shadow: 0 0 70px rgba(0,255,255,0.35), 0 0 120px rgba(0,200,255,0.15); }
|
||||
}
|
||||
.holo-core .label { font-size: 2.8rem; font-weight: 900; color: #0ff; text-shadow: 0 0 20px rgba(0,255,255,0.5); }
|
||||
.holo-core .sub { font-size: 0.7rem; color: rgba(0,255,255,0.5); margin-top: 4px; font-weight: 600; }
|
||||
|
||||
/* Scanline effect */
|
||||
.holo-core::after {
|
||||
content: ''; position: absolute; inset: 0; border-radius: 50%;
|
||||
background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,255,255,0.03) 2px, rgba(0,255,255,0.03) 4px);
|
||||
pointer-events: none; z-index: 1;
|
||||
}
|
||||
|
||||
/* Satellites - holographic */
|
||||
.holo-sat {
|
||||
width: 115px; height: 115px;
|
||||
background: rgba(0,255,255,0.04);
|
||||
border: 1.5px solid rgba(0,255,255,0.35);
|
||||
box-shadow: 0 0 25px rgba(0,255,255,0.1), inset 0 0 20px rgba(0,255,255,0.04);
|
||||
z-index: 5;
|
||||
left: 50%; top: 50%;
|
||||
}
|
||||
.holo-sat::after {
|
||||
content: ''; position: absolute; inset: 0; border-radius: 50%;
|
||||
background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,255,255,0.02) 2px, rgba(0,255,255,0.02) 4px);
|
||||
pointer-events: none;
|
||||
}
|
||||
.holo-sat:nth-child(2) { transform: translate(-50%,-50%) translate3d(-220px,-140px,-80px); animation: hfloat1 5s ease-in-out infinite; }
|
||||
.holo-sat:nth-child(3) { transform: translate(-50%,-50%) translate3d(180px,-20px,-30px); animation: hfloat2 6s ease-in-out infinite; }
|
||||
.holo-sat:nth-child(4) { transform: translate(-50%,-50%) translate3d(-100px,210px,-100px); animation: hfloat3 5.5s ease-in-out infinite; }
|
||||
@keyframes hfloat1 { 0%,100%{transform:translate(-50%,-50%) translate3d(-220px,-140px,-80px)} 50%{transform:translate(-50%,-50%) translate3d(-230px,-155px,-100px)} }
|
||||
@keyframes hfloat2 { 0%,100%{transform:translate(-50%,-50%) translate3d(180px,-20px,-30px)} 50%{transform:translate(-50%,-50%) translate3d(195px,-35px,-55px)} }
|
||||
@keyframes hfloat3 { 0%,100%{transform:translate(-50%,-50%) translate3d(-100px,210px,-100px)} 50%{transform:translate(-50%,-50%) translate3d(-115px,225px,-130px)} }
|
||||
|
||||
.holo-sat .tag { font-size: 0.9rem; font-weight: 800; color: #0ff; text-shadow: 0 0 10px rgba(0,255,255,0.4); }
|
||||
.holo-sat .desc { font-size: 0.65rem; color: rgba(0,255,255,0.5); margin-top: 3px; }
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(0,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">C. Holographic 3D — Hologram Sci-Fi</span>
|
||||
<div class="demo">
|
||||
<canvas id="holoCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node holo-core" data-node="center">
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node holo-sat" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node holo-sat" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุนและเวลา</span>
|
||||
</div>
|
||||
<div class="node holo-sat" data-node="biz">
|
||||
<span class="tag">Business<br>Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('holoCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize(); window.addEventListener('resize', resize);
|
||||
|
||||
let t = 0;
|
||||
function draw() {
|
||||
t++;
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const center = document.querySelector('[data-node="center"]');
|
||||
const sats = document.querySelectorAll('.holo-sat');
|
||||
if (!center) { requestAnimationFrame(draw); return; }
|
||||
|
||||
const cr = center.getBoundingClientRect();
|
||||
const cx = cr.left + cr.width/2 - rect.left;
|
||||
const cy = cr.top + cr.height/2 - rect.top;
|
||||
|
||||
sats.forEach((sat, i) => {
|
||||
const pr = sat.getBoundingClientRect();
|
||||
const px = pr.left + pr.width/2 - rect.left;
|
||||
const py = pr.top + pr.height/2 - rect.top;
|
||||
const dx = px - cx, dy = py - cy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
// Hologram beam line (dotted)
|
||||
ctx.beginPath();
|
||||
ctx.setLineDash([4, 8]);
|
||||
ctx.lineDashOffset = -t * 2;
|
||||
ctx.moveTo(cx + (dx/dist)*85, cy + (dy/dist)*85);
|
||||
ctx.lineTo(px - (dx/dist)*58, py - (dy/dist)*58);
|
||||
ctx.strokeStyle = 'rgba(0,255,255,0.3)';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
|
||||
// Glow nodes at intervals
|
||||
for (let j = 0; j < 5; j++) {
|
||||
const phase = ((t * 0.02 + j/5 + i*0.33) % 1);
|
||||
const x = cx + (dx/dist)*85 + dx * (1 - 85/dist - 58/dist) * phase;
|
||||
const y = cy + (dy/dist)*85 + dy * (1 - 85/dist - 58/dist) * phase;
|
||||
const alpha = Math.sin(phase * Math.PI);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 2, 0, Math.PI*2);
|
||||
ctx.fillStyle = `rgba(0,255,255,${0.6 * alpha})`;
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', e => {
|
||||
scene.style.transform = `rotateX(${(e.clientY/window.innerHeight-0.5)*-8}deg) rotateY(${(e.clientX/window.innerWidth-0.5)*8}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
208
public/demos/d-constellation.html
Normal file
208
public/demos/d-constellation.html
Normal file
@@ -0,0 +1,208 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>D: Constellation — แผนที่ดาว</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: radial-gradient(ellipse at center, #0d1520 0%, #040810 100%);
|
||||
color: #fff; overflow: hidden;
|
||||
display: flex; align-items: center; justify-content: center; min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Starfield background */
|
||||
.stars {
|
||||
position: fixed; inset: 0; z-index: 0; pointer-events: none;
|
||||
}
|
||||
|
||||
.demo { position: relative; width: 700px; height: 600px; z-index: 1; }
|
||||
canvas#constCanvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d;
|
||||
transition: transform 0.3s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; text-align: center;
|
||||
}
|
||||
|
||||
/* Polaris - main star */
|
||||
.star-main {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 150px; height: 150px; border-radius: 50%;
|
||||
background: radial-gradient(circle at 38% 35%, rgba(255,255,255,0.25), rgba(254,212,0,0.15) 50%, transparent 100%);
|
||||
z-index: 10;
|
||||
}
|
||||
.star-main .glow {
|
||||
position: absolute; inset: -30px; border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(254,212,0,0.08), transparent 70%);
|
||||
animation: starGlow 3s ease-in-out infinite;
|
||||
}
|
||||
@keyframes starGlow {
|
||||
0%, 100% { transform: scale(1); opacity: 0.5; }
|
||||
50% { transform: scale(1.15); opacity: 0.8; }
|
||||
}
|
||||
.star-main .label { font-size: 2.6rem; font-weight: 900; color: #fed400; text-shadow: 0 0 30px rgba(254,212,0,0.6); position: relative; z-index: 1; }
|
||||
.star-main .sub { font-size: 0.7rem; color: rgba(254,212,0,0.5); margin-top: 4px; font-weight: 600; position: relative; z-index: 1; }
|
||||
|
||||
/* Constellation stars */
|
||||
.c-star {
|
||||
width: 70px; height: 70px; border-radius: 50%;
|
||||
background: radial-gradient(circle at 40% 35%, rgba(255,255,255,0.15), transparent);
|
||||
z-index: 5;
|
||||
left: 50%; top: 50%;
|
||||
}
|
||||
/* Star twinkle */
|
||||
.c-star::before {
|
||||
content: ''; position: absolute; inset: -15px; border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(254,240,200,0.1), transparent 70%);
|
||||
animation: twinkle 4s ease-in-out infinite;
|
||||
}
|
||||
@keyframes twinkle {
|
||||
0%, 100% { opacity: 0.3; transform: scale(0.8); }
|
||||
50% { opacity: 0.7; transform: scale(1.15); }
|
||||
}
|
||||
|
||||
.c-star:nth-child(2)::before { animation-delay: 0s; }
|
||||
.c-star:nth-child(3)::before { animation-delay: 1.2s; }
|
||||
.c-star:nth-child(4)::before { animation-delay: 2.5s; }
|
||||
|
||||
/* Star points (4-point cross) */
|
||||
.c-star::after {
|
||||
content: ''; position: absolute; inset: -8px; border-radius: 50%;
|
||||
box-shadow:
|
||||
0 -25px 0 -8px rgba(254,240,200,0.3),
|
||||
0 25px 0 -8px rgba(254,240,200,0.3),
|
||||
-25px 0 0 -8px rgba(254,240,200,0.3),
|
||||
25px 0 0 -8px rgba(254,240,200,0.3);
|
||||
animation: starRotate 10s linear infinite;
|
||||
}
|
||||
@keyframes starRotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
|
||||
|
||||
.c-star:nth-child(2) { transform: translate(-50%,-50%) translate3d(-220px,-160px,-60px); }
|
||||
.c-star:nth-child(3) { transform: translate(-50%,-50%) translate3d(190px,-30px,-30px); }
|
||||
.c-star:nth-child(4) { transform: translate(-50%,-50%) translate3d(-120px,200px,-70px); }
|
||||
|
||||
.c-star .tag { font-size: 0.8rem; font-weight: 800; color: #fff; position: relative; z-index: 1; text-shadow: 0 0 15px rgba(255,255,255,0.4); }
|
||||
.c-star .desc { font-size: 0.6rem; color: rgba(255,255,255,0.5); margin-top: 2px; position: relative; z-index: 1; }
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(255,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">D. Constellation — แผนที่ดาว</span>
|
||||
|
||||
<!-- Starfield -->
|
||||
<svg class="stars" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient id="s"><stop offset="0%" stop-color="#fff" stop-opacity="0.8"/><stop offset="100%" stop-color="#fff" stop-opacity="0"/></radialGradient>
|
||||
</defs>
|
||||
<circle cx="8%" cy="12%" r="1.5" fill="#fff" opacity="0.6"/><circle cx="15%" cy="8%" r="1" fill="#fff" opacity="0.3"/>
|
||||
<circle cx="22%" cy="18%" r="0.8" fill="#fff" opacity="0.5"/><circle cx="78%" cy="10%" r="1.2" fill="#fff" opacity="0.4"/>
|
||||
<circle cx="85%" cy="22%" r="1" fill="#fff" opacity="0.3"/><circle cx="92%" cy="8%" r="0.6" fill="#fff" opacity="0.7"/>
|
||||
<circle cx="6%" cy="85%" r="1" fill="#fff" opacity="0.4"/><circle cx="14%" cy="92%" r="0.8" fill="#fff" opacity="0.5"/>
|
||||
<circle cx="88%" cy="88%" r="1.3" fill="#fff" opacity="0.35"/><circle cx="95%" cy="78%" r="0.7" fill="#fff" opacity="0.6"/>
|
||||
<circle cx="42%" cy="5%" r="0.9" fill="#fff" opacity="0.45"/><circle cx="55%" cy="3%" r="0.5" fill="#fff" opacity="0.55"/>
|
||||
<circle cx="65%" cy="92%" r="1.1" fill="#fff" opacity="0.3"/><circle cx="35%" cy="95%" r="0.7" fill="#fff" opacity="0.5"/>
|
||||
</svg>
|
||||
|
||||
<div class="demo">
|
||||
<canvas id="constCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node star-main" data-node="center">
|
||||
<div class="glow"></div>
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node c-star" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node c-star" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุน</span>
|
||||
</div>
|
||||
<div class="node c-star" data-node="biz">
|
||||
<span class="tag">Business Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('constCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize(); window.addEventListener('resize', resize);
|
||||
|
||||
function draw() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const center = document.querySelector('[data-node="center"]');
|
||||
const stars = document.querySelectorAll('.c-star');
|
||||
if (!center) { requestAnimationFrame(draw); return; }
|
||||
|
||||
const cr = center.getBoundingClientRect();
|
||||
const cx = cr.left + cr.width/2 - rect.left;
|
||||
const cy = cr.top + cr.height/2 - rect.top;
|
||||
|
||||
// Draw constellation lines (thin, elegant)
|
||||
stars.forEach((star, i) => {
|
||||
const pr = star.getBoundingClientRect();
|
||||
const px = pr.left + pr.width/2 - rect.left;
|
||||
const py = pr.top + pr.height/2 - rect.top;
|
||||
const dx = px - cx, dy = py - cy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
// Constellation line
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(cx + (dx/dist)*75, cy + (dy/dist)*75);
|
||||
ctx.lineTo(px - (dx/dist)*35, py - (dy/dist)*35);
|
||||
ctx.strokeStyle = 'rgba(254,240,200,0.25)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.setLineDash([2, 6]);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
|
||||
// Tiny connecting stars along line
|
||||
for (let j = 0; j < 3; j++) {
|
||||
const p = 0.25 + j * 0.25;
|
||||
const sx = cx + (dx/dist)*75 + dx * (1 - 75/dist - 35/dist) * p;
|
||||
const sy = cy + (dy/dist)*75 + dy * (1 - 75/dist - 35/dist) * p;
|
||||
ctx.beginPath();
|
||||
ctx.arc(sx, sy, 1.2, 0, Math.PI*2);
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.3)';
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', e => {
|
||||
scene.style.transform = `rotateX(${(e.clientY/window.innerHeight-0.5)*-5}deg) rotateY(${(e.clientX/window.innerWidth-0.5)*5}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
197
public/demos/e-magnetic.html
Normal file
197
public/demos/e-magnetic.html
Normal file
@@ -0,0 +1,197 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>E: Magnetic Field — สนามแม่เหล็ก</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #060a12;
|
||||
color: #fff; overflow: hidden;
|
||||
display: flex; align-items: center; justify-content: center; min-height: 100vh;
|
||||
}
|
||||
|
||||
.demo { position: relative; width: 700px; height: 600px; }
|
||||
canvas#magCanvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d;
|
||||
transition: transform 0.3s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; text-align: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Magnet core */
|
||||
.magnet {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 170px; height: 170px;
|
||||
background: radial-gradient(circle at 40% 35%, #3a2000, #0d0500);
|
||||
border: 3px solid #fed400;
|
||||
box-shadow: 0 0 0 12px rgba(254,212,0,0.1), 0 0 60px rgba(254,212,0,0.3), 0 0 140px rgba(254,180,0,0.1);
|
||||
z-index: 10;
|
||||
animation: magnetPulse 2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes magnetPulse {
|
||||
0%, 100% { box-shadow: 0 0 0 12px rgba(254,212,0,0.1), 0 0 60px rgba(254,212,0,0.3), 0 0 140px rgba(254,180,0,0.1); }
|
||||
50% { box-shadow: 0 0 0 18px rgba(254,212,0,0.15), 0 0 80px rgba(254,212,0,0.4), 0 0 160px rgba(254,180,0,0.15); }
|
||||
}
|
||||
.magnet .label { font-size: 2.6rem; font-weight: 900; color: #fed400; }
|
||||
.magnet .sub { font-size: 0.7rem; color: rgba(254,212,0,0.5); margin-top: 4px; font-weight: 600; }
|
||||
|
||||
/* Attracted nodes */
|
||||
.attract {
|
||||
width: 105px; height: 105px;
|
||||
background: rgba(254,212,0,0.04);
|
||||
border: 1.5px solid rgba(254,212,0,0.3);
|
||||
box-shadow: 0 0 20px rgba(254,212,0,0.08);
|
||||
z-index: 5;
|
||||
left: 50%; top: 50%;
|
||||
animation: attract 3s ease-in-out infinite alternate;
|
||||
}
|
||||
.attract:nth-child(2) {
|
||||
transform: translate(-50%,-50%) translate3d(-200px,-150px,-60px);
|
||||
animation-name: attract1;
|
||||
}
|
||||
.attract:nth-child(3) {
|
||||
transform: translate(-50%,-50%) translate3d(170px,-20px,-25px);
|
||||
animation-name: attract2;
|
||||
}
|
||||
.attract:nth-child(4) {
|
||||
transform: translate(-50%,-50%) translate3d(-100px,190px,-70px);
|
||||
animation-name: attract3;
|
||||
}
|
||||
|
||||
@keyframes attract1 {
|
||||
0% { transform: translate(-50%,-50%) translate3d(-220px,-160px,-80px); }
|
||||
100% { transform: translate(-50%,-50%) translate3d(-185px,-140px,-50px); }
|
||||
}
|
||||
@keyframes attract2 {
|
||||
0% { transform: translate(-50%,-50%) translate3d(185px,-25px,-35px); }
|
||||
100% { transform: translate(-50%,-50%) translate3d(155px,-15px,-20px); }
|
||||
}
|
||||
@keyframes attract3 {
|
||||
0% { transform: translate(-50%,-50%) translate3d(-120px,210px,-90px); }
|
||||
100% { transform: translate(-50%,-50%) translate3d(-90px,180px,-60px); }
|
||||
}
|
||||
|
||||
.attract .tag { font-size: 0.9rem; font-weight: 800; color: #fff; }
|
||||
.attract .desc { font-size: 0.65rem; color: rgba(255,255,255,0.5); margin-top: 3px; }
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(255,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">E. Magnetic Field — สนามแม่เหล็กดึงดูด</span>
|
||||
<div class="demo">
|
||||
<canvas id="magCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node magnet" data-node="center">
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node attract" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node attract" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุนและเวลา</span>
|
||||
</div>
|
||||
<div class="node attract" data-node="biz">
|
||||
<span class="tag">Business<br>Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('magCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize(); window.addEventListener('resize', resize);
|
||||
|
||||
let t = 0;
|
||||
function draw() {
|
||||
t++;
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const center = document.querySelector('[data-node="center"]');
|
||||
const nodes = document.querySelectorAll('.attract');
|
||||
if (!center) { requestAnimationFrame(draw); return; }
|
||||
|
||||
const cr = center.getBoundingClientRect();
|
||||
const cx = cr.left + cr.width/2 - rect.left;
|
||||
const cy = cr.top + cr.height/2 - rect.top;
|
||||
|
||||
// Magnetic field lines (ripple waves)
|
||||
for (let r = 0; r < 4; r++) {
|
||||
const radius = 95 + r * 30 + (t * 0.02) % 30;
|
||||
const alpha = Math.max(0, 0.25 - r * 0.06 - ((t * 0.02) % 30) / 120);
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx, cy, radius, 0, Math.PI*2);
|
||||
ctx.strokeStyle = `rgba(254,212,0,${alpha})`;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Connection lines with magnetic field arcs
|
||||
nodes.forEach((node, i) => {
|
||||
const pr = node.getBoundingClientRect();
|
||||
const px = pr.left + pr.width/2 - rect.left;
|
||||
const py = pr.top + pr.height/2 - rect.top;
|
||||
const dx = px - cx, dy = py - cy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
// Main connection
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(cx + (dx/dist)*85, cy + (dy/dist)*85);
|
||||
ctx.lineTo(px - (dx/dist)*53, py - (dy/dist)*53);
|
||||
ctx.strokeStyle = `rgba(254,212,0,0.4)`;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Field curve arcs on both sides
|
||||
for (let side = -1; side <= 1; side += 2) {
|
||||
const offset = side * 15;
|
||||
const midX = cx + dx * 0.5 + (-dy/dist) * offset;
|
||||
const midY = cy + dy * 0.5 + (dx/dist) * offset;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(cx + (dx/dist)*85, cy + (dy/dist)*85);
|
||||
ctx.quadraticCurveTo(midX, midY, px - (dx/dist)*53, py - (dy/dist)*53);
|
||||
ctx.strokeStyle = `rgba(254,212,0,0.1)`;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', e => {
|
||||
scene.style.transform = `rotateX(${(e.clientY/window.innerHeight-0.5)*-6}deg) rotateY(${(e.clientX/window.innerWidth-0.5)*6}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
75
public/demos/index.html
Normal file
75
public/demos/index.html
Normal file
@@ -0,0 +1,75 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Hero Design Demos</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #0d1117;
|
||||
color: #fff;
|
||||
min-height: 100vh;
|
||||
padding: 48px 24px;
|
||||
}
|
||||
h1 { font-size: 2rem; text-align: center; margin-bottom: 8px; }
|
||||
h1 span { color: #fed400; }
|
||||
.sub { text-align: center; color: rgba(255,255,255,0.5); margin-bottom: 40px; font-size: 1rem; }
|
||||
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px; max-width: 1000px; margin: 0 auto; }
|
||||
.card {
|
||||
background: rgba(255,255,255,0.04);
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 16px;
|
||||
padding: 32px 24px;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
transition: all 0.3s ease;
|
||||
display: flex; flex-direction: column; gap: 12px;
|
||||
}
|
||||
.card:hover { background: rgba(254,212,0,0.06); border-color: rgba(254,212,0,0.3); transform: translateY(-2px); }
|
||||
.card .emoji { font-size: 3rem; }
|
||||
.card .name { font-size: 1.3rem; font-weight: 800; }
|
||||
.card .name span { color: #fed400; }
|
||||
.card .desc { font-size: 0.82rem; color: rgba(255,255,255,0.5); line-height: 1.5; }
|
||||
.card .tag { display: inline-block; font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.15em; color: rgba(254,212,0,0.6); border: 1px solid rgba(254,212,0,0.2); border-radius: 20px; padding: 4px 10px; width: fit-content; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hero Section — <span>5 Design Demos</span></h1>
|
||||
<p class="sub">เลือกดูแต่ละแนวคิดเพื่อเปรียบเทียบ</p>
|
||||
<div class="grid">
|
||||
<a href="a-orbital.html" class="card">
|
||||
<div class="emoji">🌌</div>
|
||||
<div class="name">A. <span>Orbital</span></div>
|
||||
<div class="tag">ระบบดาวเคราะห์โคจร</div>
|
||||
<div class="desc">กำไรเป็นดวงอาทิตย์เรืองแสง 3 ป้ายโคจรรอบด้วยวงแหวน orbital พร้อมหมุนอัตโนมัติ</div>
|
||||
</a>
|
||||
<a href="b-energyflow.html" class="card">
|
||||
<div class="emoji">⚡</div>
|
||||
<div class="name">B. <span>Energy Flow</span></div>
|
||||
<div class="tag">กระแสพลังงาน</div>
|
||||
<div class="desc">Particle วิ่งตามเส้นเชื่อมสีทอง เหมือนพลังงาน/ข้อมูลไหลเข้าสู่กำไร ดูมีชีวิตชีวา</div>
|
||||
</a>
|
||||
<a href="c-holographic.html" class="card">
|
||||
<div class="emoji">🌀</div>
|
||||
<div class="name">C. <span>Holographic 3D</span></div>
|
||||
<div class="tag">Hologram Sci-Fi</div>
|
||||
<div class="desc">โทน Cyan เรืองแสง พร้อม scanline และ beam เชื่อมต่อ ดูล้ำสมัย ดูแพง</div>
|
||||
</a>
|
||||
<a href="d-constellation.html" class="card">
|
||||
<div class="emoji">✨</div>
|
||||
<div class="name">D. <span>Constellation</span></div>
|
||||
<div class="tag">แผนที่ดาว</div>
|
||||
<div class="desc">โหนดเป็นดาวระยิบระยับ เส้นเชื่อมแบบกลุ่มดาว พื้นหลังมีดาวกระจาย ดูลึกลับสง่า</div>
|
||||
</a>
|
||||
<a href="e-magnetic.html" class="card">
|
||||
<div class="emoji">🧲</div>
|
||||
<div class="name">E. <span>Magnetic Field</span></div>
|
||||
<div class="tag">สนามแม่เหล็ก</div>
|
||||
<div class="desc">กำไรเป็นแม่เหล็กทรงพลัง มี ripple wave + field curve สื่อถึงการดึงดูดทุกอย่างสู่กำไร</div>
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
@@ -10,7 +10,7 @@ import { process } from '../data/site.js';
|
||||
<section class="page-hero scene scene-light" data-scene="light">
|
||||
<div class="page-hero-grid">
|
||||
<div>
|
||||
<p class="eyebrow">About MoreminiMore</p>
|
||||
<p class="eyebrow">เกี่ยวกับเรา</p>
|
||||
<h1>ที่ปรึกษาที่เริ่มจากคำถาม ไม่ใช่เริ่มจากขายแพ็กเกจ</h1>
|
||||
</div>
|
||||
<p class="hero-lead">
|
||||
@@ -25,7 +25,7 @@ import { process } from '../data/site.js';
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<p class="eyebrow">Why we exist</p>
|
||||
<p class="eyebrow">ทำไมเราถึงมีอยู่</p>
|
||||
<h2>ธุรกิจไม่ควรเสียเงินกับสิ่งที่ยังไม่รู้ว่าคุ้มไหม</h2>
|
||||
<p>
|
||||
เราเห็น SME หลายรายจ่ายเงินกับเว็บที่สวยแต่ไม่มีคนทัก โฆษณาที่มีคนคลิกแต่ไม่เกิดยอดขาย หรือเครื่องมือ AI ที่ดูน่าตื่นเต้นแต่ไม่เข้ากับงานจริง จึงเลือกทำงานแบบดูโจทย์ก่อน แล้วค่อยเสนอสิ่งที่ควรทำ
|
||||
@@ -35,7 +35,7 @@ import { process } from '../data/site.js';
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<p class="eyebrow">Policy</p>
|
||||
<p class="eyebrow">นโยบาย</p>
|
||||
<h2>เป้าหมายของเราคือการเพิ่มกำไรให้ลูกค้า</h2>
|
||||
<p>
|
||||
ถ้าลูกค้ามีกำไรมากขึ้น ลูกค้าก็อยู่ต่อได้ และเราก็ทำงานต่อได้ด้วย ทุกงานจึงต้องตอบให้ได้ว่าช่วยเพิ่มยอดขาย ลดต้นทุน ประหยัดเวลา หรือช่วยตัดสินใจได้ดีขึ้นอย่างไร
|
||||
@@ -46,7 +46,7 @@ import { process } from '../data/site.js';
|
||||
|
||||
<section class="page-section page-section-tight">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Process</p>
|
||||
<p class="eyebrow">ขั้นตอน</p>
|
||||
<h2>วิธีทำงานที่ลดการเดา</h2>
|
||||
</div>
|
||||
<div class="process-grid">
|
||||
@@ -65,7 +65,7 @@ import { process } from '../data/site.js';
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<p class="eyebrow">Talk to us</p>
|
||||
<p class="eyebrow">คุยกับเรา</p>
|
||||
<h2>เล่าโจทย์ของธุรกิจคุณก่อน แล้วค่อยดูว่าควรเริ่มตรงไหน</h2>
|
||||
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@ const posts = (await getCollection('blog', ({ data }) => !data.draft)).sort(
|
||||
<section class="page-hero scene scene-light" data-scene="light">
|
||||
<div class="page-hero-grid">
|
||||
<div>
|
||||
<p class="eyebrow">Blog</p>
|
||||
<p class="eyebrow">บทความ</p>
|
||||
<h1>บทความสำหรับธุรกิจที่อยากตัดสินใจจากข้อมูล</h1>
|
||||
</div>
|
||||
<p class="hero-lead">
|
||||
|
||||
@@ -45,7 +45,7 @@ const formattedDate = new Intl.DateTimeFormat('th-TH', {
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<p class="eyebrow">Next step</p>
|
||||
<p class="eyebrow">ขั้นตอนถัดไป</p>
|
||||
<h2>อ่านแล้วเจอโจทย์คล้ายกัน ส่งปัญหามาให้เราช่วยดูก่อนได้</h2>
|
||||
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { problems } from '../data/site.js';
|
||||
<section class="page-hero scene scene-light" data-scene="light">
|
||||
<div class="page-hero-grid">
|
||||
<div>
|
||||
<p class="eyebrow">Contact</p>
|
||||
<p class="eyebrow">ติดต่อ</p>
|
||||
<h1>ส่งโจทย์ให้เราดู แล้วค่อยตัดสินใจว่าจะทำอะไร</h1>
|
||||
</div>
|
||||
<p class="hero-lead">
|
||||
@@ -24,7 +24,7 @@ import { problems } from '../data/site.js';
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<p class="eyebrow">Start here</p>
|
||||
<p class="eyebrow">เริ่มต้นที่นี่</p>
|
||||
<h2>เลือกปัญหาที่ใกล้ที่สุด</h2>
|
||||
<div class="contact-problem-list">
|
||||
{problems.map(([, label]) => <span>{label}</span>)}
|
||||
@@ -33,7 +33,7 @@ import { problems } from '../data/site.js';
|
||||
</div>
|
||||
|
||||
<aside class="contact-info">
|
||||
<p class="eyebrow">Contact info</p>
|
||||
<p class="eyebrow">ข้อมูลติดต่อ</p>
|
||||
<h2>ช่องทางติดต่อ</h2>
|
||||
<dl>
|
||||
<div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { faqs } from '../data/site.js';
|
||||
<section class="page-hero scene scene-light" data-scene="light">
|
||||
<div class="page-hero-grid">
|
||||
<div>
|
||||
<p class="eyebrow">FAQ</p>
|
||||
<p class="eyebrow">คำถามที่พบบ่อย</p>
|
||||
<h1>คำถามที่ควรถามก่อนเริ่มทำอะไรเพิ่ม</h1>
|
||||
</div>
|
||||
<p class="hero-lead">
|
||||
@@ -39,7 +39,7 @@ import { faqs } from '../data/site.js';
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<p class="eyebrow">Still unsure?</p>
|
||||
<p class="eyebrow">ยังไม่แน่ใจ?</p>
|
||||
<h2>ถ้าคำถามของคุณไม่อยู่ในนี้ ส่งโจทย์มาให้เราดูได้</h2>
|
||||
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
|
||||
</div>
|
||||
|
||||
@@ -102,7 +102,7 @@ const process = [
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta name="description" content="MoreminiMore ช่วย SME ดูข้อมูลจริงก่อนตัดสินใจทำเว็บ การตลาด AI หรือระบบอัตโนมัติ เพื่อเลือกสิ่งที่ควรทำให้คุ้มที่สุด" />
|
||||
<meta name="theme-color" content="#f8f5ea" />
|
||||
<title>MoreminiMore | ธุรกิจไม่ควรเสียเงินกับสิ่งที่ยังไม่รู้ว่าคุ้มไหม</title>
|
||||
<title>MoreminiMore | เป้าหมายของเราคือการเพิ่มกำไรให้ลูกค้า</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="background-stage" aria-hidden="true">
|
||||
@@ -199,17 +199,14 @@ const process = [
|
||||
<div class="hero-copy">
|
||||
<p class="eyebrow">พาร์ทเนอร์สำหรับ SME ที่อยากตัดสินใจให้คุ้มขึ้น</p>
|
||||
<h1 class="desktop-title">
|
||||
<span>ธุรกิจไม่ควร</span>
|
||||
<span>เสียเงินกับสิ่งที่ยัง</span>
|
||||
<span>ไม่รู้ว่าคุ้มไหม</span>
|
||||
<span>เป้าหมายของเราคือ<br>การเพิ่ม<span class="text-highlight">กำไร</span>ให้ลูกค้า</span>
|
||||
</h1>
|
||||
<h1 class="mobile-title" aria-hidden="true">
|
||||
<span>ธุรกิจ</span>
|
||||
<span>ไม่ควร</span>
|
||||
<span>เสียเงิน</span>
|
||||
<span>กับสิ่งที่ยัง</span>
|
||||
<span>ไม่รู้ว่า</span>
|
||||
<span>คุ้มไหม</span>
|
||||
<span>เป้าหมาย</span>
|
||||
<span>ของเราคือ</span>
|
||||
<span>การเพิ่ม</span>
|
||||
<span><span class="text-highlight">กำไร</span></span>
|
||||
<span>ให้ลูกค้า</span>
|
||||
</h1>
|
||||
<p class="hero-lead">
|
||||
เราช่วย SME ดูข้อมูลจริงก่อนตัดสินใจทำเว็บ การตลาด AI หรือระบบอัตโนมัติ เพื่อเลือกสิ่งที่ควรทำอย่างมีประสิทธิภาพ และเหมาะกับธุรกิจของคุณ
|
||||
@@ -224,37 +221,25 @@ const process = [
|
||||
<canvas class="neural-canvas" aria-hidden="true"></canvas>
|
||||
<div class="neural-scene">
|
||||
<!-- Center node: กำไร -->
|
||||
<div class="neural-node node-center liquid-glass liquidGlass-wrapper" data-node="center">
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<div class="neural-node node-center" data-node="center">
|
||||
<span class="node-label">กำไร</span>
|
||||
<span class="node-sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
|
||||
<!-- Outer node: Marketing -->
|
||||
<div class="neural-node neural-card node-marketing liquid-glass liquidGlass-wrapper" data-node="marketing">
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<div class="neural-node neural-card node-marketing" data-node="marketing">
|
||||
<span class="card-tag">Marketing</span>
|
||||
<span class="card-desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
|
||||
<!-- Outer node: AI -->
|
||||
<div class="neural-node neural-card node-ai liquid-glass liquidGlass-wrapper" data-node="ai">
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<div class="neural-node neural-card node-ai" data-node="ai">
|
||||
<span class="card-tag">AI</span>
|
||||
<span class="card-desc">ลดต้นทุนและเวลา</span>
|
||||
</div>
|
||||
|
||||
<!-- Outer node: Business Knowledge -->
|
||||
<div class="neural-node neural-card node-biz liquid-glass liquidGlass-wrapper" data-node="biz">
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<div class="neural-node neural-card node-biz" data-node="biz">
|
||||
<span class="card-tag">Business Knowledge</span>
|
||||
<span class="card-desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
@@ -265,7 +250,7 @@ const process = [
|
||||
|
||||
<section class="problem-strip">
|
||||
<div>
|
||||
<p class="eyebrow">Problem first</p>
|
||||
<p class="eyebrow">เริ่มจากปัญหา</p>
|
||||
<h2>คุณเล่าปัญหา เราช่วยหา service ที่เหมาะสม</h2>
|
||||
</div>
|
||||
<div class="problem-strip-content">
|
||||
@@ -282,7 +267,7 @@ const process = [
|
||||
|
||||
<section id="dataroot" class="case-section scene scene-dark" data-scene="dark">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Diagnosis story</p>
|
||||
<p class="eyebrow">ขั้นตอนวินิจฉัย</p>
|
||||
<h2>Dataroot: ก่อนแก้ ต้องรู้ก่อนว่าข้อมูลกำลังบอกอะไร</h2>
|
||||
</div>
|
||||
|
||||
@@ -328,7 +313,7 @@ const process = [
|
||||
|
||||
<section id="services" class="services-section scene scene-light" data-scene="light">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Services</p>
|
||||
<p class="eyebrow">บริการ</p>
|
||||
<h2>บริการมีไว้ให้เราเลือกให้เหมาะกับปัญหา ไม่ใช่ให้คุณเดาเอง</h2>
|
||||
</div>
|
||||
|
||||
@@ -348,7 +333,7 @@ const process = [
|
||||
|
||||
<section id="portfolio" class="portfolio-section scene scene-dark" data-scene="dark">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Portfolio</p>
|
||||
<p class="eyebrow">ผลงาน</p>
|
||||
<h2>งานเว็บที่ต้องดูน่าเชื่อถือก่อน แล้วค่อยสวยแบบมีเหตุผล</h2>
|
||||
</div>
|
||||
|
||||
@@ -371,7 +356,7 @@ const process = [
|
||||
|
||||
<section id="process" class="process-section">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">How we work</p>
|
||||
<p class="eyebrow">วิธีการทำงาน</p>
|
||||
<h2>ไม่เริ่มจากขายของ เริ่มจากเข้าใจธุรกิจก่อน</h2>
|
||||
</div>
|
||||
<div class="process-grid">
|
||||
@@ -393,7 +378,7 @@ const process = [
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<p class="eyebrow">Start small</p>
|
||||
<p class="eyebrow">เริ่มต้นง่าย ๆ</p>
|
||||
<h2>ส่งโจทย์สั้น ๆ มาก่อนก็ได้ เดี๋ยวเราช่วยดูว่าควรเริ่มตรงไหน</h2>
|
||||
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { portfolio } from '../data/site.js';
|
||||
<section class="page-hero scene scene-light" data-scene="light">
|
||||
<div class="page-hero-grid">
|
||||
<div>
|
||||
<p class="eyebrow">Portfolio</p>
|
||||
<p class="eyebrow">ผลงาน</p>
|
||||
<h1>ผลงานจริงที่เปิดดูเว็บจริงได้</h1>
|
||||
</div>
|
||||
<p class="hero-lead">
|
||||
@@ -21,7 +21,7 @@ import { portfolio } from '../data/site.js';
|
||||
|
||||
<section id="dataroot" class="case-section scene scene-dark" data-scene="dark">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Featured case</p>
|
||||
<p class="eyebrow">ผลงานเด่น</p>
|
||||
<h2>Dataroot: ก่อนแก้ ต้องรู้ก่อนว่าข้อมูลกำลังบอกอะไร</h2>
|
||||
</div>
|
||||
<div class="case-grid">
|
||||
@@ -65,7 +65,7 @@ import { portfolio } from '../data/site.js';
|
||||
|
||||
<section class="portfolio-section scene scene-dark" data-scene="dark">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Selected work</p>
|
||||
<p class="eyebrow">ผลงานทั้งหมด</p>
|
||||
<h2>เว็บที่มีโจทย์ต่างกัน จึงต้องออกแบบต่างกัน</h2>
|
||||
</div>
|
||||
<div class="portfolio-grid">
|
||||
|
||||
@@ -10,7 +10,7 @@ import { services, process } from '../data/site.js';
|
||||
<section class="page-hero scene scene-light" data-scene="light">
|
||||
<div class="page-hero-grid">
|
||||
<div>
|
||||
<p class="eyebrow">Services</p>
|
||||
<p class="eyebrow">บริการ</p>
|
||||
<h1>เลือกบริการจากปัญหา ไม่ใช่จากชื่อแพ็กเกจ</h1>
|
||||
</div>
|
||||
<p class="hero-lead">
|
||||
@@ -42,7 +42,7 @@ import { services, process } from '../data/site.js';
|
||||
|
||||
<section class="page-section page-section-tight">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">How we work</p>
|
||||
<p class="eyebrow">วิธีการทำงาน</p>
|
||||
<h2>ทำให้ง่ายต่อการตัดสินใจ ไม่ใช่ทำให้ดูเยอะ</h2>
|
||||
</div>
|
||||
<div class="process-grid">
|
||||
@@ -61,7 +61,7 @@ import { services, process } from '../data/site.js';
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<p class="eyebrow">Next step</p>
|
||||
<p class="eyebrow">ขั้นตอนถัดไป</p>
|
||||
<h2>ไม่แน่ใจว่าควรเริ่มบริการไหน ส่งโจทย์มาให้เราดูก่อนได้</h2>
|
||||
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
|
||||
</div>
|
||||
|
||||
@@ -34,9 +34,9 @@ const relatedServices = services.filter((item) => item.slug !== service.slug);
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section service-story-section">
|
||||
<section class="page-section service-story-section scene scene-light" data-scene="light">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Diagnosis first</p>
|
||||
<p class="eyebrow">วินิจฉัยก่อน</p>
|
||||
<h2>เริ่มจากดูว่าโจทย์นี้ควรแก้ตรงไหนก่อน</h2>
|
||||
</div>
|
||||
<div class="service-story-grid">
|
||||
@@ -63,7 +63,7 @@ const relatedServices = services.filter((item) => item.slug !== service.slug);
|
||||
|
||||
<section class="case-section service-proof-section scene scene-dark" data-scene="dark">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">What matters</p>
|
||||
<p class="eyebrow">สิ่งที่สำคัญ</p>
|
||||
<h2>{service.objective}</h2>
|
||||
</div>
|
||||
<div class="service-proof-grid">
|
||||
@@ -87,9 +87,9 @@ const relatedServices = services.filter((item) => item.slug !== service.slug);
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="page-section page-section-tight">
|
||||
<section class="page-section page-section-tight scene scene-light" data-scene="light">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Other services</p>
|
||||
<p class="eyebrow">บริการอื่น ๆ</p>
|
||||
<h2>บางโจทย์อาจต้องเริ่มจากบริการอื่นก่อน</h2>
|
||||
</div>
|
||||
<div class="related-service-grid">
|
||||
@@ -111,7 +111,7 @@ const relatedServices = services.filter((item) => item.slug !== service.slug);
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<p class="eyebrow">Next step</p>
|
||||
<p class="eyebrow">ขั้นตอนถัดไป</p>
|
||||
<h2>เล่าโจทย์ของคุณก่อน แล้วเราช่วยดูว่าบริการนี้ใช่จุดเริ่มต้นไหม</h2>
|
||||
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
|
||||
</div>
|
||||
|
||||
@@ -208,6 +208,7 @@ if (heroNeural && neuralScene && canvas && ctx && nodes.length > 0) {
|
||||
window.addEventListener('resize', resizeCanvas);
|
||||
|
||||
// Find intersection point on node border
|
||||
// Coordinates are relative to heroNeural container
|
||||
function findBorderPoint(nodeRect, targetX, targetY) {
|
||||
const cx = nodeRect.left + nodeRect.width / 2;
|
||||
const cy = nodeRect.top + nodeRect.height / 2;
|
||||
@@ -219,24 +220,21 @@ if (heroNeural && neuralScene && canvas && ctx && nodes.length > 0) {
|
||||
|
||||
if (dx === 0 && dy === 0) return { x: cx, y: cy };
|
||||
|
||||
const absDx = Math.abs(dx);
|
||||
const absDy = Math.abs(dy);
|
||||
|
||||
let scale;
|
||||
if (absDx * hh > absDy * hw) {
|
||||
scale = hw / absDx;
|
||||
} else {
|
||||
scale = hh / absDy;
|
||||
}
|
||||
|
||||
// All neural nodes are circular — use circle intersection
|
||||
const r = Math.min(hw, hh);
|
||||
const dist = Math.sqrt(dx * dx + dy * dy);
|
||||
return {
|
||||
x: cx + dx * scale,
|
||||
y: cy + dy * scale
|
||||
x: cx + (dx / dist) * r,
|
||||
y: cy + (dy / dist) * r
|
||||
};
|
||||
}
|
||||
|
||||
// Draw connections
|
||||
// Magnetic field time counter
|
||||
let magTime = 0;
|
||||
|
||||
// Draw connections with magnetic field effects
|
||||
function drawConnections() {
|
||||
magTime++;
|
||||
const rect = heroNeural.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, rect.width, rect.height);
|
||||
|
||||
@@ -249,6 +247,17 @@ if (heroNeural && neuralScene && canvas && ctx && nodes.length > 0) {
|
||||
const centerX = centerRect.left + centerRect.width / 2 - rect.left;
|
||||
const centerY = centerRect.top + centerRect.height / 2 - rect.top;
|
||||
|
||||
// Magnetic ripple rings from center
|
||||
for (let r = 0; r < 4; r++) {
|
||||
const radius = 95 + r * 28 + (magTime * 0.03) % 28;
|
||||
const alpha = Math.max(0, 0.22 - r * 0.05 - ((magTime * 0.03) % 28) / 130);
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
|
||||
ctx.strokeStyle = `rgba(19, 18, 13, ${alpha})`;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
outerNodes.forEach(node => {
|
||||
const nodeRect = node.getBoundingClientRect();
|
||||
const nodeX = nodeRect.left + nodeRect.width / 2 - rect.left;
|
||||
@@ -266,13 +275,32 @@ if (heroNeural && neuralScene && canvas && ctx && nodes.length > 0) {
|
||||
centerX, centerY
|
||||
);
|
||||
|
||||
const dx = endPt.x - startPt.x;
|
||||
const dy = endPt.y - startPt.y;
|
||||
const dist = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
// Main connection line
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(startPt.x, startPt.y);
|
||||
ctx.lineTo(endPt.x, endPt.y);
|
||||
ctx.strokeStyle = 'rgba(254, 212, 0, 0.5)';
|
||||
ctx.lineWidth = 3;
|
||||
ctx.strokeStyle = 'rgba(19, 18, 13, 0.3)';
|
||||
ctx.lineWidth = 2.5;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.stroke();
|
||||
|
||||
// Field curve arcs on both sides (magnetic field lines)
|
||||
for (let side = -1; side <= 1; side += 2) {
|
||||
const offset = side * 18;
|
||||
const midX = startPt.x + dx * 0.5 + (-dy / dist) * offset;
|
||||
const midY = startPt.y + dy * 0.5 + (dx / dist) * offset;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(startPt.x, startPt.y);
|
||||
ctx.quadraticCurveTo(midX, midY, endPt.x, endPt.y);
|
||||
ctx.strokeStyle = 'rgba(19, 18, 13, 0.08)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -281,8 +309,8 @@ if (heroNeural && neuralScene && canvas && ctx && nodes.length > 0) {
|
||||
const x = e.clientX / window.innerWidth;
|
||||
const y = e.clientY / window.innerHeight;
|
||||
|
||||
targetRotateY = (x - 0.5) * 10;
|
||||
targetRotateX = (y - 0.5) * -10;
|
||||
targetRotateY = (x - 0.5) * 6;
|
||||
targetRotateX = (y - 0.5) * -6;
|
||||
});
|
||||
|
||||
document.addEventListener('mouseleave', () => {
|
||||
|
||||
@@ -459,7 +459,6 @@ color: rgb(255 255 255 / .72);
|
||||
/* Links inside inverted page sections */
|
||||
.page-section a,
|
||||
.page-section-tight a,
|
||||
.page-section button,
|
||||
.page-section-tight button,
|
||||
.page-section .text-link,
|
||||
.page-section-tight .text-link {
|
||||
@@ -473,6 +472,17 @@ color: rgb(255 255 255 / .72);
|
||||
.page-section-tight .text-link:hover {
|
||||
color: var(--yellow);
|
||||
}
|
||||
/* Yellow buttons keep black text even in dark sections */
|
||||
.page-section .button,
|
||||
.page-section-tight .button,
|
||||
.scene-dark .button {
|
||||
color: var(--ink);
|
||||
}
|
||||
.page-section .button:hover,
|
||||
.page-section-tight .button:hover,
|
||||
.scene-dark .button:hover {
|
||||
color: var(--ink);
|
||||
}
|
||||
.page-section li,
|
||||
.page-section-tight li {
|
||||
color: rgb(255 255 255 / .72);
|
||||
@@ -709,7 +719,7 @@ align-items: stretch;
|
||||
}
|
||||
|
||||
.service-proof-grid .process-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -743,8 +753,8 @@ color: var(--muted);
|
||||
.hero-neural {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
height: 520px;
|
||||
max-width: 650px;
|
||||
height: 560px;
|
||||
margin-inline: auto;
|
||||
perspective: 1200px;
|
||||
}
|
||||
@@ -792,15 +802,38 @@ color: var(--muted);
|
||||
border-radius: 50%;
|
||||
padding: 32px;
|
||||
border: 3px solid var(--yellow);
|
||||
background: rgba(255, 255, 255, 0.45);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
box-shadow:
|
||||
0 0 0 10px rgb(254 212 0 / .12),
|
||||
0 30px 80px rgb(254 212 0 / .20),
|
||||
0 10px 30px rgb(0 0 0 / .12);
|
||||
0 0 0 14px rgb(254 212 0 / .10),
|
||||
0 0 60px rgb(254 212 0 / .20),
|
||||
0 0 120px rgb(254 180 0 / .08);
|
||||
z-index: 10;
|
||||
animation: magnetPulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.node-center:hover {
|
||||
transform: translate(-50%, -50%) translateZ(20px) scale(1.05);
|
||||
transform: translate(-50%, -50%) translateZ(20px) scale(1.08);
|
||||
|
||||
@keyframes magnetPulse {
|
||||
0%, 100% {
|
||||
box-shadow:
|
||||
0 0 0 14px rgb(254 212 0 / .10),
|
||||
0 0 60px rgb(254 212 0 / .20),
|
||||
0 0 120px rgb(254 180 0 / .08);
|
||||
}
|
||||
50% {
|
||||
box-shadow:
|
||||
0 0 0 20px rgb(254 212 0 / .14),
|
||||
0 0 80px rgb(254 212 0 / .30),
|
||||
0 0 150px rgb(254 180 0 / .12);
|
||||
}
|
||||
}
|
||||
box-shadow:
|
||||
0 0 0 18px rgb(254 212 0 / .12),
|
||||
0 0 80px rgb(254 212 0 / .25),
|
||||
0 0 150px rgb(254 180 0 / .10);
|
||||
}
|
||||
|
||||
.node-label {
|
||||
@@ -817,19 +850,29 @@ color: var(--muted);
|
||||
font-weight: 600;
|
||||
color: var(--muted);
|
||||
line-height: 1.4;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.neural-card {
|
||||
width: 220px;
|
||||
padding: 30px 26px;
|
||||
min-height: 130px;
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
border-radius: 50%;
|
||||
padding: 18px 16px;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border: 1.5px solid rgba(19, 18, 13, 0.2);
|
||||
box-shadow: 0 0 20px rgba(19, 18, 13, 0.06);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: box-shadow 0.4s ease, border-color 0.4s ease;
|
||||
}
|
||||
|
||||
/* Marketing: top-left, clearly separated */
|
||||
.node-marketing {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%) translate3d(-280px, -170px, -100px);
|
||||
transform: translate(-50%, -50%) translate3d(-290px, -180px, -100px);
|
||||
animation: float-1 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@@ -837,7 +880,7 @@ color: var(--muted);
|
||||
.node-ai {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%) translate3d(280px, -40px, -80px);
|
||||
transform: translate(-50%, -50%) translate3d(210px, -30px, -50px);
|
||||
animation: float-2 7s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@@ -845,39 +888,42 @@ color: var(--muted);
|
||||
.node-biz {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%) translate3d(-100px, 190px, -130px);
|
||||
transform: translate(-50%, -50%) translate3d(-180px, 160px, -100px);
|
||||
animation: float-3 8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.card-tag {
|
||||
font-size: 20px;
|
||||
font-weight: 900;
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
color: var(--ink);
|
||||
letter-spacing: .02em;
|
||||
text-transform: uppercase;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
margin-top: 10px;
|
||||
font-size: 16px;
|
||||
margin-top: 4px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--muted);
|
||||
line-height: 1.4;
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@keyframes float-1 {
|
||||
0%, 100% { transform: translate(-50%, -50%) translate3d(-280px, -170px, -100px); }
|
||||
50% { transform: translate(-50%, -50%) translate3d(-310px, -200px, -150px); }
|
||||
0%, 100% { transform: translate(-50%, -50%) translate3d(-290px, -180px, -100px); }
|
||||
50% { transform: translate(-50%, -50%) translate3d(-250px, -150px, -70px); }
|
||||
}
|
||||
|
||||
@keyframes float-2 {
|
||||
0%, 100% { transform: translate(-50%, -50%) translate3d(280px, -40px, -80px); }
|
||||
50% { transform: translate(-50%, -50%) translate3d(310px, -70px, -120px); }
|
||||
0%, 100% { transform: translate(-50%, -50%) translate3d(210px, -30px, -50px); }
|
||||
50% { transform: translate(-50%, -50%) translate3d(175px, -15px, -30px); }
|
||||
}
|
||||
|
||||
@keyframes float-3 {
|
||||
0%, 100% { transform: translate(-50%, -50%) translate3d(-100px, 190px, -130px); }
|
||||
50% { transform: translate(-50%, -50%) translate3d(-140px, 220px, -200px); }
|
||||
0%, 100% { transform: translate(-50%, -50%) translate3d(-180px, 160px, -100px); }
|
||||
50% { transform: translate(-50%, -50%) translate3d(-145px, 130px, -65px); }
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
@@ -896,7 +942,7 @@ color: var(--muted);
|
||||
|
||||
.hero h1 {
|
||||
max-width: 15ch;
|
||||
font-size: clamp(2.55rem, 4.6vw, 4.63rem);
|
||||
font-size: clamp(2.55rem, 4vw, 4rem);
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
@@ -904,6 +950,14 @@ color: var(--muted);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hero h1 .text-highlight {
|
||||
display: inline;
|
||||
color: var(--yellow);
|
||||
font-weight: 900;
|
||||
-webkit-text-stroke: 2px var(--ink);
|
||||
paint-order: stroke fill;
|
||||
}
|
||||
|
||||
.desktop-title span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -1271,7 +1325,7 @@ line-height: 1.32;
|
||||
.section-heading h2,
|
||||
.final-cta h2 {
|
||||
max-width: 13ch;
|
||||
font-size: clamp(2.4rem, 5vw, 5rem);
|
||||
font-size: clamp(2.4rem, 4vw, 4rem);
|
||||
}
|
||||
|
||||
.problem-strip p,
|
||||
@@ -1307,6 +1361,8 @@ position: absolute;
|
||||
left: 0;
|
||||
color: var(--yellow);
|
||||
font-weight: 700;
|
||||
-webkit-text-stroke: 1px var(--ink);
|
||||
paint-order: stroke fill;
|
||||
}
|
||||
|
||||
.case-section,
|
||||
@@ -1414,6 +1470,8 @@ box-shadow: 0 24px 70px rgb(0 0 0 / .34), inset 1px 1px 0 rgb(255 255 255 / .18)
|
||||
font-weight: 900;
|
||||
letter-spacing: .04em;
|
||||
text-transform: uppercase;
|
||||
-webkit-text-stroke: 0.5px var(--ink);
|
||||
paint-order: stroke fill;
|
||||
}
|
||||
|
||||
.story-step h3 {
|
||||
@@ -1629,7 +1687,7 @@ height: 34px;
|
||||
z-index: 2;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border: 1px solid rgb(19 18 13 / .14);
|
||||
border: 1.5px solid rgb(19 18 13 / 0.35);
|
||||
border-radius: 999px;
|
||||
background: var(--yellow);
|
||||
box-shadow: 0 10px 30px rgb(254 212 0 / .26);
|
||||
@@ -1948,11 +2006,11 @@ grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: clamp(3rem, 14vw, 5.2rem);
|
||||
font-size: clamp(3rem, 10vw, 4rem);
|
||||
}
|
||||
|
||||
.page-hero h1 {
|
||||
font-size: clamp(3rem, 12vw, 5rem);
|
||||
font-size: clamp(3rem, 10vw, 4rem);
|
||||
}
|
||||
|
||||
.service-hero-panel {
|
||||
@@ -2034,7 +2092,7 @@ max-width: calc(100% - 32px);
|
||||
|
||||
.hero h1 {
|
||||
max-width: 100%;
|
||||
font-size: clamp(2.45rem, 12vw, 3.1rem);
|
||||
font-size: clamp(2.45rem, 10vw, 2.8rem);
|
||||
line-height: .98;
|
||||
}
|
||||
|
||||
@@ -2081,7 +2139,7 @@ max-width: calc(100% - 32px);
|
||||
.section-heading h2,
|
||||
.final-cta h2,
|
||||
.page-hero h1 {
|
||||
font-size: clamp(2rem, 9vw, 2.7rem);
|
||||
font-size: clamp(2rem, 7vw, 2.5rem);
|
||||
max-width: 11ch;
|
||||
}
|
||||
|
||||
@@ -2175,8 +2233,9 @@ border-radius: 18px;
|
||||
min-width: 180px;
|
||||
}
|
||||
.neural-card {
|
||||
width: 100%;
|
||||
max-width: 280px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 50%;
|
||||
min-height: auto;
|
||||
}
|
||||
@keyframes float-1,
|
||||
@@ -2206,7 +2265,7 @@ border-radius: 18px;
|
||||
.blog-article-heading h1 {
|
||||
max-width: 15ch;
|
||||
margin-top: 14px;
|
||||
font-size: clamp(2.7rem, 5.6vw, 5.8rem);
|
||||
font-size: clamp(2.7rem, 4vw, 4rem);
|
||||
font-weight: 900;
|
||||
line-height: .96;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user