类型:Site模板 · 收录:2026-11-05 01:12:44 · 源码:会员可见
付费可阅读内容 · 可复制
Build a single standalone index.html (one inline <style>, one plain inline <script> for the menu, one <script type="importmap"> and one <script type="module"> for Three.js). No frameworks, no build step, no local assets: all media loads from the remote URLs below. It is a full-screen dark hero section for a brand called "Lumora.", centred on a REAL-TIME 3D scene: a wobbling liquid-glass orb with a swirling blue galaxy inside, orbited by a ribbon of thin glass strands carrying glass beads. It must be fully mobile responsive.
=== REMOTE ASSETS (use exactly; load from these URLs) ===
- 3D model (GLB, made with Higgsfield multi_image_to_3d from a close-up model sheet):
https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261018_202332_9ca7052f-8d5e-4803-9431-d0eaff627b54.glb
- Orb image (Higgsfield render of the blue galaxy orb on black; wrapped onto the 3D blob):
https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261018_200844_5fa95511-57c1-4919-8acf-9136e1a125c5.png
The orb in this image is centred at uv (0.495, 0.5) with a radius of 0.33 in uv units.
- Three.js r160 via importmap:
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js"
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
Imports: GLTFLoader, RoomEnvironment, EffectComposer, RenderPass, UnrealBloomPass, OutputPass.
- Font: Google Fonts "Inter Tight" 400;500;600;700, display=swap (preconnect fonts.googleapis.com and fonts.gstatic.com crossorigin).
=== HEAD ===
doctype html, lang en, charset utf-8, viewport "width=device-width, initial-scale=1, viewport-fit=cover", <meta name="color-scheme" content="dark">, title "Lumora — Immersive Visuals".
=== CSS ===
:root { --bg:#010205; --text:#fff; --muted:rgba(220,232,255,.72); --link:rgba(235,242,255,.82); --cyan:#19e3f5; --cyan-2:#5df0ff; --blue:#1f6bff; --pad:clamp(16px,3.2vw,44px); }
Reset * {box-sizing:border-box;margin:0;padding:0}. html,body: bg var(--bg), color var(--text), height 100%. body: Inter Tight / system-ui stack, antialiased, overflow-x hidden. a: inherit color, no underline.
.hero: relative; min-height 100vh then 100svh; overflow hidden; isolation isolate; background var(--bg) (plain black, NO radial glow).
3D stage:
- .stage: absolute; inset 0; z-index 0; grid; place-items center; pointer-events none.
- #gl canvas: absolute; inset 0; 100% x 100%; display block; opacity 0; transition opacity 1.2s ease. #gl.ready → opacity 1.
- .loader (placeholder until the first frame renders): absolute; left 50%; top 56%; translate -50% -50%; 120px circle; background radial-gradient(circle, rgba(60,190,255,.55), rgba(20,80,255,.12) 50%, transparent 70%); blur(8px); animation pulse 1.6s infinite (0/100%: opacity .6 scale 1; 50%: opacity 1 scale 1.15); transition opacity .6s. .loader.hide → opacity 0.
Nav:
- .nav: relative; z 3; flex; align center; padding clamp(18px,3vw,34px) var(--pad) 0; gap clamp(24px,6vw,80px).
- .brand: 700; clamp(22px,2vw,28px); letter-spacing -0.02em.
- .links: flex; gap clamp(16px,1.8vw,26px); 15px; color var(--link). Links are relative with color transition .25s; hover/active turn #fff. ::after underline: absolute, left/right 0, bottom -6px, 1px high, var(--cyan), scaleX(0) with origin left, transition .3s; on hover scaleX(1).
- .join: margin-left auto; 16px; 500; padding-bottom 4px; border-bottom 1.5px solid #fff; on hover color and border var(--cyan).
- .burger: hidden on desktop; margin-left auto; 38x38; no border or bg; 3 spans of 22x1.5px white, margin 6px auto, transition transform/opacity .3s.
Headline row:
- .top: relative; z 2; grid with columns minmax(120px,18%) 1fr auto; align start; padding clamp(36px,7vh,80px) var(--pad) 0.
- .counter 14px #fff letter-spacing .02em padding-top 10px; b 600; the "/005" span var(--muted).
- .dots-mini: flex gap 6px margin-top 12px; <i> 7px circles rgba(255,255,255,.35); the first is var(--cyan) with box-shadow 0 0 10px var(--cyan).
- h1: 600; clamp(34px,4.6vw,66px); line-height .98; letter-spacing -0.035em; uppercase. Each .line is display block with overflow hidden; the inner span is inline-block, starts at translateY(105%), and animates "rise" 1s cubic-bezier(.2,.8,.2,1) forwards; line 2 has a .12s delay.
- .more: flex gap 6px; padding 14px 8px 0 0; margin-right clamp(0px,18vw,300px); 6px white dots.
Side card (BOTTOM-RIGHT, level with the bottom bar so the rings never cover it):
- .card: absolute; z 2; right clamp(16px,3.4vw,50px); bottom clamp(20px,4vh,38px); width min(260px,26vw); opacity 0 with animation fade 1s .5s forwards.
- h2 500 20px letter-spacing -0.01em margin-bottom 18px. p 14px line-height 1.5 var(--muted) margin-bottom 26px.
- .cta: inline-flex gap 8px; bg var(--cyan); color #00121a; 600; 14.5px; padding 12px 22px; radius 4px; transition transform .25s, box-shadow .35s, background .25s. Hover: bg var(--cyan-2), translateY(-2px), box-shadow 0 10px 34px -6px rgba(25,227,245,.65); the arrow svg moves translateX(3px).
Bottom bar:
- .bottom: absolute; z 2; left/right 0; bottom clamp(20px,4vh,38px); grid with columns minmax(120px,18%) 1fr; align end; padding 0 var(--pad).
- .social: stacked grid gap 8px, 15px, letter-spacing .02em, uppercase, var(--link); hover cyan.
- .discover: inline-flex gap 12px, 15px, letter-spacing .04em, uppercase, justify-self start; hover cyan; its svg animates bob 2s infinite (50%: translateY(4px)).
Tablet (max-width 1024px): .stage top 4vh; .card bottom clamp(20px,4vh,38px); .more margin-right 0.
Mobile (max-width 720px):
- Hide .links and .join; show .burger. nav.open .links becomes a dropdown: flex column, gap 18px, absolute top 100% left/right var(--pad), margin-top 14px, padding 20px, bg rgba(6,12,24,.85), backdrop-filter blur(14px) (+ -webkit-), 1px border rgba(255,255,255,.08), radius 10px, 17px. The burger turns into an X: span1 translateY(7.5px) rotate(45deg), span2 opacity 0, span3 translateY(-7.5px) rotate(-45deg).
- .hero is a flex column with order: nav 0, top 1, stage 2, card 3, bottom 4.
- .top columns 1fr auto, padding-top 28px, row-gap 18px. .counter spans full width, flex row, align center, gap 12px, padding-top 0. .dots-mini margin-top 0. h1 clamp(32px,10vw,46px). Hide .more.
- .stage: relative; inset auto; height 96vw; min-height 320px; margin -6vw 0 -4vw; overflow visible; mask-image (and -webkit-) linear-gradient(transparent, #000 14%, #000 86%, transparent) to feather the top and bottom.
- .card: relative; reset right/top/bottom; width auto; padding 0 var(--pad); margin-top 6px; h2 19px margin-bottom 10px; p margin-bottom 20px max-width 340px.
- .bottom: relative; bottom auto; margin-top auto; padding 36px var(--pad) 28px; columns 1fr auto. .social is a single row (grid-auto-flow column, gap 18px, 13px). .discover 13px, justify-self end.
Reduced motion: no animation on .loader or the discover svg; h1 spans have no animation or transform; .card has no animation and opacity 1; the 3D scene runs at 15% speed.
=== HTML (inside <section class="hero" id="hero">) ===
1. div.stage[aria-hidden] > div.loader#loader + canvas#gl
2. nav.nav#nav: a.brand "Lumora." | div.links: "Showcase" (class active), "Use Cases", "Innovation", "Connect" | a.join "Apply Now" | button.burger#burger (aria-label Menu, aria-expanded false) with 3 spans
3. div.top: div.counter (<div><b>001</b><span>/005</span></div> + div.dots-mini with 3 <i>) | h1 with two lines: "The next leap" / "in living visuals." | div.more (3 <i>)
4. aside.card: h2 "3D Lumora Engines." | p "Living 3D engines that sense, adapt, and respond in real time to unite imagination and compute." | a.cta "Enter the Studio" + arrow svg (14px, viewBox 0 0 24 24, stroke 2.4, round caps, path "M5 12h14M13 6l6 6-6 6")
5. div.bottom: div.social (Instagram, LinkedIn, GitHub) | a.discover with a down-arrow svg (16px, stroke 2, path "M12 4v16M6 14l6 6 6-6") followed by "Continue"
Plain script: clicking #burger toggles class "open" on #nav and sets aria-expanded to match.
=== THREE.JS SCENE (module script) ===
Renderer: WebGLRenderer({canvas, antialias, alpha, powerPreference 'high-performance'}); clear colour transparent; ACESFilmic tone mapping, exposure 1.0; SRGB output. scene.environment = PMREM of RoomEnvironment (sigma 0.02). PerspectiveCamera fov 30.
Lights: Ambient 0x88aaff 0.25; Directional 0xffffff 1.4 at (3,4,5); Directional 0x5aa0ff 1.0 at (-4,-1,3); Point 0x47b8ff 6, distance 5, decay 2 at the origin.
Hierarchy: scene > system (pointer tilt) > floatG (gentle float) > [blobHolder, ringRoot].
Shared GLSL: Ashima 3D simplex noise snoise(vec3), plus
float wobble(vec3 d){ return snoise(d*1.1 + vec3(uTime*.30, uTime*.21, -uTime*.26))*uAmp + snoise(d*2.3 - vec3(uTime*.42))*uAmp*.3; }
Uniforms U: uTime, uAmp (0.07), uR (blob local radius, default 1), uTex (the orb image; until it loads use a 1x1 DataTexture rgb(8,40,160)), uImgC = (0.495, 0.5), uImgR = 0.33.
Load the orb image with TextureLoader, crossOrigin 'anonymous', colorSpace SRGB, max anisotropy.
BLOB material (ShaderMaterial), which wraps the orb image onto the 3D mesh:
- Vertex: d = normalize(position); L0 = length(position); p = position + d*wobble(d)*L0. Approximate the displaced normal by sampling wobble at two tangent offsets (t1 = normalize(cross(d, (0,1,0.001))), t2 = cross(d,t1), offset 0.02), cross the differences, flip it to face the original normal, then vN = normalMatrix * mix(normal, n, 0.85).
Camera-facing projection: c = modelViewMatrix*(0,0,0,1); rv = length(modelViewMatrix*(uR,0,0,0)); vQ = (mv.xy - c.xy)/rv (-1..1 across the silhouette). vV = normalize(-mv.xyz).
- Fragment: r = length(vQ). Flowing vortex: a = uTime*0.16 + sin(uTime*0.45)*(1 - smoothstep(0,1,r))*0.55; rotate q by a; then q += 0.022*vec2(snoise(vec3(q*3, uTime*.35)), snoise(vec3(q*3+7.3, uTime*.35))). uv = uImgC + q*0.94*uImgR; col = texture(uTex, uv).rgb.
Breathing core: col += (0.55,0.85,1.0)*exp(-r*r*18)*(0.25 + 0.15*sin(uTime*1.3)).
Glass skin: fres = pow(1 - dot(n,vV), 3); col += (0.1,0.55,1.0)*fres*0.55. Speculars from L1 = normalize(0.35,0.7,0.6), power 70, ×0.5, colour (0.8,0.95,1.0); and L2 = normalize(-0.7,-0.2,0.6), power 30, ×0.35, colour (0.4,0.8,1.0). Output col*1.1.
- Start with a fallback IcosahedronGeometry(1, 64) using this material inside blobHolder.
- Load the GLB with GLTFLoader. Bake each mesh's matrixWorld into a cloned geometry and centre everything on the combined bounding box. Compute the max vertex radius maxR. Build a 60-bin histogram of vertex radius/maxR; take the peak bin among bins 1–51 (the blob surface); walk outward while the next bin is still > 4% of the peak; cut = (cutBin+1.5)/60*maxR. Keep only triangles whose 3 vertices are all < cut (this removes the model's built-in rings), then recompute normals. Measure the kept blob radius blobR, scale the group by 1/blobR, set U.uR = blobR, and swap it in for the fallback.
RINGS (built like a Blender torus + array):
- ringRoot.rotation = (-1.34, -0.12, -0.56), which reverses the old diagonal so the ring ends stay clear of the bottom-right copy.
- Glass ShaderMaterial factory glass(edge, body, glint): transparent, depthWrite false, AdditiveBlending, DoubleSide. Fragment: n flipped for back faces; f = 1 - abs(dot(n,vV)); col = (0.08,0.38,1.0)*body + (0.22,0.72,1.0)*pow(f,2.4)*edge; s1 = pow(max(dot(reflect(-L1,n),vV),0),90) with L1 = normalize(0.35,0.7,0.6); s2 = same with L2 = normalize(-0.6,-0.35,0.7), power 40; caustic = pow(max(dot(n,-L1),0),6)*0.35; col += (0.85,0.97,1.0)*(s1*glint + s2*0.35) + (0.3,0.8,1.0)*caustic.
strandMat = glass(0.85, 0.10, 1.2); beadMat = glass(1.25, 0.06, 2.6); beadGeo = SphereGeometry(1, 40, 28).
- Seeded RNG (Park–Miller: s = s*16807 % 2147483647, seed 7). 16 strands; for i in 0..15: k = i/15 - 0.5; R = 1.6 + k*0.5 ± 0.02. Each strand has a tilt group with rotation.x = k*0.20 ± 0.02 and rotation.y = k*0.07, so the strands bundle in front and splay at the ends. Inside it, a spin group holding TorusGeometry(R, 0.0035–0.0075, 8, 560) with strandMat; 3–7 beads at random angles on radius R, scale 0.022–0.06 (18% chance ×1.6); every 3rd strand also gets 26 evenly spaced micro-beads, scale 0.008–0.016. Spin speed 0.09–0.22 rad/s (even strands ×1.2).
- NO glow sprite and NO halo behind the orb.
Post-processing: EffectComposer with RenderPass, UnrealBloomPass(strength 0.38, radius 0.45, threshold 0.88) and OutputPass.
Layout fit() (run it with a ResizeObserver on .stage): pixel ratio min(dpr, 1.5 on mobile, else 2); size the renderer and composer to the stage. wantH = mobile ? 2/0.7 : 2/0.66; wantW = 4.4/(mobile ? 1.35 : 0.97); visH = max(wantH, wantW/aspect); camera.z = visH/(2*tan(fov/2)); system.position.y = mobile ? 0 : -visH*0.06.
Interaction:
- pointermove: target tilt = normalised pointer (-1..1); "near" = max(0, 1 - distance to the stage centre (y at 50% on mobile, 56% on desktop) / (stage height*0.4)).
- pointerleave resets; pointerdown sets pulse = 1; deviceorientation sets the target to (gamma/30, (beta-45)/30).
Animation loop (renderer.setAnimationLoop): dt capped at 0.05; speed 0.15 if reduced motion. Ease cx/cy toward the target by 0.05; ease nearS toward near by 0.05; pulse *= 0.94.
U.uTime = t*(1 + nearS*0.7); U.uAmp = 0.065 + nearS*0.06 + pulse*0.1.
system.rotation.y = cx*0.36; system.rotation.x = cy*0.24; floatG.position.y = sin(t*0.7)*0.05; blobHolder.rotation.y = sin(t*0.25)*0.25; blobHolder.rotation.z += dt*0.04; blobHolder scale = 1 + nearS*0.035 + pulse*0.05.
Each strand's spin.rotation.z += dt*speed*(1 + nearS*1.1 + pulse*2).
composer.render(). On the first frame add class "ready" to #gl and "hide" to #loader.
=== RESULT ===
Pure black hero. A large, wobbling liquid-glass blob shows the blue galaxy vortex image (always facing the viewer, constantly swirling, with a breathing white core and a cyan glass rim). A ribbon of 16 clear-glass strands with glowing cyan-edged glass beads orbits it on a diagonal and passes in front of and behind it. The scene tilts toward the cursor or device tilt; hovering near the orb makes it wobble more and spins the rings faster; a click sends a pulse. The headline sits top-left, the "3D Lumora Engines." card bottom-right, the socials and "Continue" bottom-left. There is no horizontal scroll at any width.