From 759875ec36e780b21585cfe84fc7b8ae8dc717c4 Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 27 Mar 2026 18:38:36 -0500 Subject: [PATCH] 's' --- app/topic/[topicId]/layout.tsx | 4 +- app/topic/components/TopicComingSoon.tsx | 2 +- app/topic/components/TopicPrepThreeScene.tsx | 633 ++++++++++++------- app/topic/config.ts | 8 +- 4 files changed, 414 insertions(+), 233 deletions(-) diff --git a/app/topic/[topicId]/layout.tsx b/app/topic/[topicId]/layout.tsx index 122c999..1f39fe8 100644 --- a/app/topic/[topicId]/layout.tsx +++ b/app/topic/[topicId]/layout.tsx @@ -9,8 +9,8 @@ export async function generateMetadata({ const titles: Record = { cloudphone: "云手机 | 低成本自建云手机", livestream: "无人直播 | TikTok/YouTube 24小时自动化", - indie: "独立开发 | 即将上线", - aiagent: "AI Agent | 即将上线", + indie: "独立开发 | 课程筹备", + aiagent: "AI Agent | 课程筹备", }; return { title: titles[topicId] ?? "模块 | 异度星球", diff --git a/app/topic/components/TopicComingSoon.tsx b/app/topic/components/TopicComingSoon.tsx index fe77959..2935e66 100644 --- a/app/topic/components/TopicComingSoon.tsx +++ b/app/topic/components/TopicComingSoon.tsx @@ -15,7 +15,7 @@ export function TopicComingSoon({ topicId }: TopicComingSoonProps) {
{config.icon}
-

即将上线

+

课程筹备

{config.desc}

m.dispose()); } -/** 独立开发:居家书桌 + 显示器 + homelab 机架 */ -function buildIndieDeskScene(root: THREE.Group) { - const wood = new THREE.MeshStandardMaterial({ - color: 0x6b5344, +function applyFilmicRenderer(renderer: THREE.WebGLRenderer, exposure: number) { + renderer.outputColorSpace = THREE.SRGBColorSpace; + renderer.toneMapping = THREE.ACESFilmicToneMapping; + renderer.toneMappingExposure = exposure; +} + +/** 独立开发:三面墙+顶+地 半封闭小房间(朝镜头开口),萌系配色与小狗 */ +function buildIndieEnclosedRoom(root: THREE.Group): { dog: THREE.Group; tail: THREE.Mesh } { + const wall = new THREE.MeshStandardMaterial({ + color: 0xfff0f3, + roughness: 0.94, + metalness: 0, + }); + const floorMat = new THREE.MeshStandardMaterial({ + color: 0xf5e0d4, roughness: 0.88, - metalness: 0.05, + metalness: 0, }); - const deskDark = new THREE.MeshStandardMaterial({ - color: 0x18181b, - roughness: 0.55, - metalness: 0.25, - }); - const screenGlow = new THREE.MeshStandardMaterial({ - color: 0x052e16, - emissive: 0x4ade80, - emissiveIntensity: 0.55, - roughness: 0.35, - }); - const keyCap = new THREE.MeshStandardMaterial({ - color: 0x3f3f46, - roughness: 0.45, - metalness: 0.15, - }); - const rackLed = new THREE.MeshStandardMaterial({ - color: 0x0c0a09, - emissive: 0xf59e0b, - emissiveIntensity: 0.5, - roughness: 0.4, + const ceilMat = new THREE.MeshStandardMaterial({ + color: 0xfff7fb, + roughness: 0.92, + metalness: 0, }); - const floor = new THREE.Mesh(new THREE.PlaneGeometry(7, 5.5), wood); + const floor = new THREE.Mesh(new THREE.PlaneGeometry(5.2, 4.2), floorMat); floor.rotation.x = -Math.PI / 2; - floor.position.y = -1.15; + floor.position.y = -1; root.add(floor); - const rug = new THREE.Mesh(new THREE.PlaneGeometry(2.8, 2), new THREE.MeshStandardMaterial({ - color: 0x3d3832, - roughness: 0.95, - })); - rug.rotation.x = -Math.PI / 2; - rug.position.set(0, -1.14, 0.1); - root.add(rug); + const back = new THREE.Mesh(new THREE.PlaneGeometry(5.2, 3.2), wall); + back.position.set(0, 0.6, -2.1); + root.add(back); - const deskTop = new THREE.Mesh(new THREE.BoxGeometry(2.4, 0.07, 1), deskDark); - deskTop.position.set(0, -0.38, 0.15); + const left = new THREE.Mesh(new THREE.PlaneGeometry(4.2, 3.2), wall); + left.rotation.y = Math.PI / 2; + left.position.set(-2.6, 0.6, 0); + root.add(left); + + const right = new THREE.Mesh(new THREE.PlaneGeometry(4.2, 3.2), wall); + right.rotation.y = -Math.PI / 2; + right.position.set(2.6, 0.6, 0); + root.add(right); + + const ceiling = new THREE.Mesh(new THREE.PlaneGeometry(5.2, 4.2), ceilMat); + ceiling.rotation.x = Math.PI / 2; + ceiling.position.y = 2.2; + root.add(ceiling); + + const lamp = new THREE.Mesh( + new THREE.PlaneGeometry(1.4, 0.9), + new THREE.MeshStandardMaterial({ + color: 0xffffff, + emissive: 0xfff1f2, + emissiveIntensity: 0.55, + roughness: 1, + }), + ); + lamp.rotation.x = Math.PI / 2; + lamp.position.set(0, 2.18, 0.2); + root.add(lamp); + + const deskMat = new THREE.MeshStandardMaterial({ + color: 0xf5e6d8, + roughness: 0.5, + metalness: 0.04, + }); + const deskTop = new THREE.Mesh(new THREE.BoxGeometry(1.65, 0.055, 0.72), deskMat); + deskTop.position.set(-0.25, -0.45, 0.05); root.add(deskTop); - const legGeo = new THREE.BoxGeometry(0.08, 0.45, 0.08); - const legPositions: [number, number, number][] = [ - [-1, -0.65, -0.25], - [1, -0.65, -0.25], - [-1, -0.65, 0.55], - [1, -0.65, 0.55], - ]; - for (const [x, y, z] of legPositions) { - const leg = new THREE.Mesh(legGeo, deskDark); - leg.position.set(x, y, z); + const legGeo = new THREE.CylinderGeometry(0.038, 0.042, 0.36, 14); + const legMat = new THREE.MeshStandardMaterial({ color: 0xe8d5c4, roughness: 0.58 }); + for (const [x, z] of [ + [-0.72, -0.22], + [0.22, -0.22], + [-0.72, 0.38], + [0.22, 0.38], + ]) { + const leg = new THREE.Mesh(legGeo, legMat); + leg.position.set(x, -0.66, z); root.add(leg); } - const monitorBezel = new THREE.Mesh(new THREE.BoxGeometry(1, 0.62, 0.045), deskDark); - monitorBezel.position.set(0, 0.12, -0.28); - root.add(monitorBezel); + const bezel = new THREE.MeshStandardMaterial({ + color: 0x3f3f46, + roughness: 0.42, + metalness: 0.12, + }); + const monitor = new THREE.Mesh(new THREE.BoxGeometry(0.62, 0.42, 0.028), bezel); + monitor.position.set(-0.25, -0.08, -0.38); + root.add(monitor); - const screen = new THREE.Mesh(new THREE.PlaneGeometry(0.88, 0.52), screenGlow); - screen.position.set(0, 0.12, -0.28 + 0.023); + const screenMat = new THREE.MeshStandardMaterial({ + color: 0xa5d8ff, + emissive: 0xc5eaff, + emissiveIntensity: 0.28, + roughness: 0.4, + }); + const screen = new THREE.Mesh(new THREE.PlaneGeometry(0.56, 0.36), screenMat); + screen.position.set(-0.25, -0.08, -0.38 + 0.015); root.add(screen); - const stand = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.12, 0.15), deskDark); - stand.position.set(0, -0.28, -0.22); - root.add(stand); - - const keyboard = new THREE.Mesh(new THREE.BoxGeometry(0.75, 0.035, 0.3), keyCap); - keyboard.position.set(0, -0.32, 0.38); - keyboard.rotation.x = -0.06; - root.add(keyboard); - - const mug = new THREE.Mesh( - new THREE.CylinderGeometry(0.09, 0.08, 0.12, 16), - new THREE.MeshStandardMaterial({ color: 0x3f3f46, roughness: 0.4 }), + const kb = new THREE.Mesh( + new THREE.BoxGeometry(0.48, 0.022, 0.18), + new THREE.MeshStandardMaterial({ color: 0xa8a29e, roughness: 0.55 }), ); - mug.position.set(-0.85, -0.31, 0.42); - root.add(mug); + kb.position.set(-0.25, -0.4, 0.22); + kb.rotation.x = -0.035; + root.add(kb); - const rack = new THREE.Mesh(new THREE.BoxGeometry(0.38, 0.95, 0.42), deskDark); - rack.position.set(1.05, 0.1, -0.05); - root.add(rack); + const tower = new THREE.Mesh( + new THREE.BoxGeometry(0.18, 0.36, 0.32), + new THREE.MeshStandardMaterial({ color: 0xfafafa, roughness: 0.32 }), + ); + tower.position.set(0.38, -0.38, -0.28); + root.add(tower); - const rackFace = new THREE.Mesh(new THREE.PlaneGeometry(0.3, 0.82), rackLed); - rackFace.position.set(1.05 + 0.191, 0.1, -0.05); - root.add(rackFace); + const chairSeat = new THREE.Mesh( + new THREE.BoxGeometry(0.4, 0.055, 0.36), + new THREE.MeshStandardMaterial({ color: 0x78716c, roughness: 0.72 }), + ); + chairSeat.position.set(-0.25, -0.72, 0.55); + root.add(chairSeat); - for (let row = 0; row < 4; row++) { - const led = new THREE.Mesh( - new THREE.PlaneGeometry(0.22, 0.04), - new THREE.MeshStandardMaterial({ - color: 0x000000, - emissive: row % 2 === 0 ? 0x22c55e : 0xf59e0b, - emissiveIntensity: 0.65, - }), - ); - led.position.set(1.05 + 0.192, 0.35 - row * 0.18, -0.05); - root.add(led); + const fur = new THREE.MeshStandardMaterial({ + color: 0xffc4a8, + roughness: 0.82, + metalness: 0, + }); + const furDeep = new THREE.MeshStandardMaterial({ + color: 0xf59e7c, + roughness: 0.85, + metalness: 0, + }); + + const dog = new THREE.Group(); + dog.position.set(0.75, -0.86, 0.22); + + const body = new THREE.Mesh(new THREE.SphereGeometry(0.2, 22, 18), fur); + body.scale.set(1.05, 0.78, 1.12); + body.position.y = 0.11; + dog.add(body); + + const head = new THREE.Mesh(new THREE.SphereGeometry(0.16, 20, 18), fur); + head.position.set(0, 0.3, 0.1); + dog.add(head); + + const snout = new THREE.Mesh(new THREE.SphereGeometry(0.065, 14, 14), furDeep); + snout.position.set(0, 0.26, 0.22); + snout.scale.set(1, 0.88, 1.15); + dog.add(snout); + + const nose = new THREE.Mesh( + new THREE.SphereGeometry(0.022, 10, 10), + new THREE.MeshStandardMaterial({ color: 0x292524, roughness: 0.35 }), + ); + nose.position.set(0, 0.28, 0.3); + dog.add(nose); + + const eyeWhiteL = new THREE.Mesh( + new THREE.SphereGeometry(0.045, 12, 12), + new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.25 }), + ); + eyeWhiteL.position.set(-0.055, 0.32, 0.18); + const eyeWhiteR = eyeWhiteL.clone(); + eyeWhiteR.position.x = 0.055; + dog.add(eyeWhiteL, eyeWhiteR); + + const pupilL = new THREE.Mesh( + new THREE.SphereGeometry(0.022, 10, 10), + new THREE.MeshStandardMaterial({ color: 0x1c1917, roughness: 0.2 }), + ); + pupilL.position.set(-0.052, 0.32, 0.2); + const pupilR = pupilL.clone(); + pupilR.position.x = 0.052; + dog.add(pupilL, pupilR); + + const blushMat = new THREE.MeshStandardMaterial({ + color: 0xff9eb5, + roughness: 0.6, + emissive: 0xff8fab, + emissiveIntensity: 0.12, + }); + const blushL = new THREE.Mesh(new THREE.SphereGeometry(0.035, 10, 10), blushMat); + blushL.scale.set(1.2, 0.45, 0.6); + blushL.position.set(-0.1, 0.24, 0.16); + const blushR = blushL.clone(); + blushR.position.x = 0.1; + dog.add(blushL, blushR); + + const earL = new THREE.Mesh(new THREE.SphereGeometry(0.055, 12, 12), furDeep); + earL.position.set(-0.11, 0.36, 0.05); + earL.scale.set(0.45, 0.95, 0.4); + const earR = earL.clone(); + earR.position.x = 0.11; + dog.add(earL, earR); + + const tail = new THREE.Mesh( + new THREE.CylinderGeometry(0.028, 0.036, 0.2, 12), + furDeep, + ); + tail.rotation.z = Math.PI / 2.8; + tail.rotation.x = 0.25; + tail.position.set(-0.18, 0.16, -0.06); + dog.add(tail); + + for (const [x, z] of [ + [-0.09, 0.07], + [0.09, 0.07], + [-0.07, -0.07], + [0.07, -0.07], + ]) { + const paw = new THREE.Mesh(new THREE.SphereGeometry(0.048, 12, 12), furDeep); + paw.scale.set(1, 0.58, 1); + paw.position.set(x, 0, z); + dog.add(paw); } - const miniServer = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.15, 0.18), deskDark); - miniServer.position.set(1.05, -0.28, 0.45); - root.add(miniServer); + root.add(dog); + return { dog, tail }; } -/** AI Agent:赛博空间网格 + 机器人 + 霓虹光环 */ -function buildAiCyberScene(root: THREE.Group) { - const grid = new THREE.GridHelper(9, 28, 0x6366f1, 0x312e81); - grid.position.y = -1.05; - const gMat = grid.material; - if (Array.isArray(gMat)) { - gMat.forEach((m) => { - if ("opacity" in m) { - (m as THREE.Material & { opacity: number }).opacity = 0.45; - m.transparent = true; - } - }); - } else if (gMat && "opacity" in gMat) { - (gMat as THREE.Material & { opacity: number }).opacity = 0.45; - gMat.transparent = true; - } - root.add(grid); - - const bodyMat = new THREE.MeshStandardMaterial({ - color: 0x52525b, - metalness: 0.55, - roughness: 0.28, - flatShading: true, - }); - const glowCyan = new THREE.MeshStandardMaterial({ - color: 0x06b6d4, - emissive: 0x22d3ee, - emissiveIntensity: 0.85, - }); - const glowMagenta = new THREE.MeshStandardMaterial({ - color: 0xd946ef, - emissive: 0xc026d3, - emissiveIntensity: 0.55, - }); - - const robot = new THREE.Group(); - robot.position.y = -0.15; - - const torso = new THREE.Mesh(new THREE.BoxGeometry(0.52, 0.58, 0.32), bodyMat); - torso.position.y = 0.1; - robot.add(torso); - - const chestPanel = new THREE.Mesh(new THREE.PlaneGeometry(0.35, 0.25), glowCyan); - chestPanel.position.set(0, 0.12, 0.161); - robot.add(chestPanel); - - const head = new THREE.Mesh(new THREE.BoxGeometry(0.44, 0.36, 0.38), bodyMat); - head.position.y = 0.55; - robot.add(head); - - const visor = new THREE.Mesh(new THREE.BoxGeometry(0.38, 0.12, 0.02), glowCyan); - visor.position.set(0, 0.52, 0.19); - robot.add(visor); - - const eyeL = new THREE.Mesh(new THREE.SphereGeometry(0.055, 16, 16), glowCyan); - eyeL.position.set(-0.1, 0.56, 0.18); - const eyeR = new THREE.Mesh(new THREE.SphereGeometry(0.055, 16, 16), glowCyan); - eyeR.position.set(0.1, 0.56, 0.18); - robot.add(eyeL, eyeR); - - const antenna = new THREE.Mesh(new THREE.CylinderGeometry(0.025, 0.03, 0.28, 8), glowMagenta); - antenna.position.set(0, 0.82, 0); - robot.add(antenna); - - const armL = new THREE.Mesh(new THREE.BoxGeometry(0.12, 0.45, 0.12), bodyMat); - armL.position.set(-0.38, 0.05, 0); - const armR = armL.clone(); - armR.position.x = 0.38; - robot.add(armL, armR); - - root.add(robot); - - for (let i = 0; i < 3; i++) { - const ringMat = new THREE.MeshBasicMaterial({ - color: i === 1 ? 0xa855f7 : 0x22d3ee, - transparent: true, - opacity: 0.35 - i * 0.08, - }); - const ring = new THREE.Mesh(new THREE.TorusGeometry(0.95 + i * 0.22, 0.012, 8, 64), ringMat); - ring.rotation.x = Math.PI / 2; - ring.position.y = -0.85 + i * 0.15; - root.add(ring); - } - - const holo = new THREE.Mesh( - new THREE.OctahedronGeometry(0.18, 0), - new THREE.MeshBasicMaterial({ color: 0x67e8f9, wireframe: true, transparent: true, opacity: 0.5 }), +/** AI:赛博空间,无网格线;萌系圆润机器人 + 实体光晕环(非线框) */ +function buildAiCuteCyber(root: THREE.Group): { + bot: THREE.Group; + halo: THREE.Mesh; + orbs: THREE.Mesh[]; +} { + const backdrop = new THREE.Mesh( + new THREE.SphereGeometry(16, 48, 48), + new THREE.MeshBasicMaterial({ color: 0x0c0618, side: THREE.BackSide }), ); - holo.position.set(-0.55, 0.35, 0.35); - root.add(holo); + root.add(backdrop); - return { robot, holo }; + const floor = new THREE.Mesh( + new THREE.CircleGeometry(4.5, 64), + new THREE.MeshStandardMaterial({ + color: 0x1e1435, + roughness: 0.55, + metalness: 0.15, + emissive: 0x4c1d95, + emissiveIntensity: 0.06, + }), + ); + floor.rotation.x = -Math.PI / 2; + floor.position.y = -1.05; + root.add(floor); + + const haloMat = new THREE.MeshStandardMaterial({ + color: 0xa78bfa, + emissive: 0x8b5cf6, + emissiveIntensity: 0.25, + roughness: 0.35, + metalness: 0.25, + transparent: true, + opacity: 0.55, + side: THREE.DoubleSide, + }); + const halo = new THREE.Mesh(new THREE.TorusGeometry(1.05, 0.035, 16, 64), haloMat); + halo.rotation.x = Math.PI / 2; + halo.position.y = -0.35; + root.add(halo); + + const shell = new THREE.MeshStandardMaterial({ + color: 0xe8e0ff, + roughness: 0.42, + metalness: 0.18, + }); + const shellDark = new THREE.MeshStandardMaterial({ + color: 0xc4b5fd, + roughness: 0.45, + metalness: 0.22, + }); + const eyeGlow = new THREE.MeshStandardMaterial({ + color: 0x67e8f9, + emissive: 0x22d3ee, + emissiveIntensity: 0.35, + roughness: 0.28, + }); + + const bot = new THREE.Group(); + bot.position.set(0, -0.25, 0); + + const body = new THREE.Mesh(new THREE.SphereGeometry(0.32, 28, 24), shell); + body.scale.set(1, 0.88, 0.92); + body.position.y = 0.05; + bot.add(body); + + const tummy = new THREE.Mesh(new THREE.CircleGeometry(0.18, 24), shellDark); + tummy.rotation.x = -0.15; + tummy.position.set(0, 0.02, 0.27); + bot.add(tummy); + + const head = new THREE.Mesh(new THREE.SphereGeometry(0.26, 28, 24), shell); + head.position.y = 0.48; + bot.add(head); + + const eyeWL = new THREE.Mesh(new THREE.SphereGeometry(0.07, 14, 14), new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.2 })); + eyeWL.position.set(-0.08, 0.5, 0.22); + const eyeWR = eyeWL.clone(); + eyeWR.position.x = 0.08; + bot.add(eyeWL, eyeWR); + + const eyeL = new THREE.Mesh(new THREE.SphereGeometry(0.038, 12, 12), eyeGlow); + eyeL.position.set(-0.078, 0.5, 0.26); + const eyeR = eyeL.clone(); + eyeR.position.x = 0.078; + bot.add(eyeL, eyeR); + + const cheek = new THREE.MeshStandardMaterial({ + color: 0xf9a8d4, + emissive: 0xf472b6, + emissiveIntensity: 0.15, + roughness: 0.5, + }); + const chL = new THREE.Mesh(new THREE.SphereGeometry(0.04, 10, 10), cheek); + chL.scale.set(1.3, 0.5, 0.5); + chL.position.set(-0.14, 0.42, 0.2); + const chR = chL.clone(); + chR.position.x = 0.14; + bot.add(chL, chR); + + const antStem = new THREE.Mesh( + new THREE.CylinderGeometry(0.02, 0.025, 0.16, 10), + shellDark, + ); + antStem.position.set(0, 0.72, 0); + bot.add(antStem); + const antBall = new THREE.Mesh(new THREE.SphereGeometry(0.055, 16, 16), eyeGlow); + antBall.position.set(0, 0.82, 0); + bot.add(antBall); + + const armGeo = new THREE.CapsuleGeometry(0.07, 0.22, 6, 12); + const armL = new THREE.Mesh(armGeo, shell); + armL.position.set(-0.42, 0.08, 0); + armL.rotation.z = 0.35; + const armR = new THREE.Mesh(armGeo, shell); + armR.position.set(0.42, 0.08, 0); + armR.rotation.z = -0.35; + bot.add(armL, armR); + + const leg = new THREE.Mesh(new THREE.CapsuleGeometry(0.09, 0.12, 6, 12), shellDark); + leg.position.set(-0.12, -0.32, 0.05); + const leg2 = leg.clone(); + leg2.position.x = 0.12; + bot.add(leg, leg2); + + root.add(bot); + + const orbMat = [ + new THREE.MeshStandardMaterial({ color: 0xf0abfc, roughness: 0.35, metalness: 0.2 }), + new THREE.MeshStandardMaterial({ color: 0x7dd3fc, roughness: 0.35, metalness: 0.2 }), + new THREE.MeshStandardMaterial({ color: 0xfde68a, roughness: 0.35, metalness: 0.15 }), + ]; + const orbs: THREE.Mesh[] = []; + for (let i = 0; i < 3; i++) { + const o = new THREE.Mesh(new THREE.SphereGeometry(0.09, 16, 16), orbMat[i]); + const a = (i / 3) * Math.PI * 2; + o.position.set(Math.cos(a) * 1.15, 0.25 + i * 0.08, Math.sin(a) * 1.15); + root.add(o); + orbs.push(o); + } + + return { bot, halo, orbs }; } export function TopicPrepThreeScene({ variant }: Props) { @@ -243,59 +405,70 @@ export function TopicPrepThreeScene({ variant }: Props) { const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, - alpha: true, + alpha: false, powerPreference: "high-performance", }); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(42, 1, 0.1, 100); - camera.position.set(0, 0.35, 5.2); + camera.position.set(0.35, 0.45, 3.85); const group = new THREE.Group(); scene.add(group); - let bobRefs: { robot?: THREE.Group; holo?: THREE.Mesh } | null = null; + let anim: { + dog?: THREE.Group; + tail?: THREE.Mesh; + bot?: THREE.Group; + halo?: THREE.Mesh; + orbs?: THREE.Mesh[]; + } | null = null; if (variant === "indie") { - scene.background = null; - const ambient = new THREE.AmbientLight(0xfff5e6, 0.45); - scene.add(ambient); - const warm = new THREE.PointLight(0xffb86b, 1.1, 12); - warm.position.set(0.6, 1.2, 1.2); - scene.add(warm); - const cool = new THREE.PointLight(0x4ade80, 0.35, 8); - cool.position.set(-0.3, 0.5, 0.5); - scene.add(cool); - const dir = new THREE.DirectionalLight(0xffffff, 0.35); - dir.position.set(-2, 4, 3); - scene.add(dir); + scene.fog = new THREE.Fog(0xfff5f7, 3.8, 11); + applyFilmicRenderer(renderer, 1.02); - buildIndieDeskScene(group); - group.rotation.y = 0.25; - } else { - scene.fog = new THREE.FogExp2(0x0a0a14, 0.055); - const ambient = new THREE.AmbientLight(0x4c1d95, 0.35); - scene.add(ambient); - const key = new THREE.PointLight(0x22d3ee, 1.2, 16); - key.position.set(1.5, 2, 2); + const hemi = new THREE.HemisphereLight(0xffffff, 0xfce7f3, 0.95); + scene.add(hemi); + const key = new THREE.DirectionalLight(0xffffff, 0.48); + key.position.set(2, 5, 3); scene.add(key); - const rim = new THREE.PointLight(0xd946ef, 0.85, 14); - rim.position.set(-2, 0.5, -1); - scene.add(rim); - const dir = new THREE.DirectionalLight(0xa78bfa, 0.4); - dir.position.set(0, 3, 4); - scene.add(dir); + const fill = new THREE.DirectionalLight(0xffe4e8, 0.28); + fill.position.set(-3, 2, -1); + scene.add(fill); + const scr = new THREE.PointLight(0xbfdbfe, 0.35, 5); + scr.position.set(-0.25, 0, 0); + scene.add(scr); - bobRefs = buildAiCyberScene(group); + anim = buildIndieEnclosedRoom(group); + group.rotation.set(0.1, 0.28, 0); + } else { + scene.fog = new THREE.FogExp2(0x0c0618, 0.048); + applyFilmicRenderer(renderer, 1.05); + + const hemi = new THREE.HemisphereLight(0xc4b5fd, 0x1e1038, 0.75); + scene.add(hemi); + const key = new THREE.DirectionalLight(0xf5f3ff, 0.5); + key.position.set(2, 4.5, 3); + scene.add(key); + const rim = new THREE.DirectionalLight(0x7c3aed, 0.22); + rim.position.set(-2.5, 1, -1.5); + scene.add(rim); + const glow = new THREE.PointLight(0xa78bfa, 0.4, 9); + glow.position.set(0.8, 1.2, 1); + scene.add(glow); + + anim = buildAiCuteCyber(group); + group.rotation.set(0.06, -0.15, 0); } - let rx = 0.1; - let ry = variant === "indie" ? 0.2 : 0; + let rx = group.rotation.x; + let ry = group.rotation.y; let vx = 0; let vy = 0; - const sens = 0.0052; - const damping = 0.93; - const autoRy = variant === "indie" ? 0.0018 : 0.0024; + const sens = 0.0046; + const damping = 0.936; + const autoRy = variant === "indie" ? 0.001 : 0.0013; let dragging = false; let lastX = 0; @@ -333,7 +506,7 @@ export function TopicPrepThreeScene({ variant }: Props) { const resize = () => { const w = Math.max(280, container.clientWidth); - const h = Math.min(440, Math.max(236, Math.round(w * 0.5))); + const h = Math.min(440, Math.max(240, Math.round(w * 0.52))); camera.aspect = w / h; camera.updateProjectionMatrix(); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); @@ -357,12 +530,27 @@ export function TopicPrepThreeScene({ variant }: Props) { group.rotation.x = rx; group.rotation.y = ry; - if (bobRefs?.robot) { - bobRefs.robot.position.y = -0.15 + Math.sin(t * 1.8) * 0.035; + if (anim?.dog) { + anim.dog.position.y = -0.86 + Math.sin(t * 2) * 0.016; + anim.dog.rotation.y = Math.sin(t * 0.85) * 0.05; } - if (bobRefs?.holo) { - bobRefs.holo.rotation.y = t * 0.9; - bobRefs.holo.rotation.x = t * 0.45; + if (anim?.tail) { + anim.tail.rotation.z = Math.PI / 2.8 + Math.sin(t * 4.5) * 0.22; + } + if (anim?.bot) { + anim.bot.position.y = -0.25 + Math.sin(t * 1.5) * 0.03; + anim.bot.rotation.y = Math.sin(t * 0.6) * 0.04; + } + if (anim?.halo) { + anim.halo.rotation.z = t * 0.15; + } + if (anim?.orbs) { + anim.orbs.forEach((o, i) => { + const a = t * 0.5 + (i / 3) * Math.PI * 2; + o.position.y = 0.25 + i * 0.08 + Math.sin(t * 1.8 + i) * 0.06; + o.position.x = Math.cos(a) * 1.15; + o.position.z = Math.sin(a) * 1.15; + }); } renderer.render(scene, camera); @@ -383,20 +571,13 @@ export function TopicPrepThreeScene({ variant }: Props) { }; }, [variant]); - const label = - variant === "indie" ? "独立开发:居家工作台与 homelab 预览" : "AI Agent:赛博空间与机器人预览"; - - const hint = - variant === "indie" - ? "拖动旋转 · 居家书桌、显示器与 homelab 机架(课程筹备视觉预告)" - : "拖动旋转 · 赛博网格空间与机器人(课程筹备视觉预告)"; + const label = variant === "indie" ? "独立开发互动预览" : "AI Agent 互动预览"; return (
-

{hint}

diff --git a/app/topic/config.ts b/app/topic/config.ts index 04c0d36..d72ef68 100644 --- a/app/topic/config.ts +++ b/app/topic/config.ts @@ -51,10 +51,10 @@ export const TOPIC_CONFIGS: Record = { icon: "🛠️", title: "独立开发", subtitle: "从想法到产品,独立开发者全流程指南", - desc: "即将上线,敬请期待。", + desc: "", stats: [ { value: "—", label: "课程筹备中" }, - { value: "—", label: "敬请期待" }, + { value: "—", label: "内容策划中" }, ], moduleIndices: [], payUrl: "/", @@ -64,10 +64,10 @@ export const TOPIC_CONFIGS: Record = { icon: "🤖", title: "AI Agent", subtitle: "AIGC 与智能体,Vibe Coding 跨界创造", - desc: "即将上线,敬请期待。", + desc: "", stats: [ { value: "—", label: "课程筹备中" }, - { value: "—", label: "敬请期待" }, + { value: "—", label: "内容策划中" }, ], moduleIndices: [], payUrl: "/",