[
one goal
]
creators, developers & designers working as one.
A connected network of teams collaborating across every layer of our projects & platforms.
A connected network of teams collaborating across every layer of our projects & platforms.
[
lines shipped
]
refusing to overlook any detail
[
lines shipped
]
refusing to overlook any detail
[
assets
]
Designed across brands, platforms, and systems.
[
assets
]
Designed across brands, platforms, and systems.
[
countries
]
Creating experiences around the world.
[
countries
]
Creating experiences around the world.
[
1
]
SICKK_SOFTWARE
SICKK SOFTWARE
Our dev team designs, builds, and deploys systems from the ground up. Every interface, every interaction, every layer — engineered for precision, performance, and scale.
POS, enterprise, UI/UX overhauls, brand rebuilds and more. Whatever the challenge, we can handle it.


database
cloud
server
API
auth
CLIENTS
analytics
Architecture built to move fast, scale cleanly, and stay reliable under real-world pressure.
From connected APIs and cloud infrastructure to live data systems and operational tooling, every component is engineered to work together seamlessly — visually, technically, and at scale.
SasS
dashboards
tournament software
asset libraries
POS
management platforms
marketplaces
[
2
]
Sickk GAMING
We always create high-performance gaming experiences — from competitive platforms and player systems, to branding, community, and digital infrastructure engineered to perform under pressure.
Built by players, for players, and the future of gaming.


ARENA coming 2027
#
#
score
score
level
level
player_name
player_name
1
1
381
381
INSANE
INSANE
anonymous
anonymous
2
2
277
277
INSANE
INSANE
anonymous
anonymous
3
3
254
254
HARD
HARD
anonymous
anonymous
< FUN GAME CODE - WHY NOT />
<div id="jump-game" style="background-color: black;"> <div class="hud-bar"> <div class="hud-left"> <button type="button" class="play-pause-btn" id="jump-pause" aria-pressed="false" aria-label="Pause game"> <span class="btn-icon icon-pause" aria-hidden="true"> <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor"> <rect x="2" y="2" width="3.5" height="10" rx="0.5" /> <rect x="8.5" y="2" width="3.5" height="10" rx="0.5" /> </svg> </span> <span class="btn-icon icon-play" aria-hidden="true"> <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor"> <path d="M3 2 L12 7 L3 12 Z" /> </svg> </span> </button> <button type="button" class="play-pause-btn trophy-btn" id="jump-trophy" aria-pressed="true" aria-label="Leaderboard prompts on"> <span class="btn-icon icon-trophy-on" aria-hidden="true"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"> <path d="M8 21h8 M9 21V11h6v10 M7 21h10" /> <path d="M7 11H5a2 2 0 01-2-2V9h18v6a2 2 0 01-2 2h-2" /> <path d="M16 11V9a4 4 0 10-8 0v2" /> <path d="M9 6V5a3 3 0 016 0v1" /> </svg> </span> <span class="btn-icon icon-trophy-off" aria-hidden="true"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"> <path d="M8 21h8 M9 21V11h6v10 M7 21h10" /> <path d="M7 11H5a2 2 0 01-2-2V9h18v6a2 2 0 01-2 2h-2" /> <path d="M16 11V9a4 4 0 10-8 0v2" /> <path d="M9 6V5a3 3 0 016 0v1" /> <path d="M4 20 L20 4" stroke-width="2.1" stroke-linecap="square" /> </svg> </span> </button> </div> <span class="score-label" id="jump-score" aria-live="polite">0</span> </div> <div class="leaderboard-overlay" id="jump-leaderboard-overlay" aria-hidden="true"> <div class="leaderboard-overlay-inner"> <p class="leaderboard-title">New high score</p> <p class="leaderboard-score" id="jump-leaderboard-score">0</p> <button type="button" class="leaderboard-submit-btn" id="jump-leaderboard-submit"> Submit to leaderboard </button> </div> </div> <div class="speed-controls" role="group" aria-label="Game speed"> <button type="button" class="speed-btn active" data-speed="2.8">Easy</button> <button type="button" class="speed-btn" data-speed="3.8">Hard</button> <button type="button" class="speed-btn" data-speed="5">Insane</button> </div> <div class="scene-dim" aria-hidden="true"></div> <div class="ground"></div> <div class="player"></div> </div> <style> @import url("https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;600&display=swap"); html, body { margin: 0; height: 100%; overflow: hidden; overscroll-behavior: none; touch-action: none; } #jump-game { position: relative; width: 100%; height: 140px; overflow: hidden; background: transparent; user-select: none; touch-action: none; } #jump-game .hud-bar { position: absolute; top: 8px; left: 10px; right: 10px; z-index: 3; display: flex; align-items: center; justify-content: space-between; } #jump-game .hud-left { display: flex; align-items: center; gap: 8px; } #jump-game .scene-dim { position: absolute; inset: 0; z-index: 2; background: rgba(0, 0, 0, 0.52); opacity: 0; pointer-events: none; transition: opacity 0.22s ease; } #jump-game .leaderboard-overlay { position: absolute; inset: 0; z-index: 6; display: none; align-items: center; justify-content: center; background: rgba(0, 0, 0, 0.62); pointer-events: auto; padding: 12px; } #jump-game .leaderboard-overlay.is-visible { display: flex; } #jump-game .leaderboard-overlay-inner { width: min(340px, 100%); height: fit-content; text-align: center; padding: 20px; border: 1px solid rgba(255, 255, 255, 0.38); border-radius: 8px; background: rgba(20, 20, 22, 0.92); } #jump-game .leaderboard-title { margin: 0 0 6px; font-family: "Geist Mono", ui-monospace, monospace; font-size: 12px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: rgba(255, 255, 255, 0.92); } #jump-game .leaderboard-score { margin: 0 0 5px; font-family: "Geist Mono", ui-monospace, monospace; font-size: 28px; font-weight: 600; color: #f5d785; text-shadow: 0 0 16px rgba(245, 215, 133, 0.45); } #jump-game .leaderboard-submit-btn { box-sizing: border-box; width: 100%; margin: 0; padding: 6px 10px; border: 1px solid rgba(255, 255, 255, 0.4); border-radius: 4px; background: rgba(255, 255, 255, 0.1); font-family: "Geist Mono", ui-monospace, monospace; font-size: 12px; font-weight: 600; letter-spacing: 0.06em; color: rgba(255, 255, 255, 0.95); cursor: pointer; touch-action: manipulation; } #jump-game .leaderboard-submit-btn:hover { background: rgba(255, 255, 255, 0.16); border-color: rgba(255, 255, 255, 0.55); } #jump-game .leaderboard-submit-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.55); outline-offset: 3px; } #jump-game .speed-controls { position: absolute; top: 8px; left: 50%; transform: translateX(-50%); z-index: 3; display: inline-flex; align-items: center; gap: 8px; } #jump-game .speed-btn { box-sizing: border-box; margin: 0; padding: 0 10px; height: 32px; min-width: 62px; border: 1px solid rgba(255, 255, 255, 0.35); border-radius: 4px; background: rgba(255, 255, 255, 0.08); font-family: "Geist Mono", ui-monospace, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: rgba(255, 255, 255, 0.92); cursor: pointer; touch-action: manipulation; } #jump-game .speed-btn:hover { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.5); } #jump-game .speed-btn.active { background: rgba(255, 255, 255, 0.22); border-color: rgba(255, 255, 255, 0.72); } #jump-game .speed-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.55); outline-offset: 2px; } #jump-game.is-paused .scene-dim { opacity: 1; } #jump-game .score-label { display: inline-block; transform-origin: center center; font-family: "Geist Mono", ui-monospace, monospace; font-size: 13px; font-weight: 600; letter-spacing: 0.04em; color: rgba(255, 255, 255, 0.92); text-shadow: 0 0 14px rgba(255, 255, 255, 0.25); pointer-events: none; } #jump-game .score-label.score-gold { color: #f5d785; text-shadow: 0 0 10px rgba(245, 215, 133, 0.55), 0 0 22px rgba(212, 168, 75, 0.35); } #jump-game .score-label.score-gold-win { animation: scoreGoldSpring 0.5s cubic-bezier(0.34, 1.4, 0.64, 1) both; } @keyframes scoreGoldSpring { 0% { transform: scale(1); } 30% { transform: scale(1.42); } 58% { transform: scale(0.93); } 82% { transform: scale(1.08); } 100% { transform: scale(1); } } #jump-game .play-pause-btn { box-sizing: border-box; margin: 0; padding: 0; width: 32px; height: 32px; flex-shrink: 0; position: relative; display: inline-flex; align-items: center; justify-content: center; border: 1px solid rgba(255, 255, 255, 0.35); border-radius: 4px; background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.92); cursor: pointer; touch-action: manipulation; } #jump-game .play-pause-btn .btn-icon { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; } #jump-game #jump-pause .icon-play { display: none; } #jump-game.is-paused #jump-pause .icon-pause { display: none; } #jump-game.is-paused #jump-pause .icon-play { display: flex; } #jump-game .trophy-btn .icon-trophy-off { display: none; } #jump-game.leaderboard-prompt-off .trophy-btn .icon-trophy-on { display: none; } #jump-game.leaderboard-prompt-off .trophy-btn .icon-trophy-off { display: flex; } #jump-game .play-pause-btn:hover { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.5); } #jump-game .play-pause-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.55); outline-offset: 2px; } #jump-game .ground { position: absolute; z-index: 1; left: 0; right: 0; bottom: 0; height: 2px; background: linear-gradient(90deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.05)); box-shadow: 0 0 12px rgba(255, 255, 255, 0.18), 0 0 30px rgba(255, 255, 255, 0.08); } #jump-game .player { position: absolute; z-index: 1; left: 70px; bottom: 2px; width: 22px; height: 22px; background: white; /* box-shadow: 0 0 18px rgba(255, 255, 255, 0.45); */ transform: translateY(0); } #jump-game .player.invincible { animation: blinkLife 0.18s linear 8; } @keyframes blinkLife { 0%, 100% { opacity: 1; } 50% { opacity: 0.2; } } #jump-game .triangle { position: absolute; z-index: 1; bottom: 2px; width: 0; height: 0; border-left: 11px solid transparent; border-right: 11px solid transparent; border-bottom: 22px solid #ff3faf; /* filter: drop-shadow(0 0 10px rgba(255, 63, 175, 0.6)); */ } #jump-game .piece { position: absolute; z-index: 1; width: 9px; height: 9px; background: white; border-radius: 2px; pointer-events: none; } #jump-game .bg-shape { position: absolute; z-index: 0; pointer-events: none; opacity: 0.25; color: #fff; filter: blur(0.2px); } #jump-game .bg-tree { width: 0; height: 0; border-left: 10px solid transparent; border-right: 10px solid transparent; border-bottom: 24px solid rgba(255, 255, 255, 1); } #jump-game .bg-bush { width: 30px; height: 15px; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 15px; border-top-right-radius: 15px; background: rgba(255, 255, 255, 1); } </style> <script> (() => { const game = document.getElementById("jump-game") let player = game.querySelector(".player") let y = 0 let velocity = 0 let jumping = false let obstacles = [] let backgroundShapes = [] let pieces = [] let alive = true let reloading = false let spawning = true let score = 0 let paused = false let jumpHeld = false let jumpHoldTime = 0 let burstRemaining = 0 let postBurstRecovery = false let nextSpawnGap = 130 const leaderboardUiEnabled = false let leaderboardPromptsEnabled = leaderboardUiEnabled let goldBounceUsedThisRun = false let persistedBest = null const scoreLabel = document.getElementById("jump-score") const pauseBtn = document.getElementById("jump-pause") const trophyBtn = document.getElementById("jump-trophy") const leaderboardOverlay = document.getElementById("jump-leaderboard-overlay") const leaderboardScoreEl = document.getElementById("jump-leaderboard-score") const leaderboardSubmitBtn = document.getElementById("jump-leaderboard-submit") const speedButtons = Array.from(game.querySelectorAll(".speed-btn")) const highScoreStorageKey = "fun-scroller-high-score" const gravity = 0.42 const jumpForce = -6.7 const maxJumpHeight = -70 let speed = 2.8 const maxJumpHoldTime = 1.8 const jumpHoldLift = 0.36 const clusterGapMin = 24 const clusterGapMax = 34 const normalGapMin = 110 const normalGapMax = 170 const minLandingGap = 155 const frameSeconds = 1 / 60 function loadPersistedBest() { const raw = localStorage.getItem(highScoreStorageKey) if (raw === null) { persistedBest = null return } const parsed = Number.parseInt(raw, 10) persistedBest = Number.isFinite(parsed) ? parsed : null } function savePersistedBest(value) { persistedBest = value localStorage.setItem(highScoreStorageKey, String(value)) } function leaderboardOpen() { if (!leaderboardUiEnabled) return false return !!(leaderboardOverlay && leaderboardOverlay.classList.contains("is-visible")) } function hideLeaderboardOverlay() { if (!leaderboardUiEnabled) return if (!leaderboardOverlay) return leaderboardOverlay.classList.remove("is-visible") leaderboardOverlay.setAttribute("aria-hidden", "true") } function showLeaderboardOverlay(finalScore) { if (!leaderboardUiEnabled) return if (leaderboardScoreEl) leaderboardScoreEl.textContent = String(finalScore) if (!leaderboardOverlay) return leaderboardOverlay.classList.add("is-visible") leaderboardOverlay.setAttribute("aria-hidden", "false") } function updateScoreLabel() { if (!scoreLabel) return scoreLabel.textContent = String(score) const hasStored = persistedBest !== null if (!hasStored) { scoreLabel.classList.add("score-gold") return } if (score > persistedBest) { scoreLabel.classList.add("score-gold") if (!goldBounceUsedThisRun) { goldBounceUsedThisRun = true scoreLabel.classList.remove("score-gold-win") void scoreLabel.offsetWidth scoreLabel.classList.add("score-gold-win") scoreLabel.addEventListener( "animationend", () => scoreLabel.classList.remove("score-gold-win"), { once: true } ) } } else { scoreLabel.classList.remove("score-gold") scoreLabel.classList.remove("score-gold-win") goldBounceUsedThisRun = false } } function toggleLeaderboardPromptPreference() { if (!leaderboardUiEnabled) return leaderboardPromptsEnabled = !leaderboardPromptsEnabled game.classList.toggle("leaderboard-prompt-off", !leaderboardPromptsEnabled) if (trophyBtn) { trophyBtn.setAttribute("aria-pressed", String(leaderboardPromptsEnabled)) trophyBtn.setAttribute( "aria-label", leaderboardPromptsEnabled ? "Leaderboard prompts on" : "Leaderboard prompts off" ) } } function spawnBackgroundShape(force = false) { if (!force) { const last = backgroundShapes[backgroundShapes.length - 1] const lastX = last ? parseFloat(last.style.left) : 0 if (last && lastX > game.offsetWidth - 100) return } const shape = document.createElement("div") const isTree = Math.random() < 0.55 shape.className = `bg-shape ${isTree ? "bg-tree" : "bg-bush"}` shape.style.left = game.offsetWidth + Math.random() * 120 + "px" shape.style.bottom = (isTree ? 6 : 4) + Math.random() * 10 + "px" shape.style.opacity = (0.25 + Math.random() * 0.4).toFixed(2) game.appendChild(shape) backgroundShapes.push(shape) } function seedInitialBackgroundShapes() { const count = 6 const minSpacing = 30 let cursorX = -16 for (let i = 0; i < count; i++) { const shape = document.createElement("div") const isTree = Math.random() < 0.55 shape.className = `bg-shape ${isTree ? "bg-tree" : "bg-bush"}` const shapeWidth = isTree ? 20 : 22 const randomGap = minSpacing + Math.random() * 38 cursorX += randomGap shape.style.left = cursorX + "px" shape.style.bottom = (isTree ? 6 : 4) + Math.random() * 10 + "px" shape.style.opacity = (0.25 + Math.random() * 0.4).toFixed(2) game.appendChild(shape) backgroundShapes.push(shape) cursorX += shapeWidth } } function jump() { if (paused || leaderboardOpen()) return if (!alive || reloading) return if (!jumping) { jumping = true velocity = jumpForce jumpHoldTime = 0 } jumpHeld = true } function releaseJump() { jumpHeld = false } function spawnTriangle() { if (!spawning || !alive) return const last = obstacles[obstacles.length - 1] const lastX = last ? parseFloat(last.style.left) : 999 if (last && lastX > game.offsetWidth - nextSpawnGap) return const triangle = document.createElement("div") triangle.className = "triangle" triangle.style.left = game.offsetWidth + Math.random() * 120 + "px" game.appendChild(triangle) obstacles.push(triangle) if (burstRemaining > 0) { burstRemaining-- if (burstRemaining > 0) { nextSpawnGap = clusterGapMin + Math.random() * (clusterGapMax - clusterGapMin) } else { postBurstRecovery = true nextSpawnGap = minLandingGap + Math.random() * 35 } return } if (postBurstRecovery) { postBurstRecovery = false nextSpawnGap = normalGapMin + Math.random() * (normalGapMax - normalGapMin) return } const burstRoll = Math.random() if (burstRoll < 0.16) { // Triple stack (3 total): this + 2 rapid followers. burstRemaining = 2 nextSpawnGap = clusterGapMin + Math.random() * (clusterGapMax - clusterGapMin) } else if (burstRoll < 0.42) { // Double stack (2 total): this + 1 rapid follower. burstRemaining = 1 nextSpawnGap = clusterGapMin + Math.random() * (clusterGapMax - clusterGapMin) } else { nextSpawnGap = normalGapMin + Math.random() * (normalGapMax - normalGapMin) } } function rectsHit(a, b) { return ( a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top ) } /** True if p is inside or on the edge of triangle ABC (CCW or CW). */ function pointInTriangle(px, py, ax, ay, bx, by, cx, cy) { const eps = 1e-6 const c1 = (bx - ax) * (py - ay) - (by - ay) * (px - ax) const c2 = (cx - bx) * (py - by) - (cy - by) * (px - bx) const c3 = (ax - cx) * (py - cy) - (ay - cy) * (px - cx) const hasNeg = c1 < -eps || c2 < -eps || c3 < -eps const hasPos = c1 > eps || c2 > eps || c3 > eps return !(hasNeg && hasPos) } function pointInRect(px, py, left, top, right, bottom, pad) { return ( px >= left - pad && px <= right + pad && py >= top - pad && py <= bottom + pad ) } function segmentIntersect(x1, y1, x2, y2, x3, y3, x4, y4) { const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) if (Math.abs(denom) < 1e-12) return false const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom const u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom const eps = 1e-9 return t >= -eps && t <= 1 + eps && u >= -eps && u <= 1 + eps } /** * Player was only tested at its center, so corners could graze the slope with no hit. * Full AABB vs triangle: corners in tri, verts in rect, or any edge crossing. */ function rectHitsTriangle(left, top, right, bottom, ax, ay, bx, by, cx, cy) { const pad = 2 const l = left - pad const t = top - pad const r = right + pad const b = bottom + pad const rc = [ [l, t], [r, t], [r, b], [l, b], ] for (let i = 0; i < 4; i++) { const [x, y] = rc[i] if (pointInTriangle(x, y, ax, ay, bx, by, cx, cy)) return true } if (pointInRect(ax, ay, l, t, r, b, 0)) return true if (pointInRect(bx, by, l, t, r, b, 0)) return true if (pointInRect(cx, cy, l, t, r, b, 0)) return true const triE = [ [ax, ay, bx, by], [bx, by, cx, cy], [cx, cy, ax, ay], ] const rectE = [ [l, t, r, t], [r, t, r, b], [r, b, l, b], [l, b, l, t], ] for (let i = 0; i < 4; i++) { const [x1, y1, x2, y2] = rectE[i] for (let j = 0; j < 3; j++) { const [x3, y3, x4, y4] = triE[j] if (segmentIntersect(x1, y1, x2, y2, x3, y3, x4, y4)) return true } } return false } function checkCollisions() { if (!alive || reloading) return const pr = player.getBoundingClientRect() obstacles.forEach(triangle => { const triRect = triangle.getBoundingClientRect() const ax = triRect.left + triRect.width / 2 const ay = triRect.top const bx = triRect.left const by = triRect.bottom const cx = triRect.right const cy = triRect.bottom if ( rectHitsTriangle( pr.left, pr.top, pr.right, pr.bottom, ax, ay, bx, by, cx, cy ) ) { breakPlayer() } }) } function breakPlayer() { const finalScore = score alive = false spawning = false jumping = false jumpHeld = false jumpHoldTime = 0 const beatsRecord = finalScore > 0 && (persistedBest === null || finalScore > persistedBest) if (beatsRecord) { savePersistedBest(finalScore) } score = 0 updateScoreLabel() if (leaderboardPromptsEnabled && beatsRecord) { showLeaderboardOverlay(finalScore) } const playerRect = player.getBoundingClientRect() const gameRect = game.getBoundingClientRect() const baseX = playerRect.left - gameRect.left const baseY = playerRect.top - gameRect.top player.remove() for (let i = 0; i < 6; i++) { const piece = document.createElement("div") piece.className = "piece" piece.style.left = baseX + 6 + "px" piece.style.top = baseY + 6 + "px" piece.vx = (Math.random() - 0.5) * 7 piece.vy = -Math.random() * 6 - 2 piece.life = 45 game.appendChild(piece) pieces.push(piece) } setTimeout(resetGame, 900) } function resetGame() { reloading = true goldBounceUsedThisRun = false obstacles.forEach(triangle => triangle.remove()) obstacles = [] pieces.forEach(piece => piece.remove()) pieces = [] y = 0 velocity = 0 jumping = false jumpHeld = false jumpHoldTime = 0 burstRemaining = 0 postBurstRecovery = false nextSpawnGap = normalGapMin + Math.random() * (normalGapMax - normalGapMin) player = document.createElement("div") player.className = "player invincible" game.appendChild(player) setTimeout(() => { player.classList.remove("invincible") alive = true reloading = false spawning = true updateScoreLabel() }, 1500) } function updatePlayer() { if (!alive || reloading) return if (jumping) { if (jumpHeld && jumpHoldTime < maxJumpHoldTime) { velocity -= jumpHoldLift jumpHoldTime += frameSeconds } y += velocity velocity += gravity if (y < maxJumpHeight) { y = maxJumpHeight velocity *= -0.08 } if (y >= 0) { y = 0 velocity = 0 jumping = false jumpHoldTime = 0 } player.style.transform = `translateY(${y}px)` } } function updatePieces() { pieces.forEach((piece, index) => { piece.vy += 0.35 const x = parseFloat(piece.style.left) + piece.vx const y = parseFloat(piece.style.top) + piece.vy piece.style.left = x + "px" piece.style.top = y + "px" piece.style.opacity = piece.life / 45 piece.life-- if (piece.life <= 0) { piece.remove() pieces.splice(index, 1) } }) } function updateObstacles() { obstacles.forEach((triangle, index) => { let x = parseFloat(triangle.style.left) if (alive && !reloading) { x -= speed triangle.style.left = x + "px" } if (x < -40) { if (alive && !reloading) { score += 1 updateScoreLabel() } triangle.remove() obstacles.splice(index, 1) } }) if (Math.random() < 0.012) { spawnTriangle() } } function updateBackgroundShapes() { const backgroundSpeed = speed * 0.22 backgroundShapes.forEach((shape, index) => { let x = parseFloat(shape.style.left) if (alive && !reloading) { x -= backgroundSpeed shape.style.left = x + "px" } if (x < -40) { shape.remove() backgroundShapes.splice(index, 1) } }) if (alive && !reloading && Math.random() < 0.02) { spawnBackgroundShape() } } function loop() { if (!paused) { updatePlayer() updateBackgroundShapes() updateObstacles() updatePieces() checkCollisions() } requestAnimationFrame(loop) } function togglePause() { paused = !paused game.classList.toggle("is-paused", paused) if (pauseBtn) { pauseBtn.setAttribute("aria-pressed", String(paused)) pauseBtn.setAttribute( "aria-label", paused ? "Resume game" : "Pause game" ) } } function setGameSpeed(nextSpeed, sourceButton) { speed = nextSpeed speedButtons.forEach(btn => { const active = btn === sourceButton btn.classList.toggle("active", active) btn.setAttribute("aria-pressed", String(active)) }) } const scrollKeys = new Set([ "Space", "ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", ]) window.addEventListener( "keydown", e => { if (e.code === "Space") { e.preventDefault() if (!e.repeat) jump() } else if (scrollKeys.has(e.code)) { e.preventDefault() } }, { passive: false } ) window.addEventListener( "keyup", e => { if (e.code === "Space") { e.preventDefault() releaseJump() } else if (scrollKeys.has(e.code)) { e.preventDefault() } }, { passive: false } ) const blockScroll = e => e.preventDefault() window.addEventListener("wheel", blockScroll, { passive: false }) window.addEventListener("touchmove", blockScroll, { passive: false }) game.addEventListener("mousedown", jump) game.addEventListener("touchstart", jump, { passive: true }) window.addEventListener("mouseup", releaseJump) window.addEventListener("touchend", releaseJump, { passive: true }) window.addEventListener("touchcancel", releaseJump, { passive: true }) if (pauseBtn) { pauseBtn.addEventListener("click", e => { e.stopPropagation() togglePause() }) pauseBtn.addEventListener("mousedown", e => e.stopPropagation()) pauseBtn.addEventListener( "touchstart", e => e.stopPropagation(), { passive: true } ) } if (trophyBtn && leaderboardUiEnabled) { trophyBtn.addEventListener("click", e => { e.stopPropagation() toggleLeaderboardPromptPreference() }) trophyBtn.addEventListener("mousedown", e => e.stopPropagation()) trophyBtn.addEventListener( "touchstart", e => e.stopPropagation(), { passive: true } ) } if (leaderboardSubmitBtn && leaderboardUiEnabled) { leaderboardSubmitBtn.addEventListener("click", e => { e.stopPropagation() hideLeaderboardOverlay() }) leaderboardSubmitBtn.addEventListener("mousedown", e => e.stopPropagation()) leaderboardSubmitBtn.addEventListener( "touchstart", e => e.stopPropagation(), { passive: true } ) } speedButtons.forEach(btn => { btn.addEventListener("click", e => { e.stopPropagation() const nextSpeed = Number(btn.dataset.speed) if (!Number.isNaN(nextSpeed)) setGameSpeed(nextSpeed, btn) }) btn.addEventListener("mousedown", e => e.stopPropagation()) btn.addEventListener( "touchstart", e => e.stopPropagation(), { passive: true } ) }) loadPersistedBest() updateScoreLabel() if (!leaderboardUiEnabled) { leaderboardPromptsEnabled = false game.classList.add("leaderboard-prompt-off") if (trophyBtn) trophyBtn.style.display = "none" if (leaderboardOverlay) leaderboardOverlay.style.display = "none" } seedInitialBackgroundShapes() setTimeout(spawnTriangle, 600) loop() })() </script>
<div id="jump-game" style="background-color: black;"> <div class="hud-bar"> <div class="hud-left"> <button type="button" class="play-pause-btn" id="jump-pause" aria-pressed="false" aria-label="Pause game"> <span class="btn-icon icon-pause" aria-hidden="true"> <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor"> <rect x="2" y="2" width="3.5" height="10" rx="0.5" /> <rect x="8.5" y="2" width="3.5" height="10" rx="0.5" /> </svg> </span> <span class="btn-icon icon-play" aria-hidden="true"> <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor"> <path d="M3 2 L12 7 L3 12 Z" /> </svg> </span> </button> <button type="button" class="play-pause-btn trophy-btn" id="jump-trophy" aria-pressed="true" aria-label="Leaderboard prompts on"> <span class="btn-icon icon-trophy-on" aria-hidden="true"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"> <path d="M8 21h8 M9 21V11h6v10 M7 21h10" /> <path d="M7 11H5a2 2 0 01-2-2V9h18v6a2 2 0 01-2 2h-2" /> <path d="M16 11V9a4 4 0 10-8 0v2" /> <path d="M9 6V5a3 3 0 016 0v1" /> </svg> </span> <span class="btn-icon icon-trophy-off" aria-hidden="true"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"> <path d="M8 21h8 M9 21V11h6v10 M7 21h10" /> <path d="M7 11H5a2 2 0 01-2-2V9h18v6a2 2 0 01-2 2h-2" /> <path d="M16 11V9a4 4 0 10-8 0v2" /> <path d="M9 6V5a3 3 0 016 0v1" /> <path d="M4 20 L20 4" stroke-width="2.1" stroke-linecap="square" /> </svg> </span> </button> </div> <span class="score-label" id="jump-score" aria-live="polite">0</span> </div> <div class="leaderboard-overlay" id="jump-leaderboard-overlay" aria-hidden="true"> <div class="leaderboard-overlay-inner"> <p class="leaderboard-title">New high score</p> <p class="leaderboard-score" id="jump-leaderboard-score">0</p> <button type="button" class="leaderboard-submit-btn" id="jump-leaderboard-submit"> Submit to leaderboard </button> </div> </div> <div class="speed-controls" role="group" aria-label="Game speed"> <button type="button" class="speed-btn active" data-speed="2.8">Easy</button> <button type="button" class="speed-btn" data-speed="3.8">Hard</button> <button type="button" class="speed-btn" data-speed="5">Insane</button> </div> <div class="scene-dim" aria-hidden="true"></div> <div class="ground"></div> <div class="player"></div> </div> <style> @import url("https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;600&display=swap"); html, body { margin: 0; height: 100%; overflow: hidden; overscroll-behavior: none; touch-action: none; } #jump-game { position: relative; width: 100%; height: 140px; overflow: hidden; background: transparent; user-select: none; touch-action: none; } #jump-game .hud-bar { position: absolute; top: 8px; left: 10px; right: 10px; z-index: 3; display: flex; align-items: center; justify-content: space-between; } #jump-game .hud-left { display: flex; align-items: center; gap: 8px; } #jump-game .scene-dim { position: absolute; inset: 0; z-index: 2; background: rgba(0, 0, 0, 0.52); opacity: 0; pointer-events: none; transition: opacity 0.22s ease; } #jump-game .leaderboard-overlay { position: absolute; inset: 0; z-index: 6; display: none; align-items: center; justify-content: center; background: rgba(0, 0, 0, 0.62); pointer-events: auto; padding: 12px; } #jump-game .leaderboard-overlay.is-visible { display: flex; } #jump-game .leaderboard-overlay-inner { width: min(340px, 100%); height: fit-content; text-align: center; padding: 20px; border: 1px solid rgba(255, 255, 255, 0.38); border-radius: 8px; background: rgba(20, 20, 22, 0.92); } #jump-game .leaderboard-title { margin: 0 0 6px; font-family: "Geist Mono", ui-monospace, monospace; font-size: 12px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: rgba(255, 255, 255, 0.92); } #jump-game .leaderboard-score { margin: 0 0 5px; font-family: "Geist Mono", ui-monospace, monospace; font-size: 28px; font-weight: 600; color: #f5d785; text-shadow: 0 0 16px rgba(245, 215, 133, 0.45); } #jump-game .leaderboard-submit-btn { box-sizing: border-box; width: 100%; margin: 0; padding: 6px 10px; border: 1px solid rgba(255, 255, 255, 0.4); border-radius: 4px; background: rgba(255, 255, 255, 0.1); font-family: "Geist Mono", ui-monospace, monospace; font-size: 12px; font-weight: 600; letter-spacing: 0.06em; color: rgba(255, 255, 255, 0.95); cursor: pointer; touch-action: manipulation; } #jump-game .leaderboard-submit-btn:hover { background: rgba(255, 255, 255, 0.16); border-color: rgba(255, 255, 255, 0.55); } #jump-game .leaderboard-submit-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.55); outline-offset: 3px; } #jump-game .speed-controls { position: absolute; top: 8px; left: 50%; transform: translateX(-50%); z-index: 3; display: inline-flex; align-items: center; gap: 8px; } #jump-game .speed-btn { box-sizing: border-box; margin: 0; padding: 0 10px; height: 32px; min-width: 62px; border: 1px solid rgba(255, 255, 255, 0.35); border-radius: 4px; background: rgba(255, 255, 255, 0.08); font-family: "Geist Mono", ui-monospace, monospace; font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: rgba(255, 255, 255, 0.92); cursor: pointer; touch-action: manipulation; } #jump-game .speed-btn:hover { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.5); } #jump-game .speed-btn.active { background: rgba(255, 255, 255, 0.22); border-color: rgba(255, 255, 255, 0.72); } #jump-game .speed-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.55); outline-offset: 2px; } #jump-game.is-paused .scene-dim { opacity: 1; } #jump-game .score-label { display: inline-block; transform-origin: center center; font-family: "Geist Mono", ui-monospace, monospace; font-size: 13px; font-weight: 600; letter-spacing: 0.04em; color: rgba(255, 255, 255, 0.92); text-shadow: 0 0 14px rgba(255, 255, 255, 0.25); pointer-events: none; } #jump-game .score-label.score-gold { color: #f5d785; text-shadow: 0 0 10px rgba(245, 215, 133, 0.55), 0 0 22px rgba(212, 168, 75, 0.35); } #jump-game .score-label.score-gold-win { animation: scoreGoldSpring 0.5s cubic-bezier(0.34, 1.4, 0.64, 1) both; } @keyframes scoreGoldSpring { 0% { transform: scale(1); } 30% { transform: scale(1.42); } 58% { transform: scale(0.93); } 82% { transform: scale(1.08); } 100% { transform: scale(1); } } #jump-game .play-pause-btn { box-sizing: border-box; margin: 0; padding: 0; width: 32px; height: 32px; flex-shrink: 0; position: relative; display: inline-flex; align-items: center; justify-content: center; border: 1px solid rgba(255, 255, 255, 0.35); border-radius: 4px; background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.92); cursor: pointer; touch-action: manipulation; } #jump-game .play-pause-btn .btn-icon { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; } #jump-game #jump-pause .icon-play { display: none; } #jump-game.is-paused #jump-pause .icon-pause { display: none; } #jump-game.is-paused #jump-pause .icon-play { display: flex; } #jump-game .trophy-btn .icon-trophy-off { display: none; } #jump-game.leaderboard-prompt-off .trophy-btn .icon-trophy-on { display: none; } #jump-game.leaderboard-prompt-off .trophy-btn .icon-trophy-off { display: flex; } #jump-game .play-pause-btn:hover { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.5); } #jump-game .play-pause-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.55); outline-offset: 2px; } #jump-game .ground { position: absolute; z-index: 1; left: 0; right: 0; bottom: 0; height: 2px; background: linear-gradient(90deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.05)); box-shadow: 0 0 12px rgba(255, 255, 255, 0.18), 0 0 30px rgba(255, 255, 255, 0.08); } #jump-game .player { position: absolute; z-index: 1; left: 70px; bottom: 2px; width: 22px; height: 22px; background: white; /* box-shadow: 0 0 18px rgba(255, 255, 255, 0.45); */ transform: translateY(0); } #jump-game .player.invincible { animation: blinkLife 0.18s linear 8; } @keyframes blinkLife { 0%, 100% { opacity: 1; } 50% { opacity: 0.2; } } #jump-game .triangle { position: absolute; z-index: 1; bottom: 2px; width: 0; height: 0; border-left: 11px solid transparent; border-right: 11px solid transparent; border-bottom: 22px solid #ff3faf; /* filter: drop-shadow(0 0 10px rgba(255, 63, 175, 0.6)); */ } #jump-game .piece { position: absolute; z-index: 1; width: 9px; height: 9px; background: white; border-radius: 2px; pointer-events: none; } #jump-game .bg-shape { position: absolute; z-index: 0; pointer-events: none; opacity: 0.25; color: #fff; filter: blur(0.2px); } #jump-game .bg-tree { width: 0; height: 0; border-left: 10px solid transparent; border-right: 10px solid transparent; border-bottom: 24px solid rgba(255, 255, 255, 1); } #jump-game .bg-bush { width: 30px; height: 15px; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 15px; border-top-right-radius: 15px; background: rgba(255, 255, 255, 1); } </style> <script> (() => { const game = document.getElementById("jump-game") let player = game.querySelector(".player") let y = 0 let velocity = 0 let jumping = false let obstacles = [] let backgroundShapes = [] let pieces = [] let alive = true let reloading = false let spawning = true let score = 0 let paused = false let jumpHeld = false let jumpHoldTime = 0 let burstRemaining = 0 let postBurstRecovery = false let nextSpawnGap = 130 const leaderboardUiEnabled = false let leaderboardPromptsEnabled = leaderboardUiEnabled let goldBounceUsedThisRun = false let persistedBest = null const scoreLabel = document.getElementById("jump-score") const pauseBtn = document.getElementById("jump-pause") const trophyBtn = document.getElementById("jump-trophy") const leaderboardOverlay = document.getElementById("jump-leaderboard-overlay") const leaderboardScoreEl = document.getElementById("jump-leaderboard-score") const leaderboardSubmitBtn = document.getElementById("jump-leaderboard-submit") const speedButtons = Array.from(game.querySelectorAll(".speed-btn")) const highScoreStorageKey = "fun-scroller-high-score" const gravity = 0.42 const jumpForce = -6.7 const maxJumpHeight = -70 let speed = 2.8 const maxJumpHoldTime = 1.8 const jumpHoldLift = 0.36 const clusterGapMin = 24 const clusterGapMax = 34 const normalGapMin = 110 const normalGapMax = 170 const minLandingGap = 155 const frameSeconds = 1 / 60 function loadPersistedBest() { const raw = localStorage.getItem(highScoreStorageKey) if (raw === null) { persistedBest = null return } const parsed = Number.parseInt(raw, 10) persistedBest = Number.isFinite(parsed) ? parsed : null } function savePersistedBest(value) { persistedBest = value localStorage.setItem(highScoreStorageKey, String(value)) } function leaderboardOpen() { if (!leaderboardUiEnabled) return false return !!(leaderboardOverlay && leaderboardOverlay.classList.contains("is-visible")) } function hideLeaderboardOverlay() { if (!leaderboardUiEnabled) return if (!leaderboardOverlay) return leaderboardOverlay.classList.remove("is-visible") leaderboardOverlay.setAttribute("aria-hidden", "true") } function showLeaderboardOverlay(finalScore) { if (!leaderboardUiEnabled) return if (leaderboardScoreEl) leaderboardScoreEl.textContent = String(finalScore) if (!leaderboardOverlay) return leaderboardOverlay.classList.add("is-visible") leaderboardOverlay.setAttribute("aria-hidden", "false") } function updateScoreLabel() { if (!scoreLabel) return scoreLabel.textContent = String(score) const hasStored = persistedBest !== null if (!hasStored) { scoreLabel.classList.add("score-gold") return } if (score > persistedBest) { scoreLabel.classList.add("score-gold") if (!goldBounceUsedThisRun) { goldBounceUsedThisRun = true scoreLabel.classList.remove("score-gold-win") void scoreLabel.offsetWidth scoreLabel.classList.add("score-gold-win") scoreLabel.addEventListener( "animationend", () => scoreLabel.classList.remove("score-gold-win"), { once: true } ) } } else { scoreLabel.classList.remove("score-gold") scoreLabel.classList.remove("score-gold-win") goldBounceUsedThisRun = false } } function toggleLeaderboardPromptPreference() { if (!leaderboardUiEnabled) return leaderboardPromptsEnabled = !leaderboardPromptsEnabled game.classList.toggle("leaderboard-prompt-off", !leaderboardPromptsEnabled) if (trophyBtn) { trophyBtn.setAttribute("aria-pressed", String(leaderboardPromptsEnabled)) trophyBtn.setAttribute( "aria-label", leaderboardPromptsEnabled ? "Leaderboard prompts on" : "Leaderboard prompts off" ) } } function spawnBackgroundShape(force = false) { if (!force) { const last = backgroundShapes[backgroundShapes.length - 1] const lastX = last ? parseFloat(last.style.left) : 0 if (last && lastX > game.offsetWidth - 100) return } const shape = document.createElement("div") const isTree = Math.random() < 0.55 shape.className = `bg-shape ${isTree ? "bg-tree" : "bg-bush"}` shape.style.left = game.offsetWidth + Math.random() * 120 + "px" shape.style.bottom = (isTree ? 6 : 4) + Math.random() * 10 + "px" shape.style.opacity = (0.25 + Math.random() * 0.4).toFixed(2) game.appendChild(shape) backgroundShapes.push(shape) } function seedInitialBackgroundShapes() { const count = 6 const minSpacing = 30 let cursorX = -16 for (let i = 0; i < count; i++) { const shape = document.createElement("div") const isTree = Math.random() < 0.55 shape.className = `bg-shape ${isTree ? "bg-tree" : "bg-bush"}` const shapeWidth = isTree ? 20 : 22 const randomGap = minSpacing + Math.random() * 38 cursorX += randomGap shape.style.left = cursorX + "px" shape.style.bottom = (isTree ? 6 : 4) + Math.random() * 10 + "px" shape.style.opacity = (0.25 + Math.random() * 0.4).toFixed(2) game.appendChild(shape) backgroundShapes.push(shape) cursorX += shapeWidth } } function jump() { if (paused || leaderboardOpen()) return if (!alive || reloading) return if (!jumping) { jumping = true velocity = jumpForce jumpHoldTime = 0 } jumpHeld = true } function releaseJump() { jumpHeld = false } function spawnTriangle() { if (!spawning || !alive) return const last = obstacles[obstacles.length - 1] const lastX = last ? parseFloat(last.style.left) : 999 if (last && lastX > game.offsetWidth - nextSpawnGap) return const triangle = document.createElement("div") triangle.className = "triangle" triangle.style.left = game.offsetWidth + Math.random() * 120 + "px" game.appendChild(triangle) obstacles.push(triangle) if (burstRemaining > 0) { burstRemaining-- if (burstRemaining > 0) { nextSpawnGap = clusterGapMin + Math.random() * (clusterGapMax - clusterGapMin) } else { postBurstRecovery = true nextSpawnGap = minLandingGap + Math.random() * 35 } return } if (postBurstRecovery) { postBurstRecovery = false nextSpawnGap = normalGapMin + Math.random() * (normalGapMax - normalGapMin) return } const burstRoll = Math.random() if (burstRoll < 0.16) { // Triple stack (3 total): this + 2 rapid followers. burstRemaining = 2 nextSpawnGap = clusterGapMin + Math.random() * (clusterGapMax - clusterGapMin) } else if (burstRoll < 0.42) { // Double stack (2 total): this + 1 rapid follower. burstRemaining = 1 nextSpawnGap = clusterGapMin + Math.random() * (clusterGapMax - clusterGapMin) } else { nextSpawnGap = normalGapMin + Math.random() * (normalGapMax - normalGapMin) } } function rectsHit(a, b) { return ( a.left < b.right && a.right > b.left && a.top < b.bottom && a.bottom > b.top ) } /** True if p is inside or on the edge of triangle ABC (CCW or CW). */ function pointInTriangle(px, py, ax, ay, bx, by, cx, cy) { const eps = 1e-6 const c1 = (bx - ax) * (py - ay) - (by - ay) * (px - ax) const c2 = (cx - bx) * (py - by) - (cy - by) * (px - bx) const c3 = (ax - cx) * (py - cy) - (ay - cy) * (px - cx) const hasNeg = c1 < -eps || c2 < -eps || c3 < -eps const hasPos = c1 > eps || c2 > eps || c3 > eps return !(hasNeg && hasPos) } function pointInRect(px, py, left, top, right, bottom, pad) { return ( px >= left - pad && px <= right + pad && py >= top - pad && py <= bottom + pad ) } function segmentIntersect(x1, y1, x2, y2, x3, y3, x4, y4) { const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) if (Math.abs(denom) < 1e-12) return false const t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom const u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom const eps = 1e-9 return t >= -eps && t <= 1 + eps && u >= -eps && u <= 1 + eps } /** * Player was only tested at its center, so corners could graze the slope with no hit. * Full AABB vs triangle: corners in tri, verts in rect, or any edge crossing. */ function rectHitsTriangle(left, top, right, bottom, ax, ay, bx, by, cx, cy) { const pad = 2 const l = left - pad const t = top - pad const r = right + pad const b = bottom + pad const rc = [ [l, t], [r, t], [r, b], [l, b], ] for (let i = 0; i < 4; i++) { const [x, y] = rc[i] if (pointInTriangle(x, y, ax, ay, bx, by, cx, cy)) return true } if (pointInRect(ax, ay, l, t, r, b, 0)) return true if (pointInRect(bx, by, l, t, r, b, 0)) return true if (pointInRect(cx, cy, l, t, r, b, 0)) return true const triE = [ [ax, ay, bx, by], [bx, by, cx, cy], [cx, cy, ax, ay], ] const rectE = [ [l, t, r, t], [r, t, r, b], [r, b, l, b], [l, b, l, t], ] for (let i = 0; i < 4; i++) { const [x1, y1, x2, y2] = rectE[i] for (let j = 0; j < 3; j++) { const [x3, y3, x4, y4] = triE[j] if (segmentIntersect(x1, y1, x2, y2, x3, y3, x4, y4)) return true } } return false } function checkCollisions() { if (!alive || reloading) return const pr = player.getBoundingClientRect() obstacles.forEach(triangle => { const triRect = triangle.getBoundingClientRect() const ax = triRect.left + triRect.width / 2 const ay = triRect.top const bx = triRect.left const by = triRect.bottom const cx = triRect.right const cy = triRect.bottom if ( rectHitsTriangle( pr.left, pr.top, pr.right, pr.bottom, ax, ay, bx, by, cx, cy ) ) { breakPlayer() } }) } function breakPlayer() { const finalScore = score alive = false spawning = false jumping = false jumpHeld = false jumpHoldTime = 0 const beatsRecord = finalScore > 0 && (persistedBest === null || finalScore > persistedBest) if (beatsRecord) { savePersistedBest(finalScore) } score = 0 updateScoreLabel() if (leaderboardPromptsEnabled && beatsRecord) { showLeaderboardOverlay(finalScore) } const playerRect = player.getBoundingClientRect() const gameRect = game.getBoundingClientRect() const baseX = playerRect.left - gameRect.left const baseY = playerRect.top - gameRect.top player.remove() for (let i = 0; i < 6; i++) { const piece = document.createElement("div") piece.className = "piece" piece.style.left = baseX + 6 + "px" piece.style.top = baseY + 6 + "px" piece.vx = (Math.random() - 0.5) * 7 piece.vy = -Math.random() * 6 - 2 piece.life = 45 game.appendChild(piece) pieces.push(piece) } setTimeout(resetGame, 900) } function resetGame() { reloading = true goldBounceUsedThisRun = false obstacles.forEach(triangle => triangle.remove()) obstacles = [] pieces.forEach(piece => piece.remove()) pieces = [] y = 0 velocity = 0 jumping = false jumpHeld = false jumpHoldTime = 0 burstRemaining = 0 postBurstRecovery = false nextSpawnGap = normalGapMin + Math.random() * (normalGapMax - normalGapMin) player = document.createElement("div") player.className = "player invincible" game.appendChild(player) setTimeout(() => { player.classList.remove("invincible") alive = true reloading = false spawning = true updateScoreLabel() }, 1500) } function updatePlayer() { if (!alive || reloading) return if (jumping) { if (jumpHeld && jumpHoldTime < maxJumpHoldTime) { velocity -= jumpHoldLift jumpHoldTime += frameSeconds } y += velocity velocity += gravity if (y < maxJumpHeight) { y = maxJumpHeight velocity *= -0.08 } if (y >= 0) { y = 0 velocity = 0 jumping = false jumpHoldTime = 0 } player.style.transform = `translateY(${y}px)` } } function updatePieces() { pieces.forEach((piece, index) => { piece.vy += 0.35 const x = parseFloat(piece.style.left) + piece.vx const y = parseFloat(piece.style.top) + piece.vy piece.style.left = x + "px" piece.style.top = y + "px" piece.style.opacity = piece.life / 45 piece.life-- if (piece.life <= 0) { piece.remove() pieces.splice(index, 1) } }) } function updateObstacles() { obstacles.forEach((triangle, index) => { let x = parseFloat(triangle.style.left) if (alive && !reloading) { x -= speed triangle.style.left = x + "px" } if (x < -40) { if (alive && !reloading) { score += 1 updateScoreLabel() } triangle.remove() obstacles.splice(index, 1) } }) if (Math.random() < 0.012) { spawnTriangle() } } function updateBackgroundShapes() { const backgroundSpeed = speed * 0.22 backgroundShapes.forEach((shape, index) => { let x = parseFloat(shape.style.left) if (alive && !reloading) { x -= backgroundSpeed shape.style.left = x + "px" } if (x < -40) { shape.remove() backgroundShapes.splice(index, 1) } }) if (alive && !reloading && Math.random() < 0.02) { spawnBackgroundShape() } } function loop() { if (!paused) { updatePlayer() updateBackgroundShapes() updateObstacles() updatePieces() checkCollisions() } requestAnimationFrame(loop) } function togglePause() { paused = !paused game.classList.toggle("is-paused", paused) if (pauseBtn) { pauseBtn.setAttribute("aria-pressed", String(paused)) pauseBtn.setAttribute( "aria-label", paused ? "Resume game" : "Pause game" ) } } function setGameSpeed(nextSpeed, sourceButton) { speed = nextSpeed speedButtons.forEach(btn => { const active = btn === sourceButton btn.classList.toggle("active", active) btn.setAttribute("aria-pressed", String(active)) }) } const scrollKeys = new Set([ "Space", "ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", ]) window.addEventListener( "keydown", e => { if (e.code === "Space") { e.preventDefault() if (!e.repeat) jump() } else if (scrollKeys.has(e.code)) { e.preventDefault() } }, { passive: false } ) window.addEventListener( "keyup", e => { if (e.code === "Space") { e.preventDefault() releaseJump() } else if (scrollKeys.has(e.code)) { e.preventDefault() } }, { passive: false } ) const blockScroll = e => e.preventDefault() window.addEventListener("wheel", blockScroll, { passive: false }) window.addEventListener("touchmove", blockScroll, { passive: false }) game.addEventListener("mousedown", jump) game.addEventListener("touchstart", jump, { passive: true }) window.addEventListener("mouseup", releaseJump) window.addEventListener("touchend", releaseJump, { passive: true }) window.addEventListener("touchcancel", releaseJump, { passive: true }) if (pauseBtn) { pauseBtn.addEventListener("click", e => { e.stopPropagation() togglePause() }) pauseBtn.addEventListener("mousedown", e => e.stopPropagation()) pauseBtn.addEventListener( "touchstart", e => e.stopPropagation(), { passive: true } ) } if (trophyBtn && leaderboardUiEnabled) { trophyBtn.addEventListener("click", e => { e.stopPropagation() toggleLeaderboardPromptPreference() }) trophyBtn.addEventListener("mousedown", e => e.stopPropagation()) trophyBtn.addEventListener( "touchstart", e => e.stopPropagation(), { passive: true } ) } if (leaderboardSubmitBtn && leaderboardUiEnabled) { leaderboardSubmitBtn.addEventListener("click", e => { e.stopPropagation() hideLeaderboardOverlay() }) leaderboardSubmitBtn.addEventListener("mousedown", e => e.stopPropagation()) leaderboardSubmitBtn.addEventListener( "touchstart", e => e.stopPropagation(), { passive: true } ) } speedButtons.forEach(btn => { btn.addEventListener("click", e => { e.stopPropagation() const nextSpeed = Number(btn.dataset.speed) if (!Number.isNaN(nextSpeed)) setGameSpeed(nextSpeed, btn) }) btn.addEventListener("mousedown", e => e.stopPropagation()) btn.addEventListener( "touchstart", e => e.stopPropagation(), { passive: true } ) }) loadPersistedBest() updateScoreLabel() if (!leaderboardUiEnabled) { leaderboardPromptsEnabled = false game.classList.add("leaderboard-prompt-off") if (trophyBtn) trophyBtn.style.display = "none" if (leaderboardOverlay) leaderboardOverlay.style.display = "none" } seedInitialBackgroundShapes() setTimeout(spawnTriangle, 600) loop() })() </script>
Our gaming team develops competitive multiplayer experiences, immersive worlds, and modern gameplay systems built to AAA-inspired standards.
With experience across tournament platforms, open-world systems, side scrollers, and online multiplayer infrastructure, we focus on polished design, responsive gameplay, and high-quality player experiences.
scrollers
open world
multiplayer networks
AI behavior
character models
custom HUDs
physics engines
tournament infrastructure
physics engines
[
3
]
UI / UX
UI / UX
Our UI / UX team designs refined digital experiences built around interaction, identity, and visual precision.
Through modern interface systems, immersive design languages, motion, branding, and scalable component ecosystems, we create premium experiences engineered to feel intuitive & memorable.



Every detail is intentional — from typography, spacing, and animation behavior to full design systems built for consistency across products, platforms, and brands. The result is a cohesive experience that not only looks premium, but performs like it.
interface systems
UX architecture
branding
design languages
motion
prototypes
custom interactions
theme mapping
[
engineered with
]
All product names, logos, and brands are property of their respective owners.