Code Sketch


vedika kumbhar
By: Mhalsakant School
Category: Programming
// ============================================================
// ? AI TV ROBOT - ULTRA ADVANCED ANIMATION
// 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)

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

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

    // tiny floating AI particles
    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

    // TV shadow
    c.fill(0, 0, 0, 35)
    c.noStroke()

    c.ellipse(
      tvX,
      68,
      480,
      35
    )

    // Main TV body
    c.fill(
      28,
      35,
      45
    )

    c.stroke(
      5,
      15,
      25
    )

    c.strokeWeight(4)

    c.rect(
      tvX - 260,
      tvY - 105,
      520,
      285
    )

    // outer highlight
    c.noFill()
    c.stroke(
      75,
      95,
      110,
      180
    )

    c.strokeWeight(2)

    c.rect(
      tvX - 250,
      tvY - 95,
      500,
      265
    )

    // --------------------------------------------------------
    // SCREEN
    // --------------------------------------------------------

    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
    )

    // Screen inner area
    c.fill(
      10,
      32,
      43
    )

    c.noStroke()

    c.rect(
      tvX - 216,
      tvY - 61,
      432,
      202
    )

    // --------------------------------------------------------
    // SCREEN GLOW
    // --------------------------------------------------------

    c.fill(
      0,
      190,
      220,
      18
    )

    c.ellipse(
      tvX,
      tvY + 30,
      380,
      190
    )

    // --------------------------------------------------------
    // SCAN LINES
    // --------------------------------------------------------

    val movingScanY =
      tvY - 55 +
      ((scanLine % 195.0))

    c.stroke(
      80,
      220,
      255,
      55
    )

    c.strokeWeight(1)

    c.line(
      tvX - 210,
      movingScanY,
      tvX + 210,
      movingScanY
    )

    // static scanlines
    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
      )
    }

    // --------------------------------------------------------
    // TV REFLECTION
    // --------------------------------------------------------

    c.fill(
      255,
      255,
      255,
      18
    )

    c.noStroke()

    c.ellipse(
      tvX - 145,
      tvY + 100,
      150,
      40
    )

    // --------------------------------------------------------
    // TV BUTTONS
    // --------------------------------------------------------

    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
    )

    // power light
    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
    )

    // --------------------------------------------------------
    // TV STAND
    // --------------------------------------------------------

    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
    )

    // stand reflection
    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

    // head shadow
    c.fill(
      0,
      0,
      0,
      50
    )

    c.noStroke()

    c.ellipse(
      hx + 3,
      hy - 3,
      72,
      58
    )

    // head
    c.fill(
      225,
      230,
      235
    )

    c.stroke(
      40,
      50,
      60
    )

    c.strokeWeight(2.5)

    c.rect(
      hx - 34,
      hy - 28,
      68,
      56
    )

    // forehead panel
    c.fill(
      35,
      105,
      135
    )

    c.stroke(
      90,
      215,
      240
    )

    c.strokeWeight(2)

    c.ellipse(
      hx,
      hy + 20,
      32,
      9
    )

    // --------------------------------------------------------
    // EYES
    // --------------------------------------------------------

    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
    )

    // eye cyan glow
    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
    )

    // mouth
    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
      )
    }

    // ears
    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
    )

    // ear LEDs
    c.fill(
      0,
      210,
      255,
      210
    )

    c.noStroke()

    c.ellipse(
      hx - 38,
      hy,
      5,
      7
    )

    c.ellipse(
      hx + 38,
      hy,
      5,
      7
    )

    // --------------------------------------------------------
    // ANTENNA
    // --------------------------------------------------------

    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

    // torso
    c.fill(
      215,
      220,
      228
    )

    c.stroke(
      45,
      55,
      65
    )

    c.strokeWeight(2)

    c.ellipse(
      bx,
      by + 20,
      90,
      100
    )

    // shoulder armor
    c.fill(
      40,
      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
    )

    // chest AI reactor
    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
    )

    // AI symbol
    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
      }

    // LEFT ARM
    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
    )

    // LEFT hand
    c.fill(
      225,
      230,
      235
    )

    c.stroke(
      60,
      70,
      80
    )

    c.strokeWeight(1.5)

    c.ellipse(
      bx - 73,
      by - 27,
      16,
      18
    )

    // RIGHT ARM
    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
    )

    // right hand
    c.fill(
      225,
      230,
      235
    )

    c.stroke(
      60,
      70,
      80
    )

    c.strokeWeight(1.5)

    c.ellipse(
      bx + 74,
      handY,
      17,
      19
    )

    // fingers
    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

    // hips
    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
    )

    // body lower support
    c.fill(
      160,
      170,
      182
    )

    c.rect(
      bx - 25,
      by - 58,
      50,
      28
    )

    // glowing base
    c.fill(
      0,
      180,
      240,
      180
    )

    c.ellipse(
      bx,
      by - 62,
      40,
      9
    )
  }

  // ----------------------------------------------------------
  // AI SPEECH BUBBLE
  // ----------------------------------------------------------

  def drawSpeechBubble(c: CanvasDraw): Unit = {

    val bx = robotX + 93
    val by = robotY + 105

    val pulse =
      1.0 +
      math.sin(bubblePhase) * 0.02

    // bubble body
    c.fill(
      245,
      250,
      252,
      245
    )

    c.stroke(
      15,
      110,
      130
    )

    c.strokeWeight(2)

    c.rect(
      bx,
      by,
      180 * pulse,
      83 * pulse
    )

    // tail
    c.fill(
      245,
      250,
      252
    )

    c.noStroke()

    c.ellipse(
      bx - 2,
      by + 4,
      20,
      18
    )

    // title
    c.fill(
      10,
      90,
      110
    )

    c.text(
      "AI IS ONLINE",
      bx + 15,
      by + 63
    )

    // animated message
    c.fill(
      35,
      85,
      105
    )

    c.text(
      "I AM YOUR",
      bx + 15,
      by + 45
    )

    c.text(
      "SMART ROBOT",
      bx + 15,
      by + 29
    )

    // typing dots
    val dotPhase =
      (math.sin(t * 5.0) + 1.0) * 0.5

    c.fill(
      0,
      160,
      205,
      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 = {

    // animation time
    t += 0.04
    screenGlow += 0.08
    scanLine += 1.5
    eyeBlink += 0.03
    bubblePhase += 0.05

    // --------------------------------------------------------
    // BACKGROUND
    // --------------------------------------------------------

    drawBackground(c)

    // --------------------------------------------------------
    // TV
    // --------------------------------------------------------

    drawTV(c)

    // --------------------------------------------------------
    // CLICK / TOUCH
    // --------------------------------------------------------

    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
    }

    // --------------------------------------------------------
    // ROBOT LOOKS TOWARD TOUCH
    // --------------------------------------------------------

    lookX =
      clamp(
        (targetX - robotX) * 0.03,
        -4.0,
        4.0
      )

    lookY =
      clamp(
        (targetY - robotY) * 0.03,
        -3.0,
        3.0
      )

    // --------------------------------------------------------
    // HEAD FOLLOW
    // --------------------------------------------------------

    robotHead +=
      ((targetX - robotX) * 0.015 -
       robotHead) * 0.08

    robotHead =
      clamp(
        robotHead,
        -8.0,
        8.0
      )

    // --------------------------------------------------------
    // ROBOT BOB
    // --------------------------------------------------------

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

    // --------------------------------------------------------
    // WAVE ARM
    // --------------------------------------------------------

    if (wave) {

      armWave += 0.24

      if (armWave > 12.0) {

        wave = false
        armWave = 0.0
      }
    }

    // --------------------------------------------------------
    // ROBOT PARTS
    // --------------------------------------------------------

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

    // --------------------------------------------------------
    // SPEECH
    // --------------------------------------------------------

    drawSpeechBubble(c)

    // --------------------------------------------------------
    // EFFECTS
    // --------------------------------------------------------

    drawClickEffect(c)

    // --------------------------------------------------------
    // STATUS
    // --------------------------------------------------------

    drawStatus(c)
  }
}

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

val sketch = new Sketch
canvasSketch(sketch)