AI Constellation Drawer - Create Your Own Star Patterns - xelsed.ai
55 views ยท Dec 17, 2025
Draw your own constellations in the night sky! Click on twinkling stars to connect them with lines. Watch the stars twinkle as you create patterns. Clear and start over anytime. A creative stargazing experience. Created with xelsed-alpha6-flash.
๐ Embed Code
Copy this code to embed this sketch on your website:
<iframe src="https://p5js.ai/embed/d03a092f-cd5a-4699-bff9-1f8dcc3dbdd0" width="400" height="400" frameborder="0" allow="autoplay" title="AI Constellation Drawer - Create Your Own Star Patterns - xelsed.ai"></iframe>
Adjust width and height as needed. Preview embed โ
โ About This Sketch 3 questions
What visual experience does the AI Constellation Drawer provide?
The sketch creates a dynamic night sky where users can draw their own constellations by connecting twinkling stars with lines.
How can users interact with the AI Constellation Drawer sketch?
Users can click on stars to connect them, watch them twinkle, and clear the canvas to start over anytime.
What creative coding concept is demonstrated in the AI Constellation Drawer?
It showcases the use of object-oriented programming by implementing a Star class that encapsulates properties and behaviors for creating interactive visual elements.
๐ฌ AI Chat History 2 messages
Here's the complete code for your `sketch.js`, `index.html`, and `style.css` files.
---
### `sketch.js`
```js
// ============================================================
// This sketch was created using the xelsed-alpha06-flash model
// A sample of P5.js AI-assisted coding at www.p5js.ai
// ============================================================
// === Global Variables ===
let stars = []; // Array to store Star objects
let connections = []; // Array to store connections between stars (pairs of Star objects)
let selectedStar = null; // Stores the star currently selected for connection, or null
let clearButton; // p5.js button object
let infoDiv; // p5.js div object for displaying counts
let starCount = 0; // Number of stars currently on screen
let lineCount = 0; // Number of constellation lines drawn
let gradientColors = []; // Array for background gradient colors
// Parallax effect strength (adjust for more or less movement)
let parallaxStrength = 0.01;
// === Star Class ===
// Represents a single star with position, size, and twinkle effect
class Star {
constructor(x, y, size) {
this.x = x;
this.y = y;
this.size = size;
// Alpha offset for twinkling, creates a unique twinkle pattern for each star
// sin() oscillates between -1 and 1. Adding alphaOffset gives each star a different phase.
this.alphaOffset = random(TWO_PI);
this.isHovered = false; // Track hover state for glow effect
this.isSelected = false; // Track selection state for highlighting
}
// Displays the star on the canvas
display() {
// Calculate alpha for twinkling effect
// sin() creates a smooth oscillation between -1 and 1
// map() converts this to an alpha value between 100 and 200 (semi-transparent white)
let alpha = map(sin(frameCount * 0.05 + this.alphaOffset), -1, 1, 100, 200);
fill(255, alpha); // White color with dynamic transparency
// Apply glow effect if hovered or selected
if (this.isHovered || this.isSelected) {
// drawingContext is the raw WebGL/Canvas2D context
// shadowBlur creates a blur effect around the shape
drawingContext.shadowBlur = this.size * 2; // Adjust glow intensity based on star size
drawingContext.shadowColor = 'rgba(255, 255, 255, 0.8)'; // White glow
} else {
drawingContext.shadowBlur = 0; // No glow
}
// Draw the star as a circle
circle(this.x, this.y, this.size);
// Reset shadow blur to 0 to prevent it from affecting other drawings
// It's good practice to reset drawing styles after applying them locally
drawingContext.shadowBlur = 0;
}
// Checks if a point (px, py) is near the star (within a given tolerance)
checkHover(px, py) {
// dist() calculates the distance between two points
// The tolerance is this.size + 10, meaning it glows when mouse is within 10px of its edge
return dist(px, py, this.x, this.y) < this.size + 10;
}
// Checks if a point (px, py) is clicked near the star (within 20px)
checkClick(px, py) {
// The tolerance for clicking is 20px from the star's center
return dist(px, py, this.x, this.y) < 20;
}
}
// === setup() function ===
// This function is called once when the sketch starts.
function setup() {
createCanvas(windowWidth, windowHeight);
noStroke(); // Disable outlines for shapes
colorMode(RGB); // Use RGB color mode
// Define gradient colors (dark blue/black) for the background
gradientColors = [
color(0, 0, 20), // Darkest blue/black
color(0, 0, 40), // Slightly lighter
color(0, 0, 60), // Even lighter
color(0, 0, 80) // Lightest blue/black
];
generateStars(); // Populate the stars array
// Create UI elements
clearButton = createButton('Clear Constellations');
clearButton.position(20, 20); // Position button in top-left
clearButton.mousePressed(clearConnections); // Attach clear function
clearButton.addClass('p5-button'); // Add CSS class for styling
infoDiv = createDiv(`Stars: ${starCount} | Lines: ${lineCount}`);
infoDiv.position(20, 60); // Position info below button
infoDiv.addClass('p5-info'); // Add CSS class for styling
}
// === draw() function ===
// This function is called repeatedly, typically 60 times per second.
function draw() {
drawBackgroundGradient(); // Draw the gradient background
// Update and display stars
for (let star of stars) {
// Check for hover state
star.isHovered = star.checkHover(mouseX, mouseY);
// Calculate parallax effect based on mouse position
// The offset is proportional to how far the mouse is from the canvas center
let parallaxX = (mouseX - width / 2) * parallaxStrength;
let parallaxY = (mouseY - height / 2) * parallaxStrength;
// Apply parallax to the star's displayed position using translate
// push() and pop() ensure the translation only affects the current star
push();
translate(parallaxX, parallaxY);
star.display();
pop();
}
// Draw connections (constellation lines)
stroke(255, 150); // White color with slight transparency (150 out of 255)
strokeWeight(1); // Thin lines
for (let pair of connections) {
// Apply parallax to lines as well for consistency
let parallaxX = (mouseX - width / 2) * parallaxStrength;
let parallaxY = (mouseY - height / 2) * parallaxStrength;
line(
pair[0].x + parallaxX, pair[0].y + parallaxY,
pair[1].x + parallaxX, pair[1].y + parallaxY
);
}
noStroke(); // Disable stroke after drawing lines
// Update info display
infoDiv.html(`Stars: ${starCount} | Lines: ${lineCount}`);
}
// === Helper Functions ===
// Generates a random number of stars and adds them to the stars array
function generateStars() {
stars = []; // Clear existing stars
connections = []; // Clear existing connections
starCount = 0;
lineCount = 0;
selectedStar = null; // Clear selected star
// Also clear selection highlighting on all stars, just in case
for (let star of stars) {
star.isSelected = false;
}
// Random number of stars between 50 and 80
let numStars = floor(random(50, 81));
for (let i = 0; i < numStars; i++) {
// Random position within the canvas boundaries
let x = random(width);
let y = random(height);
// Random size between 1 and 4 pixels
let size = random(1, 4);
stars.push(new Star(x, y, size));
starCount++;
}
}
// Clears all constellation lines and resets star selection
function clearConnections() {
connections = []; // Empty the connections array
selectedStar = null; // De-select any active star
lineCount = 0;
// Also clear selection highlighting on all stars
for (let star of stars) {
star.isSelected = false;
}
}
// Handles mouse clicks for star selection and connection
function mouseClicked() {
// Check if click was on the clear button using its position and size
if (mouseX > clearButton.x && mouseX < clearButton.x + clearButton.width &&
mouseY > clearButton.y && mouseY < clearButton.y + clearButton.height) {
return; // Do nothing if the button was clicked, its own handler will fire
}
// Find if a star was clicked
let clickedStar = null;
for (let star of stars) {
if (star.checkClick(mouseX, mouseY)) {
clickedStar = star;
break; // Found a star, exit loop
}
}
if (clickedStar) {
// If a star was clicked
if (selectedStar === null) {
// This is the first star selected for a connection
selectedStar = clickedStar;
selectedStar.isSelected = true; // Highlight it
} else if (selectedStar === clickedStar) {
// Same star clicked again, de-select it
selectedStar.isSelected = false; // De-highlight
selectedStar = null;
} else {
// This is the second star selected, create a connection
connections.push([selectedStar, clickedStar]); // Store the pair of star objects
lineCount++;
selectedStar.isSelected = false; // De-highlight the first star
clickedStar.isSelected = false; // De-highlight the second star immediately after connection
selectedStar = null; // Reset selection for the next connection
}
}
}
// Handles touch events (mirrors mouseClicked for touch devices)
function touchStarted() {
// Prevent default browser behavior like scrolling or zooming
// This is crucial for touch interactions on mobile
return false;
// Check if touch was on the clear button
if (touchX > clearButton.x && touchX < clearButton.x + clearButton.width &&
touchY > clearButton.y && touchY < clearButton.y + clearButton.height) {
return; // Do nothing if the button was touched, its own handler will fire
}
// Find if a star was touched
let touchedStar = null;
for (let star of stars) {
if (star.checkClick(touchX, touchY)) {
touchedStar = star;
break; // Found a star, exit loop
}
}
if (touchedStar) {
// If a star was touched
if (selectedStar === null) {
// First star selected
selectedStar = touchedStar;
selectedStar.isSelected = true; // Highlight
} else if (selectedStar === touchedStar) {
// Same star touched again, de-select
selectedStar.isSelected = false; // De-highlight
selectedStar = null;
} else {
// Second star selected, create connection
connections.push([selectedStar, touchedStar]);
lineCount++;
selectedStar.isSelected = false; // De-highlight first star
touchedStar.isSelected = false; // De-highlight second star immediately after connection
selectedStar = null; // Reset selection
}
}
}
// Draws a linear gradient background from top to bottom
function drawBackgroundGradient() {
// Loop through gradient colors to create smooth transitions
for (let i = 0; i < gradientColors.length - 1; i++) {
// Calculate the y-coordinate for the top and bottom of each gradient segment
// map() converts the index 'i' (from 0 to gradientColors.length-2) to a y-coordinate (from 0 to height)
let y1 = map(i, 0, gradientColors.length - 1, 0, height);
let y2 = map(i + 1, 0, gradientColors.length - 1, 0, height);
// Create a linear gradient object using the raw drawing context
// It goes from (0, y1) to (0, y2), creating a vertical gradient
let gradient = drawingContext.createLinearGradient(0, y1, 0, y2);
// Add the starting color to the gradient at position 0 (top)
gradient.addColorStop(0, gradientColors[i]);
// Add the ending color to the gradient at position 1 (bottom)
gradient.addColorStop(1, gradientColors[i + 1]);
// Set the fill style to our newly created gradient
drawingContext.fillStyle = gradient;
// Draw a rectangle covering the current gradient segment
rect(0, y1, width, y2 - y1);
}
}
// This function is called automatically whenever the browser window is resized.
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
// Re-generate stars to fit the new window size
generateStars();
}
```
---
### `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>Constellation Drawing Tool</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 code -->
<script src="sketch.js"></script>
</body>
</html>
```
---
### `style.css`
```css
html, body {
margin: 0;
padding: 0;
overflow: hidden; /* Prevent scrolling if canvas is larger than window */
background-color: #000; /* Fallback background color */
font-family: Arial, sans-serif; /* Set a clean font for UI elements */
color: #fff; /* White text for UI elements */
}
canvas {
display: block; /* Removes extra space below the canvas */
}
/* Styling for the p5.js button */
.p5-button {
background-color: rgba(50, 50, 100, 0.7); /* Dark blue, semi-transparent */
color: white;
border: 1px solid rgba(100, 100, 200, 0.8); /* Lighter blue border */
padding: 10px 15px;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.2s, border-color 0.2s; /* Smooth transition on hover */
}
.p5-button:hover {
background-color: rgba(70, 70, 120, 0.9); /* Slightly lighter on hover */
border-color: rgba(120, 120, 220, 1); /* Brighter border on hover */
}
/* Styling for the info div */
.p5-info {
background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent black */
color: white;
padding: 8px 12px;
font-size: 14px;
border-radius: 5px;
}
```
---
### How to Use:
1. **`sketch.js`**: Copy and paste the provided JavaScript code into your `sketch.js` file.
2. **`index.html`**: Copy and paste the provided HTML code into your `index.html` file.
3. **`style.css`**: Copy and paste the provided CSS code into your `style.css` file.
4. **Run**: Open `index.html` in your browser.
### Key Features Explained:
* **Star Class**: Each star is an instance of the `Star` class, holding its position, size, and state (hovered, selected).
* **Twinkle Effect**: The `Star.display()` method uses `sin(frameCount * 0.05 + this.alphaOffset)` to create a smooth, oscillating alpha value for each star, giving it a unique twinkle. `frameCount` is a built-in p5.js variable that counts the number of frames since the sketch started.
* **Hover Glow**: When your mouse (or touch) is near a star (`Star.checkHover()`), `drawingContext.shadowBlur` is used in `Star.display()` to create a soft, white glow. `drawingContext` gives you direct access to the underlying canvas API.
* **Star Selection**:
* Clicking (or touching) near a star (`Star.checkClick()`) selects it and highlights it with the glow effect.
* Clicking the *same* star again de-selects it.
* Clicking a *second, different* star creates a connection (line) between the two stars and stores the connection in the `connections` array. Both stars are then de-highlighted, and the selection is reset.
* **Background Gradient**: The `drawBackgroundGradient()` function dynamically draws a vertical linear gradient from dark blue to black using `drawingContext.createLinearGradient()`.
* **Parallax Effect**: In `draw()`, for each star and for each line, a small offset (`parallaxX`, `parallaxY`) is calculated based on how far your mouse is from the center of the canvas. This offset is then applied using `translate()` before drawing, creating a subtle 3D-like movement.
* **UI Elements**: p5.js's `createButton()` and `createDiv()` functions are used to add interactive elements to the page, which are styled with CSS.
* **Responsiveness**: `windowResized()` is implemented to resize the canvas and regenerate stars whenever the browser window is resized, ensuring the sketch looks good on different screen sizes.
* **Touch Input**: `touchStarted()` is included to ensure the star selection and connection logic works seamlessly on touch-enabled devices. The `return false;` is important to prevent default browser actions like scrolling.