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"); } }