๐ค AI
Here's a p5.js sketch that creates a spiral galaxy animation with rotating stars, a color gradient from purple to blue, and a glowing center.
**Explanation:**
1. **WebGL Mode**: The sketch uses `createCanvas(windowWidth, windowHeight, WEBGL);` to render in 3D, allowing for depth and better rotation effects.
2. **Galaxy Structure**:
* **Stars Array**: An array `stars` stores objects, each containing `x`, `y`, `z` coordinates, a `color`, and a `size`.
* **Generation (`generateStars()` function)**:
* Stars are randomly placed either in the central "core" or in the "arms" of the galaxy.
* **Core Stars**: Clustered within a `coreRadius`, they tend to be brighter (using `glowCenterColor`).
* **Arm Stars**: Their positions are calculated using a modified polar coordinate system to form a logarithmic spiral pattern. `armDensity` controls how tightly the spiral arms wrap, and `armOffset` adds randomness for a natural, slightly fuzzy arm appearance.
* **Depth (Z-axis)**: Stars are given random `z` coordinates, with more variation in the core and less at the edges, simulating the flattened shape of a spiral galaxy.
* **Color Gradient**: `lerpColor()` is used to create a gradient for arm stars, transitioning from `purpleColor` near the core to `blueColor` at the outer edges, based on their radial distance.
3. **Glowing Center**:
* This effect is simulated by drawing multiple semi-transparent `sphere()` shapes, stacked from largest and most transparent to smallest and most opaque, all at the center of the galaxy. This creates a soft, luminous glow without needing complex shaders.
4. **Rotation**:
* The entire galaxy is rotated around its `Z` axis (`rotateZ(currentRotation);`) in the `draw()` function, giving the impression of a slowly spinning celestial body.
5. **Rendering Stars**:
* `beginShape(POINTS)` and `vertex(x, y, z)` are used to draw all the stars efficiently. In WebGL mode, `point()` and `POINTS` shapes typically render as single pixels unless a custom shader is applied. For distant stars, this single-pixel look is often effective. If larger stars are desired, rendering small `sphere()` or `ellipse()` for each star would be necessary, but this would significantly impact performance for a large number of stars.
**Important Note on `index.html`:**
The original `index.html` loads `sketch.js` before `p5.min.js`. This will cause errors because p5.js functions like `createCanvas` and `color` will not be defined yet. I have corrected the `index.html` to load `p5.min.js` first.
---
### `index.html`
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>p5.js Spiral Galaxy</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- Load p5.js library first -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/p5.min.js"></script>
<!-- Then load your sketch.js file -->
<script src="sketch.js"></script>
</body>
</html>
```
### `style.css`
```css
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #000; /* Ensure black background even if canvas isn't full screen */
}
canvas {
display: block;
}
```
### `sketch.js`
```javascript
// Array to store star data
let stars = [];
// Total number of stars in the galaxy
let numStars = 20000; // Increased for higher density
// Galaxy dimensions and parameters
let galaxyRadius = 450; // Overall radius of the galaxy
let coreRadius = 80; // Radius of the central dense core
// armDensity controls how tightly the spiral arms wrap (smaller values = looser arms)
let armDensity = 0.007;
let armCount = 2; // Number of spiral arms
// armOffset adds randomness to arm positions for a more organic look
let armOffset = 0.6;
// Colors for the galaxy
let purpleColor, blueColor;
// Color for the glowing center
let glowCenterColor;
// Variable for the galaxy's rotation angle
let currentRotation = 0;
function setup() {
// Create a WebGL canvas that fills the window
createCanvas(windowWidth, windowHeight, WEBGL);
// Disable drawing outlines for stars and glow
noStroke();
// Enable anti-aliasing for smoother edges (optional, but recommended)
smooth();
// Define the purple and blue colors for the gradient
purpleColor = color(80, 0, 120);
blueColor = color(0, 50, 150);
// Define the warm white/yellow color for the glowing center
glowCenterColor = color(255, 240, 220);
// Generate all the star positions and colors
generateStars();
}
function generateStars() {
for (let i = 0; i < numStars; i++) {
let r, theta, z;
let starColor;
// Randomly decide if the star is in the core or arms (30% chance for core stars)
if (random() < 0.3) {
// Core Star: Random position within the core radius
r = random(coreRadius);
theta = random(TWO_PI);
// Core stars have less z-variation, creating a thicker bulge
z = random(-15, 15);
// Core stars are brighter, matching the glow center
starColor = glowCenterColor;
} else {
// Arm Star:
// Choose which arm the star belongs to
let armIndex = floor(random(armCount));
// Radius ranges from the core edge to the galaxy's outer edge
r = random(coreRadius, galaxyRadius);
// Calculate theta for a logarithmic spiral pattern
// The theta increases with radius, creating the spiral shape
// armDensity controls the tightness of the spiral
// random(-armOffset, armOffset) adds thickness to the arms
// armIndex * TWO_PI / armCount offsets each arm evenly
theta = (r - coreRadius) * armDensity + random(-armOffset, armOffset) + armIndex * TWO_PI / armCount;
// Arm stars have more z-variation further from the center, creating a thinner disc
z = random(-r * 0.08, r * 0.08);
// Apply color gradient: purple near the core, blue towards the edge
// map(r, coreRadius, galaxyRadius, 0, 1, true) ensures values stay between 0 and 1
starColor = lerpColor(purpleColor, blueColor, map(r, coreRadius, galaxyRadius, 0, 1, true));
}
// Convert polar coordinates (r, theta) to Cartesian coordinates (x, y)
let x = r * cos(theta);
let y = r * sin(theta);
// Add the star data to the stars array
stars.push({
x: x,
y: y,
z: z,
color: starColor,
size: random(1, 3) // Random small star size (single pixel in WebGL)
});
}
}
function draw() {
// Set the background to black
background(0);
// Position the camera back from the origin and lay the galaxy flat on the XY plane
translate(0, 0, -300); // Move camera back
rotateX(PI / 2); // Rotate the galaxy to be horizontal (on the XY plane)
// Rotate the entire galaxy around its Z-axis
rotateZ(currentRotation);
// Increment rotation speed (adjust value for faster/slower rotation)
currentRotation += 0.002;
// --- Draw the glowing center ---
let glowRadius = coreRadius * 1.8; // Glow extends beyond the core
let glowLayers = 15; // Number of transparent spheres for the glow effect
// Loop from largest (most transparent) to smallest (most opaque) spheres
for (let i = glowLayers; i >= 1; i--) {
// Calculate radius and alpha for the current glow layer
let r = map(i, 0, glowLayers, 0, glowRadius);
let alpha = map(i, 0, glowLayers, 0, 80); // Alpha decreases towards the outside (more transparent)
// Set fill color with transparency
fill(glowCenterColor, alpha);
// Draw a sphere for the glow layer
sphere(r);
}
// --- Draw the stars ---
// beginShape(POINTS) is an efficient way to draw many single-pixel points in WebGL
beginShape(POINTS);
for (let i = 0; i < stars.length; i++) {
let star = stars[i];
// Set the fill color for the current star
fill(star.color);
// Add the star's 3D coordinates as a vertex
vertex(star.x, star.y, star.z);
}
endShape(); // End the POINTS shape
}
function windowResized() {
// Resize the canvas when the window is resized
resizeCanvas(windowWidth, windowHeight);
}
```