Code Sketch


ganux art
By: Mhalsakant School
Category: Art

cleari()
originBottomLeft()

class Sketch {

  var t = 0.0
  var bob = 0.0
  var headX = 0.0
  var eyeX = 0.0
  var eyeY = 0.0
  var blink = 0.0
  var glow = 0.0
  var scan = 0.0
  var wave = 0.0
  var clickX = 0.0
  var clickY = 0.0
  var ripple = 0.0
  var pulse = 0.0

  var waving = false
  var clicked = false
  var talking = true

  val messages = Array(
    "HELLO HUMAN!",
    "AI SYSTEM ONLINE",
    "WELCOME CREATOR",
    "FUTURE IS HERE!",
    "I AM YOUR ROBOT"
  )

  var messageIndex = 0
  var messageTimer = 0.0

  def clamp(v: Double, lo: Double, hi: Double): Double =
    math.max(lo, math.min(hi, v))

  def alpha(v: Double): Int =
    clamp(v, 0.0, 255.0).toInt

  def cx: Double = cwidth / 2.0
  def cy: Double = cheight / 2.0

  def setup(c: CanvasDraw): Unit = {
    c.background(3, 8, 24)
  }

  // --------------------------------------------------
  // SPACE BACKGROUND
  // --------------------------------------------------

  def backgroundFX(c: CanvasDraw): Unit = {

    c.background(3, 8, 24)

    for (i <- 0 until 70) {

      val x = ((i * 137 + 19) % 997).toDouble *
        cwidth / 997.0

      val y = ((i * 83 + 31) % 991).toDouble *
        cheight / 991.0

      val s = 1.0 +
        math.abs(math.sin(t * 2.0 + i)) * 2.0

      c.noStroke()
      c.fill(
        40,
        180,
        255,
        alpha(50 + 100 *
          math.abs(math.sin(t + i)))
      )

      c.ellipse(x, y, s, s)
    }

    // Floor
    c.noStroke()
    c.fill(8, 19, 38)
    c.rect(0, 0, cwidth, 38)

    c.fill(0, 180, 255, 40)
    c.ellipse(cx, 35, 430, 22)

    // Floor grid
    c.stroke(0, 120, 180, 45)
    c.strokeWeight(1)

    for (i <- 0 until 15) {
      val x = i * cwidth / 14.0
      c.line(cx, 38, x, 0)
    }

    for (i <- 0 until 5) {
      val y = i * 8.0
      c.line(0, y, cwidth, y)
    }
  }

  // --------------------------------------------------
  // FUTURISTIC TV
  // --------------------------------------------------

  def drawTV(c: CanvasDraw): Unit = {

    val x = cx
    val y = cy + 10

    // Shadow
    c.noStroke()
    c.fill(0, 0, 0, 130)
    c.ellipse(x, 48, 500, 40)

    // TV body
    c.fill(12, 24, 42)
    c.stroke(0, 160, 220)
    c.strokeWeight(4)
    c.rect(x - 265, y - 105, 530, 290)

    // Outer frame
    c.noFill()
    c.stroke(0, 230, 255, 180)
    c.strokeWeight(2)
    c.rect(x - 255, y - 95, 510, 270)

    // Inner metallic border
    c.stroke(80, 115, 150)
    c.strokeWeight(2)
    c.rect(x - 238, y - 78, 476, 236)

    // Screen
    c.fill(3, 15, 32)
    c.stroke(0, 220, 255, alpha(140 + 90 *
      math.sin(glow)))
    c.strokeWeight(3)
    c.rect(x - 225, y - 65, 450, 210)

    // Screen glow
    c.noStroke()
    c.fill(0, 140, 220, 22)
    c.ellipse(x, y + 20, 410, 180)

    // Scan beam
    val scanY = y - 60 + (scan % 195.0)

    c.fill(0, 220, 255, 35)
    c.rect(x - 220, scanY, 440, 9)

    c.stroke(0, 230, 255, 120)
    c.strokeWeight(1)
    c.line(x - 220, scanY, x + 220, scanY)

    // Screen scan lines
    for (i <- 0 until 20) {
      c.stroke(20, 180, 230, 18)
      c.line(
        x - 220,
        y - 57 + i * 10.0,
        x + 220,
        y - 57 + i * 10.0
      )
    }

    // Frame corner indicators
    c.stroke(0, 255, 255)
    c.strokeWeight(3)

    c.line(x - 245, y + 145, x - 215, y + 145)
    c.line(x - 245, y + 145, x - 245, y + 120)

    c.line(x + 245, y + 145, x + 215, y + 145)
    c.line(x + 245, y + 145, x + 245, y + 120)

    c.line(x - 245, y - 85, x - 215, y - 85)
    c.line(x + 245, y - 85, x + 215, y - 85)

    // Buttons
    for (i <- 0 until 3) {
      c.fill(25, 80, 110)
      c.stroke(0, 200, 255)
      c.strokeWeight(1)
      c.ellipse(x - 35 + i * 35, y - 88, 10, 10)
    }

    // Power LED
    c.noStroke()
    c.fill(0, 255, 190, alpha(120 + 120 *
      math.sin(t * 4)))
    c.ellipse(x + 215, y - 88, 9, 9)

    // Stand
    c.fill(15, 29, 48)
    c.stroke(0, 160, 210)
    c.strokeWeight(2)
    c.rect(x - 45, 48, 90, 26)
    c.rect(x - 100, 36, 200, 12)

    c.fill(0, 190, 255, 70)
    c.noStroke()
    c.rect(x - 80, 39, 160, 3)
  }

  // --------------------------------------------------
  // ROTATING ENERGY RINGS
  // --------------------------------------------------

  def energyRings(c: CanvasDraw): Unit = {

    val x = cx
    val y = cy + 2 + bob

    c.noFill()

    c.stroke(0, 210, 255, 90)
    c.strokeWeight(2)
    c.ellipse(x, y, 155, 100)

    c.stroke(0, 255, 210, 120)
    c.ellipse(
      x,
      y,
      175 + math.sin(t * 2) * 8,
      115 + math.cos(t * 2) * 6
    )

    // Energy nodes
    for (i <- 0 until 8) {

      val a = t * 1.5 + i * math.Pi / 4.0

      val px = x + math.cos(a) * 82
      val py = y + math.sin(a) * 48

      c.noStroke()
      c.fill(0, 230, 255, 210)
      c.ellipse(px, py, 5, 5)
    }

    // Reactor beams
    c.stroke(0, 180, 255, 55)
    c.strokeWeight(1)

    for (i <- 0 until 12) {

      val a = t + i * math.Pi / 6.0

      c.line(
        x + math.cos(a) * 40,
        y + math.sin(a) * 28,
        x + math.cos(a) * 75,
        y + math.sin(a) * 44
      )
    }
  }

  // --------------------------------------------------
  // ROBOT LOWER BODY
  // --------------------------------------------------

  def drawBase(c: CanvasDraw): Unit = {

    val x = cx
    val y = cy - 8 + bob

    // Legs
    c.stroke(190, 220, 235)
    c.strokeWeight(12)

    c.line(x - 19, y - 35, x - 23, y - 57)
    c.line(x + 19, y - 35, x + 23, y - 57)

    // Feet
    c.fill(25, 65, 90)
    c.stroke(0, 220, 255)
    c.strokeWeight(2)

    c.ellipse(x - 25, y - 60, 29, 12)
    c.ellipse(x + 25, y - 60, 29, 12)

    // Hips
    c.fill(120, 155, 180)
    c.ellipse(x, y - 30, 56, 28)
  }

  // --------------------------------------------------
  // ROBOT BODY + REACTOR
  // --------------------------------------------------

  def drawBody(c: CanvasDraw): Unit = {

    val x = cx
    val y = cy + 3 + bob

    // Shoulder joints
    c.fill(25, 85, 115)
    c.stroke(0, 210, 255)
    c.strokeWeight(2)

    c.ellipse(x - 43, y + 28, 25, 28)
    c.ellipse(x + 43, y + 28, 25, 28)

    // Torso
    c.fill(180, 205, 220)
    c.stroke(45, 80, 105)
    c.strokeWeight(3)

    c.ellipse(x, y + 4, 82, 90)

    // Chest armor
    c.fill(28, 80, 112)
    c.stroke(0, 210, 255)
    c.strokeWeight(2)

    c.ellipse(x, y + 17, 49, 50)

    // Reactor aura
    c.noStroke()
    c.fill(0, 190, 255, alpha(60 +
      60 * math.sin(t * 3)))
    c.ellipse(x, y + 17, 40, 40)

    // Reactor core
    c.fill(0, 235, 255)
    c.ellipse(x, y + 17, 24, 24)

    c.fill(225, 255, 255)
    c.ellipse(x, y + 17, 10, 10)

    // Chest labels
    c.fill(5, 35, 55)
    c.text("AI", x - 7, y - 5)

    // Chest status lights
    for (i <- 0 until 3) {
      c.fill(
        0,
        255,
        190,
        alpha(100 + 100 *
          math.sin(t * 4 + i))
      )
      c.ellipse(x - 15 + i * 15, y - 22, 5, 5)
    }
  }

  // --------------------------------------------------
  // ARTICULATED ARMS
  // --------------------------------------------------

  def drawArms(c: CanvasDraw): Unit = {

    val x = cx
    val y = cy + 3 + bob

    val swing =
      if (waving) math.sin(wave) * 22
      else math.sin(t * 2) * 4

    // Left upper arm
    c.stroke(195, 220, 235)
    c.strokeWeight(10)
    c.line(x - 42, y + 30, x - 61, y + 7)

    c.fill(30, 100, 135)
    c.stroke(0, 210, 255)
    c.strokeWeight(2)
    c.ellipse(x - 61, y + 7, 17, 17)

    // Left forearm
    c.stroke(195, 220, 235)
    c.strokeWeight(8)
    c.line(x - 61, y + 7, x - 69, y - 18)

    c.fill(185, 215, 230)
    c.stroke(0, 180, 220)
    c.ellipse(x - 70, y - 22, 17, 18)

    // Right arm
    val handY = y + 12 + swing

    c.stroke(195, 220, 235)
    c.strokeWeight(10)
    c.line(x + 42, y + 30, x + 61, y + 7)

    c.fill(30, 100, 135)
    c.stroke(0, 210, 255)
    c.strokeWeight(2)
    c.ellipse(x + 61, y + 7, 17, 17)

    c.stroke(195, 220, 235)
    c.strokeWeight(8)
    c.line(x + 61, y + 7, x + 73, handY)

    // Hand
    c.fill(200, 225, 238)
    c.stroke(0, 200, 245)
    c.strokeWeight(2)
    c.ellipse(x + 75, handY, 18, 20)

    // Fingers
    c.stroke(100, 180, 210)
    c.strokeWeight(2)

    for (i <- 0 until 3) {
      c.line(
        x + 79,
        handY - 6 + i * 5,
        x + 86,
        handY - 8 + i * 5
      )
    }
  }

  // --------------------------------------------------
  // ADVANCED ROBOT HEAD
  // --------------------------------------------------

  def drawHead(c: CanvasDraw): Unit = {

    val x = cx + headX
    val y = cy + 68 + bob

    // Antenna
    c.stroke(130, 180, 205)
    c.strokeWeight(3)
    c.line(x, y + 28, x, y + 43)

    c.noStroke()
    c.fill(0, 240, 255, alpha(120 +
      120 * math.sin(t * 5)))
    c.ellipse(x, y + 47, 15, 15)

    c.fill(210, 255, 255)
    c.ellipse(x, y + 47, 5, 5)

    // Ears
    c.fill(40, 105, 135)
    c.stroke(0, 200, 255)
    c.strokeWeight(2)

    c.ellipse(x - 40, y, 13, 25)
    c.ellipse(x + 40, y, 13, 25)

    // Main head
    c.fill(190, 215, 230)
    c.stroke(65, 125, 155)
    c.strokeWeight(3)

    c.rect(x - 35, y - 27, 70, 55)

    // Face visor
    c.fill(4, 22, 40)
    c.stroke(0, 210, 255)
    c.strokeWeight(2)

    c.rect(x - 29, y - 16, 58, 31)

    // Eyes
    val eyeHeight =
      if (math.sin(blink) > 0.985) 2.0 else 10.0

    c.noStroke()
    c.fill(0, 190, 255, 70)
    c.ellipse(x - 14 + eyeX, y + 1 + eyeY, 20, 19)
    c.ellipse(x + 14 + eyeX, y + 1 + eyeY, 20, 19)

    c.fill(70, 240, 255)
    c.ellipse(x - 14 + eyeX, y + 1 + eyeY, 9, eyeHeight)
    c.ellipse(x + 14 + eyeX, y + 1 + eyeY, 9, eyeHeight)

    c.fill(255, 255, 255, 220)
    c.ellipse(x - 16 + eyeX, y + 3 + eyeY, 3, 3)
    c.ellipse(x + 12 + eyeX, y + 3 + eyeY, 3, 3)

    // Mouth
    c.stroke(0, 230, 255)
    c.strokeWeight(2)

    if (talking) {
      c.noFill()
      c.ellipse(
        x,
        y - 10,
        15,
        3 + math.abs(math.sin(t * 7)) * 7
      )
    } else {
      c.line(x - 7, y - 10, x + 7, y - 10)
    }

    // Forehead LED
    c.noStroke()
    c.fill(0, 255, 210, alpha(140 +
      100 * math.sin(t * 4)))
    c.ellipse(x, y + 21, 7, 5)
  }

  // --------------------------------------------------
  // HOLOGRAPHIC SPEECH PANEL
  // --------------------------------------------------

  def drawHUD(c: CanvasDraw): Unit = {

    val x = cx + 108
    val y = cy + 98

    // Panel
    c.fill(3, 22, 40, 235)
    c.stroke(0, 210, 255, 220)
    c.strokeWeight(2)

    c.rect(x, y - 5, 126, 72)

    // Header
    c.fill(0, 175, 220, 100)
    c.noStroke()
    c.rect(x + 2, y + 48, 122, 16)

    c.fill(180, 250, 255)
    c.text("AI SYSTEM", x + 12, y + 53)

    // Animated dialogue
    c.fill(100, 245, 255)
    c.text(messages(messageIndex), x + 7, y + 30)

    c.fill(40, 170, 205)
    c.text("STATUS: ACTIVE", x + 7, y + 13)

    // Equalizer
    for (i <- 0 until 12) {

      val h = 3 +
        math.abs(math.sin(t * 5 + i * 0.7)) * 10

      c.fill(0, 220, 255, 210)
      c.rect(x + 8 + i * 9, y - 1, 5, h)
    }
  }

  // --------------------------------------------------
  // RADAR HUD
  // --------------------------------------------------

  def drawRadar(c: CanvasDraw): Unit = {

    val x = cx - 175
    val y = cy + 102

    c.noFill()
    c.stroke(0, 180, 220, 110)
    c.strokeWeight(1)

    c.ellipse(x, y, 56, 56)
    c.ellipse(x, y, 36, 36)
    c.ellipse(x, y, 16, 16)

    c.line(x - 28, y, x + 28, y)
    c.line(x, y - 28, x, y + 28)

    val a = t * 2.0

    c.stroke(0, 255, 190)
    c.strokeWeight(2)

    c.line(
      x, y,
      x + math.cos(a) * 26,
      y + math.sin(a) * 26
    )

    c.noStroke()
    c.fill(0, 255, 190)
    c.ellipse(
      x + math.cos(a) * 18,
      y + math.sin(a) * 18,
      4,
      4
    )

    c.fill(100, 220, 255)
    c.text("SCANNER", x - 25, y - 37)
  }

  // --------------------------------------------------
  // INTERACTION RIPPLE
  // --------------------------------------------------

  def drawRipple(c: CanvasDraw): Unit = {

    if (clicked) {

      ripple += 2.0

      c.noFill()
      c.stroke(0, 230, 255, alpha(220 - ripple))
      c.strokeWeight(2)

      c.ellipse(clickX, clickY, ripple, ripple)
      c.ellipse(clickX, clickY, ripple * 0.65, ripple * 0.65)

      if (ripple > 100) {
        ripple = 0
        clicked = false
      }
    }
  }

  // --------------------------------------------------
  // STATUS BAR
  // --------------------------------------------------

  def drawStatus(c: CanvasDraw): Unit = {

    c.fill(100, 230, 255)
    c.noStroke()

    c.text("N E U R O  /  A I", 20, cheight - 25)

    c.fill(0, 255, 190)
    c.text("SYSTEM ONLINE", cwidth - 125, cheight - 25)

    c.fill(90, 170, 205)
    c.text(
      "TOUCH SCREEN TO ACTIVATE ROBOT",
      cx - 125,
      15
    )

    // Status indicator
    c.fill(0, 255, 180, alpha(100 +
      140 * math.abs(math.sin(t * 3))))
    c.ellipse(cwidth - 20, cheight - 20, 8, 8)
  }

  // --------------------------------------------------
  // MAIN ANIMATION LOOP
  // --------------------------------------------------

  def drawLoop(c: CanvasDraw): Unit = {

    t += 0.045
    glow += 0.07
    scan += 1.6
    blink += 0.035
    pulse += 0.06
    messageTimer += 0.045

    if (messageTimer > 3.0) {
      messageTimer = 0
      messageIndex = (messageIndex + 1) % messages.length
    }

    backgroundFX(c)
    drawTV(c)

    // Mouse / touch interaction
    if (isMousePressed) {

      clickX = mouseX.toDouble
      clickY = mouseY.toDouble

      clicked = true
      ripple = 0

      waving = true
      wave = 0

      talking = !talking

      messageIndex = (messageIndex + 1) % messages.length
      messageTimer = 0
    }

    // Eye tracking
    eyeX = clamp(
      (mouseX.toDouble - cx) * 0.018,
      -4.0,
      4.0
    )

    eyeY = clamp(
      (mouseY.toDouble - cy) * 0.018,
      -3.0,
      3.0
    )

    // Smooth head tracking
    val desiredHead = clamp(
      (mouseX.toDouble - cx) * 0.025,
      -9.0,
      9.0
    )

    headX += (desiredHead - headX) * 0.08

    // Floating body
    bob = math.sin(t * 2.0) * 2.5

    // Wave animation
    if (waving) {
      wave += 0.22

      if (wave > 6.28) {
        waving = false
        wave = 0
      }
    }

    energyRings(c)
    drawBase(c)
    drawBody(c)
    drawArms(c)
    drawHead(c)
    drawHUD(c)
    drawRadar(c)
    drawRipple(c)
    drawStatus(c)
  }
}

val sketch = new Sketch
canvasSketch(sketch)