@@ -33,9 +33,9 @@ import { AthleteRenderer } from "./AthleteRenderer.js";
3333 } ;
3434
3535 const podiumColors = {
36- Gold : 0xf3e58d ,
37- Silver : 0xd5d9de ,
38- Bronze : 0xe3c38b
36+ Gold : 0xf5f5f5 ,
37+ Silver : 0xf5f5f5 ,
38+ Bronze : 0xf5f5f5
3939 } ;
4040
4141 document . addEventListener ( "DOMContentLoaded" , init ) ;
@@ -470,19 +470,19 @@ import { AthleteRenderer } from "./AthleteRenderer.js";
470470 scene . add ( fillLight ) ;
471471
472472 const positions = {
473- Silver : { x : - 10 , podiumHeight : 2.2 , podiumWidth : 3.25 , podiumDepth : 2.4 } ,
474- Gold : { x : 0 , podiumHeight : 3.2 , podiumWidth : 3.8 , podiumDepth : 2.4 } ,
475- Bronze : { x : 10 , podiumHeight : 1.5 , podiumWidth : 3.25 , podiumDepth : 2.4 }
473+ Silver : { x : - 9.75 , podiumHeight : 2.2 , podiumWidth : 10.0 , podiumDepth : 3.0 } ,
474+ Gold : { x : 0 , podiumHeight : 3.2 , podiumWidth : 9.5 , podiumDepth : 3.0 } ,
475+ Bronze : { x : 9.75 , podiumHeight : 1.5 , podiumWidth : 10.0 , podiumDepth : 3.0 }
476476 } ;
477477
478478 camera . updateProjectionMatrix ( ) ;
479479 camera . updateMatrixWorld ( ) ;
480480
481+ addConnectedPodium ( scene , positions ) ;
481482 [ "Silver" , "Gold" , "Bronze" ] . forEach ( ( medal ) => {
482483 const athlete = medalists . find ( d => d . medal === medal ) ;
483484 const pos = positions [ medal ] ;
484485
485- addPodium ( scene , pos , medal ) ;
486486 addHuman ( scene , athlete , pos ) ;
487487 addAthleteOverlay ( overlay , athlete , pos , camera , width , height ) ;
488488 } ) ;
@@ -499,36 +499,72 @@ import { AthleteRenderer } from "./AthleteRenderer.js";
499499 resizeBodytypeSelects ( ) ;
500500 }
501501
502- function addPodium ( scene , pos , medal ) {
503- const podium = new THREE . Mesh (
504- new THREE . BoxGeometry ( pos . podiumWidth , pos . podiumHeight , pos . podiumDepth ) ,
502+ function addConnectedPodium ( scene , pos ) {
503+ const depth = pos . Gold . podiumDepth ;
504+ const sideMat = new THREE . MeshStandardMaterial ( { color : 0xf5f5f5 , roughness : 0.8 } ) ;
505+ const topMat = new THREE . MeshStandardMaterial ( { color : 0xaaaaaa , roughness : 0.7 } ) ;
506+ // BoxGeometry face order: right, left, top, bottom, front, back
507+ const mat = [ sideMat , sideMat , topMat , sideMat , sideMat , sideMat ] ;
508+
509+ const silverLeft = pos . Silver . x - pos . Silver . podiumWidth / 2 ;
510+ const goldRight = pos . Gold . x + pos . Gold . podiumWidth / 2 ;
511+ const bronzeRight = pos . Bronze . x + pos . Bronze . podiumWidth / 2 ;
512+ const bronzeH = pos . Bronze . podiumHeight ;
513+ const silverH = pos . Silver . podiumHeight ;
514+ const goldH = pos . Gold . podiumHeight ;
515+
516+ // Three stacked layers forming a staircase: base / silver+gold step / gold top
517+ const layers = [
518+ { w : bronzeRight - silverLeft , h : bronzeH , cx : ( silverLeft + bronzeRight ) / 2 , cy : bronzeH / 2 } ,
519+ { w : goldRight - silverLeft , h : silverH - bronzeH , cx : ( silverLeft + goldRight ) / 2 , cy : bronzeH + ( silverH - bronzeH ) / 2 } ,
520+ { w : pos . Gold . podiumWidth , h : goldH - silverH , cx : pos . Gold . x , cy : silverH + ( goldH - silverH ) / 2 }
521+ ] ;
522+
523+ layers . forEach ( ( { w, h, cx, cy } ) => {
524+ const mesh = new THREE . Mesh ( new THREE . BoxGeometry ( w , h , depth ) , mat ) ;
525+ mesh . position . set ( cx , cy , 0 ) ;
526+ scene . add ( mesh ) ;
527+ } ) ;
528+
529+ // Olympic rings on gold section only
530+ const ringsW = 6.0 ;
531+ const ringsH = ringsW * ( 175 / 420 ) ;
532+ const ringsPlane = new THREE . Mesh (
533+ new THREE . PlaneGeometry ( ringsW , ringsH ) ,
505534 new THREE . MeshStandardMaterial ( {
506- color : podiumColors [ medal ] ,
507- roughness : 0.85
535+ map : new THREE . CanvasTexture ( makeOlympicRingsCanvas ( ) ) ,
536+ transparent : true ,
537+ depthWrite : false
508538 } )
509539 ) ;
540+ ringsPlane . position . set ( pos . Gold . x , pos . Gold . podiumHeight / 2 , depth / 2 + 0.01 ) ;
541+ scene . add ( ringsPlane ) ;
542+ }
510543
511- podium . position . set ( pos . x , pos . podiumHeight / 2 , 0 ) ;
512- scene . add ( podium ) ;
513-
514- const edges = new THREE . LineSegments (
515- new THREE . EdgesGeometry (
516- new THREE . BoxGeometry ( pos . podiumWidth , pos . podiumHeight , pos . podiumDepth )
517- ) ,
518- new THREE . LineBasicMaterial ( { color : 0x222222 } )
519- ) ;
520-
521- edges . position . copy ( podium . position ) ;
522- scene . add ( edges ) ;
523-
524- const rank = makeTextSprite ( String ( medalRank [ medal ] ) , {
525- fontsize : 90 ,
526- textColor : "#ffffff"
544+ function makeOlympicRingsCanvas ( ) {
545+ const W = 420 , H = 175 ;
546+ const canvas = document . createElement ( "canvas" ) ;
547+ canvas . width = W ;
548+ canvas . height = H ;
549+ const ctx = canvas . getContext ( "2d" ) ;
550+
551+ const rings = [
552+ { cx : 113 , cy : 62 , color : "#0085C7" } ,
553+ { cx : 210 , cy : 62 , color : "#000000" } ,
554+ { cx : 307 , cy : 62 , color : "#DF0024" } ,
555+ { cx : 162 , cy : 112 , color : "#F4C300" } ,
556+ { cx : 259 , cy : 112 , color : "#009F6B" }
557+ ] ;
558+
559+ rings . forEach ( r => {
560+ ctx . beginPath ( ) ;
561+ ctx . arc ( r . cx , r . cy , 38 , 0 , Math . PI * 2 ) ;
562+ ctx . strokeStyle = r . color ;
563+ ctx . lineWidth = 9 ;
564+ ctx . stroke ( ) ;
527565 } ) ;
528566
529- rank . position . set ( pos . x , pos . podiumHeight * 0.5 , pos . podiumDepth / 2 + 0.04 ) ;
530- rank . scale . set ( 1.4 , 0.7 , 1 ) ;
531- scene . add ( rank ) ;
567+ return canvas ;
532568 }
533569
534570 function addHuman ( scene , athlete , pos ) {
0 commit comments