<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Customer Success Portal</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/geist@1.3.0/dist/core.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/geist@1.3.0/dist/mono.min.css">
<script src="https://unpkg.com/@phosphor-icons/web"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
:root {
--bg: #05050a;
--accent: #7b61ff;
--accent-glow: rgba(123, 97, 255, 0.4);
--line: rgba(123, 97, 255, 0.1);
--text-dim: #8b8b9e;
--font-sans: 'Geist Sans', system-ui, sans-serif;
--font-mono: 'Geist Mono', monospace;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background-color: var(--bg); color: white;
font-family: var(--font-sans); overflow: hidden;
-webkit-font-smoothing: antialiased;
}
#canvas-container { position: absolute; inset: 0; z-index: 1; }
.ui-layer { position: relative; z-index: 10; padding: 4rem; height: 100vh; display: flex; flex-direction: column; pointer-events: none; }
.ui-layer * { pointer-events: auto; }
header {
background: var(--bg); padding: 2rem 0; margin: -4rem 0 0 -4rem;
padding-left: 4rem; width: 100vw; border-bottom: 1px solid var(--line);
}
header .subtitle { color: var(--accent); font-family: var(--font-mono); font-weight: 500; text-transform: uppercase; font-size: 0.7rem; letter-spacing: 0.1em; }
h1 { font-size: 2.8rem; font-weight: 400; margin-top: 0.8rem; letter-spacing: -0.03em; }
h1 span { color: #3a3a4e; }
.sidebar {
margin-top: 2rem; width: 440px; background: var(--bg);
height: 100%; margin-left: -4rem; padding-left: 4rem; border-right: 1px solid var(--line);
}
.nav-item {
position: relative; display: flex; gap: 1.2rem; align-items: flex-start;
padding: 1.5rem 1.8rem; margin-bottom: 1rem; cursor: pointer;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
background: rgba(255, 255, 255, 0.01); border: 1px solid transparent;
opacity: 0.4; height: 100px;
}
.nav-item:hover { opacity: 0.7; background: rgba(255, 255, 255, 0.03); }
.nav-item.active {
opacity: 1;
background: linear-gradient(90deg, rgba(123, 97, 255, 0.1) 0%, rgba(123, 97, 255, 0.02) 100%);
border-color: rgba(123, 97, 255, 0.3);
box-shadow: inset 0 0 25px rgba(123, 97, 255, 0.05);
}
.nav-item.active::before {
content: ''; position: absolute; top: 0; right: -1px; bottom: 0; width: 4px;
background: var(--accent); box-shadow: 0 0 20px 2px var(--accent), 0 0 40px 8px var(--accent-glow);
z-index: 2;
}
.corner-point {
position: absolute; width: 4px; height: 4px; background: white;
border-radius: 50%; box-shadow: 0 0 10px white;
opacity: 0; transition: opacity 0.3s ease; z-index: 3;
}
.nav-item.active .corner-point { opacity: 1; }
.tl { top: -2.5px; left: -2.5px; } .tr { top: -2.5px; right: -2.5px; }
.bl { bottom: -2.5px; left: -2.5px; } .br { bottom: -2.5px; right: -2.5px; }
.nav-item i { font-size: 1.4rem; color: #fff; margin-top: 2px; }
.nav-item .text-content h3 { font-size: 1.1rem; font-weight: 500; margin-bottom: 4px; color: white; }
.nav-item .text-content p { font-size: 0.85rem; color: var(--text-dim); line-height: 1.4; }
footer {
margin-top: auto; display: flex; gap: 3rem; font-size: 0.8rem; color: var(--text-dim);
font-family: var(--font-mono); background: var(--bg); padding: 20px;
width: 100vw; margin-left: -4rem; padding-left: 4rem; border-top: 1px solid var(--line);
}
</style>
</head>
<body>
<div id="canvas-container"></div>
<div class="ui-layer">
<header>
<p class="subtitle">Platform v2.4.0</p>
<h1 id="main-title">Understand your <span>shoppers better</span></h1>
</header>
<aside class="sidebar">
<div class="nav-item active" onclick="switchState('dashboard', this, 'Understand your <span>shoppers better</span>')">
<div class="corner-point tl"></div><div class="corner-point tr"></div><div class="corner-point bl"></div><div class="corner-point br"></div>
<i class="ph-duotone ph-squares-four"></i>
<div class="text-content"><h3>Overview</h3><p>Real-time performance metrics and store health snapshot.</p></div>
</div>
<div class="nav-item" onclick="switchState('trends', this, 'See where <span>your business is heading</span>')">
<div class="corner-point tl"></div><div class="corner-point tr"></div><div class="corner-point bl"></div><div class="corner-point br"></div>
<i class="ph-duotone ph-chart-line-up"></i>
<div class="text-content"><h3>Smart Growth</h3><p>AI-driven analysis of emerging market trends.</p></div>
</div>
<div class="nav-item" onclick="switchState('integration', this, 'Everything works <span>together perfectly</span>')">
<div class="corner-point tl"></div><div class="corner-point tr"></div><div class="corner-point bl"></div><div class="corner-point br"></div>
<i class="ph-duotone ph-arrows-merge"></i>
<div class="text-content"><h3>Integration</h3><p>Seamlessly link your data with Google and Box.</p></div>
</div>
</aside>
<footer>
<span><i class="ph ph-circle-wavy-check"></i> System Operational</span>
<span><i class="ph ph-lock-keyhole"></i> End-to-end Encrypted</span>
</footer>
</div>
<script>
const scene = new THREE.Scene();
const container = document.getElementById('canvas-container');
const aspect = window.innerWidth / window.innerHeight;
const d = 6;
const camera = new THREE.OrthographicCamera(-d * aspect, d * aspect, d, -d, 1, 1000);
camera.position.set(10, 8, 10);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
const world = new THREE.Group();
scene.add(world);
const grid = new THREE.GridHelper(30, 30, 0x7b61ff, 0x1a1a2e);
grid.position.y = -2.5;
grid.material.opacity = 0.15;
grid.material.transparent = true;
world.add(grid);
const globalGlowMat = new THREE.ShaderMaterial({
uniforms: { uColor: { value: new THREE.Color(0x7b61ff) } },
vertexShader: `varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,
fragmentShader: `
uniform vec3 uColor; varying vec2 vUv;
void main() {
float dist = distance(vUv, vec2(0.5));
float alpha = pow(smoothstep(0.5, 0.0, dist), 2.5);
gl_FragColor = vec4(uColor, alpha * 0.45);
}`,
transparent: true, depthWrite: false, blending: THREE.NormalBlending
});
const globalGlowPlane = new THREE.Mesh(new THREE.PlaneGeometry(40, 40), globalGlowMat);
globalGlowPlane.rotation.x = -Math.PI / 2;
globalGlowPlane.position.set(8, -2.6, 0);
world.add(globalGlowPlane);
let currentObjects = new THREE.Group();
world.add(currentObjects);
let packetMaterial;
let movingLight;
let trendCurve;
let flowMaterials = [];
function showDashboard() {
clearState();
const createFloatingSquare = (size, x, z) => {
const group = new THREE.Group();
const body = new THREE.Mesh(new THREE.BoxGeometry(size, 0.2, size), new THREE.MeshBasicMaterial({ color: 0x05050a }));
const edges = new THREE.EdgesGeometry(new THREE.BoxGeometry(size, 0.2, size));
const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0x7b61ff }));
group.add(body, line);
group.position.set(x, 0, z);
return group;
};
const positions = [];
const count = 8;
const squareSize = 2.8;
const minDistance = 8.0;
for (let i = 0; i < count; i++) {
let x, z, collision;
let attempts = 0;
do {
collision = false;
x = (Math.random() * 12) + 2;
z = (Math.random() - 0.5) * 14;
for (let p of positions) {
const dist = Math.sqrt(Math.pow(x - p.x, 2) + Math.pow(z - p.z, 2));
if (dist < minDistance) { collision = true; break; }
}
attempts++;
} while (collision && attempts < 300);
positions.push({x, z});
currentObjects.add(createFloatingSquare(squareSize, x, z));
}
}
function showTrends() {
clearState();
trendCurve = new THREE.CatmullRomCurve3([
new THREE.Vector3(-2, -1.0, -2), new THREE.Vector3(2, 0.5, 1),
new THREE.Vector3(5, -0.5, 3), new THREE.Vector3(8, 2, 0),
new THREE.Vector3(11, 0.5, -3)
]);
const baseMat = new THREE.MeshBasicMaterial({ color: 0x7b61ff, transparent: true, opacity: 0.15 });
const tube = new THREE.Mesh(new THREE.TubeGeometry(trendCurve, 100, 0.08, 8, false), baseMat);
packetMaterial = new THREE.ShaderMaterial({
uniforms: { uTime: { value: 0 }, uColor: { value: new THREE.Color(0x7b61ff) } },
vertexShader: `varying float vUv; void main() { vUv = uv.x; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,
fragmentShader: `uniform float uTime; uniform vec3 uColor; varying float vUv; void main() { float move = fract(uTime); float glow = smoothstep(0.1, 0.0, abs(vUv - move)); gl_FragColor = vec4(uColor * 15.0, glow); }`,
transparent: true, blending: THREE.AdditiveBlending
});
currentObjects.add(tube, new THREE.Mesh(new THREE.TubeGeometry(trendCurve, 100, 0.12, 8, false), packetMaterial));
movingLight = new THREE.PointLight(0x7b61ff, 8, 15);
currentObjects.add(movingLight);
}
function showIntegration() {
clearState();
const size = 4;
const spacing = 2.8;
const nodes = [];
const nodeGroup = new THREE.Group();
const createFlowMaterial = () => {
const mat = new THREE.ShaderMaterial({
uniforms: { uTime: { value: 0 }, uColor: { value: new THREE.Color(0x7b61ff) } },
vertexShader: `varying float vUv; void main() { vUv = uv.x; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,
fragmentShader: `
uniform float uTime; uniform vec3 uColor; varying float vUv;
void main() {
float flow = fract(vUv - uTime * 0.8);
float alpha = smoothstep(0.0, 0.5, flow) * smoothstep(1.0, 0.5, flow);
gl_FragColor = vec4(uColor, alpha * 0.6);
}`,
transparent: true, blending: THREE.AdditiveBlending
});
flowMaterials.push(mat);
return mat;
};
for (let i = 0; i < size; i++) {
for (let j = 0; j < size; j++) {
const x = i * spacing;
const z = (j - (size - 1) / 2) * spacing;
const g = new THREE.Group();
// Circle Body
const circle = new THREE.Mesh(new THREE.CylinderGeometry(0.5, 0.5, 0.1, 32), new THREE.MeshBasicMaterial({ color: 0x05050a }));
// Sharp Outline
const outline = new THREE.Mesh(new THREE.TorusGeometry(0.52, 0.03, 16, 100), new THREE.MeshBasicMaterial({ color: 0x7b61ff }));
outline.rotation.x = Math.PI/2;
g.add(circle, outline);
g.position.set(x, 0, z);
nodeGroup.add(g);
nodes.push({ i, j, x, z });
}
}
nodes.forEach(n1 => {
nodes.forEach(n2 => {
const isHorizontal = n1.j === n2.j && n1.i === n2.i + 1;
const isVertical = n1.i === n2.i && n1.j === n2.j + 1;
if (isHorizontal || isVertical) {
const geom = new THREE.TubeGeometry(
new THREE.CatmullRomCurve3([new THREE.Vector3(n1.x, 0, n1.z), new THREE.Vector3(n2.x, 0, n2.z)]),
20, 0.04, 8, false
);
nodeGroup.add(new THREE.Mesh(geom, createFlowMaterial()));
}
});
});
nodeGroup.position.set(2, 0, 0);
currentObjects.add(nodeGroup);
}
function clearState() {
packetMaterial = null; movingLight = null; trendCurve = null; flowMaterials = [];
while(currentObjects.children.length > 0) {
const obj = currentObjects.children[0];
if(obj.geometry) obj.geometry.dispose();
if(obj.material) {
if(Array.isArray(obj.material)) obj.material.forEach(m => m.dispose());
else obj.material.dispose();
}
currentObjects.remove(obj);
}
}
window.switchState = function(state, el, title) {
document.querySelectorAll('.nav-item').forEach(i => i.classList.remove('active'));
el.classList.add('active'); document.getElementById('main-title').innerHTML = title;
if(state === 'dashboard') showDashboard();
if(state === 'trends') showTrends();
if(state === 'integration') showIntegration();
};
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const elapsed = clock.getElapsedTime();
if (packetMaterial) packetMaterial.uniforms.uTime.value = elapsed;
if (movingLight && trendCurve) movingLight.position.copy(trendCurve.getPointAt((elapsed * 0.8) % 1));
flowMaterials.forEach(m => m.uniforms.uTime.value = elapsed);
currentObjects.position.y = Math.sin(elapsed * 0.5) * 0.12;
renderer.render(scene, camera);
}
showDashboard(); animate();
</script>
</body>
</html>“Create a "Customer Success Portal" component. Use Phosphor Icons, Three.js for 3D WebGL rendering. Implement custom GLSL shaders for visual effects. Apply gradients, layered shadows, hover transitions. Color palette: #05050a, #7b61ff, #8b8b9e. Layout: Flexbox, full-viewport sizing. Interactivity: click interactions, continuous animation loop.”