Happy Birthday Prime!

With coffee in hand and code on your side,
ThePrimeagen Spire’s a treacherous ride.
Gremlins await and errors conspire,
But cake lies ahead at the top of the Spire.

How to Navigate the Spire

  • Click a node to climb the way
  • Choose your battles night or day
  • Rest at fires, heal or train
  • Each new card will grow your gain.
  • At the summit face the fight
  • Defeat the boss, win the night

May your code be bug-free and your coffee stay hot, May this birthday bring joy in each moment you’ve got.

Legend
Rest Rest
Battle Enemy
Battle Elite
Battle Boss
Event Events
Shop Shop
${(() => { const nodePositions = { 'n1': { x: 500, y: 720 }, // Start at bottom center - moved up slightly 'n2': { x: 350, y: 650 }, // Battle - left branch - moved right and up 'n3': { x: 650, y: 650 }, // Event - right branch - moved left and up 'n4': { x: 500, y: 540 }, // Battle - converge - moved up slightly 'n5': { x: 350, y: 400 }, // Rest - left 'n6': { x: 650, y: 400 }, // Shop - right 'n7': { x: 500, y: 300 }, // Battle - converge 'n8': { x: 500, y: 130 }, // Elite 'n9': { x: 500, y: 70 }, // Rest 'n10': { x: 500, y: 20 } // Boss at top }; return m.nodes.map(node => { if (!node.next || node.next.length === 0) return ''; return node.next.map(nextId => { const fromPos = nodePositions[node.id]; const toPos = nodePositions[nextId]; if (!fromPos || !toPos) return ''; const isActivePath = (node.id === currentId && nextIds.includes(nextId)) || (parseInt(nextId.replace('n', '')) <= parseInt(currentId.replace('n', ''))); return ``; }).join(''); }).join(''); })()}
${(() => { const nodePositions = { 'n1': { x: 500, y: 720 }, 'n2': { x: 360, y: 650 }, 'n3': { x: 630, y: 650 }, 'n4': { x: 500, y: 540 }, 'n5': { x: 360, y: 400 }, 'n6': { x: 630, y: 400 }, 'n7': { x: 500, y: 300 }, 'n8': { x: 500, y: 210 }, 'n9': { x: 500, y: 120 }, 'n10': { x: 500, y: 40 } }; return m.nodes.map(n => { const isNext = nextIds.includes(n.id); const isCurrent = n.id === currentId; const isCompleted = root.completedNodes.includes(n.id); const locked = (!isNext && !isCurrent && !isCompleted); const pos = nodePositions[n.id]; if (!pos) return ''; const leftPercent = (pos.x / 1000) * 100; const topPercent = (pos.y / 800) * 100; const tooltipData = getNodeTooltipData(n); return `
${getNodeEmoji(n.kind)}
${isCurrent ? '
β˜…
' : ''}
`; }).join(''); })()}
Your deck
${Object.entries( root.player.deck.reduce((acc, cardId) => { acc[cardId] = (acc[cardId] || 0) + 1; return acc; }, {}) ).map(([cardId, count], index) => { const card = CARDS[cardId]; if (!card) return ''; const cardType = card.type === 'attack' ? 'attack' : card.type === 'skill' ? 'skill' : 'power'; return `
${card.name}
${card.cost}
${getCardArt(cardId)}
${card.text}
${count > 1 ? `
Γ—${count}
` : ''}
`; }).join('')}