WCCChallenge 2025 Week 21 - 17 Squares
Final Live Code
Final Result - Video
Summary
WCCChallenge Blurb
| Biz | Biz Biz |
|---|---|
| Author | Project Somedays |
| Title | WCCChallenge 2025 Week 21 - 17 Squares |
| 📅 Started | 2025-05-25 |
| 📅 Completed | 2025-05-25 |
| 🕒 Taken | ~2hrs |
| 🤯 Concept | 17 squares is an upsetting packing solution… why not make it 3D? |
| 🔎 Focus | Using Cannon.js physics engine with Three.js and setting cube colour by xyz velocity 🥰 |
Very short on time this week. Vibe-coding with Claude, but getting it to walk me through its process.
Made for Sableraph’s weekly creative coding challenges, reviewed weekly on https://www.twitch.tv/sableraph
See other submissions here: https://openprocessing.org/curation/78544
Join The Birb’s Nest Discord community! https://discord.gg/g5J6Ajx9Am
🎯Stretch Goals🎯:
- Make the cube actually move with the mouse so the user can jostle it about
🎓Lessons Learned🎓
- Cannon.js is pretty much just like all the other physics engines I’ve tried… Hooray! You just have to add objects into the world and tell the world to update each cycle and then set your visuals by its corresponding physics sim object 🥰
🪵Dev Log🪵
2025-05-25 Vibe-coding
- First test

- I like the background here

- Mucked around with wall thickness
- Got it to reset cubes we lose along the way
- Orientated the cube so that it was actually balanced on the corner
physicsContainer.quaternion.setFromEuler(
initialContainerRotation.x,
initialContainerRotation.y,
initialContainerRotation.z,
'XYZ' // Specify rotation order for consistency
);
- Setting the cube colours’ RBG channels by their XYZ velocities was pleasingly straightforward
function updateCubeColors() {
cubes.forEach(cube => {
const velocity = cube.body.velocity;
const maxVel = 10; // Maximum expected velocity for color mapping
// Map velocity components to color channels (0-1 range)
const r = Math.min(Math.abs(velocity.x) / maxVel, 1);
const g = Math.min(Math.abs(velocity.y) / maxVel, 1);
const b = Math.min(Math.abs(velocity.z) / maxVel, 1);
// Ensure minimum brightness
const minBrightness = 0.2;
const finalR = Math.max(r, minBrightness);
const finalG = Math.max(g, minBrightness);
const finalB = Math.max(b, minBrightness);
cube.mesh.material.color.setRGB(finalR, finalG, finalB);
});
}
- Claude had a couple of different stabs at coming up with the background, but this is definitely the simplest: setting the background of the canvas. It also tried making a sphere around the scene and projecting onto the inside… And then it wanted to use a shader to draw the backround scene with a separate camera… The version I went with wouldn’t stop the user panning away from the centre, but that’s their problem 😅
function createGradientBackground() {
// Create a canvas for the gradient texture
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
const context = canvas.getContext('2d');
// Create radial gradient
const gradient = context.createRadialGradient(
canvas.width / 2, canvas.height / 2, 0, // Inner circle (center)
canvas.width / 2, canvas.height / 2, canvas.width / 2 // Outer circle
);
// Define gradient colors
gradient.addColorStop(0, '#2a4a6b'); // Lighter navy blue in center
gradient.addColorStop(1, '#0f1419'); // Deep navy blue at edges
// Fill the canvas with the gradient
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
// Create texture from canvas and set as scene background
const texture = new THREE.CanvasTexture(canvas);
scene.background = texture;
}