Code Sketch


krishna
By: Mhalsakant School
cleari()
originBottomLeft()

// ============================================================
// SHRI KRISHNA JANMASHTAMI
// ADVANCED KOJO SCALA ANIMATION
// CLEAN VERSION
// ============================================================

// ------------------------------------------------------------
// GLOBAL ANIMATION
// ------------------------------------------------------------

var t = 0.0
var moonGlow = 0.0
var featherGlow = 0.0
var flutePhase = 0.0
var clothPhase = 0.0
var birdPhase = 0.0
var waterPhase = 0.0
var particlePhase = 0.0
var flowerPhase = 0.0

// ------------------------------------------------------------
// AUDIO
// ------------------------------------------------------------

var musicOn = false

try {
  setNoteInstrument(Instrument.PIANO)
  musicOn = true
} catch {
  case _: Exception =>
}

val fluteTune =
  Array(
    67, 69, 72, 74,
    72, 69, 67, 65,
    67, 69, 72, 77,
    74, 72, 69, 67
  )

var noteIndex = 0
var noteTimer = 0

def playKrishnaTune(): Unit = {

  if (!musicOn) return

  noteTimer += 1

  if (noteTimer % 32 == 0) {

    try {
      playNote(
        fluteTune(noteIndex),
        180
      )
    } catch {
      case _: Exception =>
    }

    noteIndex =
      (noteIndex + 1) %
      fluteTune.length
  }
}

// ============================================================
// STAR FIELD
// ============================================================

val starCount = 100

val starX =
  Array.fill(starCount)(
    math.random * cwidth
  )

val starY =
  Array.fill(starCount)(
    230.0 +
    math.random * 250.0
  )

val starS =
  Array.fill(starCount)(
    0.8 +
    math.random * 2.2
  )

// ============================================================
// LIGHT PARTICLES
// ============================================================

case class LightParticle(
  var x: Double,
  var y: Double,
  var vx: Double,
  var vy: Double,
  var size: Double,
  var phase: Double
)

val lights =
  scala.collection.mutable.ArrayBuffer.empty[LightParticle]

for (i <- 0 until 55) {

  lights.append(
    LightParticle(
      80.0 +
        math.random *
        (cwidth - 160.0),

      120.0 +
        math.random *
        330.0,

      (math.random - 0.5) * 0.25,

      0.15 +
        math.random * 0.45,

      2.0 +
        math.random * 4.0,

      math.random * 6.28
    )
  )
}

// ============================================================
// FLOWER PARTICLES
// ============================================================

case class Flower(
  var x: Double,
  var y: Double,
  var speed: Double,
  var size: Double,
  var phase: Double
)

val flowers =
  scala.collection.mutable.ArrayBuffer.empty[Flower]

for (i <- 0 until 28) {

  flowers.append(
    Flower(
      100.0 +
        math.random *
        (cwidth - 200.0),

      120.0 +
        math.random * 150.0,

      0.2 +
        math.random * 0.3,

      3.0 +
        math.random * 5.0,

      math.random * 6.28
    )
  )
}

// ============================================================
// BIRDS
// ============================================================

case class Bird(
  var x: Double,
  var y: Double,
  var speed: Double,
  var size: Double,
  var phase: Double
)

val birds =
  scala.collection.mutable.ArrayBuffer.empty[Bird]

for (i <- 0 until 10) {

  birds.append(
    Bird(
      40.0 +
        math.random * 270.0,

      355.0 +
        math.random * 95.0,

      0.25 +
        math.random * 0.55,

      4.0 +
        math.random * 4.0,

      math.random * 6.28
    )
  )
}

// ============================================================
// UPDATE PARTICLES
// ============================================================

def updateParticles(): Unit = {

  lights.foreach { p =>

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

    p.x +=
      math.sin(
        t + p.phase
      ) * 0.10

    if (p.y > 515) {

      p.y = 120

      p.x =
        80 +
        math.random *
        (cwidth - 160)
    }
  }

  flowers.foreach { f =>

    f.y -= f.speed

    f.x +=
      math.sin(
        t + f.phase
      ) * 0.20

    if (f.y < 90) {

      f.y = 280

      f.x =
        100 +
        math.random *
        (cwidth - 200)
    }
  }

  birds.foreach { b =>

    b.x += b.speed

    b.y +=
      math.sin(
        birdPhase +
        b.phase
      ) * 0.25

    if (b.x > cwidth + 30) {

      b.x = -20

      b.y =
        350 +
        math.random * 100
    }
  }
}

// ============================================================
// BACKGROUND
// ============================================================

def drawBackground(
  c: CanvasDraw
): Unit = {

  c.background(
    52,
    17,
    57
  )

  // Main purple atmosphere
  c.fill(
    95,
    25,
    85,
    80
  )

  c.noStroke()

  c.ellipse(
    cwidth / 2.0,
    320,
    560,
    470
  )

  // Extra glow
  c.fill(
    135,
    35,
    105,
    45
  )

  c.ellipse(
    cwidth / 2.0,
    350,
    420,
    350
  )

  // Stars
  for (i <- 0 until starCount) {

    val a =
      (
        70 +
        math.abs(
          math.sin(
            t * 2.0 + i
          )
        ) * 160
      ).toInt

    c.fill(
      255,
      220,
      245,
      a
    )

    c.noStroke()

    c.ellipse(
      starX(i),
      starY(i),
      starS(i),
      starS(i)
    )
  }
}

// ============================================================
// MOON
// ============================================================

def drawMoon(
  c: CanvasDraw
): Unit = {

  val cx = 325.0
  val cy = 390.0

  val pulse =
    1.0 +
    math.sin(
      moonGlow
    ) * 0.04

  // Outer glow
  c.fill(
    255,
    245,
    255,
    25
  )

  c.noStroke()

  c.ellipse(
    cx,
    cy,
    310 * pulse,
    310 * pulse
  )

  // Middle glow
  c.fill(
    255,
    250,
    255,
    45
  )

  c.ellipse(
    cx,
    cy,
    260 * pulse,
    260 * pulse
  )

  // Moon
  c.fill(
    245,
    239,
    250
  )

  c.stroke(
    235,
    225,
    245
  )

  c.strokeWeight(2)

  c.ellipse(
    cx,
    cy,
    215,
    215
  )
}

// ============================================================
// WOOD LOG
// ============================================================

def drawLog(
  c: CanvasDraw
): Unit = {

  val x1 = 170.0
  val y1 = 175.0
  val w = 520.0
  val h = 120.0

  // Shadow
  c.fill(
    0,
    0,
    0,
    60
  )

  c.noStroke()

  c.ellipse(
    430,
    145,
    600,
    45
  )

  // Main body
  c.fill(
    108,
    64,
    27
  )

  c.stroke(
    65,
    37,
    17
  )

  c.strokeWeight(3)

  c.rect(
    x1,
    y1,
    w,
    h
  )

  // Wood lines
  c.stroke(
    156,
    101,
    48,
    170
  )

  c.strokeWeight(4)

  for (i <- 0 until 8) {

    val yy =
      y1 +
      15 +
      i * 13

    c.line(
      x1 + 20,
      yy,
      x1 + w - 35,
      yy +
        math.sin(
          t + i
        ) * 2
    )
  }

  // Right end
  c.fill(
    170,
    115,
    62
  )

  c.stroke(
    98,
    57,
    26
  )

  c.strokeWeight(3)

  c.ellipse(
    x1 + w,
    y1 + h / 2,
    110,
    105
  )

  // Rings
  c.noFill()

  c.stroke(
    110,
    65,
    30,
    190
  )

  c.strokeWeight(2)

  c.ellipse(
    x1 + w,
    y1 + h / 2,
    72,
    70
  )

  c.ellipse(
    x1 + w,
    y1 + h / 2,
    47,
    45
  )
}

// ============================================================
// KRISHNA BODY
// ============================================================

def drawKrishna(
  c: CanvasDraw
): Unit = {

  val cx = 335.0

  val bodyBob =
    math.sin(
      t * 1.5
    ) * 2.0

  val faceY =
    315.0 +
    bodyBob

  // Sitting orange cloth
  c.fill(
    255,
    153,
    30
  )

  c.stroke(
    212,
    105,
    15
  )

  c.strokeWeight(2)

  c.ellipse(
    cx - 10,
    185,
    175,
    135
  )

  // Pink waist cloth
  c.fill(
    240,
    80,
    155
  )

  c.noStroke()

  c.rect(
    cx - 70,
    205,
    125,
    55
  )

  // Blue legs
  c.fill(
    50,
    175,
    235
  )

  c.stroke(
    20,
    105,
    160
  )

  c.strokeWeight(2)

  c.ellipse(
    cx - 55,
    185,
    95,
    130
  )

  c.ellipse(
    cx + 35,
    185,
    95,
    130
  )

  // Foot
  c.ellipse(
    cx + 10,
    125,
    40,
    90
  )

  // Body
  c.fill(
    45,
    175,
    235
  )

  c.ellipse(
    cx,
    260,
    95,
    145
  )

  // Shoulders
  c.ellipse(
    cx - 50,
    280,
    45,
    80
  )

  c.ellipse(
    cx + 50,
    280,
    45,
    80
  )

  // Neck
  c.fill(
    45,
    174,
    232
  )

  c.noStroke()

  c.rect(
    cx - 22,
    295,
    44,
    46
  )

  // Face
  c.fill(
    50,
    182,
    240
  )

  c.stroke(
    15,
    90,
    145
  )

  c.strokeWeight(2)

  c.ellipse(
    cx,
    faceY,
    82,
    105
  )

  // Ears
  c.fill(
    45,
    165,
    225
  )

  c.ellipse(
    cx - 44,
    faceY,
    18,
    38
  )

  c.ellipse(
    cx + 44,
    faceY,
    18,
    38
  )

  // Hair
  c.fill(
    25,
    24,
    31
  )

  c.noStroke()

  c.ellipse(
    cx,
    faceY + 42,
    66,
    52
  )

  for (i <- 0 until 14) {

    val angle =
      i * 26.0

    val rad =
      math.toRadians(
        angle
      )

    c.ellipse(
      cx +
        math.cos(rad) * 27,
      faceY +
        38 +
        math.sin(rad) * 23,
      20,
      18
    )
  }

  // Eyes
  c.noFill()

  c.stroke(
    20,
    60,
    95
  )

  c.strokeWeight(2.5)

  c.arc(
    cx - 17,
    faceY + 3,
    24,
    14,
    math.Pi,
    math.Pi * 2
  )

  c.arc(
    cx + 17,
    faceY + 3,
    24,
    14,
    math.Pi,
    math.Pi * 2
  )

  // Nose
  c.line(
    cx,
    faceY - 2,
    cx - 5,
    faceY - 22
  )

  // Smile
  c.arc(
    cx,
    faceY - 32,
    28,
    14,
    math.Pi,
    math.Pi * 2
  )

  // Tilak
  c.stroke(
    250,
    250,
    255
  )

  c.strokeWeight(3)

  c.line(
    cx - 8,
    faceY + 28,
    cx,
    faceY + 40
  )

  c.line(
    cx + 8,
    faceY + 28,
    cx,
    faceY + 40
  )

  // Golden jewelry
  c.fill(
    255,
    196,
    45
  )

  c.noStroke()

  c.ellipse(
    cx,
    faceY + 46,
    9,
    12
  )

  c.ellipse(
    cx - 34,
    290,
    10,
    20
  )

  c.ellipse(
    cx + 34,
    290,
    10,
    20
  )

  // Necklace
  c.stroke(
    255,
    205,
    55
  )

  c.strokeWeight(4)

  c.arc(
    cx,
    260,
    70,
    55,
    math.Pi * 0.2,
    math.Pi * 0.8
  )

  // Arms
  c.stroke(
    48,
    176,
    235
  )

  c.strokeWeight(14)

  c.line(
    cx - 48,
    280,
    cx - 105,
    325
  )

  c.line(
    cx + 48,
    280,
    cx + 92,
    325
  )

  // Hands
  c.fill(
    50,
    178,
    237
  )

  c.noStroke()

  c.ellipse(
    cx - 112,
    327,
    25,
    28
  )

  c.ellipse(
    cx + 100,
    327,
    25,
    28
  )
}

// ============================================================
// PEACOCK FEATHER
// ============================================================

def drawPeacockFeather(
  c: CanvasDraw
): Unit = {

  val cx = 345.0
  val cy = 395.0

  val bob =
    math.sin(
      featherGlow
    ) * 2.5

  // Stem
  c.stroke(
    50,
    135,
    55
  )

  c.strokeWeight(4)

  c.line(
    cx,
    cy,
    cx + 13,
    cy + 100
  )

  // Feather
  c.fill(
    45,
    150,
    55
  )

  c.stroke(
    25,
    105,
    40
  )

  c.strokeWeight(2)

  c.beginShape()

  c.vertex(
    cx,
    cy
  )

  c.vertex(
    cx - 28,
    cy + 40 + bob
  )

  c.vertex(
    cx - 22,
    cy + 90
  )

  c.vertex(
    cx,
    cy + 128
  )

  c.vertex(
    cx + 25,
    cy + 90
  )

  c.vertex(
    cx + 32,
    cy + 42
  )

  c.endShape()

  // Feather eye
  c.fill(
    20,
    95,
    210
  )

  c.noStroke()

  c.ellipse(
    cx + 2,
    cy + 78 + bob,
    28,
    38
  )

  c.fill(
    8,
    30,
    70
  )

  c.ellipse(
    cx + 2,
    cy + 80 + bob,
    14,
    20
  )

  c.fill(
    255,
    220,
    80
  )

  c.ellipse(
    cx - 3,
    cy + 88 + bob,
    5,
    5
  )
}

// ============================================================
// FLUTE
// ============================================================

def drawFlute(
  c: CanvasDraw
): Unit = {

  val cx = 333.0
  val cy = 327.0

  val sway =
    math.sin(
      flutePhase
    ) * 2.5

  c.pushMatrix()

  c.translate(
    sway,
    0
  )

  c.stroke(
    245,
    170,
    45
  )

  c.strokeWeight(6)

  c.line(
    cx - 115,
    cy,
    cx + 115,
    cy
  )

  // Holes
  c.fill(
    90,
    45,
    20
  )

  c.noStroke()

  for (i <- 0 until 7) {

    val x =
      cx - 72 +
      i * 24

    c.ellipse(
      x,
      cy,
      6,
      4
    )
  }

  // Ends
  c.fill(
    255,
    205,
    80
  )

  c.ellipse(
    cx - 118,
    cy,
    10,
    10
  )

  c.ellipse(
    cx + 118,
    cy,
    10,
    10
  )

  c.popMatrix()
}

// ============================================================
// ORANGE FLOWING CLOTH
// ============================================================

def drawCloth(
  c: CanvasDraw
): Unit = {

  val sway =
    math.sin(
      clothPhase
    )

  c.noStroke()

  c.fill(
    255,
    160,
    35
  )

  c.beginShape()

  c.vertex(
    270,
    260
  )

  c.vertex(
    215,
    185
  )

  c.vertex(
    190,
    120
  )

  c.vertex(
    235,
    132 + sway * 6
  )

  c.vertex(
    290,
    215
  )

  c.endShape()

  c.beginShape()

  c.vertex(
    405,
    260
  )

  c.vertex(
    465,
    180
  )

  c.vertex(
    495,
    125
  )

  c.vertex(
    450,
    140 + sway * 5
  )

  c.vertex(
    385,
    220
  )

  c.endShape()

  // Highlights
  c.stroke(
    255,
    198,
    85,
    170
  )

  c.strokeWeight(3)

  c.line(
    230,
    150,
    270,
    225
  )

  c.line(
    455,
    150,
    410,
    225
  )
}

// ============================================================
// BUTTER POT
// FIXED: ONLY RECT IS USED
// ============================================================

def drawButterPot(
  c: CanvasDraw,
  x: Double,
  y: Double,
  scale: Double
): Unit = {

  // Shadow
  c.fill(
    0,
    0,
    0,
    45
  )

  c.noStroke()

  c.ellipse(
    x,
    y - 35 * scale,
    100 * scale,
    20 * scale
  )

  // Pot
  c.fill(
    245,
    155,
    25
  )

  c.stroke(
    180,
    95,
    12
  )

  c.strokeWeight(2)

  c.ellipse(
    x,
    y,
    95 * scale,
    125 * scale
  )

  // Golden rim
  c.fill(
    255,
    204,
    60
  )

  c.noStroke()

  c.ellipse(
    x,
    y + 48 * scale,
    78 * scale,
    16 * scale
  )

  // Butter
  c.fill(
    255,
    250,
    240
  )

  c.noStroke()

  c.ellipse(
    x,
    y + 57 * scale,
    68 * scale,
    28 * scale
  )

  // Left drip
  val drip1 =
    18.0 +
    math.abs(
      math.sin(
        t * 1.5 + x
      )
    ) * 6.0

  c.rect(
    x - 32 * scale,
    y + 40 * scale,
    5 * scale,
    drip1 * scale
  )

  // Right drip
  val drip2 =
    20.0 +
    math.abs(
      math.sin(
        t * 1.7 + x + 2
      )
    ) * 7.0

  c.rect(
    x + 15 * scale,
    y + 40 * scale,
    5 * scale,
    drip2 * scale
  )

  // Center drip
  val drip3 =
    10.0 +
    math.abs(
      math.sin(
        t * 2.0 + x
      )
    ) * 5.0

  c.rect(
    x - 3 * scale,
    y + 42 * scale,
    5 * scale,
    drip3 * scale
  )

  // Golden decoration
  c.noFill()

  c.stroke(
    255,
    210,
    70
  )

  c.strokeWeight(4)

  c.arc(
    x,
    y + 48 * scale,
    80 * scale,
    18 * scale,
    0,
    math.Pi
  )
}

// ============================================================
// BUTTER POTS
// ============================================================

def drawButterPots(
  c: CanvasDraw
): Unit = {

  drawButterPot(
    c,
    145,
    115,
    0.80
  )

  drawButterPot(
    c,
    300,
    108,
    0.78
  )
}

// ============================================================
// FLOWERS
// ============================================================

def drawFlowers(
  c: CanvasDraw
): Unit = {

  for (i <- 0 until 18) {

    val x =
      150 +
      i * 27

    val y =
      88 +
      math.sin(
        flowerPhase + i
      ) * 8

    if (i % 2 == 0) {

      c.fill(
        255,
        205,
        80
      )

    } else {

      c.fill(
        240,
        165,
        80
      )
    }

    c.noStroke()

    c.ellipse(
      x,
      y,
      7,
      5
    )

    c.ellipse(
      x + 6,
      y + 2,
      7,
      5
    )

    c.ellipse(
      x - 5,
      y + 2,
      7,
      5
    )

    c.fill(
      205,
      120,
      35
    )

    c.ellipse(
      x,
      y + 1,
      4,
      4
    )
  }
}

// ============================================================
// BIRDS
// ============================================================

def drawBirds(
  c: CanvasDraw
): Unit = {

  birds.foreach { b =>

    val wing =
      math.sin(
        birdPhase * 4 +
        b.phase
      ) * 4

    c.noFill()

    c.stroke(
      205,
      190,
      220
    )

    c.strokeWeight(2)

    c.arc(
      b.x,
      b.y,
      b.size * 2,
      b.size + wing,
      math.Pi,
      math.Pi * 2
    )

    c.arc(
      b.x + b.size,
      b.y,
      b.size * 2,
      b.size - wing,
      math.Pi,
      math.Pi * 2
    )
  }
}

// ============================================================
// FLOATING LIGHTS
// ============================================================

def drawLights(
  c: CanvasDraw
): Unit = {

  lights.foreach { p =>

    val alpha =
      (
        50 +
        math.abs(
          math.sin(
            t + p.phase
          )
        ) * 170
      ).toInt

    c.fill(
      255,
      208,
      100,
      alpha
    )

    c.noStroke()

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

// ============================================================
// FESTIVE LIGHT RAYS
// ============================================================

def drawFestiveGlow(
  c: CanvasDraw
): Unit = {

  val cx = 340.0
  val cy = 375.0

  for (i <- 0 until 18) {

    val angle =
      i * 20.0 +
      t * 8.0

    val rad =
      math.toRadians(
        angle
      )

    val len =
      100.0 +
      math.abs(
        math.sin(
          t * 2.0 + i
        )
      ) * 55.0

    c.stroke(
      255,
      205,
      85,
      45
    )

    c.strokeWeight(
      2
    )

    c.line(
      cx +
        math.cos(rad) * 80,
      cy +
        math.sin(rad) * 80,
      cx +
        math.cos(rad) * len,
      cy +
        math.sin(rad) * len
    )
  }
}

// ============================================================
// TEXT
// ============================================================

def drawText(
  c: CanvasDraw
): Unit = {

  c.fill(
    255,
    210,
    45
  )

  c.noStroke()

  c.text(
    "SHRI KRISHNA",
    470,
    330
  )

  c.fill(
    250,
    245,
    245
  )

  c.text(
    "JANMASHTAMI",
    440,
    275
  )

  c.fill(
    225,
    155,
    205
  )

  c.text(
    "LOVE  PEACE  DEVOTION",
    340,
    42
  )
}

// ============================================================
// COMPLETE SCENE
// ============================================================

def drawScene(
  c: CanvasDraw
): Unit = {

  drawBackground(c)

  drawFestiveGlow(c)

  drawMoon(c)

  drawBirds(c)

  drawLog(c)

  drawButterPots(c)

  drawKrishna(c)

  drawCloth(c)

  drawPeacockFeather(c)

  drawFlute(c)

  drawFlowers(c)

  drawLights(c)

  drawText(c)
}

// ============================================================
// MAIN ANIMATION
// ============================================================

animateWithCanvasDraw { c =>

  t += 0.04

  moonGlow += 0.045

  featherGlow += 0.06

  flutePhase += 0.08

  clothPhase += 0.065

  birdPhase += 0.08

  waterPhase += 0.06

  particlePhase += 0.05

  flowerPhase += 0.05

  updateParticles()

  playKrishnaTune()

  drawScene(c)
}