Code Sketch


PURVA CHAVAN
By: Mhalsakant School
Category: Art
cleari()
originBottomLeft()

// ============================================================
// AI VS HUMAN INTELLIGENCE
// ADVANCED ANIMATED KOJO / SCALA PROJECT
// ============================================================

// ------------------------------------------------------------
// TIME / ANIMATION
// ------------------------------------------------------------

var t = 0.0
var focus = 0.0
var titleIndex = 0
var titleTimer = 0

val title =
  "ARTIFICIAL INTELLIGENCE VS HUMAN INTELLIGENCE"

// ------------------------------------------------------------
// PARTICLE SYSTEM
// ------------------------------------------------------------

case class Particle(
  var x: Double,
  var y: Double,
  var vx: Double,
  var vy: Double,
  var size: Double,
  var side: Int
)

val particles =
  scala.collection.mutable.ArrayBuffer.empty[Particle]

for (i <- 0 until 90) {

  val left =
    i % 2 == 0

  val px =
    if (left)
      30.0 + math.random * (cwidth * 0.40)
    else
      cwidth * 0.60 + math.random * (cwidth * 0.36)

  val py =
    70.0 + math.random * (cheight - 140.0)

  val vx =
    if (left)
      0.20 + math.random * 0.70
    else
      -(0.20 + math.random * 0.70)

  val vy =
    (math.random - 0.5) * 0.5

  particles.append(
    Particle(
      px,
      py,
      vx,
      vy,
      2.0 + math.random * 3.0,
      if (left) 0 else 1
    )
  )
}

// ------------------------------------------------------------
// HELPERS
// ------------------------------------------------------------

def clamp(
    v: Double,
    lo: Double,
    hi: Double
): Double = {

  math.max(
    lo,
    math.min(hi, v)
  )
}

def alphaValue(
    v: Double
): Int = {

  clamp(
    v,
    0.0,
    255.0
  ).toInt
}

// ------------------------------------------------------------
// UPDATE PARTICLES
// ------------------------------------------------------------

def updateParticles(): Unit = {

  particles.foreach { p =>

    p.x += p.vx
    p.y += p.vy

    if (p.side == 0) {

      if (p.x > cwidth * 0.48) {
        p.x = 25.0
      }

    } else {

      if (p.x < cwidth * 0.52) {
        p.x = cwidth - 25.0
      }
    }

    if (p.y < 60.0) {
      p.y = cheight - 60.0
    }

    if (p.y > cheight - 50.0) {
      p.y = 60.0
    }
  }
}

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

def drawBackground(
    canvas: CanvasDraw
): Unit = {

  canvas.background(
    6,
    9,
    22
  )

  // Left AI area
  canvas.fill(
    8,
    35,
    65,
    220
  )

  canvas.noStroke()

  canvas.rect(
    0,
    0,
    cwidth / 2.0,
    cheight
  )

  // Right human area
  canvas.fill(
    65,
    30,
    18,
    220
  )

  canvas.rect(
    cwidth / 2.0,
    0,
    cwidth / 2.0,
    cheight
  )

  // AI blue glow
  canvas.fill(
    0,
    150,
    255,
    22
  )

  canvas.ellipse(
    cwidth * 0.24,
    cheight * 0.52,
    400,
    320
  )

  // Human orange glow
  canvas.fill(
    255,
    110,
    40,
    20
  )

  canvas.ellipse(
    cwidth * 0.76,
    cheight * 0.52,
    400,
    320
  )
}

// ------------------------------------------------------------
// DIGITAL GRID
// ------------------------------------------------------------

def drawGrid(
    canvas: CanvasDraw
): Unit = {

  canvas.stroke(
    80,
    190,
    255,
    35
  )

  canvas.strokeWeight(1)

  var x = 0.0

  while (
    x < cwidth / 2.0
  ) {

    canvas.line(
      x,
      50,
      x,
      cheight - 45
    )

    x += 35.0
  }

  var y = 55.0

  while (
    y < cheight - 40.0
  ) {

    canvas.line(
      0,
      y,
      cwidth / 2.0,
      y
    )

    y += 35.0
  }

  canvas.stroke(
    255,
    170,
    100,
    30
  )

  x = cwidth / 2.0

  while (
    x < cwidth
  ) {

    canvas.line(
      x,
      50,
      x,
      cheight - 45
    )

    x += 35.0
  }

  y = 55.0

  while (
    y < cheight - 40.0
  ) {

    canvas.line(
      cwidth / 2.0,
      y,
      cwidth,
      y
    )

    y += 35.0
  }
}

// ------------------------------------------------------------
// PARTICLES
// ------------------------------------------------------------

def drawParticles(
    canvas: CanvasDraw
): Unit = {

  particles.foreach { p =>

    val glow =
      alphaValue(
        100.0 +
        math.sin(
          t * 4.0 + p.x * 0.01
        ) * 85.0
      )

    if (p.side == 0) {

      canvas.fill(
        70,
        210,
        255,
        glow
      )

    } else {

      canvas.fill(
        255,
        180,
        100,
        glow
      )
    }

    canvas.noStroke()

    canvas.ellipse(
      p.x,
      p.y,
      p.size,
      p.size
    )
  }
}

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

def drawRobotHead(
    canvas: CanvasDraw
): Unit = {

  val cx =
    cwidth * 0.24

  val cy =
    cheight * 0.51

  val pulse =
    math.sin(t * 3.0) * 3.0

  // Outer head
  canvas.fill(
    205,
    220,
    232
  )

  canvas.stroke(
    65,
    170,
    225
  )

  canvas.strokeWeight(3)

  canvas.ellipse(
    cx,
    cy,
    180 + pulse,
    215 + pulse
  )

  // Dark inner face
  canvas.fill(
    10,
    28,
    48
  )

  canvas.noStroke()

  canvas.ellipse(
    cx + 20,
    cy + 4,
    118,
    150
  )

  // Circuit rings
  canvas.noFill()

  canvas.stroke(
    40,
    190,
    255,
    180
  )

  canvas.strokeWeight(2)

  canvas.ellipse(
    cx,
    cy + 3,
    96,
    120
  )

  canvas.ellipse(
    cx,
    cy + 3,
    65,
    82
  )

  // Eye tracking
  val eyeShift =
    clamp(
      (mouseX.toDouble - cx) * 0.02,
      -7.0,
      7.0
    )

  canvas.fill(
    100,
    235,
    255
  )

  canvas.noStroke()

  canvas.ellipse(
    cx - 24 + eyeShift,
    cy + 25,
    9,
    9
  )

  canvas.ellipse(
    cx + 20 + eyeShift,
    cy + 25,
    9,
    9
  )

  // Head LEDs
  for (i <- 0 until 7) {

    val nx =
      cx - 55.0 + i * 18.0

    val ny =
      cy - 75.0 +
      math.sin(
        t * 3.0 + i
      ) * 6.0

    val glow =
      alphaValue(
        120.0 +
        math.sin(
          t * 4.0 + i
        ) * 100.0
      )

    canvas.fill(
      0,
      210,
      255,
      glow
    )

    canvas.ellipse(
      nx,
      ny,
      6,
      6
    )
  }
}

// ------------------------------------------------------------
// AI CIRCUIT NETWORK
// ------------------------------------------------------------

def drawCircuit(
    canvas: CanvasDraw
): Unit = {

  val cx =
    cwidth * 0.24

  val cy =
    cheight * 0.51

  val nodes = Array(
    (-55.0, 55.0),
    (-20.0, 80.0),
    (20.0, 60.0),
    (55.0, 32.0),
    (-45.0, 10.0),
    (0.0, 5.0),
    (45.0, -12.0),
    (-35.0, -40.0),
    (10.0, -55.0),
    (50.0, -45.0)
  )

  canvas.stroke(
    30,
    180,
    255,
    150
  )

  canvas.strokeWeight(
    1.5
  )

  for (
    i <- 0 until nodes.length - 1
  ) {

    canvas.line(
      cx + nodes(i)._1,
      cy + nodes(i)._2,
      cx + nodes(i + 1)._1,
      cy + nodes(i + 1)._2
    )
  }

  for (i <- nodes.indices) {

    val nx =
      cx + nodes(i)._1

    val ny =
      cy + nodes(i)._2

    val glow =
      4.0 +
      math.sin(
        t * 5.0 + i
      ) * 2.0

    canvas.fill(
      20,
      200,
      255,
      190
    )

    canvas.noStroke()

    canvas.ellipse(
      nx,
      ny,
      glow + 5,
      glow + 5
    )

    canvas.fill(
      220,
      250,
      255
    )

    canvas.ellipse(
      nx,
      ny,
      4,
      4
    )
  }
}

// ------------------------------------------------------------
// HUMAN BRAIN
// ------------------------------------------------------------

def drawBrain(
    canvas: CanvasDraw
): Unit = {

  val cx =
    cwidth * 0.76

  val cy =
    cheight * 0.51

  // Brain main
  canvas.fill(
    255,
    190,
    155
  )

  canvas.stroke(
    255,
    140,
    90
  )

  canvas.strokeWeight(3)

  canvas.ellipse(
    cx,
    cy,
    178,
    215
  )

  // Brain center
  canvas.fill(
    255,
    140,
    85,
    80
  )

  canvas.noStroke()

  canvas.ellipse(
    cx - 20,
    cy + 8,
    90,
    145
  )

  // Neural lines
  canvas.stroke(
    255,
    235,
    195
  )

  canvas.strokeWeight(2)

  canvas.noFill()

  for (i <- 0 until 7) {

    val yy =
      cy - 58.0 +
      i * 18.0

    canvas.line(
      cx - 45,
      yy,
      cx - 10,
      yy + 8
    )

    canvas.line(
      cx - 10,
      yy + 8,
      cx + 15,
      yy - 4
    )

    canvas.line(
      cx + 15,
      yy - 4,
      cx + 45,
      yy + 6
    )
  }

  // Eyes
  val eyeShift =
    clamp(
      (mouseX.toDouble - cx) * 0.02,
      -7.0,
      7.0
    )

  canvas.fill(
    255,
    240,
    215
  )

  canvas.noStroke()

  canvas.ellipse(
    cx - 25 + eyeShift,
    cy + 5,
    10,
    10
  )

  canvas.ellipse(
    cx + 25 + eyeShift,
    cy + 5,
    10,
    10
  )
}

// ------------------------------------------------------------
// HUMAN NEURAL NETWORK
// ------------------------------------------------------------

def drawHumanNetwork(
    canvas: CanvasDraw
): Unit = {

  val cx =
    cwidth * 0.76

  val cy =
    cheight * 0.51

  val nodes = Array(
    (-50.0, 55.0),
    (-18.0, 82.0),
    (20.0, 60.0),
    (52.0, 30.0),
    (-50.0, 8.0),
    (0.0, 4.0),
    (45.0, -12.0),
    (-35.0, -42.0),
    (8.0, -55.0),
    (48.0, -44.0)
  )

  canvas.stroke(
    255,
    185,
    105,
    150
  )

  canvas.strokeWeight(1.5)

  for (
    i <- 0 until nodes.length - 1
  ) {

    canvas.line(
      cx + nodes(i)._1,
      cy + nodes(i)._2,
      cx + nodes(i + 1)._1,
      cy + nodes(i + 1)._2
    )
  }

  for (i <- nodes.indices) {

    val nx =
      cx + nodes(i)._1

    val ny =
      cy + nodes(i)._2

    val size =
      5.0 +
      math.sin(
        t * 4.0 + i
      ) * 2.0

    canvas.fill(
      255,
      185,
      100,
      200
    )

    canvas.noStroke()

    canvas.ellipse(
      nx,
      ny,
      size,
      size
    )
  }
}

// ------------------------------------------------------------
// HUMAN STUDENTS
// ------------------------------------------------------------

def drawStudents(
    canvas: CanvasDraw
): Unit = {

  val baseX =
    cwidth * 0.80

  val baseY =
    105.0

  for (i <- 0 until 3) {

    val px =
      baseX - i * 62.0

    val py =
      baseY +
      math.sin(
        t * 2.0 + i
      ) * 2.0

    // head
    canvas.fill(
      255,
      205,
      175
    )

    canvas.noStroke()

    canvas.ellipse(
      px,
      py + 45,
      17,
      17
    )

    // body
    canvas.fill(
      90 + i * 35,
      70 + i * 20,
      60
    )

    canvas.rect(
      px - 14,
      py + 15,
      28,
      28
    )

    // arms
    canvas.stroke(
      210,
      160,
      130
    )

    canvas.strokeWeight(4)

    canvas.line(
      px - 8,
      py + 22,
      px - 20,
      py + 4
    )

    canvas.line(
      px + 8,
      py + 22,
      px + 20,
      py + 4
    )
  }

  // Learning nodes
  canvas.fill(
    255,
    180,
    90,
    200
  )

  canvas.noStroke()

  canvas.ellipse(
    baseX - 30,
    baseY + 12,
    7,
    7
  )

  canvas.ellipse(
    baseX - 45,
    baseY + 26,
    7,
    7
  )

  canvas.ellipse(
    baseX - 18,
    baseY + 30,
    7,
    7
  )
}

// ------------------------------------------------------------
// ROBOT / HUMAN HANDS
// ------------------------------------------------------------

def drawHands(
    canvas: CanvasDraw
): Unit = {

  val y =
    78.0

  // AI hand
  canvas.stroke(
    190,
    210,
    225
  )

  canvas.strokeWeight(9)

  canvas.line(
    cwidth * 0.15,
    y,
    cwidth * 0.34,
    y + 14
  )

  // Human hand
  canvas.line(
    cwidth * 0.85,
    y,
    cwidth * 0.66,
    y + 14
  )

  canvas.fill(
    210,
    220,
    230
  )

  canvas.stroke(
    90,
    120,
    140
  )

  canvas.strokeWeight(2)

  canvas.ellipse(
    cwidth * 0.34,
    y + 14,
    26,
    19
  )

  canvas.fill(
    235,
    180,
    145
  )

  canvas.ellipse(
    cwidth * 0.66,
    y + 14,
    26,
    19
  )

  canvas.strokeWeight(1.5)

  for (i <- 0 until 3) {

    val fy =
      y + 8 + i * 5

    canvas.line(
      cwidth * 0.34,
      fy,
      cwidth * 0.34 + 14,
      fy
    )

    canvas.line(
      cwidth * 0.66,
      fy,
      cwidth * 0.66 - 14,
      fy
    )
  }
}

// ------------------------------------------------------------
// CENTER ENERGY
// ------------------------------------------------------------

def drawCenterEnergy(
    canvas: CanvasDraw
): Unit = {

  val cx =
    cwidth / 2.0

  val cy =
    cheight * 0.50

  val power =
    22.0 +
    math.sin(
      t * 6.0
    ) * 8.0

  canvas.fill(
    255,
    220,
    100,
    22
  )

  canvas.noStroke()

  canvas.ellipse(
    cx,
    cy,
    power * 4,
    power * 4
  )

  canvas.stroke(
    90,
    225,
    255,
    210
  )

  canvas.strokeWeight(3)

  canvas.line(
    cwidth * 0.47,
    cy,
    cwidth * 0.53,
    cy
  )

  canvas.stroke(
    255,
    190,
    100,
    170
  )

  canvas.strokeWeight(2)

  for (i <- 0 until 6) {

    val yy =
      cy - 30.0 +
      i * 12.0

    canvas.line(
      cwidth * 0.47,
      yy,
      cwidth * 0.53,
      yy +
        math.sin(
          t * 8.0 + i
        ) * 7.0
    )
  }

  canvas.fill(
    255,
    250,
    205
  )

  canvas.noStroke()

  canvas.ellipse(
    cx,
    cy,
    power,
    power
  )
}

// ------------------------------------------------------------
// FOCUS BORDER
// ------------------------------------------------------------

def drawFocus(
    canvas: CanvasDraw
): Unit = {

  val aiAlpha =
    alphaValue(
      100.0 + focus * 110.0
    )

  val humanAlpha =
    alphaValue(
      100.0 + (1.0 - focus) * 110.0
    )

  canvas.noFill()

  canvas.stroke(
    30,
    210,
    255,
    aiAlpha
  )

  canvas.strokeWeight(3)

  canvas.rect(
    15,
    48,
    cwidth / 2.0 - 30,
    cheight - 118
  )

  canvas.stroke(
    255,
    180,
    100,
    humanAlpha
  )

  canvas.rect(
    cwidth / 2.0 + 15,
    48,
    cwidth / 2.0 - 30,
    cheight - 118
  )
}

// ------------------------------------------------------------
// TITLE
// ------------------------------------------------------------

def drawTitle(
    canvas: CanvasDraw
): Unit = {

  if (titleIndex > 0) {

    val shown =
      title.substring(
        0,
        titleIndex
      )

    canvas.fill(
      245,
      245,
      250
    )

    canvas.noStroke()

    canvas.text(
      shown,
      cwidth / 2.0 - 190,
      cheight - 22
    )
  }
}

// ------------------------------------------------------------
// HUD
// ------------------------------------------------------------

def drawHUD(
    canvas: CanvasDraw
): Unit = {

  canvas.fill(
    5,
    15,
    30,
    225
  )

  canvas.stroke(
    70,
    210,
    255,
    160
  )

  canvas.strokeWeight(2)

  canvas.rect(
    18,
    cheight - 58,
    310,
    34
  )

  canvas.fill(
    100,
    230,
    255
  )

  canvas.noStroke()

  canvas.text(
    "AI SYSTEM: ACTIVE",
    30,
    cheight - 37
  )

  canvas.fill(
    255,
    190,
    110
  )

  canvas.text(
    "HUMAN MIND: ACTIVE",
    cwidth - 150,
    cheight - 37
  )

  canvas.fill(
    225,
    235,
    245
  )

  canvas.text(
    "CLICK LEFT OR RIGHT SIDE",
    cwidth / 2.0 - 85,
    25
  )
}

// ------------------------------------------------------------
// COMPLETE SCENE
// ------------------------------------------------------------

def drawScene(
    canvas: CanvasDraw
): Unit = {

  drawBackground(canvas)

  drawGrid(canvas)

  drawFocus(canvas)

  drawRobotHead(canvas)

  drawBrain(canvas)

  drawCircuit(canvas)

  drawHumanNetwork(canvas)

  drawStudents(canvas)

  drawHands(canvas)

  drawParticles(canvas)

  drawCenterEnergy(canvas)

  drawTitle(canvas)

  drawHUD(canvas)
}

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

animateWithCanvasDraw { canvas =>

  t += 0.04

  updateParticles()

  // Mouse focus
  if (mouseX < cwidth / 2.0) {

    focus +=
      (0.0 - focus) * 0.08

  } else {

    focus +=
      (1.0 - focus) * 0.08
  }

  // Typewriter title
  titleTimer += 1

  if (
    titleTimer % 4 == 0 &&
    titleIndex < title.length
  ) {

    titleIndex += 1
  }

  drawScene(canvas)
}