📋 Template v1 vs v2

What a template is, why it matters, and how version 2 made life easier for student coders.

🏗️ What Is a Template — and Why Use One?

A template is a pre-built starter file (or pair of files) that handles all of the repetitive, mechanical plumbing of an app so the developer can focus entirely on the creative part. Think of it the way a contractor thinks about a building shell: the walls, roof, plumbing, and wiring are already in place; the interior designer just decides what goes inside.

In this SketchWave project the template provides:

  • A responsive Bootstrap page layout with a nav bar, hero, and footer
  • A p5.js canvas that auto-sizes to its column and re-scales on window resize
  • A coordinate-grid overlay (toggleable) so students can place objects precisely
  • A background colour picker and opacity slider
  • Start / Pause / Reset / Save-Image controls
  • A consistent HSB color system via SWColor
  • A theme-color system that tints the page header and nav icon automatically

All of that infrastructure is locked away in p5jsTemplate…BaseSketch.js. The student only ever edits the two files in the green boxes to the right.

📂 The Two-File Contract
✏️ myAppSketch.js  v1
✏️ myAppSketch2.js  v2

Student edits this file.
  • Grid bounds and frame rate
  • Theme color initialization
  • All drawing code in drawMyDesign(ctx)
  • (v2 only) Background & grid defaults
  • (v2 only) One-time startup data in initMyDesign()
🔒 p5jsTemplate1Sketch.js  v1
🔒 p5jsTemplate2BaseSketch.js  v2

Infrastructure — do not edit.
  • p5.js setup() and draw()
  • Canvas sizing and resize handling
  • Grid rendering (SWGrid)
  • Control panel wiring (buttons, sliders)
  • Theme-color application to the page
  • Calls drawMyDesign(ctx) each frame
The golden rule: if it’s in the green file, a student can change it freely. If it’s in the blue file, leave it alone unless you really know what you’re doing.

⚖️ Pros and Cons of Using a Template

✅ Pros — what the template gives you ❌ Cons — what you give up
Focus on creativity. All the canvas sizing, control wiring, and color setup is done. You draw; the template handles everything else. It’s a black box at first. New students don’t know why setup() calls wireControls() or what ctx contains. That’s OK — but it can feel like magic.
Consistent UI everywhere. Every sketch built on the template has the same nav bar, same grid toggle, same save button. Reviewers know exactly where to look. Overhead for tiny sketches. If all you want is three bouncing circles, loading Bootstrap + SWColor + SWGrid + SWPoint is overkill. A blank <canvas> tag runs faster and simpler.
Responsive out of the box. The template’s myResizeCanvas() fires on every window resize, so your sketch looks right on phones, tablets, and desktop monitors without any extra code. Version confusion. If a v1 user file is paired with a v2 base sketch (or vice versa), missing constants like DEFAULT_BG_HEX cause silent failures. File versions must match.
Shared vocabulary. Students who all use the same template can read each other’s drawMyDesign(ctx) immediately — they already know the context object, the grid, and the controls. You inherit the template’s choices. HSB color mode, a fixed canvas-column layout, and a particular set of controls are baked in. Changing them requires editing the base file, which breaks the “don’t edit the base” rule.

🔧 Four Improvements from v1 to v2

Template v1 was already a big win over writing everything from scratch. But testing it with real student projects revealed four friction points. Here is what changed in v2 and why each change makes the template better to use.

🎨 Improvement 1 — Background Defaults Belong to the User, Not the Engine

In v1, the starting background colour and opacity were declared as constants inside the base sketch — the file students aren’t supposed to touch:

❌ v1 — buried in the base sketch ✅ v2 — declared in the user sketch
Inside p5jsTemplate1Sketch.js:
const DEFAULT_BG_HEX = '#d1d1d4';
const DEFAULT_BG_OPACITY = 100;
Inside myAppSketch2.js:
const DEFAULT_BG_HEX = '#d1d1d4';
const DEFAULT_BG_OPACITY = 100;

A student working on a dark space sketch wants a black background. In v1, they had to open the base file, hunt for DEFAULT_BG_HEX, change it, and hope they didn’t accidentally break something else along the way. In v2, they just change the constant in their own file.

The principle: configuration that the user is expected to change should live in the file the user is expected to edit. When a template buries user-facing settings inside engine code, it forces students to violate the golden rule just to do something basic. That teaches bad habits.

📐 Improvement 2 — Grid Visibility Is Also a User Choice

The same problem applied to whether the grid is visible at startup. In v1 it was a constant in the base sketch:

❌ v1 — buried in the base sketch ✅ v2 — declared in the user sketch
Inside p5jsTemplate1Sketch.js:
const DEFAULT_SHOW_GRID = true;
Inside myAppSketch2.js:
const DEFAULT_SHOW_GRID = true;

A student whose sketch is a polished final product probably wants the grid off by default. In v1, hiding the grid required editing the base. In v2 it’s a single flag in myAppSketch2.js.

Together, Improvements 1 and 2 follow a software-design guideline sometimes called the Open/Closed Principle applied to templates: the base sketch is closed to modification but open to customization through declared constants in the user file. The engine reads those constants at startup and seeds the controls from them — no engine edit required.

⏳ Improvement 3 — A Lifecycle Hook for Startup Data

v1 gave students only one entry point: drawMyDesign(ctx), which is called every single frame. That is the right place for drawing. It is the wrong place for work that should only happen once at startup.

Consider a sketch that pre-generates 200 random star positions. In v1, a student might write:

// v1 attempt — runs every frame! Rebuilds the array 30 times per second.
function drawMyDesign(ctx) {
  let stars = [];
  for (let i = 0; i < 200; i++) {
    stars.push({ x: random(width), y: random(width) });
  }
  // ... draw stars ...
}

The stars flicker wildly because every frame re-randomises them. The fix is to generate them once, but that code needs width and height, which don’t exist until p5.js creates the canvas inside setup(). Module-level code (outside any function) runs before setup(), so width and height are zero there.

v2 solves this by adding a lifecycle hook: an optional function the base sketch calls at exactly the right moment.

What happens in setup() Timing Width/Height valid?
createCanvas(…) Canvas is created ✅ Yes — from here on
initMyDesign() v2 only Immediately after canvas ✅ Yes — safe to use
Module-level code Script load time — before setup() ❌ No — zero
// v2 — stars generated once, width is valid
let stars = [];

function initMyDesign() {
  for (let i = 0; i < 200; i++) {
    stars.push({ x: random(width), y: random(height) });
  }
}

function drawMyDesign(ctx) {
  // stars already exists, just draw them
  for (let s of stars) {
    point(s.x, s.y);
  }
}

The concept: lifecycle hooks. Most frameworks (React, Vue, Android, iOS, game engines) give you named functions that fire at specific moments in an object’s life: created, mounted, updated, destroyed. initMyDesign() is the same idea at a student-friendly scale. Run setup work once, run drawing code every frame. Never mix the two.

📦 Improvement 4 — Script Load Order: Provider Before Consumer

The v2 HTML file loads the user sketch before the base sketch. This is not an accident — it is required for v2 to work at all.

❌ Wrong order — base loads first ✅ Correct order — user loads first
<script src="p5jsBaseSketch.js"></script>
<script src="myAppSketch2.js"></script>
When base loads, DEFAULT_BG_HEX doesn’t exist yet. SWColor.fromHex(DEFAULT_BG_HEX, …) crashes or silently uses undefined.
<script src="myAppSketch2.js"></script>
<script src="p5jsBaseSketch.js"></script>
When base loads, DEFAULT_BG_HEX is already defined. wireControls() seeds the colour picker correctly.

The browser processes <script> tags in document order. When p5jsTemplate2BaseSketch.js runs, the JavaScript engine has already parsed myAppSketch2.js, so every constant that belongs to the user file — DEFAULT_BG_HEX, DEFAULT_BG_OPACITY, DEFAULT_SHOW_GRID — is a live, named variable.

v1 had the same physical load order in the HTML (user first, then base), but because the defaults lived in the base file, the order did not matter as much. v2 actually depends on it, and the HTML comment explains why:

“User sketch loaded FIRST so its constants and hooks are available when setup() runs.”

The rule: load providers before consumers. The same rule applies to every dependency in every programming language — import statements, header files, require() calls, Maven dependencies — the thing being used must exist before the thing that uses it. In plain HTML scripts, order in the file is the dependency mechanism.

📋 Summary — v1 vs v2 Side by Side
Topic v1 behaviour v2 behaviour
DEFAULT_BG_HEX & DEFAULT_BG_OPACITY Declared in the base sketch (don’t edit file) Declared in the user sketch (edit freely)
DEFAULT_SHOW_GRID Declared in the base sketch (don’t edit file) Declared in the user sketch (edit freely)
One-time startup code with valid width/height No hook — tricky to do correctly initMyDesign() called after createCanvas()
Script load order User first, then base — but didn’t technically matter for defaults User must load first; HTML comment explains why
To change background colour Edit base file (⚠️ risky) Edit user file (✅ safe)
To hide grid at startup Edit base file (⚠️ risky) Edit user file (✅ safe)
Pre-generate canvas-size-dependent data Hard (width = 0 at module level) Easy — use initMyDesign()

📜 Source Code

Browse all four files. The user-sketch pair is the most instructive for novices; the base-sketch pair shows how the engine was updated to support the new v2 design.

🤖 How this page loads the code: This page uses the browser’s Fetch API to pull each source file from the server at load time — the same technique websites use to pull JSON from an API. The advantage: this page always shows the live source. Edit a file and the showcase updates automatically on the next visit. No copy-paste. No re-escaping HTML entities. Just fetch(url).then(r => r.text()).
sketches/myAppSketch2.js JavaScript
Loading sketches/myAppSketch2.js…
sketches/myAppSketch.js JavaScript
Loading sketches/myAppSketch.js…
sketches/p5jsTemplate2BaseSketch.js JavaScript
Loading sketches/p5jsTemplate2BaseSketch.js…
sketches/p5jsTemplate1Sketch.js JavaScript
Loading sketches/p5jsTemplate1Sketch.js…

💪 Try It Yourself

Open p5jsTemplate2.html in your browser and try these challenges to prove the improvements to yourself. Use the Copy buttons above to grab either user sketch as a starting point.

  1. Change the background colour (Improvement 1) — Open sketches/myAppSketch2.js. Change DEFAULT_BG_HEX from '#d1d1d4' to '#0e0e0e' (near-black) and reload p5jsTemplate2.html. Notice the colour picker in the control panel starts at your new value automatically. Then open the v1 page (p5jsTemplate1.html) and try the same — you’ll have to hunt inside the base sketch instead.
  2. Hide the grid at startup (Improvement 2) — In myAppSketch2.js, change DEFAULT_SHOW_GRID from true to false. Reload. The grid is hidden when the page opens, but the toggle checkbox still works. Only one character changed in the user file; the base sketch required no edit at all.
  3. Use initMyDesign() for stars (Improvement 3) — Replace the body of initMyDesign() with:
    for (let i = 0; i < 200; i++) { stars.push({ x: random(width), y: random(height) }); }
    and add let stars = []; at the top of the file. Then in drawMyDesign(ctx), loop over stars and draw them with point(s.x, s.y). Notice the stars are stable — they don’t flicker each frame.
  4. Break the load order (Improvement 4) — In p5jsTemplate2.html, swap the two script tags so the base sketch loads before the user sketch. Reload and open the browser console (F12). Look for an error about DEFAULT_BG_HEX being undefined. Swap them back and confirm the error disappears.
  5. Compare both templates live — Open p5jsTemplate1.html and p5jsTemplate2.html side by side. They look identical — the improvements are all about developer experience, not user-visible features. That is a hallmark of good refactoring.

⚠️ The Copy buttons require a secure context (https:// or localhost). Viewing from a local file:// URL? Right-click the tab and choose “View Page Source” instead.