Snake Dev Sandbox - Bot & Macro Guide

Beginner's Tutorial: Writing Your First Bot

Welcome to bot scripting! The game runs in a continuous loop. Every "tick" (frame), the game engine asks your bot code: "Which direction should I move next?"

To answer that, your bot needs to look at the board. You are provided two powerful tools: state and utils.

Step 1: Find the Snake and the Food

The state object holds everything on the board. The snake is an array of segments, and the head is always the first segment in the list (index 0).

  • const head = state.snake[0]; // Gets the {x, y} coordinates of the head.
  • const food = state.foods[0]; // Gets the {x, y} coordinates of the first apple.

Step 2: Decide Which Way to Go

Compare the X (horizontal) and Y (vertical) coordinates. If the food's X is greater than the head's X, the food is to the right.

if (food.x > head.x) { return 'RIGHT'; }
if (food.x < head.x) { return 'LEFT'; }
if (food.y > head.y) { return 'DOWN'; }
if (food.y < head.y) { return 'UP'; }

Step 3: Don't Crash!

The code above is the absolute most basic bot possible, but it is dumb. It will immediately crash into walls and its own tail! To make it smart, use the utils.isWalkable(x, y, state) function to check if a tile is safe before you move into it.

// Example: Check if moving RIGHT is safe before doing it
if (food.x > head.x && utils.isWalkable(head.x + 1, head.y, state)) {
  return 'RIGHT';
}

Bot Scripting API Reference

Your script evaluates every single tick. You must return a direction string ('UP', 'DOWN', 'LEFT', 'RIGHT') or null to do nothing.

The state Object Structure:

{
  "status": "RUNNING", // IDLE, PAUSED, GAME_OVER
  "tickCount": 125,
  "score": 50,
  "currentTickRate": 120, // ms per tick
  "snake": [
    { "x": 10, "y": 15 }, // Head is always index 0
    { "x": 10, "y": 14 }  // Tail segments...
  ],
  "direction": { "x": 0, "y": 1 }, // Current moving direction vector
  "foods": [
    { "x": 5, "y": 8, "type": "NORMAL", "spawnTick": 100 }
  ],
  "obstacles": [
    { "x": 2, "y": 2 }
  ]
}

The utils Object (Helper Functions for Bots):

utils.distance(a, b); // Returns Manhattan distance between two {x,y} points
utils.isWalkable(x, y, state); // Returns true if cell is safe (no wall/tail/rock)

Global Developer Console (F12)

The entire engine is exposed globally as window.SNAKE_DEV. You can write your own custom scripts in the browser console.

SNAKE_DEV.engine.getState(); // Get current snapshot
SNAKE_DEV.engine.setDirection('UP'); // Force a move
SNAKE_DEV.engine.pause(); // Programmatically pause

// Listen to internal game events:
SNAKE_DEV.engine.on('eat', (data) => console.log('Ate food:', data));
SNAKE_DEV.engine.on('collision', (data) => console.log('Crashed:', data));

Advanced Example: The "Genius" Bot

This is a highly advanced bot that uses Breadth-First Search to find perfect paths, Flood-Fill to avoid dead ends, and Future Sight to chase its own tail and stall indefinitely when trapped! Copy and paste this into the Bot Code box.

// ====== SNAKE DEV GENIUS BOT (Future Sight) ======
// 1. Pathfinds using Breadth-First Search
// 2. Looks into the future: Treats its own tail tip as walkable because it knows it will move!
// 3. Fallback: If it's trapped and food is unreachable, it chases its own tail to stall indefinitely.
const head = state.snake[0];
const tail = state.snake[state.snake.length - 1];

const DIRS = [
  { name: 'UP', dx: 0, dy: -1 }, { name: 'DOWN', dx: 0, dy: 1 },
  { name: 'LEFT', dx: -1, dy: 0 }, { name: 'RIGHT', dx: 1, dy: 0 }
];

function getCoords(x, y) {
  if (state.config.wrapWalls) {
    x = (x + state.config.gridWidth) % state.config.gridWidth;
    y = (y + state.config.gridHeight) % state.config.gridHeight;
  }
  return { x, y };
}

function getSafetyScore(startX, startY) {
  const visited = new Set([`${startX},${startY}`]);
  const queue = [{ x: startX, y: startY }];
  let count = 0;
  const maxSearch = state.snake.length * 2;
  
  while (queue.length > 0 && count < maxSearch) {
    const curr = queue.shift();
    count++;
    for (const d of DIRS) {
      const { x: cx, y: cy } = getCoords(curr.x + d.dx, curr.y + d.dy);
      const key = `${cx},${cy}`;
      // FUTURE SIGHT: The tail is treated as walkable empty space in deep simulation!
      const isTail = (cx === tail.x && cy === tail.y); 
      if (!visited.has(key) && (utils.isWalkable(cx, cy, state) || isTail)) {
        visited.add(key); queue.push({ x: cx, y: cy });
      }
    }
  }
  return count;
}

function getPathToTarget(tx, ty) {
  const visited = new Set([`${head.x},${head.y}`]);
  const queue = [];
  
  for (const d of DIRS) {
    const { x: cx, y: cy } = getCoords(head.x + d.dx, head.y + d.dy);
    // Even the first step could be our tail retreating!
    const isFirstStepTail = (cx === tx && cy === ty && cx === tail.x && cy === tail.y);
    if (utils.isWalkable(cx, cy, state) || isFirstStepTail) {
      visited.add(`${cx},${cy}`); queue.push({ x: cx, y: cy, firstMove: d.name, dist: 1 });
    }
  }
  
  while(queue.length > 0) {
    const curr = queue.shift();
    if (curr.x === tx && curr.y === ty) return curr.firstMove;
    if (curr.dist > 150) continue; // safety limit
    
    for (const d of DIRS) {
      const { x: cx, y: cy } = getCoords(curr.x + d.dx, curr.y + d.dy);
      const key = `${cx},${cy}`;
      const isTargetTail = (cx === tx && cy === ty && cx === tail.x && cy === tail.y);
      if (!visited.has(key) && (utils.isWalkable(cx, cy, state) || isTargetTail)) {
        visited.add(key); queue.push({ x: cx, y: cy, firstMove: curr.firstMove, dist: curr.dist + 1 });
      }
    }
  }
  return null;
}

// 1. Prioritize Targets
let bestFood = null, minScore = Infinity;
for (const f of state.foods) {
  if (f.type === 'POISON') continue;
  const dist = utils.distance(head, f);
  const score = f.type === 'GOLDEN' ? dist - 30 : dist; // aggressively hunt gold
  if (score < minScore) { minScore = score; bestFood = f; }
}

let foodMove = bestFood ? getPathToTarget(bestFood.x, bestFood.y) : null;
let tailMove = getPathToTarget(tail.x, tail.y); // Safe fallback target

// 2. Eval safety of adjacent cells
let safeMoves = [];
for (const d of DIRS) {
  const { x: cx, y: cy } = getCoords(head.x + d.dx, head.y + d.dy);
  if (utils.isWalkable(cx, cy, state)) {
    safeMoves.push({ name: d.name, safety: getSafetyScore(cx, cy) });
  }
}

if (safeMoves.length === 0) return null;
safeMoves.sort((a, b) => b.safety - a.safety);

// 3. Make decision
let finalMove = safeMoves[0].name; // default to safest open area
const requiredSpace = state.snake.length;

if (foodMove) {
  const fd = safeMoves.find(m => m.name === foodMove);
  // Eat if the path opens up to enough space OR if it safely loops us back to our own tail!
  if (fd && (fd.safety >= requiredSpace || foodMove === tailMove)) return foodMove;
}

// If food path is deadly, chase our own tail to survive infinitely!
if (tailMove) {
  const td = safeMoves.find(m => m.name === tailMove);
  if (td && td.safety >= 5) return tailMove;
}

return finalMove;

Snake Dev Sandbox

Score: 0 | Length: 3 | Ticks: 0 | Speed: 120ms | Status: IDLE
Engine Modifiers & Settings (TONS OF SETTINGS)
Physics, Rules & Geometry









Snake Mechanics







Board Spawners & Lifetimes

















Chaos and Fun









Audio & Sound Effects

Visual Colors (Hex) & UI





Bot Script Injection
JavaScript Bot Logic

Write logic that returns 'UP', 'DOWN', 'LEFT', or 'RIGHT'.
Available variables: state, utils. Need help? Click [ API & Bot Guide ] in top right!


Custom Mods & Setup
JavaScript Mod Injection

Inject arbitrary code into the global console context. Overwrite SNAKE_DEV.engine functions or add events here!


Config Import/Export