Code Sketch


vedika
By: Mhalsakant School
Category: Art
// ============================================================
// ? AI TV ROBOT - ULTRA ADVANCED ANIMATION (BLUE TEXT FIXED)
// KOJO / SCALA
// ============================================================

cleari()
originBottomLeft()

class Sketch {

  // ----------------------------------------------------------
  // MAIN ANIMATION VARIABLES
  // ----------------------------------------------------------

  var t = 0.0
  var robotBob = 0.0
  var robotHead = 0.0
  var armWave = 0.0
  var eyeBlink = 0.0
  var screenGlow = 0.0
  var scanLine = 0.0
  var bubblePhase = 0.0

  // Robot position inside TV
  var robotX = cwidth / 2.0
  var robotY = 185.0

  // Click target
  var targetX = robotX
  var targetY = robotY

  // Robot eye direction
  var lookX = 0.0
  var lookY = 0.0

  // Robot state
  var talking = true
  var wave = false
  var clicked = false

  // ----------------------------------------------------------
  // SMALL HELPERS
  // ----------------------------------------------------------

  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
  }

  // ----------------------------------------------------------
  // SETUP
  // ----------------------------------------------------------

  def setup(c: CanvasDraw): Unit = {
    c.background(245, 245, 245)
  }

  // ----------------------------------------------------------
  // OUTER BACKGROUND
  // ----------------------------------------------------------

  def drawBackground(c: CanvasDraw): Unit = {
    c.background(238, 242, 246)

    c.fill(220, 224, 230)
    c.noStroke()
    c.rect(0, 0, cwidth, 55)

    c.fill(205, 210, 218, 100)
    c.ellipse(cwidth / 2.0, 48, 420, 30)

    for (i <- 0 until 25) {
      val px = 30.0 + ((i * 113) % (cwidth - 60))
      val py = 75.0 + ((i * 71) % (cheight - 130))
      val pulse = 1.0 + math.sin(t * 2.0 + i) * 0.5

      c.fill(80, 130, 150, 70)
      c.noStroke()
      c.ellipse(px, py, pulse * 2, pulse * 2)
    }
  }

  // ----------------------------------------------------------
  // TV BODY
  // ----------------------------------------------------------

  def drawTV(c: CanvasDraw): Unit = {
    val tvX = cwidth / 2.0
    val tvY = 200.0

    c.fill(0, 0, 0, 35)
    c.noStroke()
    c.ellipse(tvX, 68, 480, 35)

    c.fill(28, 35, 45)
    c.stroke(5, 15, 25)
    c.strokeWeight(4)
    c.rect(tvX - 260, tvY - 105, 520, 285)

    c.noFill()
    c.stroke(75, 95, 110, 180)
    c.strokeWeight(2)
    c.rect(tvX - 250, tvY - 95, 500, 265)

    val glow = alpha(160.0 + math.sin(screenGlow) * 60.0)

    c.fill(7, 24, 34)
    c.stroke(40, 185, 215, glow)
    c.strokeWeight(4)
    c.rect(tvX - 225, tvY - 70, 450, 220)

    c.fill(10, 32, 43)
    c.noStroke()
    c.rect(tvX - 216, tvY - 61, 432, 202)

    c.fill(0, 190, 220, 18)
    c.ellipse(tvX, tvY + 30, 380, 190)

    val movingScanY = tvY - 55 + ((scanLine % 195.0))
    c.stroke(80, 220, 255, 55)
    c.strokeWeight(1)
    c.line(tvX - 210, movingScanY, tvX + 210, movingScanY)

    for (i <- 0 until 18) {
      val sy = tvY - 55 + i * 11
      c.stroke(80, 220, 255, 15)
      c.line(tvX - 210, sy, tvX + 210, sy)
    }

    c.fill(255, 255, 255, 18)
    c.noStroke()
    c.ellipse(tvX - 145, tvY + 100, 150, 40)

    c.fill(50, 60, 70)
    c.stroke(100, 110, 120)
    c.strokeWeight(1.5)
    c.ellipse(tvX - 38, tvY - 87, 11, 11)
    c.ellipse(tvX, tvY - 87, 11, 11)
    c.ellipse(tvX + 38, tvY - 87, 11, 11)

    val powerGlow = alpha(140.0 + math.sin(t * 4.0) * 80.0)
    c.fill(0, 220, 255, powerGlow)
    c.noStroke()
    c.ellipse(tvX + 205, tvY - 87, 7, 7)

    c.fill(25, 35, 45)
    c.stroke(10, 15, 20)
    c.strokeWeight(3)
    c.rect(tvX - 55, 45, 110, 30)
    c.rect(tvX - 105, 32, 210, 13)

    c.fill(90, 110, 125, 80)
    c.noStroke()
    c.rect(tvX - 45, 51, 90, 5)
  }

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

  def drawRobotHead(c: CanvasDraw): Unit = {
    val hx = robotX + robotHead
    val hy = robotY + robotBob + 73

    c.fill(0, 0, 0, 50)
    c.noStroke()
    c.ellipse(hx + 3, hy - 3, 72, 58)

    c.fill(225, 230, 235)
    c.stroke(40, 50, 60)
    c.strokeWeight(2.5)
    c.rect(hx - 34, hy - 28, 68, 56)

    c.fill(35, 105, 135)
    c.stroke(90, 215, 240)
    c.strokeWeight(2)
    c.ellipse(hx, hy + 20, 32, 9)

    val blink = if (math.sin(eyeBlink) > 0.985) 2.0 else 9.0

    c.fill(10, 20, 25)
    c.noStroke()
    c.ellipse(hx - 14, hy + 3, 10, blink)
    c.ellipse(hx + 14, hy + 3, 10, blink)

    c.fill(65, 230, 255, 220)
    c.ellipse(hx - 13 + lookX, hy + 4 + lookY, 4, 4)
    c.ellipse(hx + 15 + lookX, hy + 4 + lookY, 4, 4)

    c.stroke(65, 75, 85)
    c.strokeWeight(2)

    if (talking) {
      val mouthOpen = 4.0 + math.abs(math.sin(t * 7.0)) * 5.0
      c.noFill()
      c.ellipse(hx, hy - 14, 18, mouthOpen)
    } else {
      c.line(hx - 8, hy - 14, hx + 8, hy - 14)
    }

    c.fill(205, 210, 218)
    c.stroke(55, 65, 75)
    c.strokeWeight(2)
    c.ellipse(hx - 38, hy, 13, 22)
    c.ellipse(hx + 38, hy, 13, 22)

    c.fill(0, 210, 255, 210)
    c.noStroke()
    c.ellipse(hx - 38, hy, 5, 7)
    c.ellipse(hx + 38, hy, 5, 7)

    c.stroke(75, 90, 100)
    c.strokeWeight(2)
    c.line(hx, hy + 29, hx, hy + 45)

    val antGlow = alpha(120.0 + math.sin(t * 5.0) * 100.0)
    c.fill(0, 220, 255, antGlow)
    c.noStroke()
    c.ellipse(hx, hy + 49, 9, 9)
  }

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

  def drawRobotBody(c: CanvasDraw): Unit = {
    val bx = robotX
    val by = robotY + robotBob

    c.fill(215, 220, 228)
    c.stroke(45, 55, 65)
    c.strokeWeight(2)
    c.ellipse(bx, by + 20, 90, 100)

    c.fill(35, 105, 135)
    c.stroke(80, 210, 235)
    c.strokeWeight(2)
    c.ellipse(bx - 45, by + 43, 25, 28)
    c.ellipse(bx + 45, by + 43, 25, 28)

    val reactor = alpha(150.0 + math.sin(t * 3.0) * 90.0)
    c.fill(0, 160, 215, reactor)
    c.ellipse(bx, by + 28, 25, 25)

    c.fill(210, 250, 255, 230)
    c.ellipse(bx, by + 28, 9, 9)

    c.fill(10, 75, 115)
    c.text("AI", bx - 7, by + 31)
  }

  // ----------------------------------------------------------
  // ROBOT ARMS
  // ----------------------------------------------------------

  def drawRobotArms(c: CanvasDraw): Unit = {
    val bx = robotX
    val by = robotY + robotBob

    val swing = if (wave) math.sin(armWave) * 15.0 else math.sin(t * 1.8) * 3.0

    c.stroke(225, 230, 235)
    c.strokeWeight(10)
    c.line(bx - 45, by + 43, bx - 64, by + 12)

    c.fill(35, 105, 135)
    c.stroke(70, 205, 235)
    c.strokeWeight(2)
    c.ellipse(bx - 64, by + 12, 17, 20)

    c.stroke(225, 230, 235)
    c.strokeWeight(9)
    c.line(bx - 64, by + 12, bx - 73, by - 18)

    c.fill(225, 230, 235)
    c.stroke(60, 70, 80)
    c.strokeWeight(1.5)
    c.ellipse(bx - 73, by - 27, 16, 18)

    val handY = by + 5 + swing

    c.stroke(225, 230, 235)
    c.strokeWeight(10)
    c.line(bx + 45, by + 43, bx + 65, by + 15)

    c.fill(35, 105, 135)
    c.stroke(70, 205, 235)
    c.strokeWeight(2)
    c.ellipse(bx + 65, by + 15, 17, 20)

    c.stroke(225, 230, 235)
    c.strokeWeight(9)
    c.line(bx + 65, by + 15, bx + 74, handY)

    c.fill(225, 230, 235)
    c.stroke(60, 70, 80)
    c.strokeWeight(1.5)
    c.ellipse(bx + 74, handY, 17, 19)

    c.stroke(80, 90, 100)
    c.strokeWeight(1)
    for (i <- 0 until 3) {
      c.line(bx + 76, handY - 5 + i * 4, bx + 84, handY - 6 + i * 4)
    }
  }

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

  def drawRobotBase(c: CanvasDraw): Unit = {
    val bx = robotX
    val by = robotY + robotBob

    c.fill(185, 192, 202)
    c.stroke(55, 65, 75)
    c.strokeWeight(2)
    c.ellipse(bx - 24, by - 28, 28, 18)
    c.ellipse(bx + 24, by - 28, 28, 18)

    c.fill(160, 170, 182)
    c.rect(bx - 25, by - 58, 50, 28)

    c.fill(0, 180, 240, 180)
    c.ellipse(bx, by - 62, 40, 9)
  }

  // ----------------------------------------------------------
  // AI SPEECH BUBBLE (BRIGHT BLUE TEXT USING java.awt.Color)
  // ----------------------------------------------------------

  def drawSpeechBubble(c: CanvasDraw): Unit = {
    val bx = robotX + 93
    val by = robotY + 105
    val pulse = 1.0 + math.sin(bubblePhase) * 0.02

    c.fill(245, 250, 252, 245)
    c.stroke(15, 110, 130)
    c.strokeWeight(2)
    c.rect(bx, by, 180 * pulse, 83 * pulse)

    c.fill(245, 250, 252)
    c.noStroke()
    c.ellipse(bx - 2, by + 4, 20, 18)

    // FORCE BRIGHT BLUE COLOR FOR TEXT
    c.fill(new java.awt.Color(0, 102, 255))

    c.text("AI IS ONLINE", bx + 15, by + 63)
    c.text("I AM YOUR", bx + 15, by + 45)
    c.text("SMART ROBOT", bx + 15, by + 29)

    val dotPhase = (math.sin(t * 5.0) + 1.0) * 0.5
    c.fill(0, 120, 255, alpha(120 + dotPhase * 120))
    c.ellipse(bx + 140, by + 18, 5, 5)
    c.ellipse(bx + 151, by + 18, 5, 5)
    c.ellipse(bx + 162, by + 18, 5, 5)
  }

  // ----------------------------------------------------------
  // AI STATUS TEXT
  // ----------------------------------------------------------

  def drawStatus(c: CanvasDraw): Unit = {
    c.fill(5, 70, 90)
    c.noStroke()
    c.text("ARTIFICIAL INTELLIGENCE", cwidth / 2.0 - 115, 20)

    c.fill(30, 110, 130, 180)
    c.text("CLICK / TOUCH THE SCREEN TO TALK WITH ROBOT", cwidth / 2.0 - 175, cheight - 25)
  }

  // ----------------------------------------------------------
  // CLICK EFFECT
  // ----------------------------------------------------------

  def drawClickEffect(c: CanvasDraw): Unit = {
    if (clicked) {
      val p = 12.0 + math.sin(t * 4.0) * 4.0
      c.noFill()
      c.stroke(0, 210, 255, 130)
      c.strokeWeight(2)
      c.ellipse(targetX, targetY, p, p)
    }
  }

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

  def drawLoop(c: CanvasDraw): Unit = {
    t += 0.04
    screenGlow += 0.08
    scanLine += 1.5
    eyeBlink += 0.03
    bubblePhase += 0.05

    drawBackground(c)
    drawTV(c)

    if (isMousePressed) {
      targetX = clamp(mouseX.toDouble, cwidth / 2.0 - 190.0, cwidth / 2.0 + 190.0)
      targetY = clamp(mouseY.toDouble, 115.0, 315.0)
      clicked = true
      wave = true
      talking = true
    }

    lookX = clamp((targetX - robotX) * 0.03, -4.0, 4.0)
    lookY = clamp((targetY - robotY) * 0.03, -3.0, 3.0)

    robotHead += ((targetX - robotX) * 0.015 - robotHead) * 0.08
    robotHead = clamp(robotHead, -8.0, 8.0)

    robotBob = math.sin(t * 2.0) * 2.0

    if (wave) {
      armWave += 0.24
      if (armWave > 12.0) {
        wave = false
        armWave = 0.0
      }
    }

    drawRobotBase(c)
    drawRobotBody(c)
    drawRobotArms(c)
    drawRobotHead(c)

    drawSpeechBubble(c)
    drawClickEffect(c)
    drawStatus(c)
  }
}

// ============================================================
// START
// ============================================================

val sketch = new Sketch
canvasSketch(sketch)