From 9422ba08951399d38678c1045f424d2bd6028a4c Mon Sep 17 00:00:00 2001 From: Johnny Huynh <115180134+Jextic@users.noreply.github.com> Date: Tue, 4 Aug 2026 14:04:58 -0700 Subject: [PATCH 01/11] First draft of issue proposal I propose an issue to defer the default canvas creation so that it's less likely for it to be created and immediately deleted. --- Submissions_SOSE_2026/submissions.md | 49 +++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/Submissions_SOSE_2026/submissions.md b/Submissions_SOSE_2026/submissions.md index c3e25bb..2b811e8 100644 --- a/Submissions_SOSE_2026/submissions.md +++ b/Submissions_SOSE_2026/submissions.md @@ -6,14 +6,13 @@ ## Team Details* 👥 -**Mentor's Name:** +**Mentor's Name:** Jim Anderson **Team Members:** | GitHub Username | Full Name | |---|---| -| @username | Full Name | -| @username | Full Name | +| @Jextic | Johnny Huynh | --- @@ -21,11 +20,13 @@ *Details about the first issue assigned to your team.* -- Link to Issue: https://github.com/processing/... +- **Link to Issue**: [github.com/processing/p5.js/issues/8922](https://github.com/processing/p5.js/issues/8922) -- Issue Title: +- **Issue Title**: [p5.js 2.0+ Bug Report]: Loading indication + #8922 -- Repository: e.g. p5.js, p5.js-web-editor + +- **Repository**: p5.js --- @@ -33,34 +34,53 @@ *3–5 sentences. What is the idea, why does it matter, and what do you plan to do?* +In p5.js v2.0+, a default canvas is created as a guard in case the user calls on drawing methods before defining a canvas. More often than not, users will define their own canvas using `createCanvas()` which destroys the default canvas and creates a new canvas. This process seems redundant, can waste memory if the user is switching from 2D to WebGL context, and can cause a visual flicker when the default canvas is being replaced with the new one. I propose deferring the default canvas creation until right after setup() is completed or until it is explicitly needed by using a canvas tracking variable, getter functions to guard against edge cases, and a check for if a canvas was created. --- ## Problem Statement* 📑 *What problem are you solving and who is affected by it?* +The resources that are used to generate the default canvas would be wasted if the canvas is usually deleted right after. It also doesn't occur with just users creating a new canvas. The default canvas has a 2D rendering context but there are many users who want to create a canvas with 3D/WebGL context. As far as I know, canvas contexts can't be changed from 2D to 3D. It is required to create a new canvas for 3D visual artworks which will inevitably destroy the default canvas. + +The p5.js editor makes the default canvas basically invisible by setting setting the canvas background to the same color as the preview color (when the user changes the theme to dark mode or high contrast mode). However, p5.js sketches might also be embedded in other websites, such as blogs or portfolio websites. If the webpage loads slowly because of asset loading or if the html background of the webpage is not monochromic, a visual flicker is more likely to occur and will be more noticeable. Users with low-end devices or users in heavy network traffic areas are also likely to experience this visual flicker if they run content-heavy sketches. To improve inclusivity and accessibility, resolving the issue of unnecessary resource allocation will improve user experience, especially for low-end device users. + --- ## Proposed Solution* 💡 *High-level description of your approach and why you chose it.* +I propose to defer the canvas creation until it is explicitly needed. In p5.js/src/core/main.js, a 100x100 canvas is created in `async #_setup()`. Users also usually create a canvas in their sketch code inside of `function setup() {...}`. The default canvas created during `async #_setup()` will be removed and a canvas tracking boolean (for example, `this._canvasWasCreated = false`) will declared in the constructor to track if the the user has defined a canvas in their sketch. Since the canvas creation is done inside p5.js/src/core/rendering.js, `fn.createCanvas` and `fn.noCanvas()` can be updated to set the boolean to true. After `await context.setup()` completes in `async #_setup()`, p5 will check the canvas tracking boolean and if it is false, that means the user didn't define their own canvas so the default canvas will be created. If it is true, that means the user already defined their own canvas so there is no need to create a default canvas. + +It's very possible that p5.js beginner's might call on drawing functions, like `background()` or `circle`, or read canvas properties in the `functio setup() {...}` in their sketch code. To handle these edge cases, a helper function (like `this._canvasExists()`) will be implemented to check the canvas tracking boolean. If the boolean is false, the default canvas will be created immediately to prevent any canvas errors or crashes. Getter functions will be added/modifed for functions like `canvas` and `drawingContext` so that if the tracking the helper function will be called on and handle the relevant function calls. This will guaratee that early draw function calls and any addons inspecting canvas properties will still be compatible. + +Since the tracking boolean will is declared in the constructor, that means that the proposed solution should work well with instance mode. If multiple sketches are created, they should each have their own canvas tracking boolean. From what I've seen as well, the internally registered addons should not be affected since the addons primarily use the presetup and postsetup lifecycle hooks. I'm not taking into account loading.js since our team is still working on it and we are still looking for a solution to perfect how the loading indicator will appear. + --- ## Research on old issues* 🔭 *If there are existing open issues that align with or validate your proposed idea, reference them here. Your proposal may also help revive or advance work that has stalled. If no directly related issue exists, demonstrate that you have researched the project's backlog by identifying similar or relevant issues. Include links to those issues and briefly explain.* +- [Issue #8922: \[p5.js 2.0+ Bug Report\]: Loading indication](https://github.com/processing/p5.js/issues/8922): +This was the previous issue that our team worked on (and are still improving on). Working on this helped me learn about lifecycle hooks and was what intrigued me to look more into the how the canvas is created. We were thinking about creating a temporary canvas on top of the default/user canvas so the indicator would appear at the center of that canvas. This issue proposal was thought of when we were determining how we would approach the placement of the loading indicator. + +- [Issue #177: createCanvas: problem with the default canvas](https://github.com/processing/p5.js/issues/177): +After looking through the issues for quite a while, I found that this issue was discussed a long time ago. That means that this issue is one that the maintainers have already looked into and found a patch a long time ago. However, this solution is over a decade old and the p5.js has evolved a lot of the years. Simply resizing the default canvas instead of destroying/replacing wouldn't work since we have different canvases as well. We can't resize a canvas with 2D context into canvas with 3D WebGL context. Additionally, resizing the canvas does nothing if the user calls on `noCanvas()` since the default canvas will still be created and immediately destroyed. Modern p5.js is much different from p5.js back then so that's why I propose to defer the canvas creation until it is necessary instead of resizing the canvas. + + + ## Impact* 🛠️ *Select all that apply and add a one-line explanation for each.* - [ ] **Feature Implementation** — -- [ ] **Bug Fix** — -- [ ] **Performance** — +- [X] **Bug Fix** — Ensures that the visual flicker won't occur and won't affect page layouts. +- [X] **Performance** — Saves memory since it'll avoid an unnecessary creation of the default canvvas. - [ ] **Scalability** — - [ ] **Documentation** — -- [ ] **Testing** — +- [X] **Testing** — Covers all edge cases (setup(), noCanvas(), createCanvas(), 3D/WebGL canvas, instance mode, non-visual scripts, etc) and implements helper functions to guard against early canvas-related calls in the sketch code. - [ ] **Other** — --- @@ -71,21 +91,32 @@ *How does your proposal increase inclusivity or accessibility?* +Not applicable - bug fix. + --- ## Implementation Plan* ⏳ *Week-by-week breakdown of how you plan to complete the work.* +Week 6: Share the proposal with the maintainers and take into account any feedback or suggested changes. If it is accepted, I'll work on it as soon as possible. If this proposal is not something the maintainer's want to focus on, I'll continue drafting another proposal. + +Week 7: Implement the proposed solution and test as many edge cases as possible. Create guard functions to help prevent crashes and errors but try to limit the guard functions so that it doesn't create additional issues. Create a PR so that the maintainers can check my progress. + +Week 8: Finalize the solution, implement suggested changes, and address any issues. Have the completed PR ready as soon as possible. + --- ## Deliverables* 📦 *What will concretely exist at the end of the internship that does not exist today?* +The default canvas creation will be refactored so that it'll only be created when necessary. A canvas tracking boolean variable will exist to determine whether a user defined canvas or the default canvas will be created. Private guard and helper functions will be implemented to ensure that all p5 functions and addons are compatible with the refactored default canvas creation without any behaviors breaking. All p5.js operations will be unchanged. The main difference is that the canvas creation will be smarter and the architecture will be cleaner. + --- ## Anything Else? +Our team would also like to continue working on issue #8922 the loading indicator issue, since the ones who started the implementation should finish the implementation. My teammate, @joshin, will be working on addressing the feedback for issue #8922 while I focus on this proposal if it is approved. *Anything you'd like maintainers to know that doesn't fit above.* From 6da0085c2087628aa53c24b545488d385c49b7ff Mon Sep 17 00:00:00 2001 From: Johnny Huynh <115180134+Jextic@users.noreply.github.com> Date: Tue, 4 Aug 2026 14:12:50 -0700 Subject: [PATCH 02/11] Commented out instructions for the proposal --- Submissions_SOSE_2026/submissions.md | 51 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/Submissions_SOSE_2026/submissions.md b/Submissions_SOSE_2026/submissions.md index 2b811e8..ddeaa12 100644 --- a/Submissions_SOSE_2026/submissions.md +++ b/Submissions_SOSE_2026/submissions.md @@ -1,10 +1,8 @@ -# Proposal Submission Template — SOSE 2026 - -> Copy this file, rename it `proposal-team-"mentor's name".md`, and place it in the `Submissions SOSE 2026` folder. Do not raise a PR until your proposal is ready for final review. All the items marked with an asterisk (*) are required. +# Proposal Submission — SOSE 2026 --- -## Team Details* 👥 +## Team Details 👥 **Mentor's Name:** Jim Anderson @@ -16,9 +14,9 @@ --- -## p5.js Issue* 📋 +## p5.js Issue 📋 -*Details about the first issue assigned to your team.* + - **Link to Issue**: [github.com/processing/p5.js/issues/8922](https://github.com/processing/p5.js/issues/8922) @@ -30,16 +28,17 @@ --- -## Abstract* 📝 +## Abstract 📝 -*3–5 sentences. What is the idea, why does it matter, and what do you plan to do?* + In p5.js v2.0+, a default canvas is created as a guard in case the user calls on drawing methods before defining a canvas. More often than not, users will define their own canvas using `createCanvas()` which destroys the default canvas and creates a new canvas. This process seems redundant, can waste memory if the user is switching from 2D to WebGL context, and can cause a visual flicker when the default canvas is being replaced with the new one. I propose deferring the default canvas creation until right after setup() is completed or until it is explicitly needed by using a canvas tracking variable, getter functions to guard against edge cases, and a check for if a canvas was created. + --- -## Problem Statement* 📑 +## Problem Statement 📑 -*What problem are you solving and who is affected by it?* + The resources that are used to generate the default canvas would be wasted if the canvas is usually deleted right after. It also doesn't occur with just users creating a new canvas. The default canvas has a 2D rendering context but there are many users who want to create a canvas with 3D/WebGL context. As far as I know, canvas contexts can't be changed from 2D to 3D. It is required to create a new canvas for 3D visual artworks which will inevitably destroy the default canvas. @@ -47,9 +46,9 @@ The p5.js editor makes the default canvas basically invisible by setting setting --- -## Proposed Solution* 💡 +## Proposed Solution 💡 -*High-level description of your approach and why you chose it.* + I propose to defer the canvas creation until it is explicitly needed. In p5.js/src/core/main.js, a 100x100 canvas is created in `async #_setup()`. Users also usually create a canvas in their sketch code inside of `function setup() {...}`. The default canvas created during `async #_setup()` will be removed and a canvas tracking boolean (for example, `this._canvasWasCreated = false`) will declared in the constructor to track if the the user has defined a canvas in their sketch. Since the canvas creation is done inside p5.js/src/core/rendering.js, `fn.createCanvas` and `fn.noCanvas()` can be updated to set the boolean to true. After `await context.setup()` completes in `async #_setup()`, p5 will check the canvas tracking boolean and if it is false, that means the user didn't define their own canvas so the default canvas will be created. If it is true, that means the user already defined their own canvas so there is no need to create a default canvas. @@ -59,21 +58,23 @@ Since the tracking boolean will is declared in the constructor, that means that --- -## Research on old issues* 🔭 +## Research on old issues 🔭 -*If there are existing open issues that align with or validate your proposed idea, reference them here. Your proposal may also help revive or advance work that has stalled. If no directly related issue exists, demonstrate that you have researched the project's backlog by identifying similar or relevant issues. Include links to those issues and briefly explain.* + - [Issue #8922: \[p5.js 2.0+ Bug Report\]: Loading indication](https://github.com/processing/p5.js/issues/8922): + This was the previous issue that our team worked on (and are still improving on). Working on this helped me learn about lifecycle hooks and was what intrigued me to look more into the how the canvas is created. We were thinking about creating a temporary canvas on top of the default/user canvas so the indicator would appear at the center of that canvas. This issue proposal was thought of when we were determining how we would approach the placement of the loading indicator. - [Issue #177: createCanvas: problem with the default canvas](https://github.com/processing/p5.js/issues/177): -After looking through the issues for quite a while, I found that this issue was discussed a long time ago. That means that this issue is one that the maintainers have already looked into and found a patch a long time ago. However, this solution is over a decade old and the p5.js has evolved a lot of the years. Simply resizing the default canvas instead of destroying/replacing wouldn't work since we have different canvases as well. We can't resize a canvas with 2D context into canvas with 3D WebGL context. Additionally, resizing the canvas does nothing if the user calls on `noCanvas()` since the default canvas will still be created and immediately destroyed. Modern p5.js is much different from p5.js back then so that's why I propose to defer the canvas creation until it is necessary instead of resizing the canvas. +After looking through the issues for quite a while, I found that this issue was discussed a long time ago. That means that this issue is one that the maintainers have already looked into and found a patch a long time ago. However, this solution is over a decade old and the p5.js has evolved a lot of the years. Simply resizing the default canvas instead of destroying/replacing wouldn't work since we have different canvases as well. We can't resize a canvas with 2D context into canvas with 3D WebGL context. Additionally, resizing the canvas does nothing if the user calls on `noCanvas()` since the default canvas will still be created and immediately destroyed. Modern p5.js is much different from p5.js back then so that's why I propose to defer the canvas creation until it is necessary instead of resizing the canvas. +--- -## Impact* 🛠️ +## Impact 🛠️ -*Select all that apply and add a one-line explanation for each.* + - [ ] **Feature Implementation** — - [X] **Bug Fix** — Ensures that the visual flicker won't occur and won't affect page layouts. @@ -87,17 +88,17 @@ After looking through the issues for quite a while, I found that this issue was ## Inclusivity and Accessibility 🤝 -> Required for proposals that are not bug fixes. If this is a bug fix, write "Not applicable — bug fix". + -Not applicable - bug fix. +Not applicable - primarily a bug fix. --- -## Implementation Plan* ⏳ +## Implementation Plan ⏳ -*Week-by-week breakdown of how you plan to complete the work.* + Week 6: Share the proposal with the maintainers and take into account any feedback or suggested changes. If it is accepted, I'll work on it as soon as possible. If this proposal is not something the maintainer's want to focus on, I'll continue drafting another proposal. @@ -107,9 +108,9 @@ Week 8: Finalize the solution, implement suggested changes, and address any issu --- -## Deliverables* 📦 +## Deliverables 📦 -*What will concretely exist at the end of the internship that does not exist today?* + The default canvas creation will be refactored so that it'll only be created when necessary. A canvas tracking boolean variable will exist to determine whether a user defined canvas or the default canvas will be created. Private guard and helper functions will be implemented to ensure that all p5 functions and addons are compatible with the refactored default canvas creation without any behaviors breaking. All p5.js operations will be unchanged. The main difference is that the canvas creation will be smarter and the architecture will be cleaner. @@ -118,5 +119,5 @@ The default canvas creation will be refactored so that it'll only be created whe ## Anything Else? Our team would also like to continue working on issue #8922 the loading indicator issue, since the ones who started the implementation should finish the implementation. My teammate, @joshin, will be working on addressing the feedback for issue #8922 while I focus on this proposal if it is approved. -*Anything you'd like maintainers to know that doesn't fit above.* + From 944fb7c322b8ac474f6caa46c9a3d5c31a3bea61 Mon Sep 17 00:00:00 2001 From: Johnny Huynh <115180134+Jextic@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:25:22 -0700 Subject: [PATCH 03/11] Reworked the proposed solution Instead of creating a new tracking variable, I might be able to utilize the this._renderer instead. --- Submissions_SOSE_2026/submissions.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Submissions_SOSE_2026/submissions.md b/Submissions_SOSE_2026/submissions.md index ddeaa12..0c15d0f 100644 --- a/Submissions_SOSE_2026/submissions.md +++ b/Submissions_SOSE_2026/submissions.md @@ -32,7 +32,7 @@ -In p5.js v2.0+, a default canvas is created as a guard in case the user calls on drawing methods before defining a canvas. More often than not, users will define their own canvas using `createCanvas()` which destroys the default canvas and creates a new canvas. This process seems redundant, can waste memory if the user is switching from 2D to WebGL context, and can cause a visual flicker when the default canvas is being replaced with the new one. I propose deferring the default canvas creation until right after setup() is completed or until it is explicitly needed by using a canvas tracking variable, getter functions to guard against edge cases, and a check for if a canvas was created. +In p5.js v2.0+, a default canvas is created as a guard in case the user calls on drawing methods before defining a canvas. More often than not, users will define their own canvas using `createCanvas()` which destroys the default canvas and creates a new canvas. This process seems redundant, can waste memory if the user is switching from 2D to WebGL context, and can cause a visual flicker when the default canvas is being replaced with the new one. I propose deferring the default canvas creation until right after setup() is completed or until it is explicitly needed by checking if `this._renderer` exists, creating a helper function to guard against edge cases, and modify getters to call on that helper function if there are early draw function calls. --- @@ -50,11 +50,13 @@ The p5.js editor makes the default canvas basically invisible by setting setting -I propose to defer the canvas creation until it is explicitly needed. In p5.js/src/core/main.js, a 100x100 canvas is created in `async #_setup()`. Users also usually create a canvas in their sketch code inside of `function setup() {...}`. The default canvas created during `async #_setup()` will be removed and a canvas tracking boolean (for example, `this._canvasWasCreated = false`) will declared in the constructor to track if the the user has defined a canvas in their sketch. Since the canvas creation is done inside p5.js/src/core/rendering.js, `fn.createCanvas` and `fn.noCanvas()` can be updated to set the boolean to true. After `await context.setup()` completes in `async #_setup()`, p5 will check the canvas tracking boolean and if it is false, that means the user didn't define their own canvas so the default canvas will be created. If it is true, that means the user already defined their own canvas so there is no need to create a default canvas. +I propose to defer the canvas creation until it is explicitly needed. In p5.js/src/core/main.js, the 100x100 canvas is created in `async #_setup()` will be removed which leaves `this._renderer` to remain null. If the user defines a canvas in their sketch code inside of `function setup() {...}`, `this._renderer` is assigned a renderer instance. After `await context.setup()` is completed and if `this._renderer` is still null, the default 100x100 canvas will be assigned to `this._renderer`. That way, if the user already defined a canvas in their sketch code, the default canvas won't be created. It's possible that the user may call on `noCanvas()` in their sketch code. A boolean variable could be track and flag if this was called on. This would be an extra condition that needs to be checked after `await context.setup()` is completed so that the default canvas won't be created if this boolean is true. -It's very possible that p5.js beginner's might call on drawing functions, like `background()` or `circle`, or read canvas properties in the `functio setup() {...}` in their sketch code. To handle these edge cases, a helper function (like `this._canvasExists()`) will be implemented to check the canvas tracking boolean. If the boolean is false, the default canvas will be created immediately to prevent any canvas errors or crashes. Getter functions will be added/modifed for functions like `canvas` and `drawingContext` so that if the tracking the helper function will be called on and handle the relevant function calls. This will guaratee that early draw function calls and any addons inspecting canvas properties will still be compatible. +It's very possible that p5.js beginner's might call on drawing functions or read canvas properties in the `functio setup() {...}` in their sketch code. To handle these edge cases, a helper function (like `this._canvasExists()`) would be implemented to check if `this._renderer` exists. If it doesn't exist, the 100x100 default canvas would be created on demand to guard against canvas errors and crashes. Getter functions will be added/modifed for `canvas` and `drawingContext` so that if there are any early property reads, the helper function would be called on to create the default canvas. Since drawing functions like `background()` or `circle()` are executed with `this._renderer`, a getter function for `this._renderer` would also be modified to call on the helper function. This would guarantee that early draw function calls and any addons inspecting canvas properties will still be compatible. -Since the tracking boolean will is declared in the constructor, that means that the proposed solution should work well with instance mode. If multiple sketches are created, they should each have their own canvas tracking boolean. From what I've seen as well, the internally registered addons should not be affected since the addons primarily use the presetup and postsetup lifecycle hooks. I'm not taking into account loading.js since our team is still working on it and we are still looking for a solution to perfect how the loading indicator will appear. +Since the `this._renderer` is bound to an individual p5 instance, this proposed solution should work well with instance mode. If multiple sketches are created, they should each have their own renderer property. + +I'd also like to make it so that if there is no `draw()` function in the user's sketch code, the canvas creation would be skipped altogether. However, I still need to research and examine the codebase thoroughly again to make sure that it won't affect any addons or p5 operations. --- @@ -112,7 +114,7 @@ Week 8: Finalize the solution, implement suggested changes, and address any issu -The default canvas creation will be refactored so that it'll only be created when necessary. A canvas tracking boolean variable will exist to determine whether a user defined canvas or the default canvas will be created. Private guard and helper functions will be implemented to ensure that all p5 functions and addons are compatible with the refactored default canvas creation without any behaviors breaking. All p5.js operations will be unchanged. The main difference is that the canvas creation will be smarter and the architecture will be cleaner. +The default canvas creation will be refactored so that it'll only be created when necessary. The automatic default canvas creation will only occur after setup() completes if `this._renderer` is null and noCanvas() was not called on. Private guard and helper functions will be implemented to ensure that all p5 functions and addons are compatible with the refactored default canvas creation without any behaviors breaking. All p5.js operations will be unchanged. The main difference is that the canvas creation will be smarter and the architecture will be cleaner. --- From da5ed4404c3be7471b68ce645aa65b1737548979 Mon Sep 17 00:00:00 2001 From: Johnny Huynh <115180134+Jextic@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:38:53 -0700 Subject: [PATCH 04/11] Tweaked some sentences to make it clearer --- Submissions_SOSE_2026/submissions.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Submissions_SOSE_2026/submissions.md b/Submissions_SOSE_2026/submissions.md index 0c15d0f..e62042c 100644 --- a/Submissions_SOSE_2026/submissions.md +++ b/Submissions_SOSE_2026/submissions.md @@ -32,7 +32,7 @@ -In p5.js v2.0+, a default canvas is created as a guard in case the user calls on drawing methods before defining a canvas. More often than not, users will define their own canvas using `createCanvas()` which destroys the default canvas and creates a new canvas. This process seems redundant, can waste memory if the user is switching from 2D to WebGL context, and can cause a visual flicker when the default canvas is being replaced with the new one. I propose deferring the default canvas creation until right after setup() is completed or until it is explicitly needed by checking if `this._renderer` exists, creating a helper function to guard against edge cases, and modify getters to call on that helper function if there are early draw function calls. +In p5.js v2.0+, a default canvas is created as a guard in case the user calls on drawing methods before defining a canvas. More often than not, users will define their own canvas using `createCanvas()` which destroys the default canvas and creates a new canvas. This process seems redundant, can waste memory if the user is switching from 2D to WebGL context, and can cause a visual flicker when the default canvas is being replaced with the new one. I propose deferring the default canvas creation until right after setup() is completed or until it is explicitly needed by checking if `this._renderer` exists and creating a helper function to guard against edge cases. --- @@ -52,12 +52,10 @@ The p5.js editor makes the default canvas basically invisible by setting setting I propose to defer the canvas creation until it is explicitly needed. In p5.js/src/core/main.js, the 100x100 canvas is created in `async #_setup()` will be removed which leaves `this._renderer` to remain null. If the user defines a canvas in their sketch code inside of `function setup() {...}`, `this._renderer` is assigned a renderer instance. After `await context.setup()` is completed and if `this._renderer` is still null, the default 100x100 canvas will be assigned to `this._renderer`. That way, if the user already defined a canvas in their sketch code, the default canvas won't be created. It's possible that the user may call on `noCanvas()` in their sketch code. A boolean variable could be track and flag if this was called on. This would be an extra condition that needs to be checked after `await context.setup()` is completed so that the default canvas won't be created if this boolean is true. -It's very possible that p5.js beginner's might call on drawing functions or read canvas properties in the `functio setup() {...}` in their sketch code. To handle these edge cases, a helper function (like `this._canvasExists()`) would be implemented to check if `this._renderer` exists. If it doesn't exist, the 100x100 default canvas would be created on demand to guard against canvas errors and crashes. Getter functions will be added/modifed for `canvas` and `drawingContext` so that if there are any early property reads, the helper function would be called on to create the default canvas. Since drawing functions like `background()` or `circle()` are executed with `this._renderer`, a getter function for `this._renderer` would also be modified to call on the helper function. This would guarantee that early draw function calls and any addons inspecting canvas properties will still be compatible. +It's very possible that p5.js beginner's might call on drawing functions or read canvas properties in the `functio setup() {...}` in their sketch code. To handle these edge cases, a helper function (like `this._canvasExists()`) would be implemented to check if `this._renderer` exists. If it doesn't exist, the 100x100 default canvas ould be created on demand to guard against canvas errors and crashes. Functions and properties that depend on the canvas, like `canvas` and `drawingContext`, would use this helper function if they are called when `this._renderer` is still null. This would guarantee that early draw function calls and any addons inspecting canvas properties will still be compatible. Since the `this._renderer` is bound to an individual p5 instance, this proposed solution should work well with instance mode. If multiple sketches are created, they should each have their own renderer property. -I'd also like to make it so that if there is no `draw()` function in the user's sketch code, the canvas creation would be skipped altogether. However, I still need to research and examine the codebase thoroughly again to make sure that it won't affect any addons or p5 operations. - --- ## Research on old issues 🔭 @@ -114,7 +112,7 @@ Week 8: Finalize the solution, implement suggested changes, and address any issu -The default canvas creation will be refactored so that it'll only be created when necessary. The automatic default canvas creation will only occur after setup() completes if `this._renderer` is null and noCanvas() was not called on. Private guard and helper functions will be implemented to ensure that all p5 functions and addons are compatible with the refactored default canvas creation without any behaviors breaking. All p5.js operations will be unchanged. The main difference is that the canvas creation will be smarter and the architecture will be cleaner. +The default canvas creation will be refactored so that it'll only be created when necessary. The automatic default canvas creation will only occur after setup() completes if `this._renderer` is null and noCanvas() was not called on. Private guard and helper functions will be implemented to ensure that all p5 methods and internal addons are compatible with the refactored default canvas creation without any behaviors breaking. All p5.js operations will be unchanged. The main difference is that the canvas creation will be smarter and the architecture will be cleaner. --- From 1fa9eb7d85412898768e02f738fe970c7cd58c9f Mon Sep 17 00:00:00 2001 From: Johnny Huynh <115180134+Jextic@users.noreply.github.com> Date: Fri, 7 Aug 2026 08:55:07 -0700 Subject: [PATCH 05/11] Proposal Reset Set aside the canvas referral proposal since it requires overhauling too much of the code (risky) and is not a common problem. --- Submissions_SOSE_2026/submissions.md | 33 ++++++++-------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/Submissions_SOSE_2026/submissions.md b/Submissions_SOSE_2026/submissions.md index e62042c..7e63525 100644 --- a/Submissions_SOSE_2026/submissions.md +++ b/Submissions_SOSE_2026/submissions.md @@ -32,7 +32,7 @@ -In p5.js v2.0+, a default canvas is created as a guard in case the user calls on drawing methods before defining a canvas. More often than not, users will define their own canvas using `createCanvas()` which destroys the default canvas and creates a new canvas. This process seems redundant, can waste memory if the user is switching from 2D to WebGL context, and can cause a visual flicker when the default canvas is being replaced with the new one. I propose deferring the default canvas creation until right after setup() is completed or until it is explicitly needed by checking if `this._renderer` exists and creating a helper function to guard against edge cases. + --- @@ -40,9 +40,7 @@ In p5.js v2.0+, a default canvas is created as a guard in case the user calls on -The resources that are used to generate the default canvas would be wasted if the canvas is usually deleted right after. It also doesn't occur with just users creating a new canvas. The default canvas has a 2D rendering context but there are many users who want to create a canvas with 3D/WebGL context. As far as I know, canvas contexts can't be changed from 2D to 3D. It is required to create a new canvas for 3D visual artworks which will inevitably destroy the default canvas. -The p5.js editor makes the default canvas basically invisible by setting setting the canvas background to the same color as the preview color (when the user changes the theme to dark mode or high contrast mode). However, p5.js sketches might also be embedded in other websites, such as blogs or portfolio websites. If the webpage loads slowly because of asset loading or if the html background of the webpage is not monochromic, a visual flicker is more likely to occur and will be more noticeable. Users with low-end devices or users in heavy network traffic areas are also likely to experience this visual flicker if they run content-heavy sketches. To improve inclusivity and accessibility, resolving the issue of unnecessary resource allocation will improve user experience, especially for low-end device users. --- @@ -50,11 +48,7 @@ The p5.js editor makes the default canvas basically invisible by setting setting -I propose to defer the canvas creation until it is explicitly needed. In p5.js/src/core/main.js, the 100x100 canvas is created in `async #_setup()` will be removed which leaves `this._renderer` to remain null. If the user defines a canvas in their sketch code inside of `function setup() {...}`, `this._renderer` is assigned a renderer instance. After `await context.setup()` is completed and if `this._renderer` is still null, the default 100x100 canvas will be assigned to `this._renderer`. That way, if the user already defined a canvas in their sketch code, the default canvas won't be created. It's possible that the user may call on `noCanvas()` in their sketch code. A boolean variable could be track and flag if this was called on. This would be an extra condition that needs to be checked after `await context.setup()` is completed so that the default canvas won't be created if this boolean is true. - -It's very possible that p5.js beginner's might call on drawing functions or read canvas properties in the `functio setup() {...}` in their sketch code. To handle these edge cases, a helper function (like `this._canvasExists()`) would be implemented to check if `this._renderer` exists. If it doesn't exist, the 100x100 default canvas ould be created on demand to guard against canvas errors and crashes. Functions and properties that depend on the canvas, like `canvas` and `drawingContext`, would use this helper function if they are called when `this._renderer` is still null. This would guarantee that early draw function calls and any addons inspecting canvas properties will still be compatible. -Since the `this._renderer` is bound to an individual p5 instance, this proposed solution should work well with instance mode. If multiple sketches are created, they should each have their own renderer property. --- @@ -62,13 +56,7 @@ Since the `this._renderer` is bound to an individual p5 instance, this proposed -- [Issue #8922: \[p5.js 2.0+ Bug Report\]: Loading indication](https://github.com/processing/p5.js/issues/8922): - -This was the previous issue that our team worked on (and are still improving on). Working on this helped me learn about lifecycle hooks and was what intrigued me to look more into the how the canvas is created. We were thinking about creating a temporary canvas on top of the default/user canvas so the indicator would appear at the center of that canvas. This issue proposal was thought of when we were determining how we would approach the placement of the loading indicator. - -- [Issue #177: createCanvas: problem with the default canvas](https://github.com/processing/p5.js/issues/177): - -After looking through the issues for quite a while, I found that this issue was discussed a long time ago. That means that this issue is one that the maintainers have already looked into and found a patch a long time ago. However, this solution is over a decade old and the p5.js has evolved a lot of the years. Simply resizing the default canvas instead of destroying/replacing wouldn't work since we have different canvases as well. We can't resize a canvas with 2D context into canvas with 3D WebGL context. Additionally, resizing the canvas does nothing if the user calls on `noCanvas()` since the default canvas will still be created and immediately destroyed. Modern p5.js is much different from p5.js back then so that's why I propose to defer the canvas creation until it is necessary instead of resizing the canvas. +- --- @@ -77,11 +65,11 @@ After looking through the issues for quite a while, I found that this issue was - [ ] **Feature Implementation** — -- [X] **Bug Fix** — Ensures that the visual flicker won't occur and won't affect page layouts. -- [X] **Performance** — Saves memory since it'll avoid an unnecessary creation of the default canvvas. +- [ ] **Bug Fix** — +- [ ] **Performance** — - [ ] **Scalability** — - [ ] **Documentation** — -- [X] **Testing** — Covers all edge cases (setup(), noCanvas(), createCanvas(), 3D/WebGL canvas, instance mode, non-visual scripts, etc) and implements helper functions to guard against early canvas-related calls in the sketch code. +- [ ] **Testing** — - [ ] **Other** — --- @@ -92,7 +80,7 @@ After looking through the issues for quite a while, I found that this issue was *How does your proposal increase inclusivity or accessibility?* --> -Not applicable - primarily a bug fix. + --- @@ -100,11 +88,7 @@ Not applicable - primarily a bug fix. -Week 6: Share the proposal with the maintainers and take into account any feedback or suggested changes. If it is accepted, I'll work on it as soon as possible. If this proposal is not something the maintainer's want to focus on, I'll continue drafting another proposal. - -Week 7: Implement the proposed solution and test as many edge cases as possible. Create guard functions to help prevent crashes and errors but try to limit the guard functions so that it doesn't create additional issues. Create a PR so that the maintainers can check my progress. -Week 8: Finalize the solution, implement suggested changes, and address any issues. Have the completed PR ready as soon as possible. --- @@ -112,12 +96,13 @@ Week 8: Finalize the solution, implement suggested changes, and address any issu -The default canvas creation will be refactored so that it'll only be created when necessary. The automatic default canvas creation will only occur after setup() completes if `this._renderer` is null and noCanvas() was not called on. Private guard and helper functions will be implemented to ensure that all p5 methods and internal addons are compatible with the refactored default canvas creation without any behaviors breaking. All p5.js operations will be unchanged. The main difference is that the canvas creation will be smarter and the architecture will be cleaner. + --- ## Anything Else? -Our team would also like to continue working on issue #8922 the loading indicator issue, since the ones who started the implementation should finish the implementation. My teammate, @joshin, will be working on addressing the feedback for issue #8922 while I focus on this proposal if it is approved. + + From 2a2ad5f5dd1488f66015404af3e728088de09fa8 Mon Sep 17 00:00:00 2001 From: Johnny Huynh <115180134+Jextic@users.noreply.github.com> Date: Tue, 11 Aug 2026 12:08:19 -0700 Subject: [PATCH 06/11] issue proposal for multilingual support for screen reader voices --- Submissions_SOSE_2026/submissions.md | 37 ++++++++++++++++------------ 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Submissions_SOSE_2026/submissions.md b/Submissions_SOSE_2026/submissions.md index 7e63525..398710a 100644 --- a/Submissions_SOSE_2026/submissions.md +++ b/Submissions_SOSE_2026/submissions.md @@ -20,9 +20,7 @@ - **Link to Issue**: [github.com/processing/p5.js/issues/8922](https://github.com/processing/p5.js/issues/8922) -- **Issue Title**: [p5.js 2.0+ Bug Report]: Loading indication - #8922 - +- **Issue Title**: [p5.js 2.0+ Bug Report]: Loading indication #8922 - **Repository**: p5.js @@ -32,7 +30,7 @@ - +p5.js has canvas description functions like describe() and describeElement() to generate invisible DOM containers with text that can be read by screen readers. These DOM elements don't have a lang attribute so the TTS engines of the screen readers will be read using the primary voice regardless of the text's language. If the screen reader's voice is defaulted to an English voice and the text is written in a non-English language, the TTS would mangle the pronunciations and produce unintelligible outputs. This could be solved by modifying the describe functions to accept an additional parameter which injects a defined lang attribute into the DOM containers. --- @@ -40,7 +38,9 @@ +Users who rely on screen readers would find this very helpful. After testing sentences in various languages for Windows Narrator and NVDA screen reader, I discovered that sentences without the lang attribute will always use the primary screen reader voice. Oftentimes, the words are hard to understand if the screen reader voice's language is different from the text's language. Additionally, if there is non-Latin text, the screen reader will skip over that block of text entirely if not supported. For example, an English narrator will skip over a sentence written in Kanji or Devanagari. Solving this issue would improve and expand access for international users. +I've also noticed that this is primarily a Windows issue. MacOS VoiceOver has basic Unicode detection so it has the capability of guessing the text's language and switching to the correct narrator although I'm unsure how accurate the macOS VoiceOver usually is. Something to take note of is that if the screen reader doesn't support or doesn't have the language voice installed, it will still use the default voice instead. For the most part, users would already have the voice language that they want already installed and popular screen readers like NVDA already have support for tons of languages. --- @@ -48,7 +48,9 @@ +I propose to update the `describe()` and `describeElement()` functions in `p5.js/src/accessibility/describe.js` to accept an additional parameter which will define the lang attribute. Screen readers can already determine the values of the attribute so abbreviations like 'vi', 'es,', 'hi', and 'fr' can be detected as Vietnamese, Spanish, Hindi, and French. The `_describeHTML()` and `_describeElementHTML()` will also be updated accordingly so that if a lang parameter exists from the previous functions, it will inject a `lang='__'` into the div container. +The parameter will also be optional so that existing p5.js sketches won't be affected. Adding the lang parameter also shouldn't affect existing parameters like `LABEL` or `FALLBACK` The reference documentations would also be updated to encourage users to write in the native script of their languages instead of the transliteration of that language in Latin characters. --- @@ -56,7 +58,13 @@ -- +- [Issue #4721: Web accessibility next steps [conversation]](https://github.com/processing/p5.js/issues/4721) + +This was a conversation of the implementation of describe functions. The author of the issue brought up the question "what should we do about web accessibility in languages other than English". This issue is one of the ways that p5.js could solve to expand language accessibility, especially for visually impaired users. + +- [Issue #6992: Accessibility Features Proposal - Expand Web Accessibility module](https://github.com/processing/p5.js/issues/6992) + +Issue #6992 focuses more on improving existing accessibility features and covering the WCAG (Web Content Accessibility Guidelines) rules. Adding support for multilingual screen reader voice switching would adhere to [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/WCAG22/#language-of-parts) --- @@ -64,12 +72,12 @@ -- [ ] **Feature Implementation** — +- [x] **Feature Implementation** — Adds an optional lang parameter for describe functions for multilingual screen reader support - [ ] **Bug Fix** — - [ ] **Performance** — - [ ] **Scalability** — -- [ ] **Documentation** — -- [ ] **Testing** — +- [X] **Documentation** — Update reference documentation to include a note about using native script instead of transliteration. +- [X] **Testing** — Add unit test cases to verify that the lang attribute is properly injected into div containers. - [ ] **Other** — --- @@ -80,7 +88,7 @@ *How does your proposal increase inclusivity or accessibility?* --> - +This proposal would satisfy WCAG Criterion 3.1.2 Language of Parts which states that text can be programmatically determined assistive technologies like screen readers. This would help Windows users who use screen readers because without the lang attribute, TTS voices would not be able to detect or switch to the proper language voices. --- @@ -88,7 +96,9 @@ +Week 1: Refactor describe functions in `p5.js/src/accessibility/describe.js` to accept an additional argument for lang attributes. Also update the HTML generator functions to inject the lang attribute. Test for functionality and create unit cases. Hopefully create a PR at the end of the week. +Week 2: Take into account feedback and add any suggested changes. Finalize the PR. --- @@ -96,13 +106,8 @@ - - ---- - -## Anything Else? - - +After adding the changes, the describe functions will have multilingual support for screen reader voice switching. `describe.js` functions would have support for an additional optional parameter for a lang attribute and the JSDOC reference comments would be updated. + From 8b45a1fd9ff4e12e0e03ac69db3430e8faafdcba Mon Sep 17 00:00:00 2001 From: Johnny Huynh <115180134+Jextic@users.noreply.github.com> Date: Tue, 11 Aug 2026 12:53:06 -0700 Subject: [PATCH 07/11] Included some HTML tests I tried with screen readers --- Submissions_SOSE_2026/submissions.md | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Submissions_SOSE_2026/submissions.md b/Submissions_SOSE_2026/submissions.md index 398710a..02c5276 100644 --- a/Submissions_SOSE_2026/submissions.md +++ b/Submissions_SOSE_2026/submissions.md @@ -42,6 +42,45 @@ Users who rely on screen readers would find this very helpful. After testing sen I've also noticed that this is primarily a Windows issue. MacOS VoiceOver has basic Unicode detection so it has the capability of guessing the text's language and switching to the correct narrator although I'm unsure how accurate the macOS VoiceOver usually is. Something to take note of is that if the screen reader doesn't support or doesn't have the language voice installed, it will still use the default voice instead. For the most part, users would already have the voice language that they want already installed and popular screen readers like NVDA already have support for tons of languages. +HTML Test used for Windows Narrator and NVDA: +`
this is a test
+this is a test
+esto es una prueba
+esto es una prueba
+Cái này là bài thi
+Cái này là bài thi
+yah test hai
+yah test hai
+यह टेस्ट है
+यह टेस्ट है
+this is a test
Cái này là bài thi
yah test hai
यह टेस्ट है