ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-04-21Advanced

Antigravity × Creative Coding: Building Interactive Art with p5.js, Three.js, and WebGL

A hands-on guide to creative coding with Antigravity — from generative art in p5.js to 3D scenes in Three.js and custom GLSL shaders. Includes working code examples, performance pitfalls, and strategies for publishing and monetizing your work.

p5.jsThree.jsWebGLGLSLcreative codinggenerative artAntigravity338monetization31

Premium Article

For a long time I thought of coding and art as separate worlds.

Writing programs felt like logic. Making art felt like intuition. Whenever I tried to do both at once, one of them pulled me away from the other.

Working with Antigravity changed that, at least a little. I could describe what I wanted in plain language — "I want something that moves like smoke, but controlled" — and get working code back. I could adjust the feel of an animation not by hunting for the right variable name, but by saying "make it more organic." The gap between idea and implementation got smaller.

This guide documents that experience in concrete terms. We'll go from setting up p5.js for generative art, to Three.js for 3D work, to writing custom GLSL shaders with AI assistance. Throughout, the emphasis is on making things that actually run, not just sketches that never quite finish.


Environment Setup: p5.js + Antigravity

Starting a Vite + p5.js Project

For creative coding, simple environments tend to stick. CDN-loaded p5.js works, but Vite gives you hot module replacement — every code change reflects in the browser immediately. For art-making, that real-time feedback loop matters.

npm create vite@latest my-generative-art -- --template vanilla
 
cd my-generative-art
npm install
npm install p5

Replace main.js with p5 in instance mode. Global mode is fine for quick sketches, but instance mode prevents variable pollution and makes it easier to manage multiple sketches in the same project:

// main.js — p5.js in instance mode
import p5 from 'p5'
 
const sketch = (p) => {
  let canvas
 
  p.setup = () => {
    canvas = p.createCanvas(p.windowWidth, p.windowHeight)
    canvas.parent('app')
    p.colorMode(p.HSB, 360, 100, 100, 100)
    p.background(0, 0, 10)
  }
 
  p.draw = () => {
    // Generative art logic goes here
  }
 
  p.windowResized = () => {
    p.resizeCanvas(p.windowWidth, p.windowHeight)
  }
}
 
new p5(sketch)

Setting Up Antigravity Project Rules

Before diving into code, define your project context in .antigravity/rules. This shifts Antigravity's suggestions from generic developer advice toward thinking like a creative coder:

# Creative Coding Project Rules
 
This project is for generative and interactive art production.
 
## Priorities
- Visual richness > code brevity
- Experimental approaches are welcome
- Suggestions for animation timing and color palette can include aesthetic judgment
- Parameters should be named constants at the top of each file, not magic numbers
 
## Tech Stack
- Frontend: Vite + p5.js or Three.js
- Shaders: GLSL (WebGL)
- Deployment: Cloudflare Pages
 
## Code Style
- Comments can be in Japanese or English
- Magic numbers must have meaningful names
- Parameters should be grouped at the top of the file

With this context file in place, the same prompt — "add some noise to the movement" — returns art-maker suggestions rather than engineering ones.


Generative Art Fundamentals: Noise, Particles, and Trails

Drawing "Living" Flow with Perlin Noise

Perlin noise is one of the most versatile tools in generative art. It produces values that look random but connect smoothly — making it ideal for simulating natural phenomena like smoke, water, and wind.

Telling Antigravity "I want a flow field with particles moving through Perlin noise — blue to purple gradient, particles that leave faint trails" produces a starting implementation. What's more useful is asking follow-up questions: "What happens if I change NOISE_SCALE to 0.01?" gets you an explanation alongside the numerical answer, which builds your own understanding over time.

// Flow field + particle system in p5.js
import p5 from 'p5'
 
const sketch = (p) => {
  // ============ Parameters (tune these to change the feel) ============
  const PARTICLE_COUNT = 800      // Number of particles
  const NOISE_SCALE = 0.003       // Noise granularity (smaller = smoother)
  const TIME_SCALE = 0.0005       // How fast the field evolves
  const TRAIL_ALPHA = 8           // Trail persistence (lower = longer trails)
  const SPEED = 2.5               // Particle velocity
  const HUE_RANGE = [200, 290]    // Hue range in HSB (blue to purple)
 
  let particles = []
  let time = 0
 
  class Particle {
    constructor() {
      this.reset()
    }
 
    reset() {
      this.x = p.random(p.width)
      this.y = p.random(p.height)
      this.hue = p.random(HUE_RANGE[0], HUE_RANGE[1])
      this.alpha = p.random(60, 100)
      this.size = p.random(1, 3)
      this.life = 0
      this.maxLife = p.random(150, 400)
    }
 
    update() {
      // Derive angle from noise value
      const noiseVal = p.noise(
        this.x * NOISE_SCALE,
        this.y * NOISE_SCALE,
        time
      )
      const angle = noiseVal * p.TWO_PI * 2
 
      this.x += p.cos(angle) * SPEED
      this.y += p.sin(angle) * SPEED
      this.life++
 
      // Reset when out of bounds or lifespan exceeded
      if (
        this.x < 0 || this.x > p.width ||
        this.y < 0 || this.y > p.height ||
        this.life > this.maxLife
      ) {
        this.reset()
      }
    }
 
    draw() {
      const lifeRatio = 1 - this.life / this.maxLife
      p.stroke(this.hue, 80, 90, this.alpha * lifeRatio)
      p.strokeWeight(this.size)
      p.point(this.x, this.y)
    }
  }
 
  p.setup = () => {
    p.createCanvas(p.windowWidth, p.windowHeight).parent('app')
    p.colorMode(p.HSB, 360, 100, 100, 100)
    p.background(240, 30, 8)
 
    for (let i = 0; i < PARTICLE_COUNT; i++) {
      particles.push(new Particle())
    }
  }
 
  p.draw = () => {
    // Repaint with low alpha to create trails
    p.fill(240, 30, 8, TRAIL_ALPHA)
    p.noStroke()
    p.rect(0, 0, p.width, p.height)
 
    particles.forEach(particle => {
      particle.update()
      particle.draw()
    })
 
    time += TIME_SCALE
  }
 
  p.windowResized = () => {
    p.resizeCanvas(p.windowWidth, p.windowHeight)
  }
 
  p.mousePressed = () => {
    particles.forEach(p => p.reset())
  }
}
 
new p5(sketch)

Increase NOISE_SCALE and the flow becomes chaotic; decrease it and you get long, sweeping curves. This kind of parameter tuning — guided by aesthetic preference rather than correctness — is where creative coding lives.

Adding Mouse Interaction

Adding interaction transforms a piece from something you watch into something you touch. Asking Antigravity to "add attraction toward the mouse cursor, with repulsion on click" returns physics-flavored code. The critical detail is the damping coefficient — without it, particles accelerate indefinitely.

class InteractiveParticle {
  constructor() {
    this.x = p.random(p.width)
    this.y = p.random(p.height)
    this.vx = 0
    this.vy = 0
    this.hue = p.random(180, 300)
  }
 
  update() {
    const dx = p.mouseX - this.x
    const dy = p.mouseY - this.y
    const dist = p.sqrt(dx * dx + dy * dy)
 
    const ATTRACT_STRENGTH = 0.3
    const MIN_DIST = 50
 
    if (dist > MIN_DIST) {
      this.vx += (dx / dist) * ATTRACT_STRENGTH
      this.vy += (dy / dist) * ATTRACT_STRENGTH
    }
 
    if (p.mouseIsPressed) {
      this.vx -= (dx / dist) * 1.5
      this.vy -= (dy / dist) * 1.5
    }
 
    // Damping — essential for stable behavior
    this.vx *= 0.95
    this.vy *= 0.95
 
    this.x += this.vx
    this.y += this.vy
 
    // Wrap at edges
    if (this.x < 0) this.x = p.width
    if (this.x > p.width) this.x = 0
    if (this.y < 0) this.y = p.height
    if (this.y > p.height) this.y = 0
  }
 
  draw() {
    const speed = p.sqrt(this.vx * this.vx + this.vy * this.vy)
    p.fill(this.hue, 80, p.map(speed, 0, 5, 60, 100), 80)
    p.noStroke()
    p.ellipse(this.x, this.y, p.map(speed, 0, 5, 2, 6))
  }
}

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Break through the math and algorithm walls that block generative art progress by working with Antigravity in conversation, arriving at finished pieces with your own artistic voice
Learn Three.js 3D scene construction and GLSL shader implementation from scratch, then deploy interactive 3D artwork that runs live in the browser
Discover concrete strategies for turning creative coding work into portfolio pieces, digital products, and income streams as an indie developer-artist
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-06-23
The Review Prompt Fired but Nothing Appeared — Designing Around Play In-App Review's Quota and No-Show Guarantee
Play In-App Review's launchReviewFlow can succeed without ever showing a dialog. This walks through the three traps — quota, no display guarantee, and silent testing — and the engagement-based trigger design that fires at the right moment without colliding with ads, with steps to have Antigravity implement it.
App Dev2026-04-15
Antigravity × App Store Connect API: Complete Automation Guide for Revenue, ASO & Reviews
A hands-on guide to automating App Store Connect with Antigravity. From JWT authentication to sales report fetching, review sentiment analysis, ASO tracking, and a daily Slack dashboard — everything indie developers need to reclaim development time.
App Dev2026-03-21
Antigravity Monetization Master Plan 2026 — Building a Dev Business with an AI IDE
A comprehensive premium guide to monetizing your Antigravity skills: SaaS development, accelerated freelancing, template sales, and technical consulting using multi-agent AI workflows.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →