PageSourceSearch

https://starwarsdatabase.com/gallery/src/robots/robot-04.js?v=0.67.1&greeting=3

js starwarsdatabase.com collected 2026-10-07 19:30:14 UTC 7,691 bytes, 78 lines download raw bytes

1import * as THREE from '../../assets/vendor/three.module.js';
2
3export const ROBOT_04 = Object.freeze({id:'robot-04',name:'Robot 04',height:1.07,radius:.4,reservation:1.2,maxTriangles:2500,maxDrawCalls:12,maxMaterials:4});
4const C={ivory:0xded6c5,blue:0x4f6478,bronze:0x827354,dark:0x303a34,amber:0xe5b759};
5const rad=THREE.MathUtils.degToRad;
6const finite=(n,fallback=0)=>Number.isFinite(n)?n:fallback;
7const clamp=(n,lo,hi)=>THREE.MathUtils.clamp(finite(n),lo,hi);
8
9// Four bevel rings, flat normals, no texture or external model dependency.
10function shell(w,h,d,bevel=.01,taper=1){
11 const positions=[],rings=[];
12 for(const [z,inset] of [[-d/2,bevel],[-d/2+bevel,0],[d/2-bevel,0],[d/2,bevel]]){
13  const x=w/2-inset,y=h/2-inset,c=Math.min(bevel*1.5,x*.3,y*.3);
14  rings.push([[-x+c,-y], [x-c,-y], [x,-y+c], [x,y-c], [x-c,y],[-x+c,y],[-x,y-c],[-x,-y+c]].map(([px,py])=>[px*(taper+(1-taper)*(py+h/2)/h),py,z]));
15 }
16 const tri=(a,b,c)=>positions.push(...a,...b,...c);
17 for(let j=0;j<3;j++)for(let i=0;i<8;i++){const n=(i+1)%8;tri(rings[j][i],rings[j][n],rings[j+1][n]);tri(rings[j][i],rings[j+1][n],rings[j+1][i]);}
18 for(let i=0;i<8;i++){const n=(i+1)%8;tri([0,0,-d/2],rings[0][n],rings[0][i]);tri([0,0,d/2],rings[3][i],rings[3][n]);}
19 const g=new THREE.BufferGeometry();g.setAttribute('position',new THREE.Float32BufferAttribute(positions,3));g.computeVertexNormals();return g;
20}
21function cylinder(r,len,axis='y'){const g=new THREE.CylinderGeometry(r,r,len,12,1,false);if(axis==='x')g.rotateZ(Math.PI/2);if(axis==='z')g.rotateX(Math.PI/2);return g;}
22function piece(g,color,x=0,y=0,z=0,rotation=null){if(rotation){g.rotateX(rotation[0]||0);g.rotateY(rotation[1]||0);g.rotateZ(rotation[2]||0);}g.translate(x,y,z);return {g,color};}
23function bar(a,b,width,depth,color){const va=new THREE.Vector3(...a),vb=new THREE.Vector3(...b),g=shell(width,va.distanceTo(vb),depth,.006);g.applyQuaternion(new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0,1,0),vb.clone().sub(va).normalize()));g.translate(...va.add(vb).multiplyScalar(.5).toArray());return {g,color};}
24function merged(parts,material,name){
25 const pos=[],norm=[],colors=[];
26 for(const {g,color} of parts){const flat=g.index?g.toNonIndexed():g,c=new THREE.Color(color),p=flat.attributes.position,n=flat.attributes.normal;pos.push(...p.array);norm.push(...n.array);for(let i=0;i<p.count;i++)colors.push(c.r,c.g,c.b);if(flat!==g)flat.dispose();g.dispose();}
27 const g=new THREE.BufferGeometry();g.setAttribute('position',new THREE.Float32BufferAttribute(pos,3));g.setAttribute('normal',new THREE.Float32BufferAttribute(norm,3));g.setAttribute('color',new THREE.Float32BufferAttribute(colors,3));g.computeBoundingSphere();const m=new THREE.Mesh(g,material);m.name=name;m.castShadow=false;m.receiveShadow=true;return m;
28}
29
30// Original pedestal archivist: a bell base, slender waist, lantern head and
31// an open three-pronged greeting hand. The support never turns or travels.
32export function createRobot04(){
33 const root=new THREE.Group();root.name=ROBOT_04.name;root.userData.robotId=ROBOT_04.id;
34 const painted=new THREE.MeshStandardMaterial({vertexColors:true,metalness:.12,roughness:.48});
35 const metal=new THREE.MeshStandardMaterial({vertexColors:true,metalness:.76,roughness:.34});
36 const optics=new THREE.MeshStandardMaterial({vertexColors:true,roughness:.4,emissive:0x765019,emissiveIntensity:.38});
37 const put=(parent,parts,material,name)=>{const mesh=merged(parts,material,name);parent.add(mesh);return mesh;};
38 put(root,[piece(new THREE.CylinderGeometry(.192,.205,.035,12),C.dark,0,.0175,0),piece(new THREE.CylinderGeometry(.082,.19,.195,12),C.ivory,0,.1325,0),piece(cylinder(.083,.055),C.blue,0,.2575,0)],painted,'Fixed bell pedestal');
39 const baseTrim=[piece(cylinder(.191,.015),C.bronze,0,.04,0),piece(cylinder(.084,.018),C.bronze,0,.230,0)];
40 for(const x of [-.045,0,.045])baseTrim.push(piece(shell(.013,.033,.006,.002),C.bronze,x,.119,.137));
41 put(root,baseTrim,metal,'Pedestal trim');
42 const torso=new THREE.Group();torso.name='Torso pivot';torso.position.y=.285;root.add(torso);
43 put(torso,[piece(cylinder(.042,.205),C.blue,0,.10,0),piece(shell(.278,.146,.172,.023,.77),C.ivory,0,.276,0),piece(shell(.091,.073,.009,.006),C.blue,0,.274,.091)],painted,'Slender waist and shoulder shell');
44 const hardware=[piece(cylinder(.061,.028),C.bronze,0,.021,0),piece(cylinder(.063,.028),C.bronze,0,.191,0),piece(cylinder(.027,.105),C.bronze,0,.39,0)];
45 for(const side of [-1,1])hardware.push(piece(cylinder(.029,.028,'x'),C.bronze,side*.147,.30,0));
46 for(let i=0;i<3;i++)hardware.push(piece(new THREE.BoxGeometry(.10,.01,.01),C.bronze,0,.244+i*.028,-.089));
47 put(torso,hardware,metal,'Waist collars, neck and rear vents');
48 const head=new THREE.Group();head.name='Head pivot';
48head.position.y=.61;torso.add(head);
49 put(head,[piece(shell(.196,.35,.172,.022,.76),C.ivory),piece(shell(.123,.213,.012,.012,.8),C.dark,0,-.006,.092),piece(shell(.145,.042,.198,.012),C.blue,0,.16,0)],painted,'Tall lantern head');
50 put(head,[piece(shell(.027,.224,.020,.006),C.bronze,-.081,-.009,.077),piece(shell(.027,.224,.020,.006),C.bronze,.081,-.009,.077),piece(shell(.092,.056,.015,.008),C.bronze,0,-.116,-.091)],metal,'Lantern rails and rear service plate');
51 const eyes=new THREE.Group();eyes.name='Following optics';head.add(eyes);
52 put(eyes,[piece(shell(.026,.092,.009,.008),C.amber,-.027,.019,.106),piece(shell(.026,.059,.009,.008),C.amber,.027,.011,.106),piece(shell(.040,.009,.006,.002),C.amber,0,-.068,.104)],optics,'Asymmetric amber optics');
53 const arms=[];
54 for(const side of [-1,1]){
55  const arm=new THREE.Group();arm.name=side<0?'Greeting hand pivot':'Resting hand pivot';arm.position.set(side*.164,.298,0);torso.add(arm);arms.push(arm);
56  const parts=[bar([0,0,0],[side*.027,-.108,.019],.032,.036,C.blue),piece(cylinder(.022,.043,'x'),C.bronze,side*.027,-.108,.019),bar([side*.027,-.108,.019],[side*.033,-.184,.076],.028,.031,C.bronze),piece(shell(.060,.041,.037,.006),C.blue,side*.033,-.193,.086)];
57  for(const finger of [-1,0,1])parts.push(piece(shell(.011,.043,.018,.003),C.ivory,side*.033+finger*.021,-.226,.094));
58  put(arm,parts,painted,side<0?'Three-pronged greeting hand':'Resting three-pronged hand');
59 }
60 let disposed=false,time=0,greeting=-1;
61 function pose({headYaw=0,headPitch=0,torsoYaw=0,armLift=0,eyeYaw=0,eyePitch=0,tilt=0}={}){
62  if(disposed)return;
63  torso.rotation.y=rad(clamp(torsoYaw,-15,15));head.rotation.set(rad(clamp(headPitch,-12,12)),rad(clamp(headYaw,-45,45)),rad(clamp(tilt,-2,2)),'YXZ');
64  arms[0].rotation.x=-rad(clamp(armLift,0,32));arms[1].rotation.x=-rad(clamp(armLift,0,32)*.12);
65  eyes.position.set(clamp(eyeYaw,-1,1)*.004,clamp(eyePitch,-1,1)*.004,0);root.updateMatrixWorld(true);
66 }
67 function update(dt,{active=true,reducedMotion=false,target=null}={}){
68  if(disposed)return false;if(reducedMotion){greeting=-1;pose();return false;}if(!active)return false;
69  const step=clamp(dt,0,.05);time+=step;let wave=0,nod=0;
70  if(greeting>=0){greeting+=step;if(greeting>=1.8*3)greeting=-1;else{const phase=greeting%1.8;wave=Math.sin(Math.PI*phase/1.8);nod=Math.sin(2*Math.PI*phase/1.8)*4;}}
71  const yaw=target?clamp(target.yaw,-45,45):Math.sin(time*.23)*6,pitch=target?clamp(target.pitch,-7,7):0;
72  pose({headYaw:yaw,headPitch:pitch+nod,armLift:wave*32,eyeYaw:yaw/45,eyePitch:-pitch/12,tilt:Math.sin(time*.17)*.7});return true;
73 }
74 function greet(){if(disposed)return false;greeting=0;return true;}
75 function reset(){time=0;greeting=-1;pose();}
76 function dispose(){if(disposed)return;disposed=true;root.removeFromParent();root.traverse(o=>{if(o.isMesh)o.geometry.dispose();});[painted,metal,optics].forEach(m=>m.dispose());root.clear();}
77 reset();return {root,pose,update,greet,reset,dispose,spec:ROBOT_04};
78}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.