Created
May 20, 2025 17:31
-
-
Save statico/d49be5c4b12f58abde77b5030bb19ed9 to your computer and use it in GitHub Desktop.
jules.google roguelike header script unminified (with AI)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { u as jsx } from "./jsxRuntime.module.Cr_7eFrB.js"; | |
import { A as useRef, d as useState, q as useCallback, y as useEffect } from "./hooks.module.B8-SMkWr.js"; | |
import "./preact.module.CzIF3XV7.js"; | |
const AnimatedLogo = (props) => { | |
const canvasRef = useRef(null); | |
const defaultConfig = { | |
logoText: [ | |
" :xx; ", | |
" XMM0 :MMW ", | |
" :MMW ", | |
" OMMx ,MMM XMMc :MMW .dXMMMMMKl ,0WMMMMMW, ", | |
" OMMx ,MMM XMMc :MMW ,WMN; .cWMX MMM: ' ", | |
" OMMx ,MMM XMMc :MMW OMMNKKKKKWMM: lXMMWNKOo. ", | |
" OMMx .MMMc :MMMc :MMW lMMN,. .,. .';dMMW ", | |
" OMMx lWMMWNWMWMMc :MMW :XMMNKKNMN. .NMN0O0NMWo ", | |
" 0MMd ,clc, ,::. .::; .;clc:' .':clc:' ", | |
" KKXMMX. ", | |
" ;cl:' " | |
], | |
mobileLogoText: [ | |
" xMMk .xxo ", | |
" .MMX ", | |
" :KKc oKK, KKK .MMX .o0XNX0o. ckKXNX0d ", | |
" lMMo kMM; MMW .MMX oMMd' dMMl kMMo ", | |
" lMMo kMM; MMW .MMX MMM00000NWN .kNMWNKOl ", | |
" lMMo lMM0,.'kMMW .MMX xMMd OMMl ", | |
" lMMo c0WMMXxNWN .WWK ,xKWMMWKo lKNMMMN0l ", | |
" lKMM ", | |
"oOOOd' " | |
], | |
fontSize: 16, | |
fontFamily: "SF Mono, monospace", | |
textColor: "#784fcf", | |
fontWeight: "bold", | |
emptySlotChar: ".", | |
backgroundColor: "#1D0245", | |
viewportBackgroundColor: "#1D0245", | |
initialEjectedPiecesCount: 15, | |
ejectionIntervalMs: 700, | |
ejectedPieceBaseSpeed: 3, | |
ejectedPieceDamping: 0.98, | |
maxEjectedPieces: 30, | |
ejectedPieceColors: ["#E1308D", "#0FD3D3", "#F0C642", "#472394"], | |
robotChar: "@", | |
robotColor: "#fffbeb", | |
robotMoveInterval: 4, | |
robotPickupDelay: 8, | |
robotPlaceDelay: 8, | |
pauseKey: "p", | |
logicalCharWidth: 100, | |
logicalCharHeight: 20, | |
mobileLogicalCharWidth: 60, | |
mobileLogicalCharHeight: 20 | |
}; | |
const config = useRef({}); | |
const [isMobile, setIsMobile] = useState(false); | |
const logoSlots = useRef([]); | |
const ejectedPieces = useRef([]); | |
const robot = useRef({}); | |
const displayGrid = useRef({}); | |
const ctx = useRef(null); | |
const animFrameId = useRef(null); | |
const charWidth = useRef(0); | |
const charHeight = useRef(0); | |
const logoGridWidth = useRef(0); | |
const logoGridHeight = useRef(0); | |
const logoOffsetX = useRef(0); | |
const logoOffsetY = useRef(0); | |
const isPausedByKey = useRef(false); | |
const isPausedByVisibility = useRef(false); | |
const isPaused = useRef(false); | |
const ejectionTimer = useRef(0); | |
const lastFrameTime = useRef(0); | |
const handlePauseStateChange = useCallback(() => { | |
const isPausedNow = isPausedByKey.current || isPausedByVisibility.current; | |
if (isPaused.current && !isPausedNow) { | |
lastFrameTime.current = performance.now(); | |
} | |
isPaused.current = isPausedNow; | |
}, []); | |
const calculateCharDimensions = useCallback(() => { | |
if (!ctx.current) return false; | |
const currentConfig = config.current; | |
ctx.current.font = `${currentConfig.fontWeight} ${currentConfig.fontSize}px ${currentConfig.fontFamily}`; | |
charWidth.current = ctx.current.measureText("M").width; | |
charHeight.current = currentConfig.fontSize * 1.2; | |
if (charWidth.current === 0) { | |
console.error("Failed to calculate character width."); | |
return false; | |
} | |
return true; | |
}, []); | |
const initializeLogoSlots = useCallback(() => { | |
logoSlots.current = []; | |
const currentConfig = config.current; | |
const canvas = canvasRef.current; | |
if (currentConfig.logoText.length === 0 || charWidth.current === 0 || !canvas) return; | |
logoGridHeight.current = currentConfig.logoText.length; | |
logoGridWidth.current = Math.max(...currentConfig.logoText.map(line => line.length)); | |
const logoPixelWidth = logoGridWidth.current * charWidth.current; | |
const logoPixelHeight = logoGridHeight.current * charHeight.current; | |
logoOffsetX.current = Math.floor((canvas.width - logoPixelWidth) / 2); | |
logoOffsetY.current = Math.floor((canvas.height - logoPixelHeight) / 2); | |
for (let row = 0; row < logoGridHeight.current; row++) { | |
for (let col = 0; col < logoGridWidth.current; col++) { | |
const char = currentConfig.logoText[row] && currentConfig.logoText[row][col] | |
? currentConfig.logoText[row][col] | |
: " "; | |
if (char !== " ") { | |
logoSlots.current.push({ | |
originalChar: char, | |
isSlotEmpty: false, | |
logoGridR: row, | |
logoGridC: col, | |
canvasX: logoOffsetX.current + col * charWidth.current, | |
canvasY: logoOffsetY.current + row * charHeight.current, | |
isTargetedForReturn: false | |
}); | |
} | |
} | |
} | |
}, []); | |
const ejectPiece = useCallback(slot => { | |
if (charWidth.current === 0 || charHeight.current === 0) return false; | |
const currentConfig = config.current; | |
if (!slot || slot.isSlotEmpty || ejectedPieces.current.length >= currentConfig.maxEjectedPieces) return false; | |
slot.isSlotEmpty = true; | |
const angle = Math.random() * Math.PI * 2; | |
const speed = currentConfig.ejectedPieceBaseSpeed * (0.7 + Math.random() * 0.6); | |
const color = currentConfig.ejectedPieceColors[ | |
Math.floor(Math.random() * currentConfig.ejectedPieceColors.length) | |
]; | |
ejectedPieces.current.push({ | |
char: slot.originalChar, | |
originalLogoGridR: slot.logoGridR, | |
originalLogoGridC: slot.logoGridC, | |
x: slot.canvasX + charWidth.current / 2, | |
y: slot.canvasY + charHeight.current / 2, | |
vx: Math.cos(angle) * speed, | |
vy: Math.sin(angle) * speed, | |
isTargetedForPickup: false, | |
color: color | |
}); | |
return true; | |
}, []); | |
const initializeEjectedPieces = useCallback(() => { | |
if (logoSlots.current.length === 0 || charWidth.current === 0) return; | |
const availableSlots = [...logoSlots.current]; | |
for ( | |
let i = 0; | |
i < config.current.initialEjectedPiecesCount && | |
availableSlots.length > 0 && | |
!(ejectedPieces.current.length >= config.current.maxEjectedPieces); | |
i++ | |
) { | |
const randomIndex = Math.floor(Math.random() * availableSlots.length); | |
const slot = availableSlots.splice(randomIndex, 1)[0]; | |
ejectPiece(slot); | |
} | |
}, [ejectPiece]); | |
const initializeRobot = useCallback(() => { | |
const canvas = canvasRef.current; | |
const currentConfig = config.current; | |
if (!canvas || charWidth.current === 0 || charHeight.current === 0) return; | |
const gridCol = Math.floor(logoOffsetX.current / charWidth.current) + | |
Math.floor(logoGridWidth.current / 2) - 5; | |
const gridRow = Math.floor(logoOffsetY.current / charHeight.current) + | |
Math.floor(logoGridHeight.current / 2); | |
robot.current = { | |
gridC: Math.max(0, Math.min(currentConfig.logicalCharWidth - 1, gridCol)), | |
gridR: Math.max(0, Math.min(currentConfig.logicalCharHeight - 1, gridRow)), | |
char: currentConfig.robotChar, | |
color: currentConfig.robotColor, | |
state: "IDLE", | |
targetPiece: null, | |
targetSlot: null, | |
carryingPieceData: null, | |
moveTimer: 0, | |
actionTimer: 0 | |
}; | |
}, []); | |
const resizeCanvas = useCallback(() => { | |
const canvas = canvasRef.current; | |
if (!canvas || !calculateCharDimensions()) return; | |
const currentConfig = config.current; | |
const canvasWidth = currentConfig.logicalCharWidth * charWidth.current; | |
const canvasHeight = currentConfig.logicalCharHeight * charHeight.current; | |
if (canvas.width !== canvasWidth || canvas.height !== canvasHeight) { | |
canvas.width = canvasWidth; | |
canvas.height = canvasHeight; | |
} | |
initializeLogoSlots(); | |
if (robot.current.gridC === undefined) { | |
initializeRobot(); | |
} else { | |
robot.current.gridC = Math.max(0, Math.min(currentConfig.logicalCharWidth - 1, robot.current.gridC)); | |
robot.current.gridR = Math.max(0, Math.min(currentConfig.logicalCharHeight - 1, robot.current.gridR)); | |
} | |
}, [calculateCharDimensions, initializeLogoSlots, initializeRobot]); | |
const moveRobotTowards = useCallback((robotObj, targetCol, targetRow) => { | |
if (charWidth.current === 0) return false; | |
const deltaX = targetCol - robotObj.gridC; | |
const deltaY = targetRow - robotObj.gridR; | |
if (deltaX === 0 && deltaY === 0) return false; | |
// Move in the direction with the largest delta | |
if (Math.abs(deltaY) >= Math.abs(deltaX)) { | |
robotObj.gridR += Math.sign(deltaY); | |
} else { | |
robotObj.gridC += Math.sign(deltaX); | |
} | |
robotObj.moveTimer = config.current.robotMoveInterval; | |
return true; | |
}, []); | |
const findNearestPiece = useCallback(robotObj => { | |
if (charWidth.current === 0 || charHeight.current === 0) return; | |
let nearestPiece = null; | |
let nearestDistanceSq = Infinity; | |
for (const piece of ejectedPieces.current) { | |
if (!piece.isTargetedForPickup) { | |
const pieceGridCol = Math.round(piece.x / charWidth.current); | |
const pieceGridRow = Math.round(piece.y / charHeight.current); | |
const distanceSq = (robotObj.gridC - pieceGridCol) ** 2 + (robotObj.gridR - pieceGridRow) ** 2; | |
if (distanceSq < nearestDistanceSq) { | |
nearestDistanceSq = distanceSq; | |
nearestPiece = piece; | |
} | |
} | |
} | |
if (nearestPiece) { | |
robotObj.targetPiece = nearestPiece; | |
robotObj.targetPiece.isTargetedForPickup = true; | |
robotObj.state = "MOVING_TO_PICKUP"; | |
} | |
}, []); | |
const handleMovingToPickup = useCallback(robotObj => { | |
if (charWidth.current === 0 || charHeight.current === 0) { | |
robotObj.state = "IDLE"; | |
return; | |
} | |
if (!robotObj.targetPiece) { | |
robotObj.state = "IDLE"; | |
return; | |
} | |
const pieceGridCol = Math.round(robotObj.targetPiece.x / charWidth.current); | |
const pieceGridRow = Math.round(robotObj.targetPiece.y / charHeight.current); | |
if (robotObj.gridC === pieceGridCol && robotObj.gridR === pieceGridRow) { | |
robotObj.state = "AT_PIECE"; | |
robotObj.actionTimer = config.current.robotPickupDelay; | |
} else if (robotObj.moveTimer <= 0) { | |
moveRobotTowards(robotObj, pieceGridCol, pieceGridRow); | |
} | |
}, [moveRobotTowards]); | |
const handlePickupPiece = useCallback(robotObj => { | |
if (robotObj.actionTimer > 0) return; | |
if (robotObj.targetPiece && robotObj.targetPiece.isTargetedForPickup) { | |
robotObj.carryingPieceData = { | |
originalChar: robotObj.targetPiece.char, | |
originalLogoGridR: robotObj.targetPiece.originalLogoGridR, | |
originalLogoGridC: robotObj.targetPiece.originalLogoGridC | |
}; | |
ejectedPieces.current = ejectedPieces.current.filter(p => p !== robotObj.targetPiece); | |
robotObj.targetPiece = null; | |
robotObj.state = "MOVING_TO_SLOT"; | |
robotObj.targetSlot = logoSlots.current.find( | |
slot => | |
slot.logoGridR === robotObj.carryingPieceData.originalLogoGridR && | |
slot.logoGridC === robotObj.carryingPieceData.originalLogoGridC | |
); | |
if (robotObj.targetSlot) { | |
robotObj.targetSlot.isTargetedForReturn = true; | |
} else { | |
console.error("Error: Target slot not found for return."); | |
robotObj.state = "IDLE"; | |
robotObj.carryingPieceData = null; | |
} | |
} else { | |
robotObj.state = "IDLE"; | |
robotObj.targetPiece = null; | |
} | |
}, []); | |
const handleMovingToSlot = useCallback(robotObj => { | |
if (charWidth.current === 0 || charHeight.current === 0) { | |
robotObj.state = "IDLE"; | |
robotObj.carryingPieceData = null; | |
return; | |
} | |
if (!robotObj.targetSlot) { | |
robotObj.state = "IDLE"; | |
robotObj.carryingPieceData = null; | |
return; | |
} | |
const slotGridCol = Math.floor(robotObj.targetSlot.canvasX / charWidth.current); | |
const slotGridRow = Math.floor(robotObj.targetSlot.canvasY / charHeight.current); | |
if (robotObj.gridC === slotGridCol && robotObj.gridR === slotGridRow) { | |
robotObj.state = "AT_SLOT"; | |
robotObj.actionTimer = config.current.robotPlaceDelay; | |
} else if (robotObj.moveTimer <= 0) { | |
moveRobotTowards(robotObj, slotGridCol, slotGridRow); | |
} | |
}, [moveRobotTowards]); | |
const handlePlacePiece = useCallback(robotObj => { | |
if (robotObj.actionTimer > 0) return; | |
if (robotObj.targetSlot && robotObj.carryingPieceData) { | |
robotObj.targetSlot.isSlotEmpty = false; | |
robotObj.targetSlot.isTargetedForReturn = false; | |
} | |
robotObj.carryingPieceData = null; | |
robotObj.targetSlot = null; | |
robotObj.state = "IDLE"; | |
}, []); | |
const updateRobot = useCallback(() => { | |
if (isPaused.current) return; | |
const robotObj = robot.current; | |
robotObj.moveTimer = Math.max(0, robotObj.moveTimer - 1); | |
robotObj.actionTimer = Math.max(0, robotObj.actionTimer - 1); | |
switch (robotObj.state) { | |
case "IDLE": | |
findNearestPiece(robotObj); | |
break; | |
case "MOVING_TO_PICKUP": | |
handleMovingToPickup(robotObj); | |
break; | |
case "AT_PIECE": | |
handlePickupPiece(robotObj); | |
break; | |
case "MOVING_TO_SLOT": | |
handleMovingToSlot(robotObj); | |
break; | |
case "AT_SLOT": | |
handlePlacePiece(robotObj); | |
break; | |
default: | |
console.warn("Unknown robot state:", robotObj.state); | |
robotObj.state = "IDLE"; | |
} | |
}, [findNearestPiece, handleMovingToPickup, handlePickupPiece, handleMovingToSlot, handlePlacePiece]); | |
const updatePieces = useCallback(deltaTime => { | |
if (isPaused.current) return; | |
const currentConfig = config.current; | |
// Handle periodic piece ejection | |
ejectionTimer.current += deltaTime; | |
if (ejectionTimer.current >= currentConfig.ejectionIntervalMs && | |
ejectedPieces.current.length < currentConfig.maxEjectedPieces) { | |
ejectionTimer.current -= currentConfig.ejectionIntervalMs; | |
const nonEmptySlots = logoSlots.current.filter(slot => !slot.isSlotEmpty); | |
if (nonEmptySlots.length > 0) { | |
ejectPiece(nonEmptySlots[Math.floor(Math.random() * nonEmptySlots.length)]); | |
} | |
} | |
// Update ejected piece positions | |
for (let i = ejectedPieces.current.length - 1; i >= 0; i--) { | |
const piece = ejectedPieces.current[i]; | |
piece.x += piece.vx; | |
piece.y += piece.vy; | |
piece.vx *= currentConfig.ejectedPieceDamping; | |
piece.vy *= currentConfig.ejectedPieceDamping; | |
// Remove any pieces with NaN positions (should never happen, but safety check) | |
if (isNaN(piece.x) || isNaN(piece.y)) { | |
ejectedPieces.current.splice(i, 1); | |
} | |
} | |
}, [ejectPiece]); | |
const updateDisplayGrid = useCallback(() => { | |
displayGrid.current = {}; | |
const currentConfig = config.current; | |
if (!canvasRef.current || charWidth.current === 0 || charHeight.current === 0) return; | |
// Add logo slots to display grid | |
for (const slot of logoSlots.current) { | |
const gridCol = Math.floor(slot.canvasX / charWidth.current); | |
const gridRow = Math.floor(slot.canvasY / charHeight.current); | |
displayGrid.current[`${gridCol},${gridRow}`] = { | |
char: slot.isSlotEmpty ? currentConfig.emptySlotChar : slot.originalChar, | |
color: currentConfig.textColor | |
}; | |
} | |
// Add ejected pieces to display grid | |
for (const piece of ejectedPieces.current) { | |
const gridCol = Math.round(piece.x / charWidth.current); | |
const gridRow = Math.round(piece.y / charHeight.current); | |
if (gridCol >= 0 && gridRow >= 0 && | |
gridCol < currentConfig.logicalCharWidth && | |
gridRow < currentConfig.logicalCharHeight) { | |
displayGrid.current[`${gridCol},${gridRow}`] = { | |
char: piece.char, | |
color: piece.color | |
}; | |
} | |
} | |
// Add robot to display grid | |
const robotObj = robot.current; | |
if (robotObj && robotObj.gridC !== undefined && robotObj.gridR !== undefined) { | |
displayGrid.current[`${robotObj.gridC},${robotObj.gridR}`] = { | |
char: robotObj.char, | |
color: robotObj.color | |
}; | |
} | |
}, []); | |
const renderCanvas = useCallback(() => { | |
if (!ctx.current || !canvasRef.current || charWidth.current === 0 || charHeight.current === 0) return; | |
const context = ctx.current; | |
const canvas = canvasRef.current; | |
const currentConfig = config.current; | |
// Clear canvas | |
context.fillStyle = currentConfig.backgroundColor; | |
context.fillRect(0, 0, canvas.width, canvas.height); | |
// Set text rendering properties | |
context.font = `${currentConfig.fontWeight} ${currentConfig.fontSize}px ${currentConfig.fontFamily}`; | |
context.textAlign = "left"; | |
context.textBaseline = "top"; | |
// Render characters from the display grid | |
for (const key in displayGrid.current) { | |
const [col, row] = key.split(",").map(Number); | |
const cellData = displayGrid.current[key]; | |
context.fillStyle = cellData.color; | |
context.fillText(cellData.char, col * charWidth.current, row * charHeight.current); | |
} | |
// Render pause overlay if needed | |
if (isPaused.current) { | |
context.fillStyle = "rgba(255, 255, 255, 0.7)"; | |
context.font = `bold ${currentConfig.fontSize * 1.5}px ${currentConfig.fontFamily}`; | |
context.textAlign = "center"; | |
context.fillText("PAUSED", canvas.width / 2, canvas.height / 2); | |
} | |
}, []); | |
const animationLoop = useCallback(timestamp => { | |
if (lastFrameTime.current === 0) { | |
lastFrameTime.current = timestamp; | |
} | |
const deltaTime = timestamp - lastFrameTime.current; | |
lastFrameTime.current = timestamp; | |
if (!isPaused.current) { | |
updatePieces(deltaTime); | |
updateRobot(); | |
} | |
updateDisplayGrid(); | |
renderCanvas(); | |
animFrameId.current = requestAnimationFrame(animationLoop); | |
}, [updatePieces, updateRobot, updateDisplayGrid, renderCanvas]); | |
// Check for mobile device | |
useEffect(() => { | |
const mediaQuery = window.matchMedia("(max-width: 768px)"); | |
const handleResize = () => setIsMobile(mediaQuery.matches); | |
mediaQuery.addEventListener("change", handleResize); | |
handleResize(); | |
return () => mediaQuery.removeEventListener("change", handleResize); | |
}, []); | |
// Initialize and handle lifecycle | |
useEffect(() => { | |
const logoTextToUse = isMobile ? defaultConfig.mobileLogoText : defaultConfig.logoText; | |
const logicalWidthToUse = isMobile ? defaultConfig.mobileLogicalCharWidth : defaultConfig.logicalCharWidth; | |
const logicalHeightToUse = isMobile ? defaultConfig.mobileLogicalCharHeight : defaultConfig.logicalCharHeight; | |
config.current = { | |
...defaultConfig, | |
...props.config, | |
logoText: props.config && props.config.logoText ? props.config.logoText : logoTextToUse, | |
logicalCharWidth: props.config && props.config.logicalCharWidth ? props.config.logicalCharWidth : logicalWidthToUse, | |
logicalCharHeight: props.config && props.config.logicalCharHeight ? props.config.logicalCharHeight : logicalHeightToUse | |
}; | |
const canvas = canvasRef.current; | |
if (!canvas) return; | |
ctx.current = canvas.getContext("2d"); | |
if (!calculateCharDimensions()) { | |
console.error("Aborting setup: Character dimensions invalid."); | |
return; | |
} | |
resizeCanvas(); | |
ejectedPieces.current = []; | |
initializeEjectedPieces(); | |
initializeRobot(); | |
lastFrameTime.current = performance.now(); | |
if (animFrameId.current) { | |
cancelAnimationFrame(animFrameId.current); | |
} | |
animFrameId.current = requestAnimationFrame(animationLoop); | |
// Handle keyboard events for pausing | |
const handleKeyDown = (event) => { | |
if (event.key.toLowerCase() === config.current.pauseKey.toLowerCase()) { | |
isPausedByKey.current = !isPausedByKey.current; | |
handlePauseStateChange(); | |
} | |
}; | |
// Handle visibility changes for pausing | |
const observer = new IntersectionObserver(([entry]) => { | |
isPausedByVisibility.current = !entry.isIntersecting; | |
handlePauseStateChange(); | |
}, { | |
threshold: 0 | |
}); | |
observer.observe(canvas); | |
window.addEventListener("keydown", handleKeyDown); | |
window.addEventListener("resize", resizeCanvas); | |
return () => { | |
cancelAnimationFrame(animFrameId.current); | |
observer.unobserve(canvas); | |
window.removeEventListener("keydown", handleKeyDown); | |
window.removeEventListener("resize", resizeCanvas); | |
}; | |
}, [ | |
isMobile, | |
props.config, | |
animationLoop, | |
calculateCharDimensions, | |
initializeEjectedPieces, | |
resizeCanvas, | |
initializeRobot, | |
handlePauseStateChange, | |
defaultConfig | |
]); | |
return jsx("div", { | |
className: "relative flex justify-center align-center mt-4 md:mt-0", | |
children: [ | |
jsx("canvas", { | |
ref: canvasRef, | |
className: "block w-full h-full pixelated-img" | |
}), | |
jsx("h1", { | |
className: "absolute bottom-10 md:bottom-20 text-purple-50 bg-[#1D0245] p-2", | |
children: " An Asynchronous Coding Agent" | |
}) | |
] | |
}); | |
}; | |
export { AnimatedLogo as default }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment