AI Lissajous Curves - Mathematical Harmonic Art Beautiful neon harmonic patterns created by oscilla

55 views Ā· Dec 12, 2025

Create an "AI Lissajous Curves" - mathematical art generator drawing beautiful harmonic patterns. Tw

#xelsedia#xelsedai#xelsedp5flashalpha6
šŸ”€ Remix This šŸ“– View Docs ā›¶ Full Screen ← Back to Gallery
šŸ“‹ Embed Code

Copy this code to embed this sketch on your website:

<iframe src="https://p5js.ai/embed/ac6343fb-0200-4979-b0f3-5bdfec606826" width="400" height="400" frameborder="0" allow="autoplay" title="AI Lissajous Curves - Mathematical Harmonic Art Beautiful neon harmonic patterns created by oscilla"></iframe>

Adjust width and height as needed. Preview embed →

ā“ About This Sketch 3 questions

What kind of visual patterns does the AI Lissajous Curves sketch generate?

The sketch creates beautiful neon harmonic patterns using Lissajous curves, which are intricate and colorful mathematical designs.

How can users customize their experience with the AI Lissajous Curves sketch?

Users can interact with the sketch by adjusting sliders for frequency and phase, and they can also generate interesting frequency ratios using an AI suggestion feature.

What creative coding concepts are demonstrated in the AI Lissajous Curves sketch?

This sketch showcases the use of mathematical concepts like frequency ratios and procedural generation to create dynamic and aesthetically pleasing visual art.

šŸ’¬ AI Chat History 4 messages
šŸ‘¤ You
Create an "AI Lissajous Curves" - mathematical art generator drawing beautiful harmonic patterns. Two oscillators control X and Y movement with adjustable frequencies and phase. The AI suggests frequency ratios that create interesting closed curves. Include color cycling along the curve path, line thickness variation, and trail fade effect. Add sliders for X/Y frequencies and phase offset. Visual style: glowing neon curves on dark background with smooth gradient colors.
šŸ¤– AI
Here’s a complete AI-driven Lissajous curve generator with sliders, an ā€œAI Suggest Curveā€ button, neon gradients, variable line thickness, and trail fade.

---

```html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI Lissajous Curves</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- Canvas container -->
<div id="sketch-container"></div>

<!-- UI controls -->
<div id="controls"></div>

<!-- p5.js core library -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/p5.min.js"></script>
<!-- Your sketch -->
<script src="sketch.js"></script>
</body>
</html>
```

---

```css
/* style.css */
* {
box-sizing: border-box;
}

body {
margin: 0;
padding: 0;
overflow: hidden;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: #ffffff;
background:
radial-gradient(circle at 20% 0%, #202050 0%, rgba(0, 0, 0, 0) 40%),
radial-gradient(circle at 80% 100%, #500050 0%, rgba(0, 0, 0, 0) 40%),
#000000;
}

/* Fullscreen canvas container */
#sketch-container {
position: fixed;
inset: 0;
z-index: 0;
}

canvas {
display: block;
}

/* Floating control bar */
#controls {
position: fixed;
left: 50%;
bottom: 20px;
transform: translateX(-50%);
z-index: 10;

display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;

padding: 10px 16px;
border-radius: 999px;
border: 1px solid rgba(0, 255, 255, 0.4);
background: rgba(0, 0, 8, 0.75);
box-shadow:
0 0 25px rgba(0, 255, 255, 0.4),
0 0 60px rgba(255, 0, 255, 0.35);
backdrop-filter: blur(16px);
}

/* Label + slider group */
.control-group {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
white-space: nowrap;
}

.control-label {
font-weight: 500;
letter-spacing: 0.06em;
text-transform: uppercase;
color: rgba(200, 255, 255, 0.85);
}

/* Slider styling */
input[type="range"].slider {
-webkit-appearance: none;
appearance: none;
width: 130px;
height: 4px;
border-radius: 999px;
background: linear-gradient(90deg, #00f5ff, #ff00ff);
outline: none;
}

/* WebKit thumb */
input[type="range"].slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 14px;
height: 14px;
border-radius: 50%;
background: #ffffff;
border: 2px solid #00f5ff;
box-shadow: 0 0 12px rgba(0, 255, 255, 0.9);
cursor: pointer;
}

/* Firefox thumb */
input[type="range"].slider::-moz-range-thumb {
width: 14px;
height: 14px;
border-radius: 50%;
background: #ffffff;
border: 2px solid #00f5ff;
box-shadow: 0 0 12px rgba(0, 255, 255, 0.9);
cursor: pointer;
}

/* Firefox track */
input[type="range"].slider::-moz-range-track {
height: 4px;
border-radius: 999px;
background: linear-gradient(90deg, #00f5ff, #ff00ff);
}

/* AI button */
.control-button {
padding: 6px 12px;
border-radius: 999px;
border: 1px solid rgba(0, 255, 255, 0.8);
background:
radial-gradient(circle at 0% 0%, #00f5ff 0%, #0055ff 40%, #ff00ff 100%);
color: #ffffff;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
cursor: pointer;
white-space: nowrap;

box-shadow:
0 0 12px rgba(0, 255, 255, 0.7),
0 0 28px rgba(255, 0, 255, 0.6);
transition:
transform 0.1s ease,
box-shadow 0.1s ease,
filter 0.1s ease;
}

.control-button:hover {
transform: translateY(-1px);
box-shadow:
0 0 18px rgba(0, 255, 255, 0.9),
0 0 40px rgba(255, 0, 255, 0.85);
filter: brightness(1.1);
}

.control-button:active {
transform: translateY(0);
box-shadow:
0 0 10px rgba(0, 255, 255, 0.7),
0 0 24px rgba(255, 0, 255, 0.7);
}
```

---

```js
// sketch.js
// AI Lissajous Curves – neon harmonic patterns with sliders and AI suggestions
// Uses p5.js v1.11.3

let freqXSlider, freqYSlider, phaseSlider;
let suggestButton;

let time = 0;
let hueOffset = 0;

// Create a labeled slider and attach it to the #controls container
function createLabeledSlider(labelText, min, max, initial, step) {
const group = createDiv();
group.parent('controls');
group.addClass('control-group');

const label = createSpan(labelText);
label.parent(group);
label.addClass('control-label');

const slider = createSlider(min, max, initial, step);
slider.parent(group);
slider.addClass('slider');

return slider;
}

// Greatest common divisor helper (for ā€œinterestingā€ ratios)
function greatestCommonDivisor(a, b) {
while (b !== 0) {
const t = b;
b = a % b;
a = t;
}
return a;
}

// AI: generate an interesting small-integer frequency ratio
function generateInterestingRatio() {
// 70% chance: pick from a curated list of known pretty Lissajous ratios
if (random() < 0.7) {
const presets = [
{ x: 1, y: 2 },
{ x: 1, y: 3 },
{ x: 2, y: 3 },
{ x: 2, y: 5 },
{ x: 3, y: 4 },
{ x: 3, y: 5 },
{ x: 3, y: 7 },
{ x: 4, y: 5 },
{ x: 4, y: 7 },
{ x: 5, y: 6 },
{ x: 5, y: 8 },
{ x: 5, y: 9 },
{ x: 6, y: 7 },
{ x: 7, y: 9 },
{ x: 8, y: 9 },
{ x: 8, y: 11 },
{ x: 9, y: 11 }
];
return random(presets);
}

// 30% chance: procedurally pick relatively prime small integers
let a = 1;
let b = 2;
for (let i = 0; i < 20; i++) {
a = int(random(1, 12));
b = int(random(1, 12));
if (a !== b && greatestCommonDivisor(a, b) === 1) {
break;
}
}
return { x: a, y: b };
}

// Reset animation phase and color offset
function resetAnimation() {
time = 0;
hueOffset = random(360);
}

function applyAISuggestion() {
const ratio = generateInterestingRatio();
freqXSlider.value(ratio.x);
freqYSlider.value(ratio.y);

// Prefer phase offsets that often make visually rich figures
const phases = [0, QUARTER_PI, HALF_PI, PI * 0.75, PI];
const chosenPhase = random(phases);
phaseSlider.value(chosenPhase);

resetAnimation();
}

function setup() {
const cnv = createCanvas(windowWidth, windowHeight);
cnv.parent('sketch-container');

colorMode(HSB, 360, 100, 100, 100);
strokeCap(ROUND);
background(0);

// Sliders (see: https://p5js.org/reference/#/p5/createSlider)
freqXSlider = createLabeledSlider('X freq', 1, 12, 3, 1);
freqYSlider = createLabeledSlider('Y freq', 1, 12, 4, 1);
phaseSlider = createLabeledSlider('Phase', 0, TWO_PI, HALF_PI, 0.01);

// AI suggestion button
const btnGroup = createDiv();
btnGroup.parent('controls');
btnGroup.addClass('control-group');

suggestButton = createButton('AI Suggest Curve');
suggestButton.parent(btnGroup);
suggestButton.addClass('control-button');
suggestButton.mousePressed(applyAISuggestion);

resetAnimation();
}

function draw() {
// Trail fade: draw a translucent black layer (blend mode must be BLEND)
blendMode(BLEND);
noStroke();
fill(0, 0, 0, 10); // HSB: black with low alpha
rect(0, 0, width, height);

const freqX = freqXSlider.value();
const freqY = freqYSlider.value();
const phase = phaseSlider.value();

// Update animation time
time += deltaTime * 0.0005; // overall motion speed
hueOffset = (hueOffset + deltaTime * 0.02) % 360; // slow hue drift

// Draw neon Lissajous curve
push();
translate(width / 2, height / 2);

// Additive blending for glow (see: https://p5js.org/reference/#/p5/blendMode)
blendMode(ADD);

const radiusX = width * 0.35;
const radiusY = height * 0.35;
const points = 1200;

// Enough cycles so closed curves fully form for small integer ratios
const cycles = max(freqX, freqY);
const maxT = TWO_PI * cycles;
const dt = maxT / points;

let px = null;
let py = null;

for (let i = 0; i <= points; i++) {
const t = i * dt;
const angle = t + time;

const x = radiusX * sin(freqX * angle + phase);
const y = radiusY * sin(freqY * angle);

if (px !== null) {
const norm = i / points;

// Color along the path: hue cycles with position and time
const hue = (hueOffset + 360 * norm) % 360;

// Line thickness variation for extra life
const thickness =
0.5 + 3.5 * (0.5 + 0.5 * sin(TWO_PI * norm + time * 2.0));

strokeWeight(thickness);
stroke(hue, 80, 100, 80); // bright neon, some transparency
line(px, py, x, y);
}

px = x;
py = y;
}

pop();

// Back to normal blending for HUD text
blendMode(BLEND);
drawHUD(freqX, freqY, phase);
}

// HUD text overlay showing current parameters
function drawHUD(freqX, freqY, phase) {
push();
resetMatrix(); // ignore any transforms
textAlign(LEFT, TOP);
textSize(12);
fill(0, 0, 100, 80); // HSB: white, slightly transparent
noStroke();

const ratioText = freqX + ' : ' + freqY;
const phaseDeg = (phase * 180 / PI).toFixed(1);

text('AI Lissajous Curves', 16, 16);
text('Ratio X : Y = ' + ratioText, 16, 32);
text('Phase = ' + phaseDeg + '°', 16, 48);
text('Use sliders or "AI Suggest Curve" for new patterns.', 16, 64);

pop();
}

function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
```

---

How to use:

- X freq / Y freq sliders: control the frequency ratio of the two oscillators (closed curves appear for many small integer ratios).
- Phase slider: offsets the X oscillator phase (in radians), dramatically changing the shape.
- AI Suggest Curve button: picks visually interesting small-integer ratios and phase offsets, then resets the animation and color scheme.

Core APIs used (for reference):

- Sliders: [`createSlider`](https://p5js.org/reference/#/p5/createSlider)
- Colors & HSB mode: [`colorMode`](https://p5js.org/reference/#/p5/colorMode)
- Blend modes for glow: [`blendMode`](https://p5js.org/reference/#/p5/blendMode)

If you want further tweaks (e.g., different fade speed, more/less thickness variation, or extra controls), I can adjust the sketch.
**Designing an AI Lissajous Curves Generator**

The user wants an "AI Lissajous Curves" generator using p5.js. I should incorporate sliders to control frequencies and phase. An "AI suggestion" button could choose interesting frequency ratios, potentially including non-integer values.

I'll implement a heuristic to achieve closed loops by using small integer ratios. Additionally, I'll add color cycling along the curve path.

Finally, I need to modify the project files to properly load p5.js and ensure the sliders function correctly.**Enhancing the AI Lissajous Curves Generator**

I need to adapt the generator to handle window resizing and set the verbosity to a more concise level of 2. It's important to provide complete updated code in markdown format with filenames included.

Advanced features could include allowing customization for friction or trail fade using sliders, even though the user didn't explicitly ask for that. I'll also implement some heuristics for maintaining known nice ratios for closed curves, like 1:2, 2:3, etc. Lastly, I'll create a glowing neon effect using multiple strokes with varied alpha and thickness to simulate a glow.**Implementing Glow Effects and Color Cycling**

I’m thinking of setting the stroke weight above 1 with bright colors to create a glow effect with a trail fade. Using `blendMode(ADD)` and HSB colors could enhance this. To achieve color cycling along the curve path, I’ll map the parameter 't' or time to the HSB hue.

The Lissajous equations will be implemented as x(t)=A sin(a t + Ī“) and y(t)=B sin(b t). We should animate by changing 't' and using sliders to adjust frequency, clearing the pattern to restart from 't=0' as necessary.**Creating Dynamic Segments and Trail Effect**

I realize that animating many segments per frame is feasible for moderate resolutions. I can vary color and thickness along the curve parameters. To add dynamism, I’ll animate the 'phaseRotation' or time, which produces variety, or I can slowly adjust the phase Ī“ while keeping the slider static.

I’ll also implement a trail fade effect by partially clearing the background each frame to preserve previous frames as ghost images. This can be achieved by using an alpha value for the background and sampling many points along the parameter while applying time-phase adjustments.**Implementing the Lissajous Curves Generator**

I’m working on defining some functions for the Lissajous Curves generator, including calculating ratios and handling animations. The `gcd` function helps in finding simplest ratios, while `generateInterestingRatio` ensures I pick unique values.

For the animation, I’ll incorporate trail fading effects and color cycling using HSB mode. Adjusting stroke weight will create a dynamic visual impact. I need to also manage blending modes for a glow effect. Lastly, I'll make sure to set up the HTML properly to integrate with p5.js for a seamless experience.**Designing UI Controls**

I'm setting up the controls for my project, making sure to keep a clean and organized layout. The body background will be a radial gradient, but I want to ensure the canvas fills nicely without margin issues. I can use p5’s sliders styled with CSS for an appealing look. I'll create labeled sliders for frequency adjustments and a suggest button.

Additionally, I need to implement the fading effect properly in the background while keeping the color mode set to HSB. I'll make sure to comment on the code effectively without overcrowding it. Let's get this implemented!**Structuring the Canvas Setup**

I'm defining my setup for a visual project where I'm creating sliders for frequency adjustment and a button for AI suggestions. I want my canvas to fill the entire window and utilize HSB color mode for vivid visuals. While drawing curves, I'm going to implement a fading trail effect for a smoother presentation. I’ll ensure to organize the UI elements nicely, add labels to my sliders for clarity, and keep track of variables like time and hue offset to enhance the animation. Let's get everything working seamlessly!**Designing Button Styles**

I'm adding styles for the `.control-button`. This includes a radial gradient background and smooth rounded corners to enhance its appearance.

The button will have padding, a border, and a slight shadow for depth. It should respond to hover events with a brightness change, ensuring an engaging user experience.

I also need to check for any other essential adjustments, like confirming that the angle mode and color settings are appropriate. Finally, I'll make sure to cite relevant p5.js references while providing users with clear implementation guidance. Let’s get it all set up!
šŸ‘¤ You
Pleaser add colors and animate it
šŸ¤– AI
The sketch you have already draws in color and animates, but here’s an enhanced version with more obvious motion (auto-animating phase and a ā€œbreathingā€ radius) and stronger color cycling.

Only `sketch.js` needs to change; `index.html` and `style.css` can stay the same.

---

```js
// sketch.js
// AI Lissajous Curves – neon harmonic patterns with sliders and AI suggestions
// Uses p5.js v1.11.3

let freqXSlider, freqYSlider, phaseSlider;
let suggestButton;

let time = 0;
let hueOffset = 0;

// Auto-animation parameters
let autoPhaseAmount = 0.7; // how far phase swings (radians)
let autoPhaseSpeed = 0.5; // how fast phase swings
let breatheAmount = 0.06; // radius "breathing" amplitude

// Create a labeled slider and attach it to the #controls container
function createLabeledSlider(labelText, min, max, initial, step) {
const group = createDiv();
group.parent('controls');
group.addClass('control-group');

const label = createSpan(labelText);
label.parent(group);
label.addClass('control-label');

const slider = createSlider(min, max, initial, step);
slider.parent(group);
slider.addClass('slider');

return slider;
}

// Greatest common divisor helper (for ā€œinterestingā€ ratios)
function greatestCommonDivisor(a, b) {
while (b !== 0) {
const t = b;
b = a % b;
a = t;
}
return a;
}

// AI: generate an interesting small-integer frequency ratio
function generateInterestingRatio() {
// 70% chance: pick from a curated list of known pretty Lissajous ratios
if (random() < 0.7) {
const presets = [
{ x: 1, y: 2 },
{ x: 1, y: 3 },
{ x: 2, y: 3 },
{ x: 2, y: 5 },
{ x: 3, y: 4 },
{ x: 3, y: 5 },
{ x: 3, y: 7 },
{ x: 4, y: 5 },
{ x: 4, y: 7 },
{ x: 5, y: 6 },
{ x: 5, y: 8 },
{ x: 5, y: 9 },
{ x: 6, y: 7 },
{ x: 7, y: 9 },
{ x: 8, y: 9 },
{ x: 8, y: 11 },
{ x: 9, y: 11 }
];
return random(presets);
}

// 30% chance: procedurally pick relatively prime small integers
let a = 1;
let b = 2;
for (let i = 0; i < 20; i++) {
a = int(random(1, 12));
b = int(random(1, 12));
if (a !== b && greatestCommonDivisor(a, b) === 1) {
break;
}
}
return { x: a, y: b };
}

// Reset animation phase and color offset
function resetAnimation() {
time = 0;
hueOffset = random(360);
}

function applyAISuggestion() {
const ratio = generateInterestingRatio();
freqXSlider.value(ratio.x);
freqYSlider.value(ratio.y);

// Prefer phase offsets that often make visually rich figures
const phases = [0, QUARTER_PI, HALF_PI, PI * 0.75, PI];
const chosenPhase = random(phases);
phaseSlider.value(chosenPhase);

resetAnimation();
}

function setup() {
const cnv = createCanvas(windowWidth, windowHeight);
cnv.parent('sketch-container');

// HSB color space makes hue cycling easier
// https://p5js.org/reference/#/p5/colorMode
colorMode(HSB, 360, 100, 100, 100);
strokeCap(ROUND);
background(0);

// Sliders: https://p5js.org/reference/#/p5/createSlider
freqXSlider = createLabeledSlider('X freq', 1, 12, 3, 1);
freqYSlider = createLabeledSlider('Y freq', 1, 12, 4, 1);
phaseSlider = createLabeledSlider('Phase', 0, TWO_PI, HALF_PI, 0.01);

// AI suggestion button
const btnGroup = createDiv();
btnGroup.parent('controls');
btnGroup.addClass('control-group');

suggestButton = createButton('AI Suggest Curve');
suggestButton.parent(btnGroup);
suggestButton.addClass('control-button');
suggestButton.mousePressed(applyAISuggestion);

resetAnimation();
}

function draw() {
// Update animation time (normalized-ish ā€œsecondsā€)
time += deltaTime * 0.0005;

// Trail fade: draw a translucent dark layer
// Use BLEND so we overwrite normally
blendMode(BLEND);
noStroke();
fill(0, 0, 0, 12); // HSB: almost black with a bit more alpha for stronger trails
rect(0, 0, width, height);

const freqX = freqXSlider.value();
const freqY = freqYSlider.value();

// Slider-controlled base phase
const basePhase = phaseSlider.value();

// AUTO-ANIMATION: phase slowly swings around basePhase
const animatedPhase = basePhase + sin(time * autoPhaseSpeed) * autoPhaseAmount;

// AUTO-ANIMATION: curve radius ā€œbreathesā€ in and out
const breathe = 1 + breatheAmount * sin(time * 1.1);

// Color offset drifts over time (stronger than before)
hueOffset = (hueOffset + deltaTime * 0.05) % 360;

// Draw neon Lissajous curve
push();
translate(width / 2, height / 2);

// Additive blending for glow
// https://p5js.org/reference/#/p5/blendMode
blendMode(ADD);

const baseRadiusX = width * 0.32;
const baseRadiusY = height * 0.32;
const radiusX = baseRadiusX * breathe;
const radiusY = baseRadiusY / breathe; // inverse to create subtle distortion

const points = 1400; // a few more points for smoother curves

// Enough cycles so closed curves fully form for small integer ratios
const cycles = max(freqX, freqY);
const maxT = TWO_PI * cycles;
const dt = maxT / points;

let px = null;
let py = null;

for (let i = 0; i <= points; i++) {
const t = i * dt;
const angle = t + time;

const x = radiusX * sin(freqX * angle + animatedPhase);
const y = radiusY * sin(freqY * angle);

if (px !== null) {
const norm = i / points;

// Color along the path: hue cycles with position and time
// hueOffset drifts, norm adds a gradient along the curve
const hue = (hueOffset + 360 * norm) % 360;

// Line thickness variation for extra life
const thickness =
0.6 + 3.9 * (0.5 + 0.5 * sin(TWO_PI * norm + time * 2.5));

strokeWeight(thickness);
stroke(hue, 90, 100, 80); // high saturation, bright, semi-transparent
line(px, py, x, y);
}

px = x;
py = y;
}

pop();

// Back to normal blending for HUD text
blendMode(BLEND);
drawHUD(freqX, freqY, animatedPhase);
}

// HUD text overlay showing current parameters
function drawHUD(freqX, freqY, phaseShown) {
push();
resetMatrix(); // ignore any transforms
textAlign(LEFT, TOP);
textSize(12);
fill(0, 0, 100, 80); // HSB: white, slightly transparent
noStroke();

const ratioText = freqX + ' : ' + freqY;
const phaseDeg = (phaseShown * 180 / PI).toFixed(1);

text('AI Lissajous Curves', 16, 16);
text('Ratio X : Y = ' + ratioText, 16, 32);
text('Animated phase = ' + phaseDeg + '°', 16, 48);
text('Use sliders or "AI Suggest Curve" for new patterns.', 16, 64);

pop();
}

function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
```

This version:

- Keeps the neon gradient color trail (HSB + `hueOffset` + `norm`).
- Automatically animates the phase so the shape slowly morphs even if you don’t touch the sliders.
- Adds a subtle ā€œbreathingā€ effect to the curve’s size so it feels more alive.
- Retains the trail fade and glow using [`blendMode(ADD)`](https://p5js.org/reference/#/p5/blendMode).

If you want even more dramatic motion (e.g., auto-changing the X/Y frequencies themselves), I can add an ā€œauto AI modeā€ that periodically calls `applyAISuggestion()` for you.
šŸŽ¬ Video Preview