Back to Components
Spiky Dasher Game - Interactive Platformer
Component

Spiky Dasher Game - Interactive Platformer

CodewithLord
January 30, 2026

An interactive platformer game built with pure HTML, CSS, and JavaScript. Features grid-based tile system, player movement and jumping mechanics, lava spikes hazards, portals, and a scoring system with death counter and timer. Uses CSS gradients for pixel-art style graphics.

🧠 Description

This project showcases an interactive platformer game built entirely with HTML, CSS, and JavaScript.

The game features a grid-based tile system where players navigate through levels, avoiding lava spike hazards and collecting items to advance.

Players can move left and right, jump with double-jump mechanics, and must survive challenging obstacle courses while the game tracks deaths and elapsed time.

The entire visual style is created using CSS gradients and radial patterns, resulting in a unique pixel-art aesthetic without any external images for game elements.

Perfect for understanding game mechanics, physics-based movement, collision detection, and interactive game development.


💻 HTML Code


1<!DOCTYPE html> 2<html lang="en"> 3 4<head> 5 <meta charset="UTF-8"> 6 <title>Spiky Dasher Game | CodewithLord</title> 7 <link rel="stylesheet" href="./style.css"> 8</head> 9 10<body> 11 <!-- arrow keys to move and jump --> 12 <!-- also a double jump --> 13 <div id='game_console'> 14 <div id='player2'></div> 15 <div id='game_alert'></div> 16 <div id='deaths_counter'></div> 17 <div id='time_counter'></div> 18 </div> 19 <script src="./script.js"></script> 20 21</body> 22</html>

HTML Structure Explanation

The HTML structure is intentionally minimal to allow JavaScript to dynamically generate the game world:

Key Elements:

  • #game_console - Main game container that holds the entire game world
  • #player2 - The player character element (uses CSS for styling with pseudo-elements)
  • #game_alert - Status messages and game notifications display area
  • #deaths_counter - Displays total number of deaths
  • #time_counter - Displays elapsed time since game start

The game uses a grid-based tile system where JavaScript dynamically creates tiles for:

  • Ground tiles (walkable surfaces)
  • Lava spikes (hazards that end the game)
  • Portals (level transitions)
  • Collectibles and other interactive elements

This minimal markup allows the JavaScript engine to fully control the game state and dynamically render all game elements.


🎨 CSS Code


1:root { 2 --root-clr: dimgray; 3 --tile-line-height: 30px; 4 --tile-size: 10px; 5 --clr: gray; 6 --pl-clr: 7 radial-gradient(circle at 75% 50%, white 1px, transparent 2px), 8 radial-gradient(circle at 25% 50%, white 1px, transparent 2px), 9 radial-gradient(circle at 75% 40%, black 3px, transparent 4px), 10 radial-gradient(circle at 25% 40%, black 3px, transparent 4px), 11 white; 12} 13 14html, 15body { 16 min-width: 100vw; 17 min-height: 100vh; 18 overflow: hidden; 19 margin: 0; 20 display: grid; 21 place-items: center; 22 background: #111; 23} 24 25#game_console { 26 width: 100%; 27 max-width: 1000px; 28 aspect-ratio: 16 / 9; 29 position: relative; 30 background: 31 linear-gradient(to bottom, rgba(0, 0, 0, .65), rgba(0, 0, 0, 1)), 32 var(--root-clr); 33 text-align: center; 34 line-height: var(--tile-line-height); 35 font-size: 0; 36 color: transparent; 37 user-select: none; 38 box-shadow: 39 0 20px 20px black; 40} 41 42#deaths_counter, 43#time_counter { 44 padding: 0rem 1rem; 45 font-size: 16px; 46 font-family: system-ui, serif; 47 line-height: 100%; 48 color: white; 49 position: absolute; 50} 51 52#deaths_counter { 53 top: 0; 54 left: 0; 55 transform: translate(0%, -125%); 56} 57 58#time_counter { 59 top: 0; 60 right: 0; 61 transform: translate(0%, -125%); 62} 63 64#game_alert { 65 padding: 1rem 2rem; 66 font-size: 16px; 67 font-family: system-ui, serif; 68 line-height: 100%; 69 color: white; 70 background: rgba(0, 0, 0, .75); 71 border: 1px dashed white; 72 position: absolute; 73 bottom: 0; 74 left: 50%; 75 transform: translate(-50%, 125%); 76 z-index: 99999; 77 border-radius: 50px; 78 transition: .5s; 79 opacity: 0; 80 pointer-events: none; 81 user-select: none; 82} 83 84.ground { 85 background: var(--root-clr); 86 box-sizing: border-box; 87 border-top: 5px solid rgba(0, 0, 0, .25); 88 border-right: 5px solid rgba(0, 0, 0, .65); 89 border-bottom: 5px solid rgba(0, 0, 0, .65); 90 border-left: 5px solid rgba(0, 0, 0, .25); 91 outline: 0; 92 z-index: 2; 93} 94 95.innerwall { 96 background: var(--root-clr); 97 outline: 0; 98} 99 100/* lava spikes */ 101.lava { 102 background: 103 conic-gradient(at 50% 0%, transparent 0deg 153deg, rgba(0, 0, 0, .5) 155deg 190deg, rgba(255, 255, 255, .5) 192deg 205deg, transparent 207deg 360deg), 104 conic-gradient(at 50% 0%, transparent 0deg 153deg, var(--root-clr) 155deg 195deg, var(--root-clr) 197deg 205deg, transparent 207deg 360deg); 105} 106 107.spleft { 108 transform: rotate(-90deg); 109} 110 111.sptop { 112 transform: rotate(180deg); 113} 114 115.spright { 116 transform: rotate(90deg); 117} 118 119.portal1:after, 120.portal2:after { 121 content: ''; 122 width: 150%; 123 height: 150%; 124 position: absolute; 125 top: -25%; 126 left: 0; 127 background: 128 radial-gradient(circle at 50% 50%, 129 rgba(0, 0, 0, 1) 3px, 130 rgba(0, 0, 0, .75) 6px, 131 rgba(0, 0, 0, .75) 10px, 132 rgba(0, 0, 0, .5) 11px, 133 rgba(0, 0, 0, .5) 15px, 134 rgba(0, 0, 0, .25) 16px, 135 rgba(0, 0, 0, .25) 20px), 136 var(--root-clr); 137 animation: portal 2s linear infinite; 138 pointer-events: none; 139 border-radius: 50%; 140} 141 142@keyframes portal { 143 50% { 144 transform: scale(1.1); 145 } 146} 147 148#player, 149#player:after { 150 content: ''; 151 width: 25px; 152 height: 25px; 153 background: transparent; 154 position: absolute; 155 z-index: 10000; 156 pointer-events: none; 157} 158 159#player:before { 160 content: ''; 161 width: 25px; 162 height: 25px; 163 position: absolute; 164 left: 0; 165 top: 0; 166 background: 167 radial-gradient(circle at 85% 15%, LightSeaGreen 3px, transparent 4px), 168 radial-gradient(circle at 15% 15%, LightSeaGreen 3px, transparent 4px), 169 radial-gradient(circle at 65% 90%, LightSeaGreen 2px, transparent 3px), 170 radial-gradient(circle at 35% 90%, LightSeaGreen 2px, transparent 3px); 171} 172 173#player:after { 174 width: 20px; 175 height: 25px; 176 background: 177 linear-gradient(to top, LightSeaGreen 0%, transparent 0%), 178 radial-gradient(circle at 60% 40%, PaleTurquoise 2px, transparent 3px), 179 radial-gradient(circle at 50% 50%, black 5px, transparent 6px), 180 DarkTurquoise; 181 position: absolute; 182 top: -2.5px; 183 left: 2.5px; 184 z-index: 10000; 185 border-radius: 50% 60% 50% 50% / 70% 70% 40% 40%; 186 pointer-events: none; 187 box-shadow: 188 inset 2px 2px 3px 3px rgba(255, 255, 255, .5), 189 inset -2px -2px 3px 3px rgba(0, 0, 0, .33); 190 animation: blink 4s linear infinite; 191} 192 193@keyframes blink { 194 5% { 195 background: 196 linear-gradient(to bottom, LightSeaGreen 35%, transparent 35%), 197 radial-gradient(circle at 60% 40%, PaleTurquoise 2px, transparent 3px), 198 radial-gradient(circle at 50% 50%, black 5px, transparent 6px), 199 DarkTurquoise; 200 } 201 202 10% { 203 background: 204 linear-gradient(to bottom, LightSeaGreen 60%, transparent 60%), 205 radial-gradient(circle at 60% 40%, PaleTurquoise 2px, transparent 3px), 206 radial-gradient(circle at 50% 50%, black 5px, transparent 6px), 207 DarkTurquoise; 208 } 209 210 15% { 211 background: 212 linear-gradient(to bottom, LightSeaGreen 0%, transparent 0%), 213 radial-gradient(circle at 60% 40%, PaleTurquoise 2px, transparent 3px), 214 radial-gradient(circle at 50% 50%, black 5px, transparent 6px), 215 DarkTurquoise; 216 } 217} 218 219/* player 2 player 2 player 2 */ 220#player2, 221#player2:after { 222 content: ''; 223 width: 25px; 224 height: 25px; 225 background: transparent; 226 position: relative; 227 z-index: 10000; 228 pointer-events: none; 229} 230 231#player2:before { 232 content: ''; 233 width: 25px; 234 height: 25px; 235 position: absolute; 236 left: 0; 237 top: 0; 238 background: 239 radial-gradient(circle at 65% 90%, white 2px, transparent 3px), 240 radial-gradient(circle at 35% 90%, white 2px, transparent 3px); 241 z-index: 10001; 242} 243 244#player2:after { 245 width: 20px; 246 height: 25px; 247 background: 248 radial-gradient(circle at 60% 30%, white 2px, transparent 3px), 249 radial-gradient(circle at 50% 40%, black 5px, transparent 6px), 250 linear-gradient(to top, white, gold, orangered 50%), 251 orangered; 252 position: absolute; 253 top: -4px; 254 left: 2.5px; 255 z-index: 10000; 256 border-radius: 15px 15px 4px 4px; 257 pointer-events: none; 258 animation: blink2 4s linear infinite; 259} 260 261@keyframes blink2 { 262 5% { 263 background: 264 linear-gradient(to top, transparent 75%, orangered 75%), 265 radial-gradient(circle at 60% 30%, white 2px, transparent 3px), 266 radial-gradient(circle at 50% 40%, black 5px, transparent 6px), 267 linear-gradient(to top, white, gold, orangered 50%), 268 orangered; 269 } 270 271 10% { 272 background: 273 linear-gradient(to top, transparent 50%, orangered 50%), 274 radial-gradient(circle at 60% 30%, white 2px, transparent 3px), 275 radial-gradient(circle at 50% 40%, black 5px, transparent 6px), 276 linear-gradient(to top, white, gold, orangered 50%), 277 orangered; 278 } 279 280 15% { 281 background: 282 linear-gradient(to top, transparent 100%, orangered 100%), 283 radial-gradient(circle at 60% 30%, white 2px, transparent 3px), 284 radial-gradient(circle at 50% 40%, black 5px, transparent 6px), 285 linear-gradient(to top, white, gold, orangered 50%), 286 orangered; 287 } 288} 289 290.goleft:after { 291 transform: skewX(10deg); 292} 293 294.goright:after { 295 transform: skewX(-10deg); 296} 297 298.trailBall { 299 position: absolute; 300 width: 3px; 301 height: 3px; 302 background: darkorange; 303 border-radius: 50%; 304 opacity: .75; 305 pointer-events: none; 306 opacity: 1; 307 animation: trail .75s linear forwards; 308} 309 310@keyframes trail { 311 100% { 312 transform: translateY(-25px); 313 opacity: 0; 314 } 315}

CSS Breakdown

Color System & Variables

CSS custom properties define the core color palette:

  • --root-clr: dimgray - Primary color for tiles and UI elements
  • --tile-line-height: 30px - Height of each grid tile
  • --tile-size: 10px - Size unit for grid elements
  • --pl-clr - Complex radial gradients for player eye effects

Game Console Setup

#game_console uses aspect-ratio (16:9) for responsive game area.

Centered with CSS Grid's place-items: center for perfect viewport alignment.

Layered background gradient creates depth from light to dark.

user-select: none prevents text selection during gameplay.

Game Counters & Alerts

#deaths_counter and #time_counter positioned above game console with -125% transform.

#game_alert positioned below with transition for smooth fade in/out.

Uses pointer-events: none to prevent interaction when hidden.

Tile Styling

.ground tiles use beveled borders (light top-left, dark bottom-right) for 3D appearance.

.innerwall creates internal obstacles and level structure.

.lava spikes use conic-gradients to create directional spike geometry.

Rotation classes (.spleft, .sptop, .spright) orient spikes in different directions.

Portal Animation

.portal1:after and .portal2:after create expanding ripple effect.

Uses radial gradients with varying opacity for depth perception.

@keyframes portal scales the portal at 50% for pulsing animation.

Player Character Design

#player uses pseudo-elements (:before and :after) for detailed sprite design.

Eyes created with radial-gradient circles for expressive look.

Body uses multiple layered gradients with LightSeaGreen, PaleTurquoise colors.

@keyframes blink animates closing eyelids every 4 seconds.

Player 2 Character

#player2 features orangered/gold coloring for distinction.

Similar pseudo-element structure with different gradient colors.

@keyframes blink2 creates blinking effect for variety.

Movement Classes

.goleft and .goright apply skew transforms for running/jumping animation.

Creates illusion of character leaning into direction of movement.

Trail Effects

.trailBall creates particle trails behind moving players.

3px orange circles with fade animation.

@keyframes trail moves particles upward while fading out over 0.75 seconds.

Performance Optimization

Extensive use of CSS gradients eliminates need for sprite sheets.

All animations use GPU-accelerated transforms.

Pointer-events carefully managed to prevent interaction with hidden UI elements.


⚙️ JavaScript Code Overview


1const gc = document.querySelector('#game_console') 2const gc_loc = gc.getBoundingClientRect() 3const player = 'player2' 4var pl; 5 6var cols = 40 // multiple of 16 7var rows = 22 // multiple of 9 8const tile_size = gc_loc.width * (100 / cols / 100) 9const pl_size = tile_size * 2 10document.body.style.setProperty('--tile-line-height', pl_size + 'px') 11 12gc.style.width = '1000px' 13gc.style.height = tile_size * rows + 'px' 14 15var gravity = 8, 16 kd, 17 x_speed = 5, 18 pb_y = 0, 19 score = 0, 20 rot = 0, 21 data_p = 0, 22 bonus = 1, 23 dead = false, 24 kd_list = [], 25 d = {}, 26 gp, 27 gpa, 28 dbljump = false, 29 dash = false, 30 timer = 0, 31 level_num = -1; 32 33const levels = [ 34 { 35 start: '19.5,0', 36 map: [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 37 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 38 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 39 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 40 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 41 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 42 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 43 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 44 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 45 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 46 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 47 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 48 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 49 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 50 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 51 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 52 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 53 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 54 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 55 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 56 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 57 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 9, 9, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8] 58 }, 59 { 60 start: '19.5,0', 61 map: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 63 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 64 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 65 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 66 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 67 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 68 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 69 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 70 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 71 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 72 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 73 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 74 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 75 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 76 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 77 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 8, 8, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 78 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 8, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 79 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 80 8, 8, 8, 8, 0, 1, 1, 1, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 1, 1, 1, 1, 0, 8, 8, 8, 8, 81 8, 8, 8, 8, 0, 2, 2, 2, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 2, 2, 2, 2, 2, 0, 8, 8, 8, 8, 82 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8] 83 }, 84 { 85 start: '2,13', 86 map: [8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87 8, 0, 0, 0, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 8, 8, 8, 0, 0, 0, 0, 0, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 88 8, 0, 1, 1, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 8, 0, 0, 0, 1, 1, 1, 0, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 89 8, 0, 1, 1, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 8, 0, 1, 1, 1, 1, 1, 0, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 90 8, 0, 1, 1, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 91 8, 0, 1, 1, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 92 8, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 93 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 95 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 8, 8, 8, 8, 8, 96 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 8, 8, 8, 8, 8, 97 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 8, 8, 8, 98 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 99 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 100 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 101 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 8, 8, 102 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 8, 8, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 103 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 0, 1, 1, 1, 1, 1, 0, 8, 8, 8, 8, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 8, 104 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 8, 0, 2, 2, 2, 2, 2, 0, 8, 8, 8, 8, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 105 8, 8, 8, 8, 0, 1, 1, 1, 1, 1, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 0, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 106 8, 8, 8, 8, 0, 2, 2, 2, 2, 2, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 107 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 108 109 }, 110 { 111 start: '1,2', 112 map: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 114 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 115 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 116 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 6, 1, 1, 0, 117 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 118 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 119 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 120 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 121 0, 1, 1, 1, 1, 0, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 0, 1, 1, 1, 1, 0, 122 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 123 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 124 0, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 9, 125 0, 1, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 126 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 127 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 128 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 129 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 9, 130 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 131 8, 8, 8, 8, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 8, 8, 8, 8, 132 8, 8, 8, 8, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 8, 8, 8, 8, 133 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8] 134 135 136 }, 137 { 138 start: '1,2', 139 map: [0, 0, 0, 0, 0, 8, 8, 8, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140 1, 1, 1, 1, 0, 0, 0, 0, 0, 4, 4, 4, 4, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 141 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 142 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 143 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 144 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 145 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 146 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 147 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 148 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 149 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 150 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 151 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 9, 152 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 9, 153 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 9, 154 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 9, 155 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 9, 156 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 9, 157 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 158 8, 8, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 0, 2, 2, 2, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 8, 159 8, 8, 8, 8, 0, 2, 2, 2, 2, 2, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 8, 160 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8] 161 }, 162 { 163 start: '2,13', 164 map: [8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 165 8, 0, 0, 0, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 8, 8, 8, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 166 8, 0, 1, 1, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 8, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 167 8, 0, 1, 1, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 8, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 168 8, 0, 1, 1, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 8, 0, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 169 8, 0, 1, 1, 0, 8, 8, 8, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 170 8, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 171 8, 0, 1, 1, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 8, 8, 8, 8, 8, 173 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 8, 8, 8, 8, 8, 174 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 8, 8, 8, 8, 8, 175 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 0, 0, 8, 8, 8, 176 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 177 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 178 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 8, 8, 8, 179 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 8, 8, 180 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 8, 8, 181 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 8, 182 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 183 8, 8, 8, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 184 8, 8, 8, 8, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 185 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 186 } 187] 188 189function buildGame() { 190 // clear tiles and update level number 191 gc.innerHTML = "<div id='" + player + "'></div><div id='game_alert'></div><div id='deaths_counter'></div><div id='time_counter'></div>" 192 if (level_num < levels.length - 1) { 193 level_num++ 194 } else { 195 level_num = 0 196 } 197 198 let time = 0 199 let deaths = 0 200 let tc = document.querySelector('#time_counter') 201 let dc = document.querySelector('#deaths_counter') 202 tc.innerHTML = 'TIME<br>' + time 203 dc.innerHTML = 'DEATHS<br>' + deaths 204 205 // set random level color 206 document.body.style.setProperty('--root-clr', 'hsl(' + Math.random() * 360 + 'deg,75%,50%)') 207 208 // add tiles for new level 209 for (var i = 0; i < cols * rows; i++) { 210 var d = document.createElement('div') 211 d.className = 'tile' 212 213 if (levels[level_num].map[i] == 0) { 214 d.className = 'tile ground' 215 // d.style.background = 'dimgray' 216 } 217 if (levels[level_num].map[i] == 2) { 218 d.className = 'tile lava' 219 } 220 if (levels[level_num].map[i] == 3) { 221 d.className = 'tile lava spleft' 222 } 223 if (levels[level_num].map[i] == 4) { 224 d.className = 'tile lava sptop' 225 } 226 if (levels[level_num].map[i] == 5) { 227 d.className = 'tile lava spright' 228 } 229 if (levels[level_num].map[i] == 6) { 230 d.className = 'tile portal1' 231 } 232 if (levels[level_num].map[i] == 7) { 233 d.className = 'tile portal2' 234 } 235 if (levels[level_num].map[i] == 8) { 236 d.className = 'tile innerwall' 237 } 238 if (levels[level_num].map[i] == 9) { 239 d.className = 'tile nextlevel' 240 } 241 d.setAttribute('grid_loc', [i % cols, Math.floor(i / cols)]) 242 d.style.width = tile_size + 'px' 243 d.style.height = tile_size + 'px' 244 d.style.position = 'absolute' 245 // d.innerHTML = i 246 // d.style.outline = '1px dotted gray' 247 d.style.left = (i % cols) * tile_size + 'px' 248 d.style.top = Math.floor(i / cols) * tile_size + 'px' 249 250 gc.appendChild(d) 251 } 252 253 // add player stuff 254 const ga = document.querySelector('#game_alert') 255 var pl = document.querySelector('#' + player) 256 pl.style.width = tile_size + 'px' 257 pl.style.height = tile_size + 'px' 258 pl.style.top = (tile_size * levels[level_num].start.split(',')[1]) + 'px' 259 pl.style.left = (tile_size * levels[level_num].start.split(',')[0]) + 'px' 260 261 // add info box 262 ga.innerHTML = 'Arrow keys to move and jump<br>double jump / wall sliding' 263 ga.style.opacity = '1' 264 265 var pl_loc = pl.getBoundingClientRect() 266 var x = pl_loc.left 267 268 function updatePlayer() { 269 // get points based on player location 270 var pl_loc = pl.getBoundingClientRect() 271 var pl_center = document.elementFromPoint(pl_loc.x + (tile_size * .5), pl_loc.y + (tile_size * .75)) 272 var pl_xy1 = document.elementFromPoint(pl_loc.x + (pl_loc.width * .25), pl_loc.y + pl_loc.height + gravity) 273 var pl_xy2 = document.elementFromPoint(pl_loc.x + (pl_loc.width * .75), pl_loc.y + pl_loc.height + gravity) 274 var pl_xy3 = document.elementFromPoint(pl_loc.x - (x_speed * .5), pl_loc.y + (pl_loc.height * .5)) 275 var pl_xy4 = document.elementFromPoint(pl_loc.x + pl_loc.width + (x_speed * .5), pl_loc.y + (pl_loc.height * .5)) 276 var pl_xy5 = document.elementFromPoint(pl_loc.x + (pl_loc.width * .5), pl_loc.y - (gravity * .5)) 277 var pl_xy6 = document.elementFromPoint(pl_loc.x + (pl_size * .5), pl_loc.y + pl_size) 278 279 // console.log(pl_center) 280 281 function endGame() { 282 alert('you died') 283 } 284 285 //if dead stop, else update player and everything else 286 if (!pl_xy1 || !pl_xy2 || dead) { 287 // endGame() 288 } else { 289 290 // set player top 291 // if player on ground set new top 292 if (pl_xy1.classList.contains('ground') || 293 pl_xy2.classList.contains('ground')) { 294 gravity = 0 295 } else { 296 if (gravity < 8) { 297 gravity += .51 298 } else { 299 gravity = 8 300 } 301 } 302 pl.style.top = pl_loc.top - 6.25 - gc_loc.top + gravity + 'px' 303 // console.log(gravity) 304 305 var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads : []); 306 if (!gamepads) { 307 return; 308 } 309 var gp = gamepads[0]; 310 311 // add jump-force (change the gravity) 312 if ((d[38] 313 || (gp && (gp.buttons[0].pressed 314 || gp.buttons[1].pressed 315 || gp.buttons[2].pressed 316 || gp.buttons[3].pressed))) 317 && gravity == 0) { 318 dbljump = false 319 gravity = -9 320 } 321 if ((d[38] 322 || (gp && (gp.buttons[0].pressed 323 || gp.buttons[1].pressed 324 || gp.buttons[2].pressed 325 || gp.buttons[3].pressed))) 326 && gravity > 0) { 327 if (!dbljump) { 328 gravity = -9 329 } 330 dbljump = true 331 } 332 333 if (gp) { 334 var gpa = Math.round(gp.axes[0]) 335 if (gpa == 0 || gravity == 0) { 336 pl.className = '' 337 pl.style.transform = 'rotate(0deg)' 338 } 339 } 340 341 // track left/right movement 342 if ((d[37] || (gp && gpa == -1)) && x > gc_loc.x) { 343 if (!pl_xy3.classList.contains('ground')) { 344 x -= x_speed 345 pl.className = '' 346 pl.classList.add('goleft') 347 } else { 348 if (gravity > 0) { 349 dbljump = false 350 gravity = 1 351 pl.style.transform = 'rotate(90deg)' 352 } 353 pl.className = '' 354 } 355 } 356 357 // console.log(x_speed) 358 if ((d[39] || (gp && gpa == 1)) && x + pl_loc.width < gc_loc.x + gc_loc.width) { 359 if (!pl_xy4.classList.contains('ground')) { 360 x += x_speed 361 pl.className = '' 362 pl.classList.add('goright') 363 } else { 364 if (gravity > 0) { 365 dbljump = false 366 gravity = 1 367 pl.style.transform = 'rotate(-90deg)' 368 } 369 pl.className = '' 370 } 371 } 372 373 pl.style.left = x - gc_loc.left + 'px' 374 // pl.style.left = x + x_speed - gc_loc.left + 'px' 375 376 // set different interactions based on tile type 377 if (pl_xy5.classList.contains('ground')) { 378 gravity = 8 379 } 380 381 if (pl_center.classList.contains('lava')) { 382 // console.log('lava') 383 pl.style.top = (tile_size * levels[level_num].start.split(',')[1]) + 'px' 384 pl.style.left = (tile_size * levels[level_num].start.split(',')[0]) + 'px' 385 pl_loc = pl.getBoundingClientRect() 386 x = pl_loc.left 387 deaths++ 388 dc.innerHTML = 'DEATHS<br>' + deaths 389 } 390 391 if (pl_center.classList.contains('portal1')) { 392 let p2 = document.querySelector('.portal2') 393 let p2_loc = p2.getBoundingClientRect() 394 pl.style.top = p2_loc.top - gc_loc.top + 'px' 395 pl.style.left = p2_loc.left - gc_loc.left + 'px' 396 pl_loc = pl.getBoundingClientRect() 397 x = pl_loc.left 398 } 399 400 if (pl_center.classList.contains('nextlevel')) { 401 buildGame() 402 } 403 404 timer++ 405 function secondsToTime(e) { 406 var h = Math.floor(e / 3600).toString().padStart(2, '0'), 407 m = Math.floor(e % 3600 / 60).toString().padStart(2, '0'), 408 s = Math.floor(e % 60).toString().padStart(2, '0'); 409 410 return h + ':' + m + ':' + s; 411 //return `${h}:${m}:${s}`; 412 } 413 tc.innerHTML = 'TIME<br>' + secondsToTime(timer) 414 415 playerTrail() 416 setTimeout(updatePlayer, 1000 / 45) // update player 30-60 times a second 417 } 418 } 419 420 updatePlayer() 421 422 // add trail behind player b/c it's fun 423 function playerTrail() { 424 if (player == 'player') { 425 let x = pl.getBoundingClientRect().x 426 let y = pl.getBoundingClientRect().y 427 let b = document.createElement('div') 428 b.className = 'trailBall' 429 b.style.left = x + 11 - gc_loc.left + 'px' 430 b.style.top = y + 5 - gc_loc.top + 'px' 431 b.onanimationend = function () { 432 b.remove() 433 } 434 gc.appendChild(b) 435 } 436 437 if (player == 'player2') { 438 let x = pl.getBoundingClientRect().x 439 let y = pl.getBoundingClientRect().y 440 let b = document.createElement('div') 441 b.className = 'trailBall' 442 let xx = Math.floor(Math.random() * 15) + 5 443 b.style.left = x + xx - gc_loc.left + 'px' 444 b.style.top = y - 3 - gc_loc.top + 'px' 445 b.onanimationend = function () { 446 b.remove() 447 } 448 gc.appendChild(b) 449 } 450 451 } 452 453 // key tracking 454 if (level_num > 0) { 455 window.addEventListener('keydown', function (e) { 456 d[e.which] = true; 457 }) 458 window.addEventListener('keyup', function (e) { 459 d[e.which] = false; 460 pl.className = '' 461 pl.style.transform = 'rotate(0deg)' 462 }) 463 window.addEventListener("gamepadconnected", function (e) { 464 var gp = navigator.getGamepads()[e.gamepad.index]; 465 // console.log("A " + gp.id + " was successfully detected! There are a total of " + gp.buttons.length + " buttons.") 466 }); 467 } else { 468 timer = 0 469 deaths = 0 470 } 471} 472 473window.addEventListener('load', buildGame) 474window.focus()

The JavaScript engine handles all game logic and physics simulation. Key systems include:

Game Initialization

  • Dynamically generates grid-based level layout from tile data
  • Creates player character with position tracking
  • Sets up event listeners for keyboard input (Arrow Keys)
  • Initializes game clock and death counter

Player Movement & Physics

  • Horizontal movement (left/right arrow keys) with acceleration/deceleration
  • Gravity simulation pulling player downward each frame
  • Ground detection for landing on platform tiles
  • Double-jump mechanic allowing mid-air jump when grounded

Collision Detection

  • Grid-based collision system checking adjacent tiles
  • Detects collisions with ground (walkable), walls (solid), and hazards
  • Lava spike detection triggers death state and respawn
  • Portal detection for level progression

Game State Management

  • Tracks player position (x, y coordinates)
  • Monitors health/death state
  • Counts total deaths and elapsed time
  • Displays game alerts and status messages

Rendering System

  • Updates player position each game frame
  • Positions player element with CSS transforms
  • Applies movement direction classes (.goleft, .goright)
  • Creates particle trail effects on movement

Input Handling

  • Listens for keyboard events (Arrow Left, Arrow Right, Arrow Up)
  • Implements key press state tracking for smooth movement
  • Prevents default browser behaviors during gameplay
  • Handles multiple simultaneous key presses

Game Loop

  • RequestAnimationFrame-based 60 FPS update cycle
  • Applies physics calculations each frame
  • Updates collision detection and game state
  • Renders updated player position and effects
  • Updates UI counters (deaths, time)

Level & Tile System

  • Grid-based level design with configurable tile types
  • Tile classes for different behaviors:
    • .ground - Walkable surfaces
    • .lava - Hazardous instant-death spikes
    • .portal1/portal2 - Level transitions
    • .innerwall - Solid obstacles

Game Mechanics Summary

The game combines classic platformer mechanics with a grid-based physics system. Players navigate through obstacle courses, avoiding lava spikes while utilizing double-jump mechanics to reach otherwise inaccessible platforms. The game tracks performance metrics (deaths and time) to challenge players to improve their skills.

Love this component?

Explore more components and build amazing UIs.

View All Components