Skip to content

Commit

Permalink
update load-balancing-for-inference for mobile world congress
Browse files Browse the repository at this point in the history
  • Loading branch information
LukeSchlangen committed Mar 3, 2025
1 parent 2ebaf58 commit 755447c
Show file tree
Hide file tree
Showing 46 changed files with 2,417 additions and 526 deletions.
13 changes: 13 additions & 0 deletions infrastructure/load-balancing-for-inference/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,16 @@
@tailwind components;
@tailwind utilities;

@font-face {
font-family: "Jersey15";
src: url("/fonts/Jersey15-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}

.clip-path-zigzag {
clip-path: polygon(
100% 0%, 90% 20%, 100% 40%, 90% 60%,
100% 80%, 90% 100%, 100% 100%, 100% 0%
);
}
107 changes: 48 additions & 59 deletions infrastructure/load-balancing-for-inference/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,56 @@
'use client'
"use client"

import { useState } from "react";
import Play from "@/components/Play";
import { Canvas } from '@react-three/fiber'
import MessagePretty from "@/components/MessagePretty";
import StartButton from "@/components/StartButton";
import { useState } from "react"
import Play from "@/components/Play"
import StartButton from "@/components/StartButton"
import Image from "next/image"
import Play3D from "@/components/play3d"; // 3D effect for home screen

export default function Home() {
const [showPlayComponent, setShowPlayComponent] = useState<boolean>(false);
const [showPlayComponent, setShowPlayComponent] = useState<boolean>(false)

if (showPlayComponent) {
return (
<Play />
);
}
return (
<div className="relative min-h-screen bg-[#FBBC04]">
{/* Show Play3D only on Home Screen, Hide it when game starts */}
{!showPlayComponent && (
<div className="absolute top-0 left-0 w-full h-full z-0">
<Play3D />
</div>
)}

const colors = ['#EA4335', '#34A853','#FBBC04', '#4285F4'];
const playerOneBlocks = Array.from(Array(50).keys()).map((index) => {
const color = colors[Math.floor(Math.random() * colors.length)];
const randomNumber = Math.random() - 0.5;
const xPosition = randomNumber * 10;
const yPosition = (index / 5) + randomNumber;
const uuid = crypto.randomUUID();
return { randomNumber, xPosition, yPosition, uuid, color }
});
{/* Game UI: Only Show Play when "S" is Pressed */}
{showPlayComponent ? (
<Play />
) : (
<main className="relative flex flex-col min-h-screen items-center justify-between p-8 z-10">
{/* Title Image */}
<div className="w-full max-w-4xl relative mt-2 -mb-8 z-20">
<Image
src="/LB-blitz title.png"
alt="Load Balancing Blitz"
width={800}
height={200}
className="w-full h-auto"
priority
/>
</div>

{/* Instruction Box */}
<div className="bg-[#FFF8E7] rounded-xl p-6 max-w-3xl relative z-10">
<p className="text-gray-800 text-center mb-2">
Press 1, 2, 3, and 4 to distribute the incoming requests across the four virtual machines.
</p>
<p className="text-gray-800 text-center font-medium">
<span className="font-bold">Hint:</span> Keep moving! Be careful not to direct all of the requests to a single machine.
</p>
</div>

return (
<>
<div className="absolute min-h-screen top-0 bottom-0 left-0 right-0 -z-10">
<Canvas>
<ambientLight intensity={Math.PI / 2} />
<pointLight position={[-10, -10, -10]} decay={0} intensity={2} />
<pointLight position={[5, 5, 5]} decay={0} intensity={3} />
{playerOneBlocks.map(({ randomNumber, xPosition, yPosition, uuid, color }) => {
return (
<MessagePretty
key={uuid}
position={[xPosition, yPosition, -3]}
endPoint={[randomNumber,0,0]}
color={color}
/>
)
})}
</Canvas>
</div>
<main className="flex flex-col min-h-screen items-center justify-between p-24">
<h1 className={`mb-3 text-7xl font-mono -z-20`}>
Load Balancing Blitz
</h1>
<StartButton
onClick={() => setShowPlayComponent(true)}
/>
<div>
<p>
Press 1, 2, 3, and 4 to distribute the incoming requests
across the four virtual machines.
</p>
<p>
Hint: Keep moving! Be careful not to direct all of the requests to a single machine.
</p>
</div>
</main>
</>
);
{/* Start Button */}
<StartButton onClick={() => setShowPlayComponent(true)} className="z-20" />

<div className="h-24" />
</main>
)}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"use client";
import Image from "next/image";

interface CountdownOverlayProps {
timeElapsed: number;
timeRemaining: number;
playerOneScore: number;
playerTwoScore: number;
}

/**
* Displays:
* - A main countdown (60s) at the top center inside timer-box.png, once timeElapsed >= 0
* - The "Get Ready!" overlay if timeElapsed < 0 (unchanged)
*/
export default function CountdownOverlay({
timeElapsed,
timeRemaining,
playerOneScore,
playerTwoScore,
}: CountdownOverlayProps) {
return (
<>
{/* Player One Name - Left Aligned */}
{timeElapsed >= 0 && timeRemaining > 0 && (
<div className="absolute top-20 left-10 z-50 text-[#2B374B] font-bold text-5xl" style={{ fontFamily: "Jersey15, sans-serif" }}>
YOU
</div>
)}

{/* Countdown Timer - Center Aligned */}
{timeElapsed >= 0 && (
<div
className={`absolute top-20 left-1/2 transform -translate-x-1/2 z-50 transition-opacity duration-1000 ${
timeRemaining > 0 && timeElapsed > -1 ? "opacity-100" : "opacity-0"
}`}
>
<div className="relative" style={{ fontFamily: "Jersey15, sans-serif" }}>
<Image
src="/assets/timer-box.png"
alt="Timer Box"
width={78}
height={60}
priority
/>
<span className="absolute inset-0 flex items-center justify-center text-5xl font-bold text-[#2B374B]">
{timeRemaining}
</span>
</div>
</div>
)}

{/* Player Two Name - Right Aligned */}
{timeElapsed >= 0 && timeRemaining > 0 && (
<div className="absolute top-20 right-10 z-50 text-[#2B374B] font-bold text-5xl" style={{ fontFamily: "Jersey15, sans-serif" }}>
GOOGLE CLOUD LOAD BALANCER
</div>
)}

{/* "GET READY!" OVERLAY if timeElapsed < 0 (unchanged) */}
{timeElapsed < 0 && (
<div
className="absolute top-0 left-0 w-full h-full flex flex-col justify-center items-center bg-[#2B374B] text-white z-50"
style={{ fontFamily: "Jersey15, sans-serif" }}
>
{/* Top Bar with Zigzag Divider */}
<div
className="absolute top-0 left-0 w-full flex h-20 text-white font-bold tracking-wider"
style={{ fontFamily: "Jersey15, sans-serif" }}
>
{/* Left Side - Player Score */}
<div className="w-1/2 bg-[#FFB800] flex justify-end items-center relative pr-2">
<span className="text-6xl">0</span> {/* Example placeholder */}
</div>

{/* Right Side - Opponent Score */}
<div className="w-1/2 bg-[#4285F4] flex justify-left items-center pl-2">
<span className="text-6xl">0</span> {/* Example placeholder */}
</div>
</div>

{/* Player Names Below the Top Bar */}
<div
className="absolute top-24 w-full flex justify-between px-20 text-white text-5xl font-bold"
style={{ fontFamily: "Jersey15, sans-serif" }}
>
<span>YOU</span>
<span>GOOGLE CLOUD LOAD BALANCER</span>
</div>

{/* Countdown Box UI */}
<div className="relative flex flex-col items-center justify-center mt-24">
<Image
src="/countdown-box.png"
alt="Countdown Box"
width={240}
height={240}
priority
/>
<span className="absolute text-[12rem] font-bold text-white leading-none">
{timeElapsed < 0 ? Math.abs(timeElapsed) : "GO!"}
</span>
</div>

{/* "Get Ready!" Text */}
<p className="text-[#FFB800] text-[3rem] font-bold mt-14">
GET READY!
</p>
</div>
)}
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"use client";

import * as THREE from "three";
import { useRef } from "react";
import { useFrame, ThreeElements, useLoader } from "@react-three/fiber";
import { TextureLoader } from "three";

export type DataBlockFallToBoxProps = ThreeElements["mesh"] & {
texturePath: string; // e.g. "/assets/yellow-datablock.png"
boxY: number; // The Y coordinate of the user box (target), e.g. 1.45
spawnXRange?: [number, number]; // Range for initial x position (before shifting)
spawnYRange?: [number, number]; // Range for initial y position (spawn height)
fallSpeed?: number; // Falling speed (units per second)
xOffset?: number; // Additional offset added to the chosen x (to shift falling to the right)
};

export default function DataBlockFallToBox(props: DataBlockFallToBoxProps) {
const {
texturePath,
boxY,
spawnXRange = [-0.2, 0.2],
spawnYRange = [6, 8],
fallSpeed = 1.5,
xOffset = 2.1,
} = props;

const meshRef = useRef<THREE.Mesh>(null!);

// Define 5 fixed x positions within spawnXRange.
const [minX, maxX] = spawnXRange;
const fixedXPoints = [
minX,
minX + (maxX - minX) * 0.25,
minX + (maxX - minX) * 0.5,
minX + (maxX - minX) * 0.75,
maxX,
];
// Choose one fixed x and add the xOffset.
const chooseFixedX = () => {
const idx = Math.floor(Math.random() * fixedXPoints.length);
return fixedXPoints[idx] + xOffset;
};

// Get a random initial Y from spawnYRange.
const getRandomY = () => {
const [minY, maxY] = spawnYRange;
return Math.random() * (maxY - minY) + minY;
};

// On the first frame, initialize the block's position if not already done.
if (meshRef.current && !meshRef.current.userData.initialized) {
const initialX = chooseFixedX();
const initialY = getRandomY();
meshRef.current.position.set(initialX, initialY, -0.1);
meshRef.current.userData.initialized = true;
}

const texture = useLoader(TextureLoader, texturePath);

useFrame((_, delta) => {
if (!meshRef.current) return;
// Move the block down by updating its y coordinate.
meshRef.current.position.y -= delta * fallSpeed;
// When the block reaches or goes below the target (boxY), reset its position.
if (meshRef.current.position.y <= boxY) {
const newX = chooseFixedX();
const newY = getRandomY();
meshRef.current.position.set(newX, newY, -0.1);
}
// No rotation applied: the block falls "as is."
});

return (
<mesh ref={meshRef}>
<planeGeometry args={[0.15, 0.15]} />
<meshStandardMaterial map={texture} transparent />
</mesh>
);
}
Loading

0 comments on commit 755447c

Please sign in to comment.