Sketch 2026-02-13 04:38

This is a spiritual wellness and productivity application built with p5.js and DOM elements that combines daily task management, affirmations, confessions, and time-based alarms. All data persists in browser localStorage and automatically resets daily, helping users maintain spiritual practices and stay organized.

🧪 Try This!

Experiment with the code by making these changes:

  1. Make alarms louder or quieter — Adjust the alarm volume by changing the dB value—lower (more negative) is quieter, higher is louder.
  2. Change the alarm check interval — Increase or decrease how often the app checks for triggered alarms—lower values check more frequently but use more CPU.
  3. Add a default task on app startup — Insert a starting task into the array by modifying the initial mustDoTasks declaration.
  4. Change the affirmation prompt message — Customize the message users see when editing the affirmation—make it more personal or spiritual.
  5. Prevent duplicate confirmation dialogs
  6. Show task completion percentage — Add a header that displays how many tasks are completed—requires adding a simple calculation before the task list.
Prefer the full editor? Open it there →

📖 About This Sketch

This sketch creates a multi-feature wellness application that combines four core practices: managing must-do tasks, displaying affirmations, writing confessions, and setting time-based alarms with custom messages. Instead of using p5.js canvas drawing, it demonstrates how p5.js can interact with HTML DOM elements through selection, event listeners, and dynamic rendering—making it perfect for learning how to build functional web applications that feel like p5.js projects.

The code is organized into setup() which initializes all DOM elements and loads saved data, several helper functions that manage each feature (tasks, affirmations, confessions, alarms), and localStorage integration that ensures data persists between browser sessions. By studying it, you will learn how to store and retrieve data with JSON.stringify and JSON.parse, how to create interactive lists that add and delete items dynamically, how to work with the browser's Date object for scheduling, and how to structure a multi-section application with p5.js.

⚙️ How It Works

  1. When the sketch loads, preload() initializes Tone.js for alarm sounds, then setup() selects all HTML elements by their IDs and attaches event listeners to buttons and inputs. The app immediately calls loadData() to retrieve any saved tasks, affirmations, confessions, and alarms from localStorage, then checks if a day has passed to trigger a daily reset.
  2. The must-do list section lets users type a task and press Enter or click 'Add Task'—addMustDoTask() pushes the new task object into the array, saves to localStorage, and renderMustDoList() rebuilds the list in the DOM with checkboxes and delete buttons. Users can check off completed tasks, and incomplete tasks carry forward each day.
  3. The affirmation and confession sections display editable text—clicking 'Edit Affirmation' or 'Edit Confession' opens a browser prompt, updates the text, saves to localStorage, and displays it immediately.
  4. The alarms section lets users set a time using an HTML time input and an optional message. addAlarm() validates that the time is unique, stores it in the alarms array, and saves to localStorage. Every second, checkAlarms() compares the current time to each alarm's time, and when they match, it plays an alarm sound using Tone.js and shows an alert.
  5. Every function that modifies data calls saveData() to write mustDoTasks, affirmationText, confessionText, alarms, and lastResetDate to localStorage as JSON strings. On the next visit, loadData() reconstructs these objects automatically.
  6. resetDailyItems() runs automatically each day—it filters out completed tasks, keeps incomplete ones, and can reset affirmations and confessions to new defaults if you edit the function logic.

🎓 Concepts You'll Learn

localStorage data persistenceDOM selection and manipulationEvent listeners and user interactionJSON serializationDate and time handlingArray methods (push, splice, filter, forEach, some)Conditional renderingAudio playback with Tone.js

📝 Code Breakdown

preload()

preload() ensures that sounds, images, and other media are ready before setup() runs. Tone.js is a JavaScript library for creating and playing sounds—it's perfect for alarms and notifications in web apps.

function preload() {
  alarmPlayer = new Tone.Player("https://tonejs.github.io/audio/casio/kick.mp3").toDestination();
  alarmPlayer.volume.value = -10;
}
Line-by-line explanation (3 lines)

🔧 Subcomponents:

initialization Create Tone.js audio player alarmPlayer = new Tone.Player("https://tonejs.github.io/audio/casio/kick.mp3").toDestination();

Loads an audio file from a URL and creates a player that can be triggered later; toDestination() sends audio to the user's speakers

configuration Set alarm volume alarmPlayer.volume.value = -10;

Reduces the alarm volume to -10 dB so it's audible but not jarring

function preload() {
preload() is a p5.js function that runs once before setup(); use it to load heavy resources like images, sounds, or fonts
alarmPlayer = new Tone.Player("https://tonejs.github.io/audio/casio/kick.mp3").toDestination();
Creates a Tone.js Player that loads a drum kick sound from the web; .toDestination() routes the sound to the user's audio output
alarmPlayer.volume.value = -10;
Sets the player's volume to -10 dB (a standard audio unit); negative values are quieter, 0 is normal, positive values are louder

setup()

setup() is the initialization heart of every p5.js sketch. Here it connects the sketch code to the HTML DOM by selecting elements, attaching listeners, loading data, and rendering initial content. The mix of p5.js methods (select, mousePressed) and vanilla JavaScript (addEventListener) shows how p5.js smooths DOM interaction.

function setup() {
  noCanvas();

  loadData();

  resetDailyItems();

  mustDoInput = select('#must-do-task-input');
  addMustDoButton = select('#add-must-do-task-button');
  mustDoList = select('#must-do-tasks-list');
  resetDailyTasksButton = select('#reset-daily-tasks-button');

  addMustDoButton.mousePressed(addMustDoTask);
  mustDoInput.elt.addEventListener('keydown', (event) => {
    if (event.key === 'Enter') {
      addMustDoTask();
    }
  });
  resetDailyTasksButton.mousePressed(() => resetDailyItems(true));

  renderMustDoList();

  affirmationDisplay = select('#affirmation-display');
  editAffirmationButton = select('#edit-affirmation-button');

  affirmationDisplay.html(affirmationText);
  editAffirmationButton.mousePressed(editAffirmation);

  confessionDisplay = select('#confession-display');
  editConfessionButton = select('#edit-confession-button');

  confessionDisplay.html(confessionText);
  editConfessionButton.mousePressed(editConfession);

  alarmTimeInput = select('#alarm-time-input');
  alarmMessageInput = select('#alarm-message-input');
  addAlarmButton = select('#add-alarm-button');
  alarmsList = select('#alarms-list');
  testAlarmButton = select('#test-alarm-button');

  addAlarmButton.mousePressed(addAlarm);
  testAlarmButton.mousePressed(playAlarmSound);

  renderAlarmsList();

  setInterval(checkAlarms, 1000);
}
Line-by-line explanation (11 lines)

🔧 Subcomponents:

initialization Select must-do list DOM elements mustDoInput = select('#must-do-task-input');

Use p5.js's select() to find and store references to HTML elements by their IDs so the sketch can later read or modify them

event-binding Attach event listeners to buttons addMustDoButton.mousePressed(addMustDoTask);

When the button is clicked, the addMustDoTask() function runs automatically

event-binding Listen for Enter key in input mustDoInput.elt.addEventListener('keydown', (event) => { if (event.key === 'Enter') { addMustDoTask(); } });

Users can press Enter to submit a task instead of clicking the button; .elt accesses the underlying HTML element

rendering Render lists and text renderMustDoList();

Rebuilds the task list in the DOM so that any previously saved tasks appear on the screen

scheduling Start checking for triggered alarms setInterval(checkAlarms, 1000);

Every 1000 milliseconds (1 second), the checkAlarms() function runs to see if any alarms should trigger

function setup() {
setup() is a p5.js function that runs once when the sketch starts; use it to initialize variables, create elements, and attach listeners
noCanvas();
Tells p5.js not to create a drawing canvas—this app is DOM-based (HTML elements) rather than canvas-based
loadData();
Calls the loadData() function to retrieve previously saved tasks, affirmations, confessions, and alarms from the browser's localStorage
resetDailyItems();
Checks if a new day has started and, if so, resets tasks and other daily items automatically
mustDoInput = select('#must-do-task-input');
p5.js's select() finds the HTML element with id='must-do-task-input' and stores it in a variable so sketch.js can use it
addMustDoButton.mousePressed(addMustDoTask);
Attaches a 'click' listener to the button; when clicked, addMustDoTask() runs automatically
mustDoInput.elt.addEventListener('keydown', (event) => {
Listens for key presses in the input field; .elt accesses the raw HTML element to use the browser's standard addEventListener
if (event.key === 'Enter') {
Checks if the pressed key was Enter; if so, the code inside this block runs
addMustDoTask();
Calls addMustDoTask() to add the typed task, just as if the user had clicked the button
affirmationDisplay.html(affirmationText);
.html() sets the text content of the affirmation display element to the current affirmationText variable
setInterval(checkAlarms, 1000);
JavaScript's setInterval() runs a function repeatedly; this runs checkAlarms() every 1000 milliseconds to monitor for triggered alarms

draw()

In many p5.js sketches, draw() contains animation and drawing logic. This sketch uses draw() but leaves it empty because it's DOM-based rather than canvas-based. The real action happens in event listeners and helper functions that update the page when users interact with it.

function draw() {
  // No p5.js drawing here as we are building a DOM-based app.
}
Line-by-line explanation (2 lines)
function draw() {
draw() is a p5.js function that repeats 60 times per second by default; in this app it's empty because all interaction is handled by event listeners and DOM updates
// No p5.js drawing here as we are building a DOM-based app.
This comment explains why draw() is empty—the app uses HTML elements instead of canvas drawing

saveData()

localStorage is a browser API that persists small amounts of data (typically up to 5-10 MB per domain) across browser sessions. JSON.stringify converts JavaScript objects and arrays into strings that can be stored; JSON.parse reverses this. This function is called after every data change to ensure nothing is lost if the browser is closed or the page is refreshed.

🔬 Each localStorage.setItem call stores one piece of data. Notice that arrays and complex objects use JSON.stringify while simple strings don't. What happens if you comment out the line that saves tasks? Try it—your tasks will be lost when you refresh the page, but affirmations and alarms persist.

    localStorage.setItem('mustDoTasks', JSON.stringify(mustDoTasks));
    localStorage.setItem('affirmationText', affirmationText);
    localStorage.setItem('confessionText', confessionText);
    localStorage.setItem('alarms', JSON.stringify(alarms));
    localStorage.setItem('lastResetDate', lastResetDate);
function saveData() {
  try {
    localStorage.setItem('mustDoTasks', JSON.stringify(mustDoTasks));
    localStorage.setItem('affirmationText', affirmationText);
    localStorage.setItem('confessionText', confessionText);
    localStorage.setItem('alarms', JSON.stringify(alarms));
    localStorage.setItem('lastResetDate', lastResetDate);
    console.log("Data saved to localStorage.");
  } catch (e) {
    console.error("Error saving to localStorage:", e);
    alert("Could not save data. Please check your browser's localStorage settings.");
  }
}
Line-by-line explanation (10 lines)

🔧 Subcomponents:

data-persistence Save tasks array localStorage.setItem('mustDoTasks', JSON.stringify(mustDoTasks));

Converts the mustDoTasks array to a JSON string and stores it in the browser's localStorage under the key 'mustDoTasks'

data-persistence Save alarms array localStorage.setItem('alarms', JSON.stringify(alarms));

Converts the alarms array to JSON and saves it so alarms persist between browser sessions

try-catch Error handling } catch (e) { console.error("Error saving to localStorage:", e); alert("Could not save data. Please check your browser's localStorage settings."); }

If saving fails (e.g., localStorage is full or disabled), the error is caught and the user is notified with an alert

function saveData() {
Defines a helper function that saves all app data to localStorage—called after every change
try {
Starts a try-catch block so that if localStorage operations fail, the error is caught rather than crashing the app
localStorage.setItem('mustDoTasks', JSON.stringify(mustDoTasks));
JSON.stringify() converts the mustDoTasks array (an object with text and completed properties) into a JSON string, then setItem stores it under the key 'mustDoTasks'
localStorage.setItem('affirmationText', affirmationText);
Stores the affirmation text string directly (no JSON.stringify needed since it's just a string, not an array or object)
localStorage.setItem('alarms', JSON.stringify(alarms));
Converts the alarms array to JSON and saves it; each alarm has a time and optional message
localStorage.setItem('lastResetDate', lastResetDate);
Stores the last reset date (a string in YYYY-MM-DD format) so the app knows when the next daily reset should occur
console.log("Data saved to localStorage.");
Logs a success message to the browser console (visible in developer tools) for debugging
} catch (e) {
If any error occurs in the try block, the code jumps to here and e contains the error details
console.error("Error saving to localStorage:", e);
Logs the error to the console so developers can see what went wrong
alert("Could not save data. Please check your browser's localStorage settings.");
Shows an alert dialog to the user explaining that data couldn't be saved and suggesting they check browser settings

loadData()

loadData() is the inverse of saveData(). It's called once in setup() to restore any previously saved data. Notice the if checks—localStorage.getItem returns null if a key doesn't exist, so we must check before parsing or assigning. This pattern of try-catch and null-checking makes the app robust: if data is corrupted or missing, it simply continues with default values rather than crashing.

🔬 This pattern appears for every data type. The if check ensures we only parse data that exists. What happens if you comment out the if check and try to JSON.parse null? Try it—you'll get an error that stops the loading process, which is why the if check is essential.

    const storedTasks = localStorage.getItem('mustDoTasks');
    if (storedTasks) {
      mustDoTasks = JSON.parse(storedTasks);
    }
function loadData() {
  try {
    const storedTasks = localStorage.getItem('mustDoTasks');
    if (storedTasks) {
      mustDoTasks = JSON.parse(storedTasks);
    }

    const storedAffirmation = localStorage.getItem('affirmationText');
    if (storedAffirmation) {
      affirmationText = storedAffirmation;
    }

    const storedConfession = localStorage.getItem('confessionText');
    if (storedConfession) {
      confessionText = storedConfession;
    }

    const storedAlarms = localStorage.getItem('alarms');
    if (storedAlarms) {
      alarms = JSON.parse(storedAlarms);
    }

    const storedResetDate = localStorage.getItem('lastResetDate');
    if (storedResetDate) {
      lastResetDate = storedResetDate;
    }
    console.log("Data loaded from localStorage.");
  } catch (e) {
    console.error("Error loading from localStorage:", e);
  }
}
Line-by-line explanation (10 lines)

🔧 Subcomponents:

data-retrieval Load tasks from storage const storedTasks = localStorage.getItem('mustDoTasks'); if (storedTasks) { mustDoTasks = JSON.parse(storedTasks); }

Retrieves the JSON string of tasks from localStorage, and if it exists, parses it back into a JavaScript array

data-retrieval Load affirmation and confession const storedAffirmation = localStorage.getItem('affirmationText'); if (storedAffirmation) { affirmationText = storedAffirmation; }

Retrieves text data that doesn't need JSON parsing—simple strings are used directly

try-catch Error handling } catch (e) { console.error("Error loading from localStorage:", e); }

If loading fails (e.g., corrupted data), the error is logged and the app continues with default values

function loadData() {
Defines a helper function that retrieves all saved app data from localStorage—called once in setup()
try {
Starts a try-catch block so parsing errors don't crash the app
const storedTasks = localStorage.getItem('mustDoTasks');
Retrieves the JSON string stored under the key 'mustDoTasks'; returns null if nothing was saved
if (storedTasks) {
Checks if storedTasks is not null (if data actually exists in localStorage)
mustDoTasks = JSON.parse(storedTasks);
JSON.parse converts the stored JSON string back into a JavaScript array of task objects
const storedAffirmation = localStorage.getItem('affirmationText');
Retrieves the stored affirmation text; this is a plain string, not JSON
if (storedAffirmation) {
Only updates affirmationText if something was stored
affirmationText = storedAffirmation;
Directly assigns the retrieved string (no JSON.parse needed since it's already a string)
console.log("Data loaded from localStorage.");
Logs a success message to the console for debugging
} catch (e) {
If JSON.parse or any other operation fails, execution jumps here

getTodayDateString()

This utility function converts the current date into a consistent string format. The YYYY-MM-DD format is ideal for comparisons because when sorted alphabetically, dates also sort chronologically. The function is called by resetDailyItems() to determine if a new day has started.

function getTodayDateString() {
  const today = new Date();
  const year = today.getFullYear();
  const month = String(today.getMonth() + 1).padStart(2, '0');
  const day = String(today.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
}
Line-by-line explanation (6 lines)

🔧 Subcomponents:

calculation Create Date object const today = new Date();

Creates a Date object representing the current moment in time

string-formatting Format date as YYYY-MM-DD const month = String(today.getMonth() + 1).padStart(2, '0');

Extracts month, converts to string, and pads with a leading zero so single-digit months (like January as 1) become '01'

return Return formatted date string return `${year}-${month}-${day}`;

Combines year, month, and day into the YYYY-MM-DD format used to detect daily resets

function getTodayDateString() {
Defines a helper function that returns today's date as a formatted string in YYYY-MM-DD format
const today = new Date();
Creates a JavaScript Date object set to the current date and time
const year = today.getFullYear();
Extracts the 4-digit year (e.g., 2025) from the Date object
const month = String(today.getMonth() + 1).padStart(2, '0');
Gets the month (0-indexed, so January is 0), adds 1 to make it 1-indexed, converts to a string, and pads with a leading zero so January becomes '01' instead of '1'
const day = String(today.getDate()).padStart(2, '0');
Gets the day of the month (1-31), converts to string, and pads with a leading zero so day 5 becomes '05'
return `${year}-${month}-${day}`;
Returns a template string combining year, month, and day as YYYY-MM-DD (e.g., '2025-02-13')

resetDailyItems()

resetDailyItems() is called automatically in setup() and can also be triggered manually by the user clicking 'Reset Daily Tasks'. It demonstrates array filtering and mapping—two essential techniques for transforming data. The force parameter allows manual resets even before a new day, useful for testing.

🔬 The filter keeps incomplete tasks, and the map resets their completion status. What happens if you remove the map line and just use incompleteTasks directly? Try it—incomplete tasks carry forward as before, but you save a tiny bit of processing. However, this is a good habit for clarity.

    const incompleteTasks = mustDoTasks.filter(task => !task.completed);
    mustDoTasks = incompleteTasks.map(task => ({ ...task, completed: false }));
function resetDailyItems(force = false) {
  const today = getTodayDateString();

  if (force || today !== lastResetDate) {
    console.log("Daily reset triggered.");
    lastResetDate = today;

    const incompleteTasks = mustDoTasks.filter(task => !task.completed);
    mustDoTasks = incompleteTasks.map(task => ({ ...task, completed: false }));

    saveData();
    renderMustDoList();
    affirmationDisplay.html(affirmationText);
    confessionDisplay.html(confessionText);
    alert("Daily reset complete! Incomplete tasks have been carried forward.");
  }
}
Line-by-line explanation (10 lines)

🔧 Subcomponents:

conditional Check if reset is needed if (force || today !== lastResetDate) {

Resets if force is true OR if today's date differs from the last reset date (a new day has started)

array-method Filter incomplete tasks const incompleteTasks = mustDoTasks.filter(task => !task.completed);

Creates a new array containing only tasks where completed is false, discarding completed tasks

array-method Reset completion status mustDoTasks = incompleteTasks.map(task => ({ ...task, completed: false }));

Maps over incomplete tasks and ensures their completed property is explicitly false (or could be used to unflag them)

rendering Update display renderMustDoList(); affirmationDisplay.html(affirmationText); confessionDisplay.html(confessionText);

Refreshes the UI to reflect the new task list and confirm that affirmations and confessions are displayed

function resetDailyItems(force = false) {
Defines a function with a parameter force (defaults to false); if true, reset happens regardless of date; if false, reset only happens on a new day
const today = getTodayDateString();
Gets today's date as a string in YYYY-MM-DD format
if (force || today !== lastResetDate) {
Enters the reset block if force is true OR if today's date is different from the last stored reset date
console.log("Daily reset triggered.");
Logs to the console for debugging—confirms that the reset is happening
lastResetDate = today;
Updates lastResetDate to today so the next check will know a reset has already happened
const incompleteTasks = mustDoTasks.filter(task => !task.completed);
JavaScript's filter() method creates a new array containing only tasks where completed is false; completed tasks are removed
mustDoTasks = incompleteTasks.map(task => ({ ...task, completed: false }));
map() transforms each task; the spread operator ({ ...task }) copies all properties, and completed is explicitly set to false to ensure they're unchecked
saveData();
Saves the updated task list to localStorage so the reset persists
renderMustDoList();
Rebuilds the task list in the DOM so users see the updated tasks immediately
alert("Daily reset complete! Incomplete tasks have been carried forward.");
Shows a browser alert notifying the user that the reset happened

renderMustDoList()

renderMustDoList() is called whenever the task list changes (add, delete, toggle, reset). It rebuilds the entire UI from the mustDoTasks array, ensuring the page always shows the current state. This is the pattern in responsive DOM-driven apps: keep an array of data, and whenever it changes, rebuild the UI to match.

function renderMustDoList() {
  mustDoList.html('');

  mustDoTasks.forEach((task, index) => {
    const listItem = createElement('li');
    listItem.addClass(task.completed ? 'completed' : '');

    const checkbox = createCheckbox('', task.completed);
    checkbox.changed(() => toggleTaskCompletion(index));

    const taskText = createElement('span', task.text);

    const deleteButton = createButton('Delete');
    deleteButton.addClass('delete-button');
    deleteButton.mousePressed(() => deleteMustDoTask(index));

    listItem.child(checkbox);
    listItem.child(taskText);
    listItem.child(deleteButton);

    mustDoList.child(listItem);
  });
}
Line-by-line explanation (13 lines)

🔧 Subcomponents:

rendering Clear previous list mustDoList.html('');

Empties the list container so a fresh list can be built from the current data

for-loop Loop through each task mustDoTasks.forEach((task, index) => {

Iterates over every task in the mustDoTasks array; index provides each task's position

element-creation Create checkbox const checkbox = createCheckbox('', task.completed); checkbox.changed(() => toggleTaskCompletion(index));

Creates a checkbox that reflects the task's completion status; when changed, toggleTaskCompletion() is called

element-assembly Assemble list item listItem.child(checkbox); listItem.child(taskText); listItem.child(deleteButton);

Adds the checkbox, task text, and delete button as children of the list item

function renderMustDoList() {
Defines a function that rebuilds the entire task list in the DOM based on the current mustDoTasks array
mustDoList.html('');
Clears all HTML inside the mustDoList element (the <ul> tag) so we can build a fresh list
mustDoTasks.forEach((task, index) => {
JavaScript's forEach iterates over each task; task is the current task object, and index is its position in the array (0, 1, 2, ...)
const listItem = createElement('li');
p5.js's createElement('li') creates a new <li> (list item) element in the DOM
listItem.addClass(task.completed ? 'completed' : '');
Adds the CSS class 'completed' if task.completed is true, allowing CSS to style completed tasks (e.g., strikethrough)
const checkbox = createCheckbox('', task.completed);
p5.js's createCheckbox creates a checkbox; the second argument sets its initial checked state
checkbox.changed(() => toggleTaskCompletion(index));
Attaches a listener so when the user checks or unchecks the box, toggleTaskCompletion(index) is called
const taskText = createElement('span', task.text);
Creates a <span> element containing the task's text
const deleteButton = createButton('Delete');
p5.js's createButton creates a clickable button labeled 'Delete'
deleteButton.addClass('delete-button');
Adds the CSS class 'delete-button' so CSS can style it (e.g., color, size)
deleteButton.mousePressed(() => deleteMustDoTask(index));
Attaches a listener so clicking the button calls deleteMustDoTask(index)
listItem.child(checkbox); listItem.child(taskText); listItem.child(deleteButton);
Adds the checkbox, task text, and delete button as children of the list item, building the structure: <li><checkbox> <text> <button></li>
mustDoList.child(listItem);
Adds the completed list item to the mustDoList container so it appears on the page

addMustDoTask()

addMustDoTask() demonstrates the input-validate-add-save-render pattern used throughout this app. Always validate user input before processing it, always save after changes, and always re-render the UI. This ensures the page stays in sync with the underlying data.

function addMustDoTask() {
  const taskText = mustDoInput.value().trim();

  if (taskText) {
    mustDoTasks.push({ text: taskText, completed: false });
    mustDoInput.value('');
    saveData();
    renderMustDoList();
  }
}
Line-by-line explanation (7 lines)

🔧 Subcomponents:

input-reading Get user input const taskText = mustDoInput.value().trim();

Reads the text from the input field and removes leading/trailing whitespace with trim()

conditional Validate non-empty if (taskText) {

Only proceeds if taskText is not empty, preventing blank tasks from being added

data-mutation Add task to array mustDoTasks.push({ text: taskText, completed: false });

Adds a new task object with text and completed properties to the mustDoTasks array

ui-update Clear input field mustDoInput.value('');

Empties the input so the user can immediately type a new task

function addMustDoTask() {
Defines a function called when the user clicks 'Add Task' or presses Enter
const taskText = mustDoInput.value().trim();
Gets the text from the input field with .value(), then .trim() removes spaces at the beginning and end
if (taskText) {
Checks if taskText is not empty (truthy); prevents adding blank tasks
mustDoTasks.push({ text: taskText, completed: false });
Adds a new object to the mustDoTasks array with the task's text and a completed flag set to false
mustDoInput.value('');
Sets the input field's value to an empty string, clearing it for the next task
saveData();
Saves the updated mustDoTasks array to localStorage so it persists
renderMustDoList();
Rebuilds the task list in the DOM to display the new task

toggleTaskCompletion()

toggleTaskCompletion() is a small but important function. It demonstrates bounds-checking (validating that an index is safe) and the boolean NOT operator (!). The pattern of validate → modify → save → render appears throughout this app.

🔬 The index check prevents errors. What if you comment out the if statement and try to click checkboxes? Try it—you'll likely see no errors, but if the index is invalid, you'll modify a non-existent task. The safeguard is essential for robust code.

  if (index >= 0 && index < mustDoTasks.length) {
    mustDoTasks[index].completed = !mustDoTasks[index].completed;
function toggleTaskCompletion(index) {
  if (index >= 0 && index < mustDoTasks.length) {
    mustDoTasks[index].completed = !mustDoTasks[index].completed;
    saveData();
    renderMustDoList();
  }
}
Line-by-line explanation (5 lines)

🔧 Subcomponents:

conditional Validate index bounds if (index >= 0 && index < mustDoTasks.length) {

Ensures the index is valid (not negative, not beyond the array length) to prevent accessing non-existent tasks

boolean-operation Toggle completed status mustDoTasks[index].completed = !mustDoTasks[index].completed;

Flips the boolean: true becomes false, false becomes true

function toggleTaskCompletion(index) {
Defines a function that flips a task's completed status; called when a checkbox is changed
if (index >= 0 && index < mustDoTasks.length) {
Validates the index: checks that it's not negative AND that it's less than the array length, ensuring the task exists
mustDoTasks[index].completed = !mustDoTasks[index].completed;
The ! operator flips the boolean: if completed is true, it becomes false; if false, it becomes true
saveData();
Saves the updated task to localStorage
renderMustDoList();
Rebuilds the task list so the UI reflects the new completion status (CSS class changes to show strikethrough, etc.)

deleteMustDoTask()

deleteMustDoTask() introduces confirm(), a browser API that shows a dialog and returns true if the user clicks OK, false if they click Cancel. It also uses splice(index, 1) to remove a single element from an array by index. This pattern protects users from accidental deletions.

function deleteMustDoTask(index) {
  if (index >= 0 && index < mustDoTasks.length) {
    if (confirm(`Are you sure you want to delete "${mustDoTasks[index].text}"?`)) {
      mustDoTasks.splice(index, 1);
      saveData();
      renderMustDoList();
    }
  }
}
Line-by-line explanation (6 lines)

🔧 Subcomponents:

conditional Validate index if (index >= 0 && index < mustDoTasks.length) {

Ensures the index is valid before attempting to delete

user-confirmation Ask user confirmation if (confirm(`Are you sure you want to delete "${mustDoTasks[index].text}"?`)) {

Shows a browser dialog asking the user to confirm; only proceeds if they click OK

array-mutation Remove from array mustDoTasks.splice(index, 1);

Removes 1 element from the array starting at the given index

function deleteMustDoTask(index) {
Defines a function called when the user clicks the Delete button for a task
if (index >= 0 && index < mustDoTasks.length) {
Validates the index to ensure the task exists
if (confirm(`Are you sure you want to delete "${mustDoTasks[index].text}"?`)) {
Shows a browser confirmation dialog with the task's text; if the user clicks OK, the outer if is true and deletion proceeds
mustDoTasks.splice(index, 1);
JavaScript's splice(index, 1) removes 1 element starting at the given index; this permanently removes the task from the array
saveData();
Saves the updated array to localStorage
renderMustDoList();
Rebuilds the task list to reflect the deletion

editAffirmation()

editAffirmation() uses the browser's prompt() API to get text input. Unlike confirm() which returns true/false, prompt() returns the user's text or null if they cancel. The check for !== null is essential because you can't safely trim() null.

function editAffirmation() {
  const newAffirmation = prompt("Edit your daily affirmation:", affirmationText);
  if (newAffirmation !== null) {
    affirmationText = newAffirmation.trim();
    affirmationDisplay.html(affirmationText);
    saveData();
  }
}
Line-by-line explanation (6 lines)

🔧 Subcomponents:

user-input Show prompt dialog const newAffirmation = prompt("Edit your daily affirmation:", affirmationText);

Shows a browser dialog asking the user to edit the affirmation; the second argument pre-fills the dialog with the current text

conditional Check if user cancelled if (newAffirmation !== null) {

Returns null if the user clicked Cancel; only proceeds if they clicked OK

data-update Update affirmation affirmationText = newAffirmation.trim();

Stores the new affirmation text after removing whitespace

function editAffirmation() {
Defines a function called when the user clicks 'Edit Affirmation'
const newAffirmation = prompt("Edit your daily affirmation:", affirmationText);
Shows a browser prompt dialog with the message and pre-fills it with the current affirmationText; returns the new text or null if cancelled
if (newAffirmation !== null) {
Checks if newAffirmation is not null (i.e., the user clicked OK, not Cancel)
affirmationText = newAffirmation.trim();
Updates the global affirmationText variable with the trimmed new text
affirmationDisplay.html(affirmationText);
.html() sets the content of the affirmation display element to the new text, updating the page immediately
saveData();
Saves the new affirmation to localStorage

editConfession()

editConfession() mirrors editAffirmation(). The function demonstrates how prompt() can be used for open-ended text input. Both functions use the same pattern: prompt → null-check → update → save → re-render.

function editConfession() {
  const newConfession = prompt("Edit your daily confession:", confessionText);
  if (newConfession !== null) {
    confessionText = newConfession.trim();
    confessionDisplay.html(confessionText);
    saveData();
  }
}
Line-by-line explanation (6 lines)

🔧 Subcomponents:

user-input Show prompt dialog const newConfession = prompt("Edit your daily confession:", confessionText);

Shows a prompt dialog pre-filled with the current confession text

conditional Check if user cancelled if (newConfession !== null) {

Only updates if the user clicked OK

function editConfession() {
Defines a function called when the user clicks 'Edit Confession'
const newConfession = prompt("Edit your daily confession:", confessionText);
Shows a browser prompt dialog pre-filled with the current confession text
if (newConfession !== null) {
Checks if the user clicked OK (not Cancel)
confessionText = newConfession.trim();
Updates the global confessionText variable with the trimmed new text
confessionDisplay.html(confessionText);
Updates the display element with the new confession text
saveData();
Saves the new confession to localStorage

renderAlarmsList()

renderAlarmsList() demonstrates array sorting and conditional rendering. The sort uses a comparison function and localeCompare for string comparison. The ternary operator handles displaying a message only if it exists. This is similar to renderMustDoList() but adapted for alarms.

🔬 The sort line organizes alarms chronologically. What happens if you comment it out or reverse the comparison? Try reversing it to sort(a, b) => b.time.localeCompare(a.time)—alarms now appear in reverse order (latest first).

  alarms.sort((a, b) => a.time.localeCompare(b.time));

  alarms.forEach((alarm, index) => {
function renderAlarmsList() {
  alarmsList.html('');

  alarms.sort((a, b) => a.time.localeCompare(b.time));

  alarms.forEach((alarm, index) => {
    const listItem = createElement('li');

    const alarmInfo = createDiv();
    alarmInfo.addClass('alarm-info');

    const alarmTime = createElement('span', alarm.time);
    alarmTime.addClass('alarm-time');

    const alarmMessage = createElement('span', alarm.message ? `"${alarm.message}"` : 'No message');
    alarmMessage.addClass('alarm-message');

    alarmInfo.child(alarmTime);
    alarmInfo.child(alarmMessage);

    const deleteButton = createButton('Delete');
    deleteButton.addClass('delete-button');
    deleteButton.mousePressed(() => deleteAlarm(index));

    listItem.child(alarmInfo);
    listItem.child(deleteButton);

    alarmsList.child(listItem);
  });
}
Line-by-line explanation (9 lines)

🔧 Subcomponents:

rendering Clear previous list alarmsList.html('');

Empties the alarms list container

sorting Sort alarms by time alarms.sort((a, b) => a.time.localeCompare(b.time));

Sorts the alarms array by time in ascending order so they appear chronologically

for-loop Loop through alarms alarms.forEach((alarm, index) => {

Iterates over each alarm to create a list item

element-assembly Build alarm list item alarmInfo.child(alarmTime); alarmInfo.child(alarmMessage); ... listItem.child(alarmInfo);

Assembles the alarm time, message, and delete button into a structured list item

function renderAlarmsList() {
Defines a function that rebuilds the alarms list in the DOM
alarmsList.html('');
Clears all HTML inside the alarms list container
alarms.sort((a, b) => a.time.localeCompare(b.time));
JavaScript's sort() method with a comparison function sorts the alarms by time; localeCompare() compares strings alphabetically, which works for HH:MM format
alarms.forEach((alarm, index) => {
Loops through each alarm in the sorted array
const alarmTime = createElement('span', alarm.time);
Creates a <span> containing the alarm's time (e.g., '14:30')
const alarmMessage = createElement('span', alarm.message ? `"${alarm.message}"` : 'No message');
Creates a span showing the alarm's message if it exists, otherwise shows 'No message'; the ternary operator (? :) makes this decision
alarmInfo.child(alarmTime); alarmInfo.child(alarmMessage);
Adds the time and message spans as children of the alarmInfo div
deleteButton.mousePressed(() => deleteAlarm(index));
When the delete button is clicked, deleteAlarm(index) is called
alarmsList.child(listItem);
Adds the completed list item to the alarms list on the page

addAlarm()

addAlarm() introduces array.some(), a higher-order function that tests whether at least one element satisfies a condition. It's more elegant than looping manually. The function also demonstrates data validation: checking for required fields and preventing duplicates—both essential patterns for robust apps.

function addAlarm() {
  const time = alarmTimeInput.value();
  const message = alarmMessageInput.value().trim();

  if (time) {
    if (alarms.some(alarm => alarm.time === time)) {
      alert("An alarm already exists at this time. Please choose a different time.");
      return;
    }

    alarms.push({ time: time, message: message });
    alarmTimeInput.value('');
    alarmMessageInput.value('');
    saveData();
    renderAlarmsList();
    console.log("Alarm added:", time, message);
  } else {
    alert("Please set a time for the alarm.");
  }
}
Line-by-line explanation (13 lines)

🔧 Subcomponents:

input-reading Get time and message const time = alarmTimeInput.value(); const message = alarmMessageInput.value().trim();

Reads the time (from HTML time input) and optional message from the form

conditional Validate time provided if (time) {

Only proceeds if a time is set; shows an alert if not

conditional Check for duplicate alarms if (alarms.some(alarm => alarm.time === time)) { alert("An alarm already exists at this time. Please choose a different time."); return; }

Uses array.some() to check if an alarm with the same time already exists; prevents duplicates

data-mutation Add alarm to array alarms.push({ time: time, message: message });

Adds a new alarm object with time and message to the alarms array

function addAlarm() {
Defines a function called when the user clicks 'Add Alarm'
const time = alarmTimeInput.value();
Reads the time from the HTML time input (format: HH:MM from type='time')
const message = alarmMessageInput.value().trim();
Reads the optional message and trims whitespace
if (time) {
Checks if a time was provided; alerts the user if not
if (alarms.some(alarm => alarm.time === time)) {
JavaScript's array.some() returns true if at least one element matches the condition; here it checks if any alarm has the same time
alert("An alarm already exists at this time. Please choose a different time.");
Alerts the user that a duplicate time was attempted
return;
Exits the function early without adding the alarm
alarms.push({ time: time, message: message });
Adds a new alarm object to the alarms array with the provided time and message
alarmTimeInput.value(''); alarmMessageInput.value('');
Clears both input fields so the user can immediately set another alarm
saveData();
Saves the updated alarms array to localStorage
renderAlarmsList();
Rebuilds the alarms list to display the new alarm
console.log("Alarm added:", time, message);
Logs to the console for debugging
} else { alert("Please set a time for the alarm."); }
If no time is provided, alerts the user

deleteAlarm()

deleteAlarm() mirrors deleteMustDoTask()—validate, confirm, delete, save, re-render. The pattern is consistent throughout the app.

function deleteAlarm(index) {
  if (index >= 0 && index < alarms.length) {
    if (confirm(`Are you sure you want to delete the alarm at ${alarms[index].time}?`)) {
      alarms.splice(index, 1);
      saveData();
      renderAlarmsList();
      console.log("Alarm deleted.");
    }
  }
}
Line-by-line explanation (7 lines)

🔧 Subcomponents:

conditional Validate index if (index >= 0 && index < alarms.length) {

Ensures the index is valid before attempting to delete

user-confirmation Ask for confirmation if (confirm(`Are you sure you want to delete the alarm at ${alarms[index].time}?`)) {

Shows a confirmation dialog with the alarm's time

array-mutation Remove alarm from array alarms.splice(index, 1);

Removes 1 element (the alarm) from the array

function deleteAlarm(index) {
Defines a function called when the user clicks the Delete button for an alarm
if (index >= 0 && index < alarms.length) {
Validates that the index is within bounds
if (confirm(`Are you sure you want to delete the alarm at ${alarms[index].time}?`)) {
Shows a confirmation dialog showing the alarm's time; only proceeds if the user clicks OK
alarms.splice(index, 1);
Removes the alarm from the array
saveData();
Saves the updated alarms array to localStorage
renderAlarmsList();
Rebuilds the alarms list to reflect the deletion
console.log("Alarm deleted.");
Logs to the console

playAlarmSound()

playAlarmSound() demonstrates the Tone.js library's Player API. The check for player.state allows different behavior depending on whether the sound is already playing. Tone.start() is a browser requirement—without it, audio won't play the first time. This function is called both by the Test Alarm button and automatically by checkAlarms() when an alarm triggers.

function playAlarmSound() {
  if (alarmPlayer.state === 'stopped') {
    Tone.start();
    alarmPlayer.start();
    console.log("Alarm sound played.");
  } else {
    alarmPlayer.stop();
    alarmPlayer.start();
    console.log("Alarm sound restarted.");
  }
}
Line-by-line explanation (8 lines)

🔧 Subcomponents:

conditional Check player state if (alarmPlayer.state === 'stopped') {

Determines whether the player is currently stopped or already playing

initialization Start Tone.js context Tone.start();

Initializes Tone.js's audio context (required by modern browsers before playing audio)

else-clause Stop and restart if playing } else { alarmPlayer.stop(); alarmPlayer.start();

If the player is already playing, stops it and restarts to allow immediate replaying

function playAlarmSound() {
Defines a function called when the user clicks 'Test Alarm' or when an alarm is triggered
if (alarmPlayer.state === 'stopped') {
Checks if the Tone.js player is in a stopped state (not currently playing)
Tone.start();
Initializes Tone.js's audio context; modern browsers require this before playing audio, usually triggered by user interaction
alarmPlayer.start();
Starts playing the alarm sound
console.log("Alarm sound played.");
Logs to the console
} else {
If the player is not stopped (i.e., it's already playing)
alarmPlayer.stop();
Stops the currently playing sound
alarmPlayer.start();
Immediately restarts it, allowing the sound to play again

checkAlarms()

checkAlarms() is the scheduling engine of the app. It runs every 1000 milliseconds (1 second) to monitor if any alarm should trigger. The function formats the current time to match the HH:MM format stored in alarms, then compares them. When a match is found, it plays a sound and shows an alert. This is a simple polling approach—more sophisticated apps might use the Web Notifications API or service workers for better battery efficiency.

🔬 The time formatting matches the HH:MM format of alarms. What happens if you remove the padStart calls? Try it—if the current time is 5:30 AM, currentTime becomes '5:30' instead of '05:30', which won't match an alarm set at '05:30'. This shows why consistent formatting is crucial.

  const currentHour = String(now.getHours()).padStart(2, '0');
  const currentMinute = String(now.getMinutes()).padStart(2, '0');
  const currentTime = `${currentHour}:${currentMinute}`;

  alarms.forEach((alarm, index) => {
    if (alarm.time === currentTime) {
function checkAlarms() {
  const now = new Date();
  const currentHour = String(now.getHours()).padStart(2, '0');
  const currentMinute = String(now.getMinutes()).padStart(2, '0');
  const currentTime = `${currentHour}:${currentMinute}`;

  alarms.forEach((alarm, index) => {
    if (alarm.time === currentTime) {
      console.log(`Alarm triggered at ${alarm.time}! Message: ${alarm.message}`);
      playAlarmSound();
      alert(`Alarm! It's ${alarm.time}. ${alarm.message || "Time to do something!"}`);
    }
  });
}
Line-by-line explanation (10 lines)

🔧 Subcomponents:

time-calculation Get current time as HH:MM const now = new Date(); const currentHour = String(now.getHours()).padStart(2, '0'); const currentMinute = String(now.getMinutes()).padStart(2, '0'); const currentTime = `${currentHour}:${currentMinute}`;

Creates a Date object, extracts hours and minutes, formats them as HH:MM strings, and combines them

for-loop Check each alarm alarms.forEach((alarm, index) => {

Loops through all alarms to check if any should trigger

conditional Check time match if (alarm.time === currentTime) {

Compares the alarm's time to the current time; if they match, the alarm triggers

action Trigger alarm playAlarmSound(); alert(`Alarm! It's ${alarm.time}. ${alarm.message || "Time to do something!"}`);

Plays the alarm sound and shows an alert with the time and message

function checkAlarms() {
Defines a function called every second (set by setInterval in setup) to monitor for triggered alarms
const now = new Date();
Creates a Date object representing the current moment
const currentHour = String(now.getHours()).padStart(2, '0');
Gets the hour (0-23), converts to string, and pads with a leading zero so 5 AM becomes '05'
const currentMinute = String(now.getMinutes()).padStart(2, '0');
Gets the minute (0-59), converts to string, and pads with a zero so minute 5 becomes '05'
const currentTime = `${currentHour}:${currentMinute}`;
Combines hour and minute into HH:MM format for comparison
alarms.forEach((alarm, index) => {
Loops through each alarm in the array
if (alarm.time === currentTime) {
Checks if this alarm's time matches the current time exactly
console.log(`Alarm triggered at ${alarm.time}! Message: ${alarm.message}`);
Logs to the console for debugging
playAlarmSound();
Calls playAlarmSound() to play the alarm audio
alert(`Alarm! It's ${alarm.time}. ${alarm.message || "Time to do something!"}`);
Shows a browser alert with the time and message; if no message was provided, shows a default message

windowResized()

windowResized() is a p5.js lifecycle function that runs when the browser is resized. In canvas-based sketches, you typically call resizeCanvas(windowWidth, windowHeight) here. In this DOM-based app, it's empty because CSS flexbox and media queries handle responsiveness automatically. The function exists as a placeholder—it's p5.js convention to include it even if unused.

function windowResized() {
  // Since we're using DOM elements and CSS for layout,
  // p5.js's resizeCanvas is not needed. The CSS media queries handle responsiveness.
}
Line-by-line explanation (3 lines)
function windowResized() {
A p5.js function that runs whenever the browser window is resized
// Since we're using DOM elements and CSS for layout,
This is a comment explaining why the function is empty
// p5.js's resizeCanvas is not needed. The CSS media queries handle responsiveness.
Since the app uses HTML/CSS rather than canvas, the browser's CSS automatically handles responsive layouts; no p5.js canvas resizing is needed

📦 Key Variables

mustDoTasks array

Stores an array of task objects, each with text and completed properties; tracks the user's daily must-do items

let mustDoTasks = [{ text: 'Morning meditation', completed: false }];
affirmationText string

Stores the current daily affirmation that the user can edit and view

let affirmationText = 'Thank you Baba for this beautiful day...';
confessionText string

Stores the current daily confession or reflection that the user can edit and view

let confessionText = 'I confess my mistakes and shortcomings...';
alarms array

Stores an array of alarm objects, each with time (HH:MM) and optional message properties; scheduled alarms are stored here

let alarms = [{ time: '06:30', message: 'Wake up!' }];
lastResetDate string

Stores the date of the last daily reset in YYYY-MM-DD format; used to detect when a new day starts

let lastResetDate = '2025-02-13';
alarmPlayer Tone.Player

A Tone.js Player object that loads and plays the alarm sound file when triggered

let alarmPlayer; // Initialized in preload()
mustDoInput p5.Element (input)

A p5.js wrapper around the HTML input element where users type new tasks

let mustDoInput; // Selected in setup()
addMustDoButton p5.Element (button)

A p5.js wrapper around the 'Add Task' button HTML element

let addMustDoButton; // Selected in setup()
mustDoList p5.Element (ul)

A p5.js wrapper around the <ul> (unordered list) that displays all tasks

let mustDoList; // Selected in setup()
resetDailyTasksButton p5.Element (button)

A p5.js wrapper around the 'Reset Daily Tasks' button

let resetDailyTasksButton; // Selected in setup()
affirmationDisplay p5.Element (p)

A p5.js wrapper around the paragraph element that displays the daily affirmation

let affirmationDisplay; // Selected in setup()
editAffirmationButton p5.Element (button)

A p5.js wrapper around the 'Edit Affirmation' button

let editAffirmationButton; // Selected in setup()
confessionDisplay p5.Element (p)

A p5.js wrapper around the paragraph that displays the daily confession

let confessionDisplay; // Selected in setup()
editConfessionButton p5.Element (button)

A p5.js wrapper around the 'Edit Confession' button

let editConfessionButton; // Selected in setup()
alarmTimeInput p5.Element (input type='time')

A p5.js wrapper around the HTML time input where users set an alarm's time

let alarmTimeInput; // Selected in setup()
alarmMessageInput p5.Element (input type='text')

A p5.js wrapper around the text input where users optionally set an alarm's message

let alarmMessageInput; // Selected in setup()
addAlarmButton p5.Element (button)

A p5.js wrapper around the 'Add Alarm' button

let addAlarmButton; // Selected in setup()
alarmsList p5.Element (ul)

A p5.js wrapper around the <ul> that displays all alarms

let alarmsList; // Selected in setup()
testAlarmButton p5.Element (button)

A p5.js wrapper around the 'Test Alarm Sound' button

let testAlarmButton; // Selected in setup()

🔧 Potential Improvements (8)

Here are some ways this code could be enhanced:

FEATURE checkAlarms()

The alarm triggers every second for a full minute once the time matches (e.g., 06:30:00 through 06:30:59), causing repeated alerts and sounds

💡 Add a 'triggered' flag to each alarm to prevent repeating in the same minute. Mark it triggered when the minute is reached, and reset it when the minute changes. Alternatively, use the Web Notifications API for a less intrusive notification.

BUG resetDailyItems()

The daily reset checks the date in setup() but not during the app's lifetime, so if the user keeps the app open past midnight, it won't reset until they refresh

💡 Add a daily check in draw() or use setInterval to check getTodayDateString() every minute and call resetDailyItems() if the date changes. Or trigger the check on the first interaction after midnight.

PERFORMANCE renderMustDoList() and renderAlarmsList()

Both functions clear and rebuild the entire list every time, even if only one item changed—inefficient for large lists

💡 Instead of clearing and rebuilding, update only the changed DOM elements. Or use a virtual DOM approach, comparing the old and new states before rendering.

STYLE Global scope

All DOM element variables are declared globally, making the code harder to maintain and test

💡 Consider wrapping the app in a class or a module pattern to encapsulate state. This improves code organization and makes it easier to reset or reinitialize the app.

FEATURE addAlarm()

Users can only set one alarm per unique time; if they want multiple alarms at 06:30 with different messages, the app rejects it

💡 Allow duplicate times but show them with unique IDs. Or allow time ranges (e.g., 'every day' vs. 'once') to make the alarm system more flexible.

BUG loadData()

If localStorage contains corrupted JSON, JSON.parse will throw an error, and all data silently fails to load

💡 Wrap individual JSON.parse calls in try-catch blocks to gracefully handle corrupted data for specific items while still loading others. Log detailed errors for debugging.

FEATURE resetDailyItems()

Completed tasks are discarded at daily reset; users lose a record of what they accomplished yesterday

💡 Store completed tasks in a separate 'history' array or export them as JSON. Let users view past accomplishments for motivation and tracking progress over time.

ACCESSIBILITY HTML structure

The app lacks ARIA labels and semantic HTML structure, making it difficult for screen reader users

💡 Add aria-labels to buttons, use semantic elements like <button> instead of <div>, and provide alt text for any visual indicators. Test with a screen reader.

🔄 Code Flow

Code flow showing preload, setup, draw, savedata, loaddata, gettoday, resetdailyitems, rendermustdolist, addmustdotask, toggletaskcompletion, deletemustdotask, editaffirmation, editconfession, renderalarmslist, addalarm, deletealarm, playalarmsound, checkalarms, windowresized

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

graph TD start[Start] --> setup[setup] setup --> preload[preload] preload --> select-must-do-elements[select-must-do-elements] preload --> create-player[create-player] create-player --> set-volume[set-volume] setup --> load-tasks[load-tasks] load-tasks --> load-error-handling[load-error-handling] load-error-handling --> load-text-data[load-text-data] setup --> resetdailyitems[resetdailyitems] resetdailyitems --> check-reset-needed[check-reset-needed] check-reset-needed -->|true| reset-completion[reset-completion] reset-completion --> update-ui[update-ui] setup --> initial-render[initial-render] initial-render --> update-ui setup --> attach-button-listeners[attach-button-listeners] attach-button-listeners --> attach-enter-key[attach-enter-key] setup --> start-alarm-check[start-alarm-check] start-alarm-check --> checkalarms[checkalarms] checkalarms --> get-current-time[get-current-time] get-current-time --> check-each-alarm[check-each-alarm] check-each-alarm --> loop-alarms[loop-alarms] loop-alarms --> time-match[time-match] time-match -->|true| trigger-alarm[trigger-alarm] trigger-alarm --> playalarmsound[playalarmsound] playalarmsound --> check-player-state[check-player-state] check-player-state -->|stopped| start-tone-context[start-tone-context] start-tone-context --> restart-sound[restart-sound] restart-sound --> playalarmsound check-player-state -->|playing| restart-sound setup --> windowresized[windowresized] draw[draw loop] --> draw click setup href "#fn-setup" click preload href "#fn-preload" click select-must-do-elements href "#sub-select-must-do-elements" click create-player href "#sub-create-player" click set-volume href "#sub-set-volume" click load-tasks href "#sub-load-tasks" click load-error-handling href "#sub-load-error-handling" click load-text-data href "#sub-load-text-data" click resetdailyitems href "#fn-resetdailyitems" click check-reset-needed href "#sub-check-reset-needed" click reset-completion href "#sub-reset-completion" click update-ui href "#sub-update-ui" click initial-render href "#sub-initial-render" click attach-button-listeners href "#sub-attach-button-listeners" click attach-enter-key href "#sub-attach-enter-key" click start-alarm-check href "#sub-start-alarm-check" click checkalarms href "#fn-checkalarms" click get-current-time href "#sub-get-current-time" click check-each-alarm href "#sub-check-each-alarm" click loop-alarms href "#sub-loop-alarms" click time-match href "#sub-time-match" click trigger-alarm href "#sub-trigger-alarm" click playalarmsound href "#fn-playalarmsound" click check-player-state href "#sub-check-player-state" click start-tone-context href "#sub-start-tone-context" click restart-sound href "#sub-restart-sound" click windowresized href "#fn-windowresized"

❓ Frequently Asked Questions

What visual elements does the p5.js sketch Sketch 2026-02-13 04:38 generate?

The sketch primarily utilizes DOM elements for user interaction, rather than creating traditional visual graphics on a canvas.

How can users interact with Sketch 2026-02-13 04:38?

Users can add tasks to a must-do list, set alarms with messages, and edit affirmations and confessions through various input fields and buttons.

What creative coding concepts are showcased in this p5.js sketch?

The sketch demonstrates the use of localStorage for data persistence and integrates audio playback with Tone.js for alarm notifications.

Preview

Sketch 2026-02-13 04:38 - p5.js creative coding sketch preview
Sketch Preview
Code flow diagram showing the structure of Sketch 2026-02-13 04:38 - Code flow showing preload, setup, draw, savedata, loaddata, gettoday, resetdailyitems, rendermustdolist, addmustdotask, toggletaskcompletion, deletemustdotask, editaffirmation, editconfession, renderalarmslist, addalarm, deletealarm, playalarmsound, checkalarms, windowresized
Code Flow Diagram