Shortcuts
"N" Normal "Z" Undo
"S" Spray can "Y" Redo
"Q" Square "E" Eraser
"T" Triangle "C" Random color
"A" Star
This program requires the CORS extension to run:
Get it here
//declare variables
var bgcolor = 'white';
var bin;
var save;
var test;
var canvasHistory = []; // Stores the history of the canvas
var redoStack = []; // Stores the undone actions
function preload(){
//image setup
test = loadImage("https://www.coolskele.com/s/astro_angry.gif");
closeW = loadImage('https://www.coolskele.com/s/closeW.png');
minimize = loadImage('https://www.coolskele.com/s/minus.png');
square = loadImage('https://www.coolskele.com/s/square.png');
//font
f = loadFont('https://www.coolskele.com/s/W95.ttf');
}
function setup() {
//define canvas properties
let sketchCanvas = createCanvas(700, 800);
sketchCanvas.parent('canvasContainer');
background(bgcolor);
setupCanvas();
saveState();
textFont(f);
}
function setupCanvas() {
noStroke();
//CREATE ELEMENTS:
//create a colorpicker
colorPicker = createColorPicker('#000000');
colorPicker.position(0, 0);
colorPicker.style('width', '50px');
colorPicker.style('height', '22px');
colorPicker.style('background-image', 'url()');
//create a colorpicker end
colorPickerEnd = createColorPicker('#000000');
colorPickerEnd.position(105, 365);
colorPickerEnd.style('width', '50px');
colorPickerEnd.style('height', '22px');
colorPickerEnd.style('background-image', 'url()');
//create a dropdown menu
sel = createSelect();
sel.position(249, 365);
sel.option("Normal Brush");
sel.option("Spiral Brush");
sel.option("Star Brush");
sel.option("Spray Paint Brush");
sel.option('Gradient Brush');
sel.option("Draw Square");
sel.option("Draw Triangle");
sel.option("Draw Circle");
sel.option("Eraser");
sel.style('background-image', 'url()');
sel.style('font-family', 'W95');
sel.style('font-size', '16px');
//create a slider
slider = createSlider(1, 100, 20, 1);
slider.position(470, 365);
slider.style('width', '180px');
//trash all button
button = createButton('');
button.position(105, 410);
button.style('width', '30px');
button.style('height', '30px');
button.style('background-image', 'url(https://www.coolskele.com/s/bin.png)');
button.style('background-size', 'cover');
button.style('background-color', '#fff2eb');
button.style('border', 'none');
button.mousePressed(clearBG);
//save image button
button = createButton("");
button.position(145, 410);
button.style('width', '30px');
button.style('height', '30px');
button.style('background-image', 'url(https://www.coolskele.com/s/save.png)');
button.style('background-size', 'cover');
button.style('background-color', '#fff2eb');
button.style('border', 'none');
button.mousePressed(SaveImage);
// Rectangle tool button
rectangleButton = createButton('');
rectangleButton.position(145, 610);
rectangleButton.style('width', '30px');
rectangleButton.style('height', '30px');
rectangleButton.style('background-image', 'url(https://www.coolskele.com/s/square.png)');
rectangleButton.style('background-size', 'cover');
rectangleButton.style('background-color', '#fff2eb');
rectangleButton.style('border', 'none');
rectangleButton.mousePressed(() => sel.selected("Draw Square"));
// Triangle tool button
triangleButton = createButton('');
triangleButton.position(105, 610);
triangleButton.style('width', '30px');
triangleButton.style('height', '30px');
triangleButton.style('background-image', 'url(https://www.coolskele.com/s/triangle.png)');
triangleButton.style('background-size', 'cover');
triangleButton.style('background-color', '#fff2eb');
triangleButton.style('border', 'none');
triangleButton.mousePressed(() => sel.selected("Draw Triangle"));
// Star tool button
StarButton = createButton('');
StarButton.position(105, 560);
StarButton.style('width', '30px');
StarButton.style('height', '30px');
StarButton.style('background-image', 'url(https://www.coolskele.com/s/star.png)');
StarButton.style('background-size', 'cover');
StarButton.style('background-color', '#fff2eb');
StarButton.style('border', 'none');
StarButton.mousePressed(() => sel.selected("Star Brush"));
// Circle tool button
CircleButton = createButton('');
CircleButton.position(145, 560);
CircleButton.style('width', '30px');
CircleButton.style('height', '30px');
CircleButton.style('background-image', 'url(https://www.coolskele.com/s/circle.png)');
CircleButton.style('background-size', 'cover');
CircleButton.style('background-color', '#fff2eb');
CircleButton.style('border', 'none');
CircleButton.mousePressed(() => sel.selected("Draw Circle"));
// Eraser tool button
eraserButton = createButton('');
eraserButton.position(105, 460);
eraserButton.style('width', '30px');
eraserButton.style('height', '30px');
eraserButton.style('background-image', 'url(https://www.coolskele.com/s/eraser.png)');
eraserButton.style('background-size', 'cover');
eraserButton.style('background-color', '#fff2eb');
eraserButton.style('border', 'none');
eraserButton.mousePressed(() => sel.selected("Eraser"));
// Gradient tool button
GradientButton = createButton('');
GradientButton.position(145, 460);
GradientButton.style('width', '30px');
GradientButton.style('height', '30px');
GradientButton.style('background-image', 'url(https://www.coolskele.com/s/gradient.png)');
GradientButton.style('background-size', 'cover');
GradientButton.style('background-color', '#fff2eb');
GradientButton.style('border', 'none');
GradientButton.mousePressed(() => sel.selected("Gradient Brush"));
// brush tool button
BrushButton = createButton('');
BrushButton.position(105, 510);
BrushButton.style('width', '30px');
BrushButton.style('height', '30px');
BrushButton.style('background-image', 'url(https://www.coolskele.com/s/paintbrush.png)');
BrushButton.style('background-size', 'cover');
BrushButton.style('background-color', '#fff2eb');
BrushButton.style('border', 'none');
BrushButton.mousePressed(() => sel.selected("Normal Brush"));
// Spiral tool button
SpiralButton = createButton('');
SpiralButton.position(145, 510);
SpiralButton.style('width', '30px');
SpiralButton.style('height', '30px');
SpiralButton.style('background-image', 'url(https://www.coolskele.com/s/spring.png)');
SpiralButton.style('background-size', 'cover');
SpiralButton.style('background-color', '#fff2eb');
SpiralButton.style('border', 'none');
SpiralButton.mousePressed(() => sel.selected("Spiral Brush"));
}
function draw() {
//Take advantage of the fact that elements in p5js are always on top, so you can always draw the menu bars to prevent the user from drawing in the menu bar
noStroke();
//black lines
fill('#000000');
rect(80,-50,3,height);
//draw a menu bar
fill('#fff2eb');
rect(0, 0, width, 100);
//left side bar
fill('#fff2eb');
rect(-20,100,100,height);
fill('#f9e7db');
rect(-20,350,100,height);
//draw a bottom bar
fill('#fff2eb');
rect(0, 750, width, 100);
//black lines
fill('#000000');
rect(0, 0, width, 35);
rect(0, 100, width, 3);
rect(0, 750, width, 3);
rect(-620, 350, width, 3);
//draw a top menu bar
fill('#f3833f');
rect(0, 0, width, 32);
fill('#ffffff');
rect(670,2,20,20);
fill('#ffffff');
rect(640,2,20,20);
fill('#ffffff');
rect(610,2,20,20);
//draw images
image(test, 600, 20, 80, 80);
image(closeW, 672, 4 , 15 , 15);
image(square, 642, 4.5 , 15 , 15);
image(minimize, 614, 10 , 15 , 15);
//create text
fill('black');
textSize(16);
text("Brush Thickness", 375, 55);
fill('black');
textSize(16);
text("Brush Type/Eraser", 150, 55);
fill('black');
textSize(16);
text("Color picker", 5, 55);
fill('black');
textSize(16);
text("File", 5, 20)
fill('black');
textSize(16);
text("Edit", 55, 20)
fill('black');
textSize(16);
text("View", 105, 20)
fill('black');
textSize(16);
text("Image", 165, 20)
fill('black');
textSize(16);
text("Option", 225, 20)
//Check if mouse is pressed and draw the lines and stuff
if (mouseIsPressed && mouseY > 100 && mouseX > 50 && mouseY < 750) {
if (sel.value() == "Normal Brush") {
//normal paint brush
//draw a line with the correct color
stroke(colorPicker.color());
strokeWeight(slider.value());
line(pmouseX, pmouseY, mouseX, mouseY);
saveState();
}
if (sel.value() == "Eraser") {
//eraser
//draw a line in background color
stroke(bgcolor);
strokeWeight(slider.value());
line(pmouseX, pmouseY, mouseX, mouseY);
saveState();
}
if (sel.value() == "Draw Square") {
//draw rectangle with brush thickness at mousex and y
fill(colorPicker.color());
rect(mouseX, mouseY, slider.value(), slider.value());
saveState();
}
if (sel.value() == "Draw Circle") {
//draw rectangle with brush thickness at mousex and y
fill(colorPicker.color());
ellipse(mouseX, mouseY, slider.value(), slider.value());
saveState();
}
if (sel.value() == "Draw Triangle") {
//draw triangle with brush thickness at mousex and y
fill(colorPicker.color());
triangle(mouseX, mouseY, mouseX + slider.value(), mouseY + slider.value(), mouseX - slider.value(), mouseY + slider.value());
saveState();
}
//Spiral brush, change dashLenght to make it more spiral
if (sel.value() == "Spiral Brush") {
stroke(colorPicker.color());
strokeWeight(slider.value());
let dashLength = 500;
for (let i = 0; i < dist(pmouseX, pmouseY, mouseX, mouseY); i += dashLength * 2) {
let x1 = lerp(pmouseX, mouseX, i / dist(pmouseX, pmouseY, mouseX, mouseY));
let y1 = lerp(pmouseY, mouseY, i / dist(pmouseX, pmouseY, mouseX, mouseY));
let x2 = lerp(pmouseX, mouseX, (i + dashLength) / dist(pmouseX, pmouseY, mouseX, mouseY));
let y2 = lerp(pmouseY, mouseY, (i + dashLength) / dist(pmouseX, pmouseY, mouseX, mouseY));
line(x1, y1, x2, y2);
saveState();
}
}
// Spray Paint Brush
if (sel.value() == "Spray Paint Brush") {
for (let i = 0; i < 50; i++) {
let angle = random(TWO_PI);
let radius = random(slider.value());
let x = mouseX + cos(angle) * radius;
let y = mouseY + sin(angle) * radius;
noStroke();
fill(colorPicker.color());
ellipse(x, y, 2, 2);
}
saveState();
}
// Star Brush
if (sel.value() == "Star Brush") {
fill(colorPicker.color());
noStroke();
drawStar(mouseX, mouseY, slider.value(), slider.value() * 2, 5); // Draw a star
saveState();
}
if (sel.value() == "Gradient Brush") {
gradientBrush(pmouseX, pmouseY, mouseX, mouseY);
saveState();
}
}
}
function gradientBrush(x1, y1, x2, y2) {
let steps = int(dist(x1, y1, x2, y2) / 5); // Adjust the number of steps based on distance
let startColor = colorPicker.color(); // Get start color from the color picker
let endColor = colorPickerEnd.color(); // Get end color from the color picker
// Draw gradient brush by interpolating color along the line
for (let i = 0; i < steps; i++) {
let interColor = lerpColor(startColor, endColor, i / steps); // Interpolate the color
let x = lerp(x1, x2, i / steps); // Interpolate the x position
let y = lerp(y1, y2, i / steps); // Interpolate the y position
stroke(interColor);
strokeWeight(slider.value()); // Set stroke weight based on slider value
point(x, y); // Draw a point at the interpolated position
}
}
function clearBG() {
//clear the background by filling everything with white
fill(bgcolor);
noStroke();
rect(0, 100, width, height - 100);
}
// Function to set the current tool to 'eraser' when the eraser button is clicked
function setEraser() {
stroke(bgcolor);
strokeWeight(slider.value());
line(pmouseX, pmouseY, mouseX, mouseY);
saveState();
}
function SaveImage() {
// Define the coordinates and dimensions of the white drawing area
let x = 95; // Starting x-coordinate for the white screen (to the right of the sidebar)
let y = 100; // Starting y-coordinate for the white screen (below the top menu)
let w = width - 100; // Width of the white screen (remaining width after sidebar)
let h = height - 150; // Height of the white screen (remaining height after menus)
// Capture only the white screen area and save as an image
var to_save = get(x, y, w, h);
to_save.save("canvas.png");
}
function saveState() {
// Save the current state of the canvas
canvasHistory.push(get());
redoStack = []; // Clear redo stack when new action is performed
}
function undo() {
if (canvasHistory.length > 1) {
redoStack.push(canvasHistory.pop()); // Move the last state to redo stack
let previousState = canvasHistory[canvasHistory.length - 1]; // Get the previous state
clearBG(); // Clear the current canvas
image(previousState, 0, 0); // Display the previous state
}
}
function redo() {
if (redoStack.length > 0) {
let redoState = redoStack.pop(); // Get the last undone state
canvasHistory.push(redoState); // Add it back to history
clearBG(); // Clear the current canvas
image(redoState, 0, 0); // Display the redo state
}
}
function drawStar(x, y, radius1, radius2, npoints) {
let angle = TWO_PI / npoints;
let halfAngle = angle / 2.0;
beginShape();
for (let a = 0; a < TWO_PI; a += angle) {
let sx = x + cos(a) * radius2;
let sy = y + sin(a) * radius2;
vertex(sx, sy);
sx = x + cos(a + halfAngle) * radius1;
sy = y + sin(a + halfAngle) * radius1;
vertex(sx, sy);
}
endShape(CLOSE);
}
//check for key press
function keyPressed() {
//check for the correct key
if (key == 'n' || key == 'N') {
//change brush type to normal brush
sel.selected("Normal Brush");
} else if (key == 's' || key == 'S') {
//change bbrush type to splatter brush
sel.selected("Spray Paint Brush");
} else if (key == 'e' || key == 'E') {
//change brush type to eraser
sel.selected("Eraser");
} else if (key == '+') {
//increase brush thickness
slider.value(slider.value() + 1);
} else if (key == '-') {
//reduce brush thickness
slider.value(slider.value() - 1);
} else if (key == 'r' || key == 'R') {
//clear the background by calling clearBG() function
clearBG();
} else if (key == 'c' || key == 'C') {
//generate a random hex code, and set that as the colorpicker color
var randomColor = "#" + Math.floor(Math.random() * 16777215).toString(16);
colorPicker = createColorPicker(randomColor);
colorPicker.position(160, 365);
colorPicker.style('width', '50px');
colorPicker.style('height', '22px');
colorPicker.style('background-image', 'url()');
} else if (key == 'i' || key == 'I') {
//save the canvas as an image by calling saveImage()
SaveImage()
} else if (key == 'q'|| key == 'Q'){
//switch brush type to rectangle
sel.selected("Draw Square");
}else if (key == 't'|| key == 'T'){
//switch brush type totriangle
sel.selected("Draw Triangle");
}else if (key === 'z' || key === 'Z'){
// Undo when 'Z' key is pressed
undo();
}else if (key === 'y' || key === 'Y') {
// Redo when 'Y' key is pressed
redo();
}else if (key === 'a' || key === 'A') {
sel.selected("Star Brush");
}
}