robux clicker

This sketch creates an interactive Robux clicker game inspired by Roblox's premium currency system. Players click a glowing Robux-style symbol to earn currency, and can toggle an auto-clicker that generates income passively every second.

🧪 Try This!

Experiment with the code by making these changes:

  1. Increase robux per click — Manual clicking earns more robux per tap, making the game feel more rewarding instantly.
  2. Speed up auto-clicker — Auto-clicker fires more times per second, accumulating robux much faster when enabled.
  3. Make the main button twice as big
  4. Change button glow color to purple — The outer glow effect around the main button shifts from green to purple, creating a different visual mood.
  5. Auto-click with every frame instead of every second — Auto-clicking happens 60 times per second instead of once per second—robux grows extremely fast!
Prefer the full editor? Open it there →

📖 About This Sketch

This sketch recreates the satisfying 'click to earn' mechanics of an idle/clicker game inspired by Roblox's Robux currency. The main interactive element is a large glowing green diamond with a cutout (mimicking the Robux logo) that responds to clicks and hover effects. The sketch combines interactive button detection, time-based automation, and visual feedback through color and scaling—core techniques for building games in p5.js.

The code is organized around three core behaviors: manual clicking that increments the robux counter, an auto-clicker system that adds income every second, and responsive UI elements that change appearance based on mouse position. By studying this sketch, you will learn how to detect mouse clicks on circular and rectangular regions, manage time-based events with millis(), combine manual and automated game mechanics, and create polished visual feedback with push/pop transforms and hover scaling.

⚙️ How It Works

  1. When the sketch loads, setup() creates a full-window canvas and centers all text alignment for cleaner positioning.
  2. Every frame, draw() first updates the robux counter if auto-clicking is enabled by checking if one second has passed since the last auto-click using millis() timestamps.
  3. The main Robux button (a large green circle at the center) is drawn with a custom drawRobuxSymbol() function that creates a rotated diamond shape with an off-center cutout and highlight, scaled up slightly when the mouse hovers over it using the dist() function.
  4. An auto-clicker toggle button at the bottom changes color based on hover state and displays whether auto-clicking is ON or OFF along with the clicks-per-second rate.
  5. When the user clicks the mouse, mousePressed() checks two collision zones: if the click hits the main button, robux increases by perClick; if it hits the auto button, autoEnabled toggles and the timer resets.
  6. Finally, windowResized() keeps the canvas full-screen and responsive by recalculating all button and button positions on every window resize.

🎓 Concepts You'll Learn

Mouse collision detection (circular and rectangular)Time-based game mechanics (millis() and timestamp tracking)Interactive button state managementTransform and scale effects (push/pop, translate, scale, rotate)Responsive UI with hover statesCustom shape drawing functions

📝 Code Breakdown

setup()

setup() runs once at the start. We use it to create the canvas and configure text alignment so our UI labels are perfectly centered.

function setup() {
  createCanvas(windowWidth, windowHeight);
  textAlign(CENTER, CENTER);
}
Line-by-line explanation (2 lines)
createCanvas(windowWidth, windowHeight);
Creates a canvas that fills the entire browser window, making the game responsive to any screen size
textAlign(CENTER, CENTER);
Sets all future text to be centered both horizontally and vertically around its coordinates, simplifying text positioning throughout the sketch

draw()

draw() runs 60 times per second and is where all animation, updates, and rendering happen. This sketch uses draw() to check time-based conditions (auto-clicker), calculate hover states (distance and rectangle containment), and redraw the entire UI every frame.

🔬 This block fires an auto-click every 1000 milliseconds (one second). What happens if you change 1000 to 500 or 100? How much faster does robux grow?

  if (autoEnabled) {
    const now = millis();
    if (now - lastAutoTime >= 1000) {
      robux += perClick * autoPerSecond;
      lastAutoTime = now;
    }
  }

🔬 These fill() calls change the auto button's color based on state. Try swapping the RGB values—for example, change (46, 204, 113) to (113, 46, 204). What new color do you see when auto is ON?

  noStroke();
  if (autoEnabled) {
    fill(46, 204, 113);
  } else if (hoverAuto) {
    fill(80);
  } else {
    fill(50);
  }
function draw() {
  background(15);

  // --- Auto-clicker logic ---
  if (autoEnabled) {
    const now = millis();
    if (now - lastAutoTime >= 1000) {
      robux += perClick * autoPerSecond;
      lastAutoTime = now;
    }
  }

  // --- Layout values ---
  const mainRadius = min(width, height) * 0.18;
  const mainX = width / 2;
  const mainY = height / 2;

  const autoBtnW = 240;
  const autoBtnH = 60;
  const autoBtnX = width / 2 - autoBtnW / 2;
  const autoBtnY = height - autoBtnH - 40;

  // --- Top text: Robux counter ---
  fill(255);
  textSize(32);
  text("Robux: " + floor(robux), width / 2, 50);

  // --- Main Robux-style button ---
  const d = dist(mouseX, mouseY, mainX, mainY);
  const hoverMain = d < mainRadius;

  push();
  translate(mainX, mainY);
  const scaleHover = hoverMain ? 1.08 : 1;
  scale(scaleHover);

  noStroke();
  // outer glow
  fill(0, 200, 120, 80);
  ellipse(0, 0, mainRadius * 2.6, mainRadius * 2.6);
  // main circle
  fill(34, 177, 76);
  ellipse(0, 0, mainRadius * 2.1, mainRadius * 2.1);

  // draw a Robux-inspired symbol
  drawRobuxSymbol(0, 0, mainRadius * 1.25);

  pop();

  // "Click!" label under main button
  fill(220);
  textSize(20);
  text("Click the Robux-style symbol!", width / 2, mainY + mainRadius * 1.5);

  // --- Auto-clicker toggle button ---
  const hoverAuto =
    mouseX > autoBtnX &&
    mouseX < autoBtnX + autoBtnW &&
    mouseY > autoBtnY &&
    mouseY < autoBtnY + autoBtnH;

  noStroke();
  if (autoEnabled) {
    fill(46, 204, 113);
  } else if (hoverAuto) {
    fill(80);
  } else {
    fill(50);
  }
  rect(autoBtnX, autoBtnY, autoBtnW, autoBtnH, 10);

  fill(255);
  textSize(18);
  const autoLabel = autoEnabled ? "Auto: ON (" + autoPerSecond + "/s)" : "Auto: OFF";
  text(autoLabel, width / 2, autoBtnY + autoBtnH / 2);

  // --- Small hint text ---
  fill(160);
  textSize(14);
  text(
    "This is a mini clicker game. It only clicks inside this canvas, not on other apps.",
    width / 2,
    height - 12
  );
}
Line-by-line explanation (18 lines)

🔧 Subcomponents:

conditional Auto-clicker Timer Logic if (now - lastAutoTime >= 1000) {

Checks if at least one second has elapsed since the last auto-click and increments robux if true

calculation Main Button Hover Detection const d = dist(mouseX, mouseY, mainX, mainY);

Uses dist() to calculate the distance from the mouse to the center of the main button

conditional Auto Button Hover Detection const hoverAuto = mouseX > autoBtnX && mouseX < autoBtnX + autoBtnW && mouseY > autoBtnY && mouseY < autoBtnY + autoBtnH;

Tests if the mouse is inside the rectangular bounds of the auto-clicker button

conditional Auto Button Color Logic if (autoEnabled) { fill(46, 204, 113); } else if (hoverAuto) { fill(80); } else { fill(50); }

Changes the button color based on whether auto is enabled and whether the mouse is hovering

background(15);
Fills the entire canvas with a dark gray (almost black) color each frame, erasing the previous frame's drawings
if (autoEnabled) {
Only runs the auto-clicker logic if the player has toggled auto-clicking ON
const now = millis();
Gets the current time in milliseconds since the sketch started, allowing us to measure elapsed time
if (now - lastAutoTime >= 1000) {
Checks if at least 1000 milliseconds (one full second) have passed since the last auto-click
robux += perClick * autoPerSecond;
Adds robux: each auto-click earns (perClick × autoPerSecond) robux, so higher autoPerSecond means more robux per second
lastAutoTime = now;
Resets the timer by saving the current time, so the next auto-click won't happen until another second passes
const mainRadius = min(width, height) * 0.18;
Calculates the radius of the main button as 18% of the smaller screen dimension, keeping it proportional on any screen size
const mainX = width / 2;
Centers the main button horizontally on the canvas
const mainY = height / 2;
Centers the main button vertically on the canvas
text("Robux: " + floor(robux), width / 2, 50);
Draws the robux counter at the top of the screen, using floor() to round down to a whole number
const d = dist(mouseX, mouseY, mainX, mainY);
Calculates the straight-line distance from the mouse cursor to the center of the main button
const hoverMain = d < mainRadius;
If the distance is less than the button's radius, the mouse is hovering over the button—store TRUE or FALSE
const scaleHover = hoverMain ? 1.08 : 1;
Uses a ternary operator: if hovering, scale to 1.08 (8% larger); otherwise scale to 1 (normal size)
scale(scaleHover);
Enlarges the main button by the calculated scale factor, creating a 'click me' visual feedback on hover
fill(0, 200, 120, 80);
Sets the color to a semi-transparent green (RGB: 0, 200, 120 with 80 alpha) for the glow effect
ellipse(0, 0, mainRadius * 2.6, mainRadius * 2.6);
Draws a large semi-transparent green ellipse as the outer glow around the main button
drawRobuxSymbol(0, 0, mainRadius * 1.25);
Calls a custom function to draw the Robux-inspired diamond shape with a cutout at the center
const autoLabel = autoEnabled ? "Auto: ON (" + autoPerSecond + "/s)" : "Auto: OFF";
If auto is enabled, show 'Auto: ON (X/s)' with the clicks-per-second rate; otherwise show 'Auto: OFF'

drawRobuxSymbol()

drawRobuxSymbol() is a custom helper function that encapsulates all the logic for drawing the Robux-inspired logo. It uses push/pop to isolate transformations, allowing the main button to be drawn at any position and size without affecting the rest of the sketch. The function demonstrates how to build complex visuals from simple primitives (rectangles and ellipses) through layering and precise coordinate calculations.

function drawRobuxSymbol(cx, cy, size) {
  push();
  translate(cx, cy);

  // Base rotation similar to the Robux "diamond" look
  rotate(PI / 4);

  rectMode(CENTER);
  strokeWeight(size * 0.08);
  stroke(240);
  fill(40, 200, 120);

  const outerSize = size;
  const cornerRadius = outerSize * 0.25;

  // Outer diamond (body)
  rect(0, 0, outerSize, outerSize, cornerRadius);

  // Inner "hole" – off-center, slightly rectangular so it's not identical
  noStroke();
  fill(15); // matches background to look like a cutout

  const innerW = outerSize * 0.48;
  const innerH = outerSize * 0.40;  // not perfectly square -> keeps it distinct
  const offsetX = outerSize * 0.14; // off-center horizontally
  const offsetY = -outerSize * 0.06; // slight vertical offset

  rect(offsetX, offsetY, innerW, innerH, outerSize * 0.18);

  // Optional: tiny highlight to make it feel more "gamey" and less like the real logo
  fill(255, 255, 255, 80);
  const highlightSize = outerSize * 0.18;
  const hiOffset = outerSize * -0.25;
  ellipse(hiOffset, hiOffset, highlightSize, highlightSize);

  pop();
}
Line-by-line explanation (20 lines)

🔧 Subcomponents:

calculation Outer Diamond Shape rect(0, 0, outerSize, outerSize, cornerRadius);

Draws the main diamond-shaped body with rounded corners

calculation Inner Cutout Hole rect(offsetX, offsetY, innerW, innerH, outerSize * 0.18);

Draws an off-center rectangular hole that gets filled with the background color to simulate a cutout

calculation Highlight Shine Effect ellipse(hiOffset, hiOffset, highlightSize, highlightSize);

Adds a small semi-transparent white ellipse in the corner to give the symbol depth and a 3D appearance

push();
Saves the current drawing state (transformations, colors, stroke settings) so changes inside this function don't affect other drawings
translate(cx, cy);
Moves the origin to the center position (cx, cy), so all subsequent coordinates are relative to this point
rotate(PI / 4);
Rotates the entire symbol 45 degrees (π/4 radians), giving the square a diamond orientation like the Robux logo
rectMode(CENTER);
Changes rectangle drawing mode so rect() uses the first two arguments as the center, not the top-left corner
strokeWeight(size * 0.08);
Sets the outline thickness proportional to the symbol size—larger symbols get thicker outlines
stroke(240);
Sets the outline color to light gray, creating a subtle border around the diamond
fill(40, 200, 120);
Sets the fill color to a green similar to Robux's signature color
const cornerRadius = outerSize * 0.25;
Calculates rounded corner radius as 25% of the symbol size, making the diamond look friendlier and less sharp
rect(0, 0, outerSize, outerSize, cornerRadius);
Draws the main diamond shape: a square rotated 45° with rounded corners, centered at origin
noStroke();
Removes the outline for the next shapes so the cutout hole and highlight blend smoothly
fill(15);
Sets fill to dark gray (15) matching the background color, so the inner rectangle looks like a cutout
const innerW = outerSize * 0.48;
Calculates the inner hole's width as 48% of the outer size—slightly smaller than half to show the diamond's edges
const innerH = outerSize * 0.40;
Calculates the inner hole's height as 40% of the outer size—intentionally different from width to create an asymmetric, distinctive look
const offsetX = outerSize * 0.14;
Moves the inner hole to the right by 14% of the size, creating off-center asymmetry that makes the design more interesting
const offsetY = -outerSize * 0.06;
Moves the inner hole up slightly by 6%, adding vertical offset to the cutout
fill(255, 255, 255, 80);
Sets fill to white with 80 alpha (semi-transparent) for the highlight shine effect
const highlightSize = outerSize * 0.18;
Calculates the highlight circle's diameter as 18% of the symbol size—small enough to feel like a subtle shine
const hiOffset = outerSize * -0.25;
Positions the highlight in the upper-left corner by offsetting it negative from the center
ellipse(hiOffset, hiOffset, highlightSize, highlightSize);
Draws a small white circle in the upper-left to simulate a light reflection, adding depth to the symbol
pop();
Restores the saved drawing state, undoing all the transformations and color settings so they don't affect subsequent drawing code

mousePressed()

mousePressed() is a p5.js built-in function that fires whenever the user clicks anywhere on the canvas. We use it to handle two separate clickable regions: the main Robux button (circular collision) and the auto-clicker toggle (rectangular collision). The return statement prevents clicking the main button from also accidentally toggling auto mode.

🔬 This circular collision detection uses dist() to measure how far the click is from the button's center. What happens if you change < mainRadius to < mainRadius * 2? Does clicking far from the button now count as a hit?

  // Check click on main Robux-style button
  const d = dist(mouseX, mouseY, mainX, mainY);
  if (d < mainRadius) {
    robux += perClick;
    return; // don't also toggle auto in same click
  }
function mousePressed() {
  const mainRadius = min(width, height) * 0.18;
  const mainX = width / 2;
  const mainY = height / 2;

  const autoBtnW = 240;
  const autoBtnH = 60;
  const autoBtnX = width / 2 - autoBtnW / 2;
  const autoBtnY = height - autoBtnH - 40;

  // Check click on main Robux-style button
  const d = dist(mouseX, mouseY, mainX, mainY);
  if (d < mainRadius) {
    robux += perClick;
    return; // don't also toggle auto in same click
  }

  // Check click on auto-clicker button
  const insideAuto =
    mouseX > autoBtnX &&
    mouseX < autoBtnX + autoBtnW &&
    mouseY > autoBtnY &&
    mouseY < autoBtnY + autoBtnH;

  if (insideAuto) {
    autoEnabled = !autoEnabled;
    lastAutoTime = millis(); // reset timer when toggled
  }
}
Line-by-line explanation (11 lines)

🔧 Subcomponents:

conditional Main Button Click Detection if (d < mainRadius) {

Tests if the click occurred inside the circular main button using distance calculation

conditional Auto Button Click Detection if (insideAuto) {

Tests if the click occurred inside the rectangular auto-clicker button

const mainRadius = min(width, height) * 0.18;
Recalculates the main button's radius to match the size used in draw()
const mainX = width / 2;
Recalculates the main button's center X coordinate
const mainY = height / 2;
Recalculates the main button's center Y coordinate
const d = dist(mouseX, mouseY, mainX, mainY);
Calculates the distance from where the user clicked to the center of the main button
if (d < mainRadius) {
If the distance is less than the button radius, the click is inside the circular button
robux += perClick;
Adds perClick robux to the counter when the player clicks the main button
return;
Exits the function immediately, preventing the auto button check from also running on the same click (avoids clicking both buttons at once)
const insideAuto = mouseX > autoBtnX && mouseX < autoBtnX + autoBtnW && mouseY > autoBtnY && mouseY < autoBtnY + autoBtnH;
Tests if the click is inside the rectangular auto button by checking if X and Y are both within the button's bounds
if (insideAuto) {
Only executes if the click is inside the auto button
autoEnabled = !autoEnabled;
Toggles auto-clicker ON if it was OFF, or OFF if it was ON using the logical NOT operator (!)
lastAutoTime = millis();
Resets the auto-click timer whenever the player toggles auto mode, so the first auto-click happens smoothly

windowResized()

windowResized() is a built-in p5.js function that fires automatically whenever the browser window is resized. By calling resizeCanvas(), we ensure the game canvas stretches to fill the new dimensions, keeping the layout responsive and centered on any screen size.

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}
Line-by-line explanation (1 lines)
resizeCanvas(windowWidth, windowHeight);
Updates the canvas to match the new browser window dimensions, making the game responsive when the user resizes their browser

📦 Key Variables

robux number

Stores the player's total robux earned from both manual clicks and auto-clicker. Displayed at the top of the screen.

let robux = 0;
perClick number

How much robux is earned per click (either manual or auto). Multiplied by autoPerSecond to calculate auto-click income.

let perClick = 1;
autoEnabled boolean

Tracks whether auto-clicking is currently ON (true) or OFF (false). Toggled when the player clicks the auto button.

let autoEnabled = false;
autoPerSecond number

How many auto-clicks happen per second when auto-clicking is enabled. Used to calculate robux gained each auto-click interval.

let autoPerSecond = 1;
lastAutoTime number

Stores the timestamp (in milliseconds) of the last auto-click, allowing the code to measure when one second has elapsed for the next auto-click.

let lastAutoTime = 0;

🔧 Potential Improvements (5)

Here are some ways this code could be enhanced:

BUG draw() and mousePressed()

Button positions and sizes are recalculated every frame in draw() and again in mousePressed(), creating duplicate code and potential desynchronization if values differ slightly.

💡 Move all layout calculations (mainRadius, autoBtnW, autoBtnX, etc.) to global variables or a separate function that runs once, so both draw() and mousePressed() use identical values.

PERFORMANCE draw()

Complex calculations like cornerRadius, innerW, innerH, offsetX, offsetY are recalculated inside drawRobuxSymbol() every single frame (60 times per second), even though the symbol size rarely changes.

💡 Pre-calculate these values once and pass them as parameters or use memoization, or only recalculate when size actually changes.

STYLE mousePressed()

The layout calculations (mainRadius, mainX, mainY, autoBtnW, etc.) are duplicated between draw() and mousePressed(), violating the DRY (Don't Repeat Yourself) principle and making the code harder to maintain.

💡 Extract these layout calculations into a separate object or function (e.g., getLayoutValues()) and call it from both draw() and mousePressed().

FEATURE overall

The sketch lacks visual or audio feedback when clicking—no animation, particle effect, or sound to reinforce the click action.

💡 Add a brief scaling animation on the main button when clicked, or create floating text that shows '+1 Robux' above the button, similar to popular clicker games.

FEATURE draw()

There is no way to save or persist the player's robux between page reloads.

💡 Use localStorage to save robux and autoEnabled each frame, then restore them in setup() so progress is preserved across sessions.

🔄 Code Flow

Code flow showing setup, draw, drawrobuxsymbol, mousepressed, windowresized

💡 Click on function names in the diagram to jump to their code

graph TD start[Start] --> setup[setup] setup --> draw[draw loop] draw --> autoclicker-timer[Auto-clicker Timer Logic] draw --> hover-main-detection[Main Button Hover Detection] draw --> hover-auto-detection[Auto Button Hover Detection] draw --> auto-button-color[Auto Button Color Logic] draw --> drawrobuxsymbol[drawRobuxSymbol] drawrobuxsymbol --> outer-diamond[Outer Diamond Shape] drawrobuxsymbol --> inner-cutout[Inner Cutout Hole] drawrobuxsymbol --> highlight-shine[Highlight Shine Effect] mousepressed --> main-button-collision[Main Button Click Detection] mousepressed --> auto-button-collision[Auto Button Click Detection] windowresized --> draw click setup href "#fn-setup" click draw href "#fn-draw" click autoclicker-timer href "#sub-autoclicker-timer" click hover-main-detection href "#sub-hover-main-detection" click hover-auto-detection href "#sub-hover-auto-detection" click auto-button-color href "#sub-auto-button-color" click drawrobuxsymbol href "#fn-drawrobuxsymbol" click outer-diamond href "#sub-outer-diamond" click inner-cutout href "#sub-inner-cutout" click highlight-shine href "#sub-highlight-shine" click mousepressed href "#fn-mousepressed" click main-button-collision href "#sub-main-button-collision" click auto-button-collision href "#sub-auto-button-collision" click windowresized href "#fn-windowresized"

❓ Frequently Asked Questions

What visual elements are present in the robux clicker sketch?

The sketch features a main Robux-inspired button with a glowing effect, a counter displaying the amount of Robux, and a toggle button for enabling auto-clicking.

How can users interact with the robux clicker sketch?

Users can click on the main button to increase their Robux and toggle the auto-clicker feature using a dedicated button.

What creative coding concepts does this p5.js sketch illustrate?

This sketch demonstrates concepts such as user interaction, dynamic updates to a visual counter, and the implementation of basic game mechanics like auto-clicking.

Preview

robux clicker - p5.js creative coding sketch preview
Sketch Preview
Code flow diagram showing the structure of robux clicker - Code flow showing setup, draw, drawrobuxsymbol, mousepressed, windowresized
Code Flow Diagram