@@ -27,208 +27,370 @@ function disposeObject3D(root: THREE.Object3D) {
materials . forEach ( ( m ) = > 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 : 0x18181 b ,
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 : 0xfff7f b ,
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 . MeshStandardMateria l( {
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) , wal l) ;
back . position . set ( 0 , 0.6 , - 2.1 ) ;
root . add ( back ) ;
const deskTop = new THREE . Mesh ( new THREE . Box Geometry( 2.4 , 0.07 , 1 ) , deskDark ) ;
deskTop . posi tion. set ( 0 , - 0.38 , 0.15 ) ;
const left = new THREE . Mesh ( new THREE . Plane Geometry( 4.2 , 3.2 ) , wall ) ;
left . rota tion. 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 . Box Geometry( 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 . Cylinder Geometry( 0.03 8 , 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 monitorB ezel = new THREE . Mesh( new THREE . BoxGeometry ( 1 , 0.62 , 0.045 ) , deskDark ) ;
monitorBezel . position . set ( 0 , 0.12 , - 0.28 ) ;
root . add ( monitorBezel ) ;
const b ezel = 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.8 5 , - 0.31 , 0.4 2 ) ;
root . add ( mug ) ;
kb . position . set ( - 0.2 5 , - 0.4 , 0.2 2 ) ;
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 ( le t 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 ) ;
cons t 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 buildAiCuteC yber ( 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 : tru e,
alpha : fals e,
powerPreference : "high-performance" ,
} ) ;
const scene = new THREE . Scene ( ) ;
const camera = new THREE . PerspectiveCamera ( 42 , 1 , 0.1 , 100 ) ;
camera . position . set ( 0 , 0.3 5 , 5.2 ) ;
camera . position . set ( 0.35 , 0.4 5 , 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 . Point Light( 0xd946ef , 0.85 , 14 ) ;
rim . position . set ( - 2 , 0.5 , - 1 ) ;
scene . add ( rim ) ;
const di r = new THREE . Directional Light( 0xa78 bfa , 0.4 ) ;
di r. position . set ( 0 , 3 , 4 ) ;
scene . add ( di r) ;
const fill = new THREE . Directional Light( 0xffe4e8 , 0.2 8 ) ;
fill . position . set ( - 3 , 2 , - 1 ) ;
scene . add ( fill ) ;
const sc r = new THREE . Point Light( 0xbfd bfe , 0.35 , 5 ) ;
sc r. position . set ( - 0.25 , 0 , 0 ) ;
scene . add ( sc r) ;
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 (
< div ref = { containerRef } className = "mx-auto mt-2 w-full max-w-2xl" >
< p className = "mb-2 text-center text-xs text-[var(--muted-foreground)]" > { hint } < / p >
< canvas
ref = { canvasRef }
className = "mx-auto block w-full cursor-grab touch-none rounded-2xl border border-[var(--border)] bg-[var(--muted)]/25 active:cursor-grabbing dark:bg-[var(--muted)]/15 "
className = "mx-auto block w-full cursor-grab touch-none rounded-2xl shadow-md outline-none active:cursor-grabbing dark:shadow-lg dark:shadow-violet-950/20 "
aria-label = { label }
role = "img"
/ >