Code Sketch


aishwarya deshmukh
By: Mhalsakant School
Category: Programming
cleari()
originBottomLeft()

// ============================================================
// NAG PANCHAMI - ADVANCED ANIMATION
// ============================================================

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

var time = 0.0
var snakePhase = 0.0
var lampPhase = 0.0
var glowPhase = 0.0

var pujaStarted = false

var titleIndex = 0
var titleTimer = 0

val titleText = "HAPPY NAG PANCHAMI"

// ------------------------------------------------------------
// HELPER FUNCTION
// ------------------------------------------------------------

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

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

// ------------------------------------------------------------
// SPARK PARTICLE
// ------------------------------------------------------------

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

val sparks =
  scala.collection.mutable.ArrayBuffer.empty[Spark]

for (i <- 0 until 45) {

  sparks.append(
    Spark(
      20.0 + math.random * (cwidth - 40.0),
      60.0 + math.random * (cheight - 100.0),
      0.3 + math.random * 0.8,
      2.0 + math.random * 3.0
    )
  )
}

// ------------------------------------------------------------
// UPDATE SPARKS
// ------------------------------------------------------------

def updateSparks(): Unit = {

  sparks.foreach { s =>

    s.y += s.speed

    if (s.y > cheight - 40.0) {

      s.y = 60.0
      s.x =
        20.0 + math.random * (cwidth - 40.0)
    }
  }
}

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

def drawBackground(
    canvas: CanvasDraw
): Unit = {

  canvas.background(
    248,
    245,
    238
  )

  // Main soft glow
  canvas.fill(
    255,
    200,
    70,
    18
  )

  canvas.noStroke()

  canvas.ellipse(
    cwidth / 2.0,
    cheight / 2.0 + 20.0,
    520.0,
    340.0
  )

  // Small warm dots
  for (i <- 0 until 20) {

    val x =
      25.0 + i * 37.0

    val y =
      cheight - 30.0 +
      math.sin(
        time * 2.0 + i
      ) * 3.0

    canvas.fill(
      220,
      155,
      40,
      90
    )

    canvas.ellipse(
      x,
      y,
      4.0,
      4.0
    )
  }
}

// ------------------------------------------------------------
// DECORATIVE BORDER
// ------------------------------------------------------------

def drawBorder(
    canvas: CanvasDraw
): Unit = {

  canvas.noFill()

  canvas.stroke(
    190,
    125,
    30,
    140
  )

  canvas.strokeWeight(2)

  canvas.rect(
    12,
    12,
    cwidth - 24.0,
    cheight - 24.0
  )

  canvas.stroke(
    240,
    175,
    50,
    80
  )

  canvas.rect(
    18,
    18,
    cwidth - 36.0,
    cheight - 36.0
  )
}

// ------------------------------------------------------------
// GROUND SHADOW
// ------------------------------------------------------------

def drawShadow(
    canvas: CanvasDraw
): Unit = {

  canvas.fill(
    0,
    0,
    0,
    35
  )

  canvas.noStroke()

  canvas.ellipse(
    cwidth / 2.0,
    70.0,
    380.0,
    24.0
  )
}

// ------------------------------------------------------------
// SHIVLING
// ------------------------------------------------------------

def drawShivling(
    canvas: CanvasDraw
): Unit = {

  val cx =
    cwidth / 2.0

  val baseY =
    88.0

  // Yoni base
  canvas.fill(
    58,
    58,
    62
  )

  canvas.stroke(
    25,
    25,
    28
  )

  canvas.strokeWeight(2)

  canvas.ellipse(
    cx,
    baseY,
    165.0,
    48.0
  )

  // Inner base
  canvas.fill(
    30,
    30,
    33
  )

  canvas.noStroke()

  canvas.ellipse(
    cx,
    baseY + 5.0,
    115.0,
    32.0
  )

  // Lingam
  canvas.fill(
    38,
    38,
    42
  )

  canvas.stroke(
    15,
    15,
    18
  )

  canvas.strokeWeight(2)

  canvas.ellipse(
    cx,
    baseY + 76.0,
    74.0,
    148.0
  )

  // Highlight
  canvas.fill(
    110,
    110,
    115,
    100
  )

  canvas.noStroke()

  canvas.ellipse(
    cx - 14.0,
    baseY + 96.0,
    18.0,
    74.0
  )

  // Tripundra
  canvas.stroke(
    245,
    245,
    245
  )

  canvas.strokeWeight(4)

  canvas.line(
    cx - 23.0,
    baseY + 72.0,
    cx + 23.0,
    baseY + 72.0
  )

  canvas.line(
    cx - 19.0,
    baseY + 60.0,
    cx + 19.0,
    baseY + 60.0
  )

  // Red mark
  canvas.stroke(
    200,
    35,
    35
  )

  canvas.strokeWeight(3)

  canvas.line(
    cx,
    baseY + 54.0,
    cx,
    baseY + 82.0
  )
}

// ------------------------------------------------------------
// SNAKE
// ------------------------------------------------------------

def drawSnake(
    canvas: CanvasDraw
): Unit = {

  val cx =
    cwidth / 2.0

  val baseY =
    130.0

  val sway =
    math.sin(
      snakePhase
    ) * 10.0

  // Curved body made of segments
  for (i <- 0 until 11) {

    val p =
      i / 10.0

    val sx =
      cx - 105.0 +
      i * 19.0

    val sy =
      baseY +
      math.sin(
        snakePhase + i * 0.55
      ) * 7.0

    val size =
      22.0 -
      i * 0.7

    canvas.fill(
      35,
      35,
      38
    )

    canvas.stroke(
      18,
      18,
      20
    )

    canvas.strokeWeight(1.5)

    canvas.ellipse(
      sx,
      sy,
      size,
      size
    )

    canvas.fill(
      100,
      75,
      48,
      170
    )

    canvas.noStroke()

    canvas.ellipse(
      sx - 2.0,
      sy + 2.0,
      size * 0.35,
      size * 0.60
    )
  }

  // Raised neck
  canvas.stroke(
    28,
    28,
    31
  )

  canvas.strokeWeight(18)

  canvas.line(
    cx + 5.0,
    baseY,
    cx + sway * 0.35,
    baseY + 142.0
  )

  // Hood
  val hx =
    cx + sway * 0.35

  val hy =
    baseY + 164.0

  val hoodPulse =
    math.sin(
      snakePhase * 1.5
    ) * 2.0

  canvas.fill(
    36,
    36,
    39
  )

  canvas.stroke(
    16,
    16,
    18
  )

  canvas.strokeWeight(2)

  canvas.ellipse(
    hx,
    hy,
    94.0 + hoodPulse,
    72.0 + hoodPulse
  )

  // Hood central pattern
  canvas.stroke(
    175,
    105,
    55
  )

  canvas.strokeWeight(2)

  canvas.line(
    hx,
    hy - 31.0,
    hx,
    hy + 31.0
  )

  canvas.line(
    hx - 22.0,
    hy - 12.0,
    hx + 22.0,
    hy + 12.0
  )

  canvas.line(
    hx - 22.0,
    hy + 12.0,
    hx + 22.0,
    hy - 12.0
  )

  // Eyes
  canvas.fill(
    235,
    50,
    45
  )

  canvas.noStroke()

  canvas.ellipse(
    hx - 15.0,
    hy + 4.0,
    8.0,
    5.0
  )

  canvas.ellipse(
    hx + 15.0,
    hy + 4.0,
    8.0,
    5.0
  )

  // Tongue
  canvas.stroke(
    215,
    45,
    60
  )

  canvas.strokeWeight(2)

  canvas.line(
    hx,
    hy - 13.0,
    hx,
    hy - 25.0
  )

  canvas.line(
    hx,
    hy - 25.0,
    hx - 5.0,
    hy - 31.0
  )

  canvas.line(
    hx,
    hy - 25.0,
    hx + 5.0,
    hy - 31.0
  )
}

// ------------------------------------------------------------
// FLOWER DECORATION
// ------------------------------------------------------------

def drawFlowers(
    canvas: CanvasDraw
): Unit = {

  val cx =
    cwidth / 2.0

  // Yellow flowers
  for (i <- 0 until 9) {

    val x =
      cx - 140.0 +
      i * 35.0

    val y =
      168.0 +
      math.sin(
        time * 2.0 + i
      ) * 2.0

    for (j <- 0 until 6) {

      val ang =
        j * math.Pi / 3.0

      canvas.fill(
        245,
        170,
        30
      )

      canvas.noStroke()

      canvas.ellipse(
        x + math.cos(ang) * 9.0,
        y + math.sin(ang) * 9.0,
        10.0,
        10.0
      )
    }

    canvas.fill(
      150,
      85,
      25
    )

    canvas.ellipse(
      x,
      y,
      6.0,
      6.0
    )
  }

  // Pink flowers
  for (i <- 0 until 5) {

    val x =
      cx - 90.0 +
      i * 45.0

    canvas.fill(
      245,
      90,
      140
    )

    canvas.noStroke()

    canvas.ellipse(
      x,
      192.0,
      10.0,
      10.0
    )

    canvas.ellipse(
      x + 8.0,
      192.0,
      10.0,
      10.0
    )

    canvas.ellipse(
      x,
      200.0,
      10.0,
      10.0
    )

    canvas.ellipse(
      x - 8.0,
      192.0,
      10.0,
      10.0
    )

    canvas.fill(
      255,
      205,
      60
    )

    canvas.ellipse(
      x,
      192.0,
      5.0,
      5.0
    )
  }
}

// ------------------------------------------------------------
// PUJA BOWL
// ------------------------------------------------------------

def drawBowl(
    canvas: CanvasDraw
): Unit = {

  val bx =
    cwidth / 2.0 + 135.0

  val by =
    90.0

  canvas.fill(
    245,
    175,
    40
  )

  canvas.stroke(
    130,
    70,
    20
  )

  canvas.strokeWeight(2)

  canvas.ellipse(
    bx,
    by,
    84.0,
    24.0
  )

  canvas.fill(
    250,
    250,
    250
  )

  canvas.noStroke()

  canvas.ellipse(
    bx,
    by + 4.0,
    60.0,
    15.0
  )

  canvas.fill(
    245,
    170,
    35
  )

  canvas.ellipse(
    bx,
    by - 10.0,
    70.0,
    15.0
  )

  for (i <- 0 until 7) {

    canvas.fill(
      175,
      80,
      25
    )

    canvas.ellipse(
      bx - 27.0 +
      i * 9.0,
      by - 9.0,
      4.0,
      4.0
    )
  }
}

// ------------------------------------------------------------
// DIYA
// ------------------------------------------------------------

def drawDiya(
    canvas: CanvasDraw
): Unit = {

  val x =
    cwidth / 2.0 - 135.0

  val y =
    90.0

  canvas.fill(
    190,
    105,
    25
  )

  canvas.stroke(
    120,
    60,
    15
  )

  canvas.strokeWeight(2)

  canvas.ellipse(
    x,
    y,
    58.0,
    20.0
  )

  val flameSize =
    15.0 +
    math.sin(
      lampPhase * 2.0
    ) * 4.0

  canvas.fill(
    255,
    175,
    30
  )

  canvas.noStroke()

  canvas.ellipse(
    x,
    y + 22.0,
    12.0,
    flameSize
  )

  canvas.fill(
    255,
    245,
    160
  )

  canvas.ellipse(
    x,
    y + 23.0,
    5.0,
    flameSize * 0.65
  )
}

// ------------------------------------------------------------
// SMOKE
// ------------------------------------------------------------

def drawSmoke(
    canvas: CanvasDraw
): Unit = {

  val x =
    cwidth / 2.0 - 135.0

  val y =
    115.0

  canvas.noFill()

  canvas.stroke(
    150,
    150,
    150,
    65
  )

  canvas.strokeWeight(2)

  for (i <- 0 until 3) {

    val sx =
      x +
      math.sin(
        time + i
      ) * 8.0

    val sy =
      y +
      22.0 +
      i * 18.0

    canvas.ellipse(
      sx,
      sy,
      22.0 + i * 6.0,
      30.0 + i * 8.0
    )
  }
}

// ------------------------------------------------------------
// SPARKS
// ------------------------------------------------------------

def drawSparks(
    canvas: CanvasDraw
): Unit = {

  sparks.foreach { s =>

    canvas.fill(
      235,
      175,
      45,
      170
    )

    canvas.noStroke()

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

// ------------------------------------------------------------
// PRAYER GLOW
// ------------------------------------------------------------

def drawPrayerGlow(
    canvas: CanvasDraw
): Unit = {

  if (pujaStarted) {

    val radius =
      150.0 +
      math.sin(
        glowPhase
      ) * 20.0

    canvas.noFill()

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

    canvas.strokeWeight(3)

    canvas.ellipse(
      cwidth / 2.0,
      180.0,
      radius,
      radius * 0.55
    )

    canvas.stroke(
      255,
      220,
      100,
      70
    )

    canvas.ellipse(
      cwidth / 2.0,
      180.0,
      radius * 0.70,
      radius * 0.40
    )
  }
}

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

def drawTitle(
    canvas: CanvasDraw
): Unit = {

  if (titleIndex > 0) {

    val shown =
      titleText.substring(
        0,
        titleIndex
      )

    canvas.fill(
      205,
      35,
      35
    )

    canvas.noStroke()

    canvas.text(
      shown,
      cwidth / 2.0 + 65.0,
      cheight / 2.0 + 95.0
    )
  }

  if (
    titleIndex >=
    titleText.length
  ) {

    canvas.fill(
      210,
      40,
      40
    )

    canvas.text(
      "FESTIVAL OF FAITH AND TRADITION",
      cwidth / 2.0 + 48.0,
      cheight / 2.0 + 65.0
    )
  }
}

// ------------------------------------------------------------
// FOOTER
// ------------------------------------------------------------

def drawFooter(
    canvas: CanvasDraw
): Unit = {

  canvas.fill(
    100,
    70,
    40
  )

  canvas.noStroke()

  canvas.text(
    "NAG PANCHAMI",
    28.0,
    cheight - 35.0
  )

  if (!pujaStarted) {

    canvas.text(
      "CLICK TO START PUJA GLOW",
      cwidth - 190.0,
      28.0
    )
  } else {

    canvas.fill(
      180,
      70,
      35
    )

    canvas.text(
      "PUJA CELEBRATION",
      cwidth - 155.0,
      28.0
    )
  }
}

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

def drawScene(
    canvas: CanvasDraw
): Unit = {

  drawBackground(canvas)

  drawBorder(canvas)

  drawShadow(canvas)

  drawShivling(canvas)

  drawSnake(canvas)

  drawFlowers(canvas)

  drawBowl(canvas)

  drawDiya(canvas)

  drawSmoke(canvas)

  drawSparks(canvas)

  drawPrayerGlow(canvas)

  drawTitle(canvas)

  drawFooter(canvas)
}

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

animateWithCanvasDraw { canvas =>

  time += 0.04
  snakePhase += 0.055
  lampPhase += 0.09
  glowPhase += 0.08

  updateSparks()

  titleTimer += 1

  if (
    titleTimer % 5 == 0 &&
    titleIndex < titleText.length
  ) {

    titleIndex += 1
  }

  if (isMousePressed) {

    pujaStarted = true
  }

  drawScene(canvas)
}