Today you will build a tiny chatbot that knows a few prepared answers. The finished program is short, but it combines several ideas that deserve to be learned separately. We will therefore build the mental model first and the final program second.
sendButton.mousePressed(answerPrompt);
promptInput.elt.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
answerPrompt();
}
});
If those lines currently look like punctuation soup, that is completely reasonable. Each dot, word, pair of parentheses, and pair of braces has a job. We will unpack all of them.
An object is a bundle of related information and abilities that a program treats as one “thing.” A real horse has information such as its name and age, and abilities such as walking or neighing. A program can use the same organisational idea.
| Word | Meaning | How it usually looks |
|---|---|---|
| Property | A value stored on an object. | horse.name or event.key |
| Method | A function belonging to an object—an action it knows how to perform. | horse.neigh() or promptInput.value() |
The dot means: “look inside this object for the named property or method.”
horse.name // Read the property called name.
horse.neigh() // Call the method called neigh.
horse.neigh refers to the function itself. horse.neigh() calls the function now. We will use both patterns later.Object-oriented programming, shortened to OOP, is a way of organising a program around objects. Each object can keep track of its own data and offer methods for working with that data. Larger programs may also use classes, which are reusable plans for making similar objects.
You will not write a class in this lesson. p5.js has already used classes behind the scenes. When you call createInput(), p5.js creates and returns an input object for you. You will use that object's properties and methods.
Our first object stores key-value pairs. A key is the lookup name. Its value is the information stored under that name.
const answers = {
"hello": "Neigh there! Welcome to the stable.",
"horse": "Horses can sleep standing up or lying down.",
"carrot": "Carrots are treats, not a whole horse dinner.",
"joke": "Why did the pony whisper? It was a little horse!",
"default": "I do not know that one yet. Try hello, horse, carrot, or joke."
};
{ } contain the object.answers["carrot"] looks up the value stored under "carrot".let prompt = "carrot";
let answer = answers[prompt];
// JavaScript reads this as answers["carrot"].
// answer now contains the carrot sentence.
promptInput = createInput("");
This line does two jobs:
createInput("") asks p5.js to create an empty text box.promptInput, so we can find and control that same text box later.The variable is not the visible text box itself. Think of it as a named handle or remote control that points to the input object.
p5.js wraps the browser's ordinary HTML input element in a friendlier p5.Element object. Most of the time, p5's methods are enough. For a standard browser keyboard listener, however, we need the original HTML element. p5 gives us that object through the property .elt.
promptInput.elt
Read this from left to right:
promptInput.elt.value(). The browser element gives us standard browser methods such as addEventListener(). They refer to the same visible input box at two different layers.A normal instruction such as replyText.html(answer) runs when JavaScript reaches that line. An interactive program is different: it often has to wait without knowing when the person will act.
An event is a message from the browser saying that something happened. Examples include a key press, a click or tap, pointer movement, the page loading, or an input value changing.
keydown is the event. A registered listener notices it and runs a callback function.| Piece | Job | WhinnyBot example |
|---|---|---|
| Target | The object we are watching. | promptInput.elt |
| Event type | The kind of action we care about. | "keydown" |
| Listener | The registration that tells the browser to keep watch. | addEventListener(...) |
| Callback | The function the browser calls later. | function (event) { ... } |
When the browser calls our callback, it also gives the callback an object containing details about what happened. We choose to name that object event.
function (event) {
// event is an object created and supplied by the browser.
}
| Property | Example | Meaning |
|---|---|---|
event.key | "a" or "Enter" | The meaning of the key. |
event.code | "KeyA" or "Enter" | The physical keyboard position. |
event.type | "keydown" | The kind of event. |
event.key normally reports the string "Enter". Capitalisation matters.Click or tap in this box and press several keys. Watch the browser describe each keydown event. Try a letter, Space, Backspace, and Return/Enter.
promptInput.elt.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
answerPrompt();
}
});
promptInput finds the p5 input wrapper object..elt follows its property to the browser input element..addEventListener(...) asks that browser element to start listening."keydown" selects the event type. It fires when any key is pushed down while the input has focus.function (event) { ... } is the callback. We give it to the browser now; the browser calls it later.event.key reads the key property from the browser-supplied event object.=== "Enter" checks whether the key was Return/Enter. Other keys fail this test.answerPrompt() calls our send function immediately after Return/Enter is detected.}); closes the callback, closes the method call, and ends the statement.// Give the function to an object so it can call it later:
sendButton.mousePressed(answerPrompt);
// Call the function now because Enter was just detected:
answerPrompt();
In the first line, there are no parentheses after answerPrompt. We pass the function itself to p5. In the second line, the parentheses call the function right now.
sendButton.mousePressed(answerPrompt()) calls the function while the page is being set up. It passes the result—not the function—to mousePressed.Do not type the complete program in one jump. Build one stage, run it, and confirm what works. If a later stage breaks, you then know where to look.
Place this above setup(). It is global, so both setup() and answerPrompt() can find it.
const answers = {
"hello": "Neigh there! Welcome to the stable.",
"horse": "Horses can sleep standing up or lying down.",
"carrot": "Crunchy, orange, and best as a small treat!",
"joke": "Why did the pony whisper? It was a little horse!",
"default": "I do not know that one yet."
};
Predict: answers["horse"] returns the horse sentence. answers["dragon"] is undefined because that key does not exist.
let promptInput;
let sendButton;
let replyText;
They are declared outside setup() because answerPrompt() also needs them. They begin empty; setup() assigns the objects later.
function setup() {
noCanvas();
promptInput = createInput("");
promptInput.attribute("placeholder", "Try: hello, horse, carrot, joke");
sendButton = createButton("Ask WhinnyBot");
sendButton.mousePressed(answerPrompt);
replyText = createP("Neigh there! Ask me something.");
}
noCanvas() says this program uses HTML controls, not a drawing canvas.create... function returns an object.mousePressed(answerPrompt) registers a callback. It does not run it yet.function answerPrompt() {
let prompt = promptInput.value().toLowerCase().trim();
let answer = answers[prompt];
if (answer === undefined) {
answer = answers.default;
}
replyText.html(answer);
promptInput.value("");
promptInput.elt.focus();
}
value() reads the text.toLowerCase() makes HORSE become horse.trim() removes spare outside spaces.answers[prompt] performs the lookup.html(answer) displays the reply.value("") clears the box.focus() returns the cursor.hello, HORSE, extra spaces, and an unknown word.Place this after createInput(). You cannot attach a listener to an object that does not exist yet.
promptInput.elt.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
event.preventDefault();
answerPrompt();
}
});
preventDefault() stops a normal built-in browser action. A one-line input usually works without it, but it prevents surprises if this code later moves into a form.
The listener is attached only to the input. Return sends the prompt only while that input has focus. This is more controlled than listening to every key everywhere.
Now compare the whole program with the five stages. Nothing below is new; it is simply the assembled version.
const answers = {
"hello": "Neigh there! Welcome to the stable.",
"horse": "Horses can sleep standing up or lying down.",
"carrot": "Crunchy, orange, and best as a small treat!",
"joke": "Why did the pony whisper? It was a little horse!",
"default": "I do not know that one yet."
};
let promptInput;
let sendButton;
let replyText;
function setup() {
noCanvas();
promptInput = createInput("");
promptInput.attribute("placeholder", "Try: hello, horse, carrot, joke");
sendButton = createButton("Ask WhinnyBot");
sendButton.mousePressed(answerPrompt);
replyText = createP("Neigh there! Ask me something.");
// Watch the input for keyboard events.
promptInput.elt.addEventListener("keydown", function (event) {
// Return and Enter normally produce event.key === "Enter".
if (event.key === "Enter") {
event.preventDefault();
answerPrompt();
}
});
}
function answerPrompt() {
// Read and clean the typed prompt.
let prompt = promptInput.value().toLowerCase().trim();
let answer = answers[prompt];
// Use a safe fallback if the key does not exist.
if (answer === undefined) {
answer = answers.default;
}
// Display, clear, and return focus.
replyText.html(answer);
promptInput.value("");
promptInput.elt.focus();
}
hello and click the button.horse and press Return/Enter. CARROT with capitals and spare spaces.createInput().promptInput.elt, including .elt."keydown" and "Enter".Look for mousePressed(answerPrompt()). Remove the final parentheses: mousePressed(answerPrompt).
toLowerCase() and trim().console.log(prompt) after cleaning to inspect the lookup key.The code may be using an object before it was created, or a variable name may be misspelled. Compare its declaration, assignment, and use.
createInput() return?.elt give us?event object come from?"Enter" when the keyboard may say “Return”?answerPrompt and another use answerPrompt()?createInput() returns a p5.Element object wrapping the visible input..elt gives the underlying browser HTML element, which has methods such as addEventListener() and focus().promptInput.elt. Event type: "keydown". Callback: function (event) { ... }.event.key normally contains the exact string "Enter".answerPrompt refers to the function so another object can call it later. answerPrompt() calls it immediately.answerPrompt()."best horse".else branch that logs non-Enter keys without sending.