AI Kaleidoscope Generator - Symmetrical Pattern Art Draw mesmerizing symmetrical patterns with real
54 views ยท Dec 12, 2025
Create an "AI Kaleidoscope Generator" - a mesmerizing symmetrical pattern creator with real-time ref
๐ Embed Code
Copy this code to embed this sketch on your website:
<iframe src="https://p5js.ai/embed/22cf18a5-73fb-4819-9c26-0cdb096b3e07" width="400" height="400" frameborder="0" allow="autoplay" title="AI Kaleidoscope Generator - Symmetrical Pattern Art Draw mesmerizing symmetrical patterns with real"></iframe>
Adjust width and height as needed. Preview embed โ
โ About This Sketch 3 questions
What type of visual patterns does the AI Kaleidoscope Generator create?
The sketch generates mesmerizing symmetrical patterns that change dynamically in real-time, utilizing a color palette and various symmetry axes.
How can users customize their experience with the AI Kaleidoscope Generator?
Users can interact with the sketch by adjusting parameters such as symmetry count, rotation speed, and color cycling speed using a GUI, as well as clearing the canvas or suggesting new color palettes.
What creative coding concepts are showcased in this p5.js sketch?
This sketch demonstrates concepts of symmetry, color theory, and real-time interactivity, utilizing WEBGL for enhanced visual effects and dynamic user input.
๐ฌ AI Chat History 2 messages
To achieve the desired visual style with subtle glows and radial gradients, using `WEBGL` mode in p5.js will be beneficial. For user controls and making the "AI suggestions" interactive, the `dat.gui` library is an excellent choice.
Here's the breakdown of the solution:
1. **`index.html`**: We'll add the p5.js and `dat.gui` CDN links.
2. **`style.css`**: Keep the existing styles.
3. **`sketch.js`**:
* **`setup()`**: Initialize the canvas in `WEBGL` mode, set `colorMode` to `HSB` for easier color manipulation, and set up `dat.gui` controls for symmetry count, rotation speed, color cycling, crystallize effect, and more.
* **`draw()`**: This is the core of the kaleidoscope.
* Clear the background.
* Draw a radial gradient background using `drawingContext.createRadialGradient`.
* Apply global rotation based on settings and device sensors.
* Loop `symmetryCount` times, applying `rotateZ` and `scale(1, -1)` for reflection to draw the `drawingPoints` symmetrically.
* Apply a subtle glow using `drawingContext.shadowBlur`.
* **User Interaction (`mousePressed`, `mouseDragged`, `touchStarted`, `touchMoved`)**: Record the user's strokes as `p5.Vector` objects in `drawingPoints`.
* **"AI" Complexity Analysis**: A simple heuristic is used: every 500 points drawn, a new harmonious color palette is generated.
* **"Crystallize" Effect**: When toggled, strokes are drawn as straight lines connecting points, creating a more angular, geometric look.
* **Device Sensors (`deviceMoved`)**: Uses `rotationX` and `rotationY` for subtle rotation control.
* **Helper Functions**:
* `generatePalette()`: Creates a harmonious color palette using `HSB` values.
* `drawRadialGradient()`: Draws the background gradient.
* `drawSymmetryLines()`: Visualizes the symmetry axes.
* `drawStroke()`: Handles drawing the stored points, applying color cycling, glow, and the crystallize effect.
Let's get this set up!
### `index.html`
We need to add the p5.js library and the `dat.gui` library. The `dat.gui` library will allow users to adjust settings easily.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Kaleidoscope Generator</title>
<link rel="stylesheet" href="style.css">
<!-- p5.js library -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/p5.min.js"></script>
<!-- dat.gui library for controls -->
<script src="https://cdn.jsdelivr.net/npm/dat.gui@0.7.9/build/dat.gui.min.js"></script>
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
```
### `style.css`
Your existing `style.css` is perfect for setting up the canvas.
```css
body {
margin: 0;
padding: 0;
overflow: hidden;
}
canvas {
display: block;
}
```
### `sketch.js`
This file contains the main logic for the kaleidoscope, including drawing, user interaction, AI suggestions, and the crystallize effect.
```js
// Store drawing points
let drawingPoints = [];
// Color palette
let palette = [];
// dat.GUI object for controls
let gui;
// Settings object to hold all adjustable parameters
let settings = {
symmetryCount: 6,
rotationSpeed: 0.005,
colorCyclingSpeed: 0.05,
showSymmetryLines: true,
isCrystallized: false,
clearCanvas: function() {
drawingPoints = [];
background(0); // Clear the WEBGL canvas
generatePalette(); // Generate a new palette
},
suggestPalette: function() {
generatePalette(); // Generate a new palette based on "AI" complexity
}
};
// Device sensor variables for subtle rotation (desktop users can ignore)
let deviceRotationX = 0;
let deviceRotationY = 0;
function setup() {
// Create a canvas in WEBGL mode for better gradient and glow effects
createCanvas(windowWidth, windowHeight, WEBGL);
// Use HSB color mode for easier color harmony generation and cycling
colorMode(HSB, 360, 100, 100, 100);
// Set angle mode to RADIANS for rotate() function
angleMode(RADIANS);
// No fill for strokes
noFill();
// Initial stroke weight
strokeWeight(2);
// Generate an initial color palette
generatePalette();
// Initialize dat.GUI
gui = new dat.GUI();
gui.add(settings, 'symmetryCount', [6, 8, 12]).name('Symmetry Axes');
gui.add(settings, 'rotationSpeed', 0, 0.02).name('Rotation Speed');
gui.add(settings, 'colorCyclingSpeed', 0, 0.1).name('Color Cycle Speed');
gui.add(settings, 'showSymmetryLines').name('Show Symmetry Lines');
gui.add(settings, 'isCrystallized').name('Crystallize Pattern');
gui.add(settings, 'clearCanvas').name('Clear Canvas');
gui.add(settings, 'suggestPalette').name('AI Suggest Palette'); // Manual trigger for AI suggestion
// Request device access for motion sensors (for mobile devices)
if (typeof DeviceOrientationEvent !== 'undefined' && typeof DeviceOrientationEvent.requestPermission === 'function') {
DeviceOrientationEvent.requestPermission()
.then(permissionState => {
if (permissionState === 'granted') {
console.log('Device orientation permission granted.');
} else {
console.log('Device orientation permission denied.');
}
})
.catch(console.error);
}
}
function draw() {
// Always clear the background in WEBGL mode
background(0);
// Translate to the center of the canvas in 3D space and move slightly back
// This allows for better perspective and viewing of 2D shapes in WEBGL
translate(0, 0, -min(width, height) / 4);
// Draw the radial gradient background
drawRadialGradient();
// Apply global rotation based on settings and device sensors
// Use deviceRotationX and deviceRotationY for subtle device-based rotation
rotateZ(frameCount * settings.rotationSpeed + deviceRotationY * 0.005);
rotateX(deviceRotationX * 0.005);
// Calculate the angle for each symmetry slice
let angle = TWO_PI / settings.symmetryCount;
// Draw all symmetrical reflections
for (let i = 0; i < settings.symmetryCount; i++) {
push(); // Save the current transformation state
// Rotate for each symmetry slice
rotateZ(i * angle);
// Draw the strokes
drawStroke(drawingPoints, settings.isCrystallized);
// Apply horizontal reflection (scale Y by -1)
scale(1, -1);
// Draw the reflected strokes
drawStroke(drawingPoints, settings.isCrystallized);
pop(); // Restore the previous transformation state
}
// Draw symmetry lines if enabled
if (settings.showSymmetryLines) {
drawSymmetryLines();
}
}
// Function to draw the stored strokes
function drawStroke(points, crystallized) {
if (points.length === 0) return;
// Use beginShape() and endShape() for drawing connected lines or curves
// WEBGL mode requires specifying a shape type (e.g., LINES, POINTS, TRIANGLES, etc.)
// For strokes, we'll use a series of short lines or curves.
// Using POINTS or LINES within a single beginShape is more efficient in WEBGL.
// Drawing points as individual points is simpler in WEBGL
if (crystallized || points.length < 2) {
beginShape(POINTS);
for (let point of points) {
let col = palette[floor(frameCount * settings.colorCyclingSpeed + points.indexOf(point)) % palette.length];
stroke(col);
// Apply subtle glow effect
drawingContext.shadowColor = color(hue(col), saturation(col), brightness(col), 50).toString();
drawingContext.shadowBlur = 10;
vertex(point.x, point.y);
}
endShape();
} else {
// For smooth curves, we can draw a series of short lines between points
// or use curveVertex() but that often looks chunky in WEBGL without custom shaders.
// Let's try drawing simple lines between points for a smoother appearance.
beginShape(LINES);
for (let i = 0; i < points.length - 1; i++) {
let p1 = points[i];
let p2 = points[i+1];
let col = palette[floor(frameCount * settings.colorCyclingSpeed + i) % palette.length];
stroke(col);
drawingContext.shadowColor = color(hue(col), saturation(col), brightness(col), 50).toString();
drawingContext.shadowBlur = 10;
vertex(p1.x, p1.y);
vertex(p2.x, p2.y);
}
endShape();
}
drawingContext.shadowBlur = 0; // Reset shadow blur
}
// Function to draw the symmetry lines
function drawSymmetryLines() {
let angle = TWO_PI / settings.symmetryCount;
let radius = min(width, height) / 2; // Radius to draw lines to
for (let i = 0; i < settings.symmetryCount; i++) {
push();
rotateZ(i * angle);
stroke(255, 50); // Semi-transparent white lines
line(0, 0, radius, 0); // Draw line from center to edge
pop();
}
}
// AI Suggestion: Generate a harmonious color palette
function generatePalette() {
palette = [];
// Pick a random base hue (0-360)
let baseHue = random(360);
// Generate a harmonious palette (e.g., analogous or complementary)
// For this example, let's create a triad palette with variations.
palette.push(color(baseHue, 80, 90)); // Bright jewel tone
palette.push(color(baseHue, 60, 70)); // Slightly darker
palette.push(color(baseHue, 40, 50)); // Even darker
// Add a complementary hue for contrast
let complementaryHue = (baseHue + 180) % 360;
palette.push(color(complementaryHue, 80, 90));
// Add analogous hues
palette.push(color((baseHue + 30) % 360, 70, 80));
palette.push(color((baseHue - 30 + 360) % 360, 70, 80));
// Shuffle the palette for more varied color cycling
palette = shuffle(palette);
console.log('New color palette generated:', palette.map(c => c.toString()));
}
// Function to draw a radial gradient background
function drawRadialGradient() {
// In WEBGL mode, we can use drawingContext to create gradients on the 2D canvas context
let gradient = drawingContext.createRadialGradient(0, 0, 0, 0, 0, min(width, height) / 2);
// Jewel-toned gradient from center to edge
gradient.addColorStop(0, color(0, 0, 0, 100).toString()); // Center: Dark, fully opaque
gradient.addColorStop(0.3, color(250, 50, 15, 80).toString()); // Inner: Subtle jewel tone
gradient.addColorStop(0.7, color(200, 50, 10, 50).toString()); // Middle: Slightly cooler jewel tone
gradient.addColorStop(1, color(0, 0, 0, 100).toString()); // Edge: Dark, fully opaque
drawingContext.fillStyle = gradient;
drawingContext.fillRect(-width / 2, -height / 2, width, height); // Fill the entire canvas area
}
// User interaction: Mouse press to start a new stroke
function mousePressed() {
// Clear drawingPoints to start a new stroke
drawingPoints = [];
// Add the initial point
drawingPoints.push(createVector(mouseX - width / 2, mouseY - height / 2));
}
// User interaction: Mouse drag to continue drawing
function mouseDragged() {
// Add current mouse position to drawingPoints array
drawingPoints.push(createVector(mouseX - width / 2, mouseY - height / 2));
// Simple "AI" complexity analysis: Suggest new palette every 500 points
if (drawingPoints.length % 500 === 0) {
generatePalette();
console.log('AI suggested a new palette based on pattern complexity!');
}
}
// User interaction: Touch interaction (for mobile devices)
function touchStarted() {
// Prevent default browser behavior (e.g., scrolling)
return false;
}
function touchMoved() {
// Record touch positions similar to mouseDragged
drawingPoints.push(createVector(touchX - width / 2, touchY - height / 2));
// Simple "AI" complexity analysis: Suggest new palette every 500 points
if (drawingPoints.length % 500 === 0) {
generatePalette();
console.log('AI suggested a new palette based on pattern complexity!');
}
// Prevent default browser behavior (e.g., scrolling)
return false;
}
// Handle window resizing
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
// Device sensor event handler for accelerometer/gyroscope (for mobile devices)
function deviceMoved() {
// Update device rotation variables
// rotationX: tilt front/back (-180 to 180)
// rotationY: tilt left/right (-90 to 90)
deviceRotationX = rotationX;
deviceRotationY = rotationY;
}
```