@@ -128,6 +128,148 @@ export const OUTFITS = { |
| 128 | } | 128 | } |
| 129 | }, | 129 | }, |
| 130 | | 130 | |
| | 131 | + doug_aviator_goggles: { |
| | 132 | + id: 'doug_aviator_goggles', |
| | 133 | + name: 'Aviator Goggles', |
| | 134 | + character: CHARACTERS.DOUG, |
| | 135 | + type: OUTFIT_TYPES.ACCESSORY_FACE, |
| | 136 | + price: 35, |
| | 137 | + meshFactory: (gradientMap) => { |
| | 138 | + const group = new THREE.Group() |
| | 139 | + const brassMat = new THREE.MeshToonMaterial({ color: 0xb8860b, gradientMap }) |
| | 140 | + const leatherMat = new THREE.MeshToonMaterial({ color: 0x5c4033, gradientMap }) |
| | 141 | + const lensMat = new THREE.MeshBasicMaterial({ color: 0x4a90d9, transparent: true, opacity: 0.6 }) |
| | 142 | + |
| | 143 | + // Large goggle lenses (round, pilot-style) |
| | 144 | + const lensGeom = new THREE.CircleGeometry(0.1, 10) |
| | 145 | + const leftLens = new THREE.Mesh(lensGeom, lensMat) |
| | 146 | + leftLens.position.set(-0.12, 0, 0.02) |
| | 147 | + group.add(leftLens) |
| | 148 | + |
| | 149 | + const rightLens = new THREE.Mesh(lensGeom, lensMat) |
| | 150 | + rightLens.position.set(0.12, 0, 0.02) |
| | 151 | + group.add(rightLens) |
| | 152 | + |
| | 153 | + // Brass frames |
| | 154 | + const frameGeom = new THREE.TorusGeometry(0.1, 0.015, 6, 16) |
| | 155 | + const leftFrame = new THREE.Mesh(frameGeom, brassMat) |
| | 156 | + leftFrame.position.set(-0.12, 0, 0) |
| | 157 | + group.add(leftFrame) |
| | 158 | + |
| | 159 | + const rightFrame = new THREE.Mesh(frameGeom, brassMat) |
| | 160 | + rightFrame.position.set(0.12, 0, 0) |
| | 161 | + group.add(rightFrame) |
| | 162 | + |
| | 163 | + // Brass bridge with rivets |
| | 164 | + const bridgeGeom = new THREE.BoxGeometry(0.06, 0.025, 0.025) |
| | 165 | + const bridge = new THREE.Mesh(bridgeGeom, brassMat) |
| | 166 | + group.add(bridge) |
| | 167 | + |
| | 168 | + // Rivets on bridge |
| | 169 | + const rivetGeom = new THREE.SphereGeometry(0.008, 4, 4) |
| | 170 | + const rivet1 = new THREE.Mesh(rivetGeom, brassMat) |
| | 171 | + rivet1.position.set(-0.02, 0, 0.015) |
| | 172 | + group.add(rivet1) |
| | 173 | + |
| | 174 | + const rivet2 = new THREE.Mesh(rivetGeom, brassMat) |
| | 175 | + rivet2.position.set(0.02, 0, 0.015) |
| | 176 | + group.add(rivet2) |
| | 177 | + |
| | 178 | + // Leather padding around lenses |
| | 179 | + const padGeom = new THREE.TorusGeometry(0.11, 0.02, 4, 16) |
| | 180 | + const leftPad = new THREE.Mesh(padGeom, leatherMat) |
| | 181 | + leftPad.position.set(-0.12, 0, -0.01) |
| | 182 | + group.add(leftPad) |
| | 183 | + |
| | 184 | + const rightPad = new THREE.Mesh(padGeom, leatherMat) |
| | 185 | + rightPad.position.set(0.12, 0, -0.01) |
| | 186 | + group.add(rightPad) |
| | 187 | + |
| | 188 | + // Leather strap connectors |
| | 189 | + const strapGeom = new THREE.BoxGeometry(0.04, 0.03, 0.015) |
| | 190 | + const leftStrap = new THREE.Mesh(strapGeom, leatherMat) |
| | 191 | + leftStrap.position.set(-0.22, 0, 0) |
| | 192 | + group.add(leftStrap) |
| | 193 | + |
| | 194 | + const rightStrap = new THREE.Mesh(strapGeom, leatherMat) |
| | 195 | + rightStrap.position.set(0.22, 0, 0) |
| | 196 | + group.add(rightStrap) |
| | 197 | + |
| | 198 | + return group |
| | 199 | + } |
| | 200 | + }, |
| | 201 | + |
| | 202 | + doug_propeller_beanie: { |
| | 203 | + id: 'doug_propeller_beanie', |
| | 204 | + name: 'Propeller Beanie', |
| | 205 | + character: CHARACTERS.DOUG, |
| | 206 | + type: OUTFIT_TYPES.ACCESSORY_HEAD, |
| | 207 | + price: 30, |
| | 208 | + meshFactory: (gradientMap) => { |
| | 209 | + const group = new THREE.Group() |
| | 210 | + const redMat = new THREE.MeshToonMaterial({ color: 0xdd3333, gradientMap }) |
| | 211 | + const yellowMat = new THREE.MeshToonMaterial({ color: 0xffdd00, gradientMap }) |
| | 212 | + const blueMat = new THREE.MeshToonMaterial({ color: 0x3366cc, gradientMap }) |
| | 213 | + |
| | 214 | + // Beanie cap base |
| | 215 | + const capGeom = new THREE.SphereGeometry(0.18, 10, 8, 0, Math.PI * 2, 0, Math.PI / 2) |
| | 216 | + const cap = new THREE.Mesh(capGeom, redMat) |
| | 217 | + group.add(cap) |
| | 218 | + |
| | 219 | + // Striped panels (alternating colors) |
| | 220 | + for (let i = 0; i < 6; i++) { |
| | 221 | + const panelGeom = new THREE.SphereGeometry(0.182, 2, 8, |
| | 222 | + i * Math.PI / 3, Math.PI / 3, 0, Math.PI / 2) |
| | 223 | + const material = i % 2 === 0 ? yellowMat : blueMat |
| | 224 | + const panel = new THREE.Mesh(panelGeom, material) |
| | 225 | + group.add(panel) |
| | 226 | + } |
| | 227 | + |
| | 228 | + // Brim |
| | 229 | + const brimGeom = new THREE.TorusGeometry(0.18, 0.02, 4, 16) |
| | 230 | + const brim = new THREE.Mesh(brimGeom, redMat) |
| | 231 | + brim.rotation.x = Math.PI / 2 |
| | 232 | + brim.position.y = 0 |
| | 233 | + group.add(brim) |
| | 234 | + |
| | 235 | + // Button on top |
| | 236 | + const buttonGeom = new THREE.CylinderGeometry(0.03, 0.03, 0.02, 8) |
| | 237 | + const button = new THREE.Mesh(buttonGeom, yellowMat) |
| | 238 | + button.position.y = 0.17 |
| | 239 | + group.add(button) |
| | 240 | + |
| | 241 | + // Propeller mount |
| | 242 | + const mountGeom = new THREE.CylinderGeometry(0.015, 0.02, 0.04, 6) |
| | 243 | + const mount = new THREE.Mesh(mountGeom, blueMat) |
| | 244 | + mount.position.y = 0.19 |
| | 245 | + group.add(mount) |
| | 246 | + |
| | 247 | + // Propeller blades (will spin in animation) |
| | 248 | + const propGroup = new THREE.Group() |
| | 249 | + propGroup.userData.isPropeller = true |
| | 250 | + propGroup.position.y = 0.22 |
| | 251 | + |
| | 252 | + const bladeGeom = new THREE.BoxGeometry(0.15, 0.01, 0.03) |
| | 253 | + const blade1 = new THREE.Mesh(bladeGeom, redMat) |
| | 254 | + blade1.rotation.z = 0.1 |
| | 255 | + propGroup.add(blade1) |
| | 256 | + |
| | 257 | + const blade2 = new THREE.Mesh(bladeGeom, yellowMat) |
| | 258 | + blade2.rotation.y = Math.PI / 2 |
| | 259 | + blade2.rotation.z = -0.1 |
| | 260 | + propGroup.add(blade2) |
| | 261 | + |
| | 262 | + // Center hub |
| | 263 | + const hubGeom = new THREE.SphereGeometry(0.02, 6, 4) |
| | 264 | + const hub = new THREE.Mesh(hubGeom, blueMat) |
| | 265 | + propGroup.add(hub) |
| | 266 | + |
| | 267 | + group.add(propGroup) |
| | 268 | + |
| | 269 | + return group |
| | 270 | + } |
| | 271 | + }, |
| | 272 | + |
| 131 | // === DOUG CLOTHING - Actual rendered garments === | 273 | // === DOUG CLOTHING - Actual rendered garments === |
| 132 | | 274 | |
| 133 | // Simple tier - basic clothing | 275 | // Simple tier - basic clothing |
@@ -593,6 +735,148 @@ export const OUTFITS = { |
| 593 | } | 735 | } |
| 594 | }, | 736 | }, |
| 595 | | 737 | |
| | 738 | + donny_bicorn: { |
| | 739 | + id: 'donny_bicorn', |
| | 740 | + name: "Captain's Bicorn", |
| | 741 | + character: CHARACTERS.DONNY, |
| | 742 | + type: OUTFIT_TYPES.ACCESSORY_HEAD, |
| | 743 | + price: 40, |
| | 744 | + meshFactory: (gradientMap) => { |
| | 745 | + const group = new THREE.Group() |
| | 746 | + const navyMat = new THREE.MeshToonMaterial({ color: 0x1a1a2e, gradientMap }) |
| | 747 | + const goldMat = new THREE.MeshToonMaterial({ color: 0xffd700, gradientMap }) |
| | 748 | + const whiteMat = new THREE.MeshToonMaterial({ color: 0xffffff, gradientMap }) |
| | 749 | + |
| | 750 | + // Main hat body (curved rectangular shape) |
| | 751 | + const bodyGeom = new THREE.BoxGeometry(0.35, 0.08, 0.2) |
| | 752 | + const body = new THREE.Mesh(bodyGeom, navyMat) |
| | 753 | + body.position.y = 0.04 |
| | 754 | + group.add(body) |
| | 755 | + |
| | 756 | + // Bicorn points (turned up sides) |
| | 757 | + const pointGeom = new THREE.BoxGeometry(0.08, 0.15, 0.18) |
| | 758 | + const leftPoint = new THREE.Mesh(pointGeom, navyMat) |
| | 759 | + leftPoint.position.set(-0.15, 0.1, 0) |
| | 760 | + leftPoint.rotation.z = 0.3 |
| | 761 | + group.add(leftPoint) |
| | 762 | + |
| | 763 | + const rightPoint = new THREE.Mesh(pointGeom, navyMat) |
| | 764 | + rightPoint.position.set(0.15, 0.1, 0) |
| | 765 | + rightPoint.rotation.z = -0.3 |
| | 766 | + group.add(rightPoint) |
| | 767 | + |
| | 768 | + // Gold trim along edges |
| | 769 | + const trimGeom = new THREE.BoxGeometry(0.36, 0.015, 0.01) |
| | 770 | + const frontTrim = new THREE.Mesh(trimGeom, goldMat) |
| | 771 | + frontTrim.position.set(0, 0.08, 0.1) |
| | 772 | + group.add(frontTrim) |
| | 773 | + |
| | 774 | + const backTrim = new THREE.Mesh(trimGeom, goldMat) |
| | 775 | + backTrim.position.set(0, 0.08, -0.1) |
| | 776 | + group.add(backTrim) |
| | 777 | + |
| | 778 | + // Cockade (rosette) decoration |
| | 779 | + const cockadeGeom = new THREE.CircleGeometry(0.04, 8) |
| | 780 | + const cockade = new THREE.Mesh(cockadeGeom, whiteMat) |
| | 781 | + cockade.position.set(0, 0.1, 0.11) |
| | 782 | + group.add(cockade) |
| | 783 | + |
| | 784 | + // Gold button on cockade |
| | 785 | + const buttonGeom = new THREE.SphereGeometry(0.015, 6, 4) |
| | 786 | + const button = new THREE.Mesh(buttonGeom, goldMat) |
| | 787 | + button.position.set(0, 0.1, 0.12) |
| | 788 | + group.add(button) |
| | 789 | + |
| | 790 | + // Feather plume |
| | 791 | + const featherGeom = new THREE.ConeGeometry(0.02, 0.15, 4) |
| | 792 | + const feather = new THREE.Mesh(featherGeom, whiteMat) |
| | 793 | + feather.position.set(0.02, 0.18, 0.08) |
| | 794 | + feather.rotation.z = -0.3 |
| | 795 | + feather.rotation.x = 0.2 |
| | 796 | + group.add(feather) |
| | 797 | + |
| | 798 | + return group |
| | 799 | + } |
| | 800 | + }, |
| | 801 | + |
| | 802 | + donny_opera_glasses: { |
| | 803 | + id: 'donny_opera_glasses', |
| | 804 | + name: 'Opera Glasses', |
| | 805 | + character: CHARACTERS.DONNY, |
| | 806 | + type: OUTFIT_TYPES.ACCESSORY_FACE, |
| | 807 | + price: 45, |
| | 808 | + meshFactory: (gradientMap) => { |
| | 809 | + const group = new THREE.Group() |
| | 810 | + const goldMat = new THREE.MeshToonMaterial({ color: 0xd4af37, gradientMap }) |
| | 811 | + const pearlMat = new THREE.MeshToonMaterial({ color: 0xfdf5e6, gradientMap }) |
| | 812 | + const lensMat = new THREE.MeshBasicMaterial({ color: 0x87ceeb, transparent: true, opacity: 0.4 }) |
| | 813 | + |
| | 814 | + // Twin barrels (binocular style) |
| | 815 | + const barrelGeom = new THREE.CylinderGeometry(0.05, 0.06, 0.12, 8) |
| | 816 | + |
| | 817 | + const leftBarrel = new THREE.Mesh(barrelGeom, pearlMat) |
| | 818 | + leftBarrel.position.set(-0.07, 0, 0) |
| | 819 | + leftBarrel.rotation.x = Math.PI / 2 |
| | 820 | + group.add(leftBarrel) |
| | 821 | + |
| | 822 | + const rightBarrel = new THREE.Mesh(barrelGeom, pearlMat) |
| | 823 | + rightBarrel.position.set(0.07, 0, 0) |
| | 824 | + rightBarrel.rotation.x = Math.PI / 2 |
| | 825 | + group.add(rightBarrel) |
| | 826 | + |
| | 827 | + // Lenses (front) |
| | 828 | + const lensGeom = new THREE.CircleGeometry(0.05, 10) |
| | 829 | + const leftLens = new THREE.Mesh(lensGeom, lensMat) |
| | 830 | + leftLens.position.set(-0.07, 0, 0.07) |
| | 831 | + group.add(leftLens) |
| | 832 | + |
| | 833 | + const rightLens = new THREE.Mesh(lensGeom, lensMat) |
| | 834 | + rightLens.position.set(0.07, 0, 0.07) |
| | 835 | + group.add(rightLens) |
| | 836 | + |
| | 837 | + // Gold rims |
| | 838 | + const rimGeom = new THREE.TorusGeometry(0.05, 0.008, 4, 12) |
| | 839 | + const leftRim = new THREE.Mesh(rimGeom, goldMat) |
| | 840 | + leftRim.position.set(-0.07, 0, 0.06) |
| | 841 | + group.add(leftRim) |
| | 842 | + |
| | 843 | + const rightRim = new THREE.Mesh(rimGeom, goldMat) |
| | 844 | + rightRim.position.set(0.07, 0, 0.06) |
| | 845 | + group.add(rightRim) |
| | 846 | + |
| | 847 | + // Bridge connecting barrels |
| | 848 | + const bridgeGeom = new THREE.BoxGeometry(0.04, 0.02, 0.03) |
| | 849 | + const bridge = new THREE.Mesh(bridgeGeom, goldMat) |
| | 850 | + bridge.position.set(0, 0, 0.02) |
| | 851 | + group.add(bridge) |
| | 852 | + |
| | 853 | + // Ornate handle |
| | 854 | + const handleGeom = new THREE.CylinderGeometry(0.012, 0.015, 0.15, 6) |
| | 855 | + const handle = new THREE.Mesh(handleGeom, goldMat) |
| | 856 | + handle.position.set(0.12, -0.06, 0) |
| | 857 | + handle.rotation.z = Math.PI / 4 |
| | 858 | + group.add(handle) |
| | 859 | + |
| | 860 | + // Handle end knob |
| | 861 | + const knobGeom = new THREE.SphereGeometry(0.02, 6, 4) |
| | 862 | + const knob = new THREE.Mesh(knobGeom, goldMat) |
| | 863 | + knob.position.set(0.18, -0.12, 0) |
| | 864 | + group.add(knob) |
| | 865 | + |
| | 866 | + // Decorative filigree on barrels |
| | 867 | + const filigreeGeom = new THREE.TorusGeometry(0.055, 0.005, 3, 12) |
| | 868 | + const leftFiligree = new THREE.Mesh(filigreeGeom, goldMat) |
| | 869 | + leftFiligree.position.set(-0.07, 0, 0) |
| | 870 | + group.add(leftFiligree) |
| | 871 | + |
| | 872 | + const rightFiligree = new THREE.Mesh(filigreeGeom, goldMat) |
| | 873 | + rightFiligree.position.set(0.07, 0, 0) |
| | 874 | + group.add(rightFiligree) |
| | 875 | + |
| | 876 | + return group |
| | 877 | + } |
| | 878 | + }, |
| | 879 | + |
| 596 | // === DONNY CLOTHING - Narwhal garments === | 880 | // === DONNY CLOTHING - Narwhal garments === |
| 597 | | 881 | |
| 598 | donny_sailor_vest: { | 882 | donny_sailor_vest: { |
@@ -836,6 +1120,156 @@ export const OUTFITS = { |
| 836 | } | 1120 | } |
| 837 | }, | 1121 | }, |
| 838 | | 1122 | |
| | 1123 | + ollie_jeweler_loupe: { |
| | 1124 | + id: 'ollie_jeweler_loupe', |
| | 1125 | + name: "Jeweler's Loupe", |
| | 1126 | + character: CHARACTERS.OLLIE, |
| | 1127 | + type: OUTFIT_TYPES.ACCESSORY_FACE, |
| | 1128 | + price: 35, |
| | 1129 | + meshFactory: (gradientMap) => { |
| | 1130 | + const group = new THREE.Group() |
| | 1131 | + const brassMat = new THREE.MeshToonMaterial({ color: 0xb8860b, gradientMap }) |
| | 1132 | + const blackMat = new THREE.MeshToonMaterial({ color: 0x1a1a1a, gradientMap }) |
| | 1133 | + const lensMat = new THREE.MeshBasicMaterial({ color: 0xaaffaa, transparent: true, opacity: 0.5 }) |
| | 1134 | + |
| | 1135 | + // Main loupe barrel |
| | 1136 | + const barrelGeom = new THREE.CylinderGeometry(0.06, 0.08, 0.1, 10) |
| | 1137 | + const barrel = new THREE.Mesh(barrelGeom, blackMat) |
| | 1138 | + barrel.rotation.x = Math.PI / 2 |
| | 1139 | + barrel.position.z = 0.03 |
| | 1140 | + group.add(barrel) |
| | 1141 | + |
| | 1142 | + // Lens (front) |
| | 1143 | + const lensGeom = new THREE.CircleGeometry(0.06, 12) |
| | 1144 | + const lens = new THREE.Mesh(lensGeom, lensMat) |
| | 1145 | + lens.position.z = 0.09 |
| | 1146 | + group.add(lens) |
| | 1147 | + |
| | 1148 | + // Brass rim |
| | 1149 | + const rimGeom = new THREE.TorusGeometry(0.06, 0.01, 4, 16) |
| | 1150 | + const rim = new THREE.Mesh(rimGeom, brassMat) |
| | 1151 | + rim.position.z = 0.08 |
| | 1152 | + group.add(rim) |
| | 1153 | + |
| | 1154 | + // Eyepiece (back) |
| | 1155 | + const eyepieceGeom = new THREE.CylinderGeometry(0.05, 0.06, 0.03, 10) |
| | 1156 | + const eyepiece = new THREE.Mesh(eyepieceGeom, brassMat) |
| | 1157 | + eyepiece.rotation.x = Math.PI / 2 |
| | 1158 | + eyepiece.position.z = -0.03 |
| | 1159 | + group.add(eyepiece) |
| | 1160 | + |
| | 1161 | + // Headband attachment (wraps around head) |
| | 1162 | + const bandGeom = new THREE.TorusGeometry(0.15, 0.015, 4, 16, Math.PI) |
| | 1163 | + const band = new THREE.Mesh(bandGeom, blackMat) |
| | 1164 | + band.position.set(0, 0.05, -0.05) |
| | 1165 | + band.rotation.x = Math.PI / 2 |
| | 1166 | + band.rotation.z = Math.PI / 2 |
| | 1167 | + group.add(band) |
| | 1168 | + |
| | 1169 | + // Adjustment knob |
| | 1170 | + const knobGeom = new THREE.CylinderGeometry(0.015, 0.02, 0.03, 6) |
| | 1171 | + const knob = new THREE.Mesh(knobGeom, brassMat) |
| | 1172 | + knob.position.set(0.07, 0, 0.02) |
| | 1173 | + knob.rotation.z = Math.PI / 2 |
| | 1174 | + group.add(knob) |
| | 1175 | + |
| | 1176 | + // Knob ridges |
| | 1177 | + for (let i = 0; i < 6; i++) { |
| | 1178 | + const ridgeGeom = new THREE.BoxGeometry(0.002, 0.025, 0.005) |
| | 1179 | + const ridge = new THREE.Mesh(ridgeGeom, brassMat) |
| | 1180 | + const angle = (i / 6) * Math.PI * 2 |
| | 1181 | + ridge.position.set(0.085, Math.sin(angle) * 0.015, 0.02 + Math.cos(angle) * 0.015) |
| | 1182 | + group.add(ridge) |
| | 1183 | + } |
| | 1184 | + |
| | 1185 | + return group |
| | 1186 | + } |
| | 1187 | + }, |
| | 1188 | + |
| | 1189 | + ollie_wizard_hat: { |
| | 1190 | + id: 'ollie_wizard_hat', |
| | 1191 | + name: 'Wizard Hat', |
| | 1192 | + character: CHARACTERS.OLLIE, |
| | 1193 | + type: OUTFIT_TYPES.ACCESSORY_HEAD, |
| | 1194 | + price: 45, |
| | 1195 | + meshFactory: (gradientMap) => { |
| | 1196 | + const group = new THREE.Group() |
| | 1197 | + const purpleMat = new THREE.MeshToonMaterial({ color: 0x4b0082, gradientMap }) |
| | 1198 | + const goldMat = new THREE.MeshToonMaterial({ color: 0xffd700, gradientMap }) |
| | 1199 | + const silverMat = new THREE.MeshToonMaterial({ color: 0xc0c0c0, gradientMap }) |
| | 1200 | + |
| | 1201 | + // Main cone |
| | 1202 | + const coneGeom = new THREE.ConeGeometry(0.2, 0.45, 8) |
| | 1203 | + const cone = new THREE.Mesh(coneGeom, purpleMat) |
| | 1204 | + cone.position.y = 0.22 |
| | 1205 | + group.add(cone) |
| | 1206 | + |
| | 1207 | + // Bent tip (wizards hats droop!) |
| | 1208 | + const tipGeom = new THREE.ConeGeometry(0.05, 0.12, 6) |
| | 1209 | + const tip = new THREE.Mesh(tipGeom, purpleMat) |
| | 1210 | + tip.position.set(0.08, 0.42, 0.05) |
| | 1211 | + tip.rotation.z = -0.8 |
| | 1212 | + tip.rotation.x = 0.3 |
| | 1213 | + group.add(tip) |
| | 1214 | + |
| | 1215 | + // Wide brim |
| | 1216 | + const brimGeom = new THREE.CylinderGeometry(0.28, 0.3, 0.03, 12) |
| | 1217 | + const brim = new THREE.Mesh(brimGeom, purpleMat) |
| | 1218 | + brim.position.y = 0 |
| | 1219 | + group.add(brim) |
| | 1220 | + |
| | 1221 | + // Gold band at base |
| | 1222 | + const bandGeom = new THREE.TorusGeometry(0.2, 0.02, 4, 16) |
| | 1223 | + const band = new THREE.Mesh(bandGeom, goldMat) |
| | 1224 | + band.position.y = 0.02 |
| | 1225 | + band.rotation.x = Math.PI / 2 |
| | 1226 | + group.add(band) |
| | 1227 | + |
| | 1228 | + // Stars on hat (scattered) |
| | 1229 | + const starPositions = [ |
| | 1230 | + { x: 0.12, y: 0.25, z: 0.1, scale: 0.8 }, |
| | 1231 | + { x: -0.08, y: 0.35, z: 0.12, scale: 0.6 }, |
| | 1232 | + { x: 0.05, y: 0.15, z: 0.15, scale: 0.5 }, |
| | 1233 | + { x: -0.1, y: 0.2, z: -0.1, scale: 0.7 }, |
| | 1234 | + { x: 0.08, y: 0.38, z: -0.05, scale: 0.5 } |
| | 1235 | + ] |
| | 1236 | + |
| | 1237 | + for (const star of starPositions) { |
| | 1238 | + // Simple 4-point star shape |
| | 1239 | + const starGroup = new THREE.Group() |
| | 1240 | + |
| | 1241 | + const point1Geom = new THREE.ConeGeometry(0.015, 0.04, 4) |
| | 1242 | + const point1 = new THREE.Mesh(point1Geom, silverMat) |
| | 1243 | + starGroup.add(point1) |
| | 1244 | + |
| | 1245 | + const point2 = new THREE.Mesh(point1Geom, silverMat) |
| | 1246 | + point2.rotation.z = Math.PI |
| | 1247 | + starGroup.add(point2) |
| | 1248 | + |
| | 1249 | + const point3 = new THREE.Mesh(point1Geom, silverMat) |
| | 1250 | + point3.rotation.z = Math.PI / 2 |
| | 1251 | + starGroup.add(point3) |
| | 1252 | + |
| | 1253 | + const point4 = new THREE.Mesh(point1Geom, silverMat) |
| | 1254 | + point4.rotation.z = -Math.PI / 2 |
| | 1255 | + starGroup.add(point4) |
| | 1256 | + |
| | 1257 | + starGroup.position.set(star.x, star.y, star.z) |
| | 1258 | + starGroup.scale.setScalar(star.scale) |
| | 1259 | + group.add(starGroup) |
| | 1260 | + } |
| | 1261 | + |
| | 1262 | + // Moon crescent |
| | 1263 | + const moonGeom = new THREE.TorusGeometry(0.03, 0.01, 4, 12, Math.PI * 1.5) |
| | 1264 | + const moon = new THREE.Mesh(moonGeom, goldMat) |
| | 1265 | + moon.position.set(-0.12, 0.3, 0.08) |
| | 1266 | + moon.rotation.z = 0.5 |
| | 1267 | + group.add(moon) |
| | 1268 | + |
| | 1269 | + return group |
| | 1270 | + } |
| | 1271 | + }, |
| | 1272 | + |
| 839 | // === OLLIE CLOTHING - Octopus garments === | 1273 | // === OLLIE CLOTHING - Octopus garments === |
| 840 | | 1274 | |
| 841 | ollie_bowtie: { | 1275 | ollie_bowtie: { |