setup()
setup() is the one-time initialization that p5.js calls when the sketch starts. It builds the entire DOM tree (the HTML structure you see on screen) from scratch using p5.js element creation functions. Unlike a typical p5.js sketch with a canvas, this one uses noCanvas() and constructs an interactive HTML interface. Everything created in setup() persists and is updated by the other functions (sendMessage, generateResponse, addMessage, etc.).
🔬 This code creates the message input field. What happens if you change the font-size from '16px' to '24px' or '10px'? Which size feels more usable?
inputBox = createInput();
inputBox.style("flex", "1");
inputBox.style("padding", "10px");
inputBox.style("font-size", "16px");
inputBox.parent(inputArea);
🔬 This styles the Settings button with background-color '#fff3cd' (light yellow). What visual change do you see if you swap it to '#ff6b6b' (red) or '#4ecdc4' (teal)? How does the new color affect the interface's vibe?
settingsButton = createButton("Settings");
settingsButton.style("padding", "6px 12px");
settingsButton.style("border-radius", "8px");
settingsButton.style("border", "1px solid #d2b48c");
settingsButton.style("background-color", "#fff3cd");
settingsButton.style("cursor", "pointer");
settingsButton.parent(controlsArea);
function setup() {
noCanvas();
// --- Create Main Flex Container ---
mainContainer = createDiv();
mainContainer.style("display", "flex");
mainContainer.style("flex-direction", "column");
mainContainer.style("height", "100vh"); // Make it full height
// --- Create the Title Element ---
titleElement = createElement('h1', 'Potato AI 2.0 🥔');
titleElement.style("text-align", "center");
titleElement.style("padding", "10px");
titleElement.style("margin", "0");
titleElement.style("background-color", "#f5e0b3");
titleElement.style("border-bottom", "1px solid #d2b48c");
titleElement.parent(mainContainer);
// --- Subtitle under the title ---
subtitleElement = createElement('p', '©️CDWW inc 2026');
subtitleElement.style("text-align", "center");
subtitleElement.style("margin", "0 0 8px 0");
subtitleElement.style("padding", "2px 0 6px 0");
subtitleElement.style("font-size", "12px");
subtitleElement.style("background-color", "#f5e0b3");
subtitleElement.style("border-bottom", "1px solid #d2b48c");
subtitleElement.parent(mainContainer);
// --- Controls area (Settings + Play GIF) ---
let controlsArea = createDiv();
controlsArea.style("display", "flex");
controlsArea.style("justify-content", "center");
controlsArea.style("gap", "10px");
controlsArea.style("padding", "8px");
controlsArea.style("background-color", "#f3d6a1");
controlsArea.parent(mainContainer);
settingsButton = createButton("Settings");
settingsButton.style("padding", "6px 12px");
settingsButton.style("border-radius", "8px");
settingsButton.style("border", "1px solid #d2b48c");
settingsButton.style("background-color", "#fff3cd");
settingsButton.style("cursor", "pointer");
settingsButton.parent(controlsArea);
playGifButton = createButton("Play Potato GIF");
playGifButton.style("padding", "6px 12px");
playGifButton.style("border-radius", "8px");
playGifButton.style("border", "1px solid #d2b48c");
playGifButton.style("background-color", "#ffe4b5");
playGifButton.style("cursor", "pointer");
playGifButton.parent(controlsArea);
// --- Chat Container ---
chatContainer = createDiv();
chatContainer.style("flex-grow", "1"); // Make chatContainer fill available space
chatContainer.style("overflow-y", "auto");
chatContainer.style("padding", "10px");
chatContainer.style("display", "flex");
chatContainer.style("flex-direction", "column");
chatContainer.style("background-color", "#f5e0b3");
chatContainer.parent(mainContainer); // Parent to mainContainer
// --- Input Area ---
inputArea = createDiv();
inputArea.style("display", "flex");
inputArea.style("padding", "10px");
inputArea.style("background-color", "#f5e0b3");
inputArea.parent(mainContainer); // Parent to mainContainer
inputBox = createInput();
inputBox.style("flex", "1");
inputBox.style("padding", "10px");
inputBox.style("font-size", "16px");
inputBox.parent(inputArea);
sendButton = createButton("Send");
sendButton.style("padding", "10px 20px");
sendButton.style("margin-left", "5px");
sendButton.style("border-radius", "8px");
sendButton.style("border", "1px solid #d2b48c");
sendButton.style("background-color", "#fff3cd");
sendButton.parent(inputArea);
sendButton.mousePressed(sendMessage);
// Store the listener function
keypressListener = function(e) {
if (e.key === "Enter") sendMessage();
};
inputBox.elt.addEventListener("keypress", keypressListener);
// --- Settings panel (hidden by default) ---
settingsPanel = createDiv();
settingsPanel.style("position", "fixed");
settingsPanel.style("top", "60px");
settingsPanel.style("right", "10px");
settingsPanel.style("padding", "10px");
settingsPanel.style("background-color", "#fffaf0");
settingsPanel.style("border", "1px solid #d2b48c");
settingsPanel.style("border-radius", "8px");
settingsPanel.style("box-shadow", "0 2px 6px rgba(0,0,0,0.15)");
settingsPanel.style("z-index", "900");
settingsPanel.style("display", "none");
settingsPanel.parent(document.body);
let settingsTitle = createElement('h3', 'Settings');
settingsTitle.style("margin", "0 0 8px 0");
settingsTitle.style("font-size", "16px");
settingsTitle.parent(settingsPanel);
smartModeCheckbox = createCheckbox(' Smart mode', false);
smartModeCheckbox.parent(settingsPanel);
smartModeCheckbox.style("margin-bottom", "8px");
smartModeCheckbox.changed(function() {
smartModeEnabled = smartModeCheckbox.checked();
if (smartModeEnabled) {
addMessage("Smart mode activated. This potato is now extra crispy 🥔✨", "ai");
} else {
addMessage("Smart mode deactivated. Back to simple spud life.", "ai");
}
});
let bgLabel = createP('Background color');
bgLabel.style("margin", "8px 0 4px 0");
bgLabel.style("font-size", "14px");
bgLabel.parent(settingsPanel);
bgColorPicker = createColorPicker('#f5e0b3');
bgColorPicker.parent(settingsPanel);
bgColorPicker.style("width", "100%");
bgColorPicker.input(function() {
const c = bgColorPicker.value();
document.body.style.backgroundColor = c;
if (chatContainer) {
chatContainer.style('background-color', c);
}
if (inputArea) {
inputArea.style('background-color', c);
}
});
// NEW: "Mess with Potato AI's code" button
let chaosLabel = createP('Danger zone: mess with Potato AI');
chaosLabel.style("margin", "10px 0 4px 0");
chaosLabel.style("font-size", "13px");
chaosLabel.style("color", "#b00000");
chaosLabel.parent(settingsPanel);
codeChaosButton = createButton("Mess with Potato AI's code");
codeChaosButton.parent(settingsPanel);
codeChaosButton.style("width", "100%");
codeChaosButton.style("margin-top", "4px");
codeChaosButton.style("padding", "6px");
codeChaosButton.style("background-color", "#ffcccc");
codeChaosButton.style("border", "1px solid #d2b48c");
codeChaosButton.style("border-radius", "6px");
codeChaosButton.mousePressed(() => {
codeChaosEnabled = !codeChaosEnabled;
if (codeChaosEnabled) {
addMessage("Uh oh... you just messed with my code. Expect some weird glitches now.", "ai");
codeChaosButton.html("Fix Potato AI's code");
showCodeChaosSequence(); // trigger GIF then static image
} else {
addMessage("Okay, I think my code is back to normal. I hope.", "ai");
codeChaosButton.html("Mess with Potato AI's code");
}
});
// Toggle settings panel visibility
settingsButton.mousePressed(() => {
settingsVisible = !settingsVisible;
settingsPanel.style("display", settingsVisible ? "block" : "none");
});
// Play GIF button behavior
playGifButton.mousePressed(handlePlayGifButton);
// --- Add the X Button (now Rickroll button) ---
let exitButton = createButton('X');
exitButton.style('position', 'fixed');
exitButton.style('top', '10px');
exitButton.style('right', '10px');
exitButton.style('padding', '10px 15px');
exitButton.style('font-size', '18px');
exitButton.style('background-color', '#ff0000'); // Red for exit
exitButton.style('color', 'white');
exitButton.style('border', 'none');
exitButton.style('border-radius', '5px');
exitButton.style('cursor', 'pointer');
exitButton.style('z-index', '1000'); // Ensure it's on top of other elements
// Instead of leaving, X now Rickrolls you
exitButton.mousePressed(showRickrollOverlay);
}
Line-by-line explanation (14 lines)
🔧 Subcomponents:
mainContainer.style("display", "flex");
Creates the root container that lays out header, chat, and input vertically
titleElement = createElement('h1', 'Potato AI 2.0 🥔');
Sets up the potato-themed header with h1 and copyright subtitle
settingsButton = createButton("Settings");
Creates Settings and Play GIF buttons with event listeners
inputBox.elt.addEventListener("keypress", keypressListener);
Allows sending messages by pressing Enter, not just clicking Send
bgColorPicker.input(function() {
Updates background color across entire interface when user picks a new color
noCanvas();- Tells p5.js not to create a canvas—this sketch uses HTML/CSS elements instead, not drawing to a canvas
mainContainer = createDiv();- Creates the root container div that will hold the entire interface
mainContainer.style("display", "flex");- Makes mainContainer a flexbox so its children (header, chat, input) can be laid out vertically and responsively
mainContainer.style("height", "100vh");- Sets mainContainer to fill the entire viewport height (100vh), ensuring it covers the whole screen
titleElement.parent(mainContainer);- Adds the title element as a child of mainContainer so it appears at the top
chatContainer.style("flex-grow", "1");- Makes the chat container expand to fill all available vertical space between header and input, pushing the input to the bottom
chatContainer.style("overflow-y", "auto");- Allows the chat to scroll vertically when messages exceed the container's height, keeping header and input visible
sendButton.mousePressed(sendMessage);- When the Send button is clicked, the sendMessage() function runs to process the user's text
keypressListener = function(e) {- Stores the keypress handler in a variable so it can be removed later (e.g., when darkScreen overlay appears)
if (e.key === "Enter") sendMessage();- Checks if the pressed key is Enter, and if so, calls sendMessage() to submit the chat
settingsPanel.style("display", "none");- Hides the settings panel by default—it only appears when the Settings button is clicked
smartModeCheckbox.changed(function() {- Runs this function whenever the Smart mode checkbox is toggled, updating smartModeEnabled and sending an AI response
bgColorPicker.input(function() {- Runs this function when the user picks a new color, updating the background color of the entire interface in real time
exitButton.mousePressed(showRickrollOverlay);- Instead of closing the page, clicking X triggers the rickroll overlay—a prank that hides the UI