Code Sketch


navya temburne
By: Mhalsakant School
clear()
setBackground(Color(8, 4, 22))

// ============================================================
// RAKSHA BANDHAN MAGIC GIFT
// CLEAN ADVANCED STEP-BY-STEP ANIMATION
// ============================================================

val sisterName = "SISTER"

var opened = false
var step = 0

var lidY = 62.0
var lidAngle = 0.0

var glow = 0.0
var rakhiSize = 0.0
var sparkleRadius = 0.0

var titleIndex = 0
var titleTimer = 0

var celebration = 0.0
var rotateAngle = 0.0

val title = "HAPPY RAKSHABANDHAN"

// ============================================================
// BACKGROUND STARS
// ============================================================

val starX =
  Array.fill(45)(
    Math.random() * 700.0 - 350.0
  )

val starY =
  Array.fill(45)(
    Math.random() * 420.0 - 210.0
  )

// ============================================================
// HELPER
// ============================================================

def clamp(
    v: Double,
    lo: Double,
    hi: Double
): Double = {
  math.max(
    lo,
    math.min(
      hi,
      v
    )
  )
}

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

def drawBackground(): Unit = {

  erasePictures()

  val bg =
    Picture.rectangle(
      760,
      520
    )

  bg.setFillColor(
    Color(
      8,
      4,
      22
    )
  )

  bg.setPosition(
    -380,
    -260
  )

  draw(bg)

  // Purple glow
  val purpleGlow =
    Picture.circle(
      420
    )

  purpleGlow.setFillColor(
    Color(
      100,
      20,
      120,
      25
    )
  )

  purpleGlow.setPosition(
    0,
    20
  )

  draw(purpleGlow)

  // Golden glow
  val goldGlow =
    Picture.circle(
      260
    )

  goldGlow.setFillColor(
    Color(
      220,
      120,
      20,
      18
    )
  )

  goldGlow.setPosition(
    0,
    35
  )

  draw(goldGlow)

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

    val size =
      2.0 +
      Math.abs(
        Math.sin(
          celebration + i
        )
      ) * 2.5

    val star =
      Picture.circle(
        size
      )

    star.setFillColor(
      Color(
        255,
        220,
        130,
        160
      )
    )

    star.setPosition(
      starX(i),
      starY(i)
    )

    draw(star)
  }
}

// ============================================================
// BOX SHADOW
// ============================================================

def drawShadow(): Unit = {

  val shadow =
    Picture.ellipse(
      280,
      45
    )

  shadow.setFillColor(
    Color(
      0,
      0,
      0,
      120
    )
  )

  shadow.setPosition(
    -140,
    -145
  )

  draw(shadow)
}

// ============================================================
// BOX BODY
// ============================================================

def drawBox(): Unit = {

  val box =
    Picture.rectangle(
      210,
      135
    )

  box.setFillColor(
    Color(
      205,
      15,
      55
    )
  )

  box.setPenColor(
    Color(
      255,
      220,
      70
    )
  )

  box.setPenThickness(
    3
  )

  box.setPosition(
    -105,
    -65
  )

  draw(box)

  // Inner panel
  val inner =
    Picture.rectangle(
      178,
      102
    )

  inner.setFillColor(
    Color(
      125,
      8,
      42
    )
  )

  inner.setPenColor(
    Color(
      155,
      20,
      60
    )
  )

  inner.setPosition(
    -89,
    -48
  )

  draw(inner)

  // Vertical ribbon
  val ribbonV =
    Picture.rectangle(
      28,
      135
    )

  ribbonV.setFillColor(
    Color(
      255,
      215,
      55
    )
  )

  ribbonV.setPosition(
    -14,
    -65
  )

  draw(ribbonV)

  // Horizontal ribbon
  val ribbonH =
    Picture.rectangle(
      210,
      25
    )

  ribbonH.setFillColor(
    Color(
      255,
      215,
      55
    )
  )

  ribbonH.setPosition(
    -105,
    -5
  )

  draw(ribbonH)

  // Edge glow
  val edge =
    Picture.rectangle(
      218,
      143
    )

  edge.setFillColor(
    Color(
      255,
      255,
      255,
      0
    )
  )

  edge.setPenColor(
    Color(
      255,
      80,
      120,
      130
    )
  )

  edge.setPenThickness(
    2
  )

  edge.setPosition(
    -109,
    -69
  )

  draw(edge)
}

// ============================================================
// BOX LID
// ============================================================

def drawLid(): Unit = {

  if (lidY < 230) {

    val lid =
      Picture.rectangle(
        235,
        38
      )

    lid.setFillColor(
      Color(
        180,
        8,
        42
      )
    )

    lid.setPenColor(
      Color(
        255,
        225,
        85
      )
    )

    lid.setPenThickness(
      3
    )

    lid.setPosition(
      -118,
      lidY
    )

    lid.rotate(
      lidAngle
    )

    draw(lid)

    // Lid highlight
    val shine =
      Picture.rectangle(
        175,
        4
      )

    shine.setFillColor(
      Color(
        255,
        240,
        160,
        180
      )
    )

    shine.setPosition(
      -88,
      lidY + 5
    )

    shine.rotate(
      lidAngle
    )

    draw(shine)
  }
}

// ============================================================
// MAGICAL LIGHT
// ============================================================

def drawMagicLight(): Unit = {

  if (step >= 2) {

    val r =
      clamp(
        glow,
        5.0,
        210.0
      )

    val light =
      Picture.circle(
        r
      )

    light.setFillColor(
      Color(
        255,
        210,
        80,
        22
      )
    )

    light.setPosition(
      0,
      45
    )

    draw(light)

    val light2 =
      Picture.circle(
        r * 0.62
      )

    light2.setFillColor(
      Color(
        255,
        235,
        150,
        32
      )
    )

    light2.setPosition(
      0,
      45
    )

    draw(light2)
  }
}

// ============================================================
// RAKHI
// ============================================================

def drawRakhi(): Unit = {

  if (rakhiSize <= 0)
    return

  // Threads
  val left =
    Picture.rectangle(
      130,
      5
    )

  left.setFillColor(
    Color(
      255,
      60,
      90
    )
  )

  left.setPosition(
    -155,
    38
  )

  draw(left)

  val right =
    Picture.rectangle(
      130,
      5
    )

  right.setFillColor(
    Color(
      255,
      60,
      90
    )
  )

  right.setPosition(
    25,
    38
  )

  draw(right)

  // Outer circle
  val outer =
    Picture.circle(
      rakhiSize
    )

  outer.setFillColor(
    Color(
      215,
      20,
      65
    )
  )

  outer.setPenColor(
    Color(
      255,
      225,
      80
    )
  )

  outer.setPenThickness(
    3
  )

  outer.setPosition(
    0,
    38
  )

  draw(outer)

  // Gold
  val gold =
    Picture.circle(
      rakhiSize * 0.68
    )

  gold.setFillColor(
    Color(
      255,
      190,
      30
    )
  )

  gold.setPosition(
    0,
    38
  )

  draw(gold)

  // Blue center
  val blue =
    Picture.circle(
      rakhiSize * 0.38
    )

  blue.setFillColor(
    Color(
      10,
      175,
      235
    )
  )

  blue.setPenColor(
    Color(
      170,
      245,
      255
    )
  )

  blue.setPenThickness(
    2
  )

  blue.setPosition(
    0,
    38
  )

  draw(blue)

  // White jewel
  val jewel =
    Picture.circle(
      rakhiSize * 0.14
    )

  jewel.setFillColor(
    Color(
      255,
      255,
      255
    )
  )

  jewel.setPosition(
    0,
    38
  )

  draw(jewel)

  // Rotating beads
  for (i <- 0 until 8) {

    val angle =
      rotateAngle +
      i * 45.0

    val rad =
      Math.toRadians(
        angle
      )

    val bx =
      Math.cos(rad) *
      (rakhiSize * 0.63)

    val by =
      38.0 +
      Math.sin(rad) *
      (rakhiSize * 0.63)

    val bead =
      Picture.circle(
        6
      )

    if (i % 2 == 0) {

      bead.setFillColor(
        Color(
          255,
          215,
          60
        )
      )

    } else {

      bead.setFillColor(
        Color(
          255,
          80,
          135
        )
      )
    }

    bead.setPosition(
      bx,
      by
    )

    draw(bead)
  }
}

// ============================================================
// SPARKLES
// ============================================================

def drawSparkles(): Unit = {

  if (!opened)
    return

  for (i <- 0 until 18) {

    val angle =
      rotateAngle +
      i * 20.0

    val rad =
      Math.toRadians(
        angle
      )

    val radius =
      sparkleRadius +
      math.sin(
        celebration + i
      ) * 10.0

    val x =
      math.cos(rad) *
      radius

    val y =
      45.0 +
      math.sin(rad) *
      radius *
      0.55

    val star =
      Picture.text(
        "*",
        12
      )

    if (i % 3 == 0) {

      star.setPenColor(
        Color(
          255,
          220,
          80
        )
      )

    } else if (i % 3 == 1) {

      star.setPenColor(
        Color(
          255,
          90,
          160
        )
      )

    } else {

      star.setPenColor(
        Color(
          100,
          220,
          255
        )
      )
    }

    star.setPosition(
      x,
      y
    )

    draw(star)
  }
}

// ============================================================
// HEARTS
// ============================================================

def drawHearts(): Unit = {

  if (step < 4)
    return

  for (i <- 0 until 8) {

    val angle =
      celebration * 0.8 +
      i * 45.0

    val rad =
      Math.toRadians(
        angle
      )

    val radius =
      100.0 +
      i * 3.0

    val x =
      Math.cos(rad) *
      radius

    val y =
      -20.0 +
      Math.sin(rad) *
      radius * 0.45

    val heart =
      Picture.text(
        "<3",
        11
      )

    if (i % 2 == 0) {

      heart.setPenColor(
        Color(
          255,
          80,
          140
        )
      )

    } else {

      heart.setPenColor(
        Color(
          255,
          205,
          70
        )
      )
    }

    heart.setPosition(
      x,
      y
    )

    draw(heart)
  }
}

// ============================================================
// TITLE
// ============================================================

def drawTitle(): Unit = {

  if (titleIndex <= 0)
    return

  val shown =
    title.substring(
      0,
      titleIndex
    )

  val text =
    Picture.text(
      shown,
      22
    )

  text.setPenColor(
    Color(
      255,
      220,
      70
    )
  )

  text.setPosition(
    -165,
    130
  )

  draw(text)

  if (
    titleIndex >=
    title.length
  ) {

    val line =
      Picture.rectangle(
        250,
        3
      )

    line.setFillColor(
      Color(
        255,
        90,
        150
      )
    )

    line.setPosition(
      -125,
      117
    )

    draw(line)

    val name =
      Picture.text(
        "FOR " + sisterName,
        18
      )

    name.setPenColor(
      Color(
        255,
        110,
        180
      )
    )

    name.setPosition(
      -60,
      -60
    )

    draw(name)

    val msg =
      Picture.text(
        "A BOND OF LOVE FOREVER",
        12
      )

    msg.setPenColor(
      Color(
        240,
        240,
        250
      )
    )

    msg.setPosition(
      -108,
      -85
    )

    draw(msg)

    val finalText =
      Picture.text(
        "HAPPY RAKSHA BANDHAN",
        16
      )

    finalText.setPenColor(
      Color(
        255,
        215,
        70
      )
    )

    finalText.setPosition(
      -120,
      -125
    )

    draw(finalText)
  }
}

// ============================================================
// INSTRUCTION
// ============================================================

def drawInstruction(): Unit = {

  if (!opened) {

    val msg =
      Picture.text(
        "MOVE CURSOR / CLICK BOX TO OPEN MAGIC",
        13
      )

    msg.setPenColor(
      Color(
        255,
        215,
        70
      )
    )

    msg.setPosition(
      -140,
      -155
    )

    draw(msg)
  }
}

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

def drawScene(): Unit = {

  drawBackground()

  drawShadow()

  drawBox()

  drawMagicLight()

  drawRakhi()

  drawLid()

  drawSparkles()

  drawHearts()

  drawTitle()

  drawInstruction()
}

// ============================================================
// FIRST FRAME
// ============================================================

drawScene()

// ============================================================
// ANIMATION LOOP
// ============================================================

animateWithState(0.0) { frame =>

  celebration += 0.06
  rotateAngle += 0.9

  if (opened) {

    // STEP 1 - OPEN LID
    if (step == 1) {

      lidY += 4.5
      lidAngle += 2.7

      if (lidY >= 225) {

        lidY = 225
        step = 2
      }
    }

    // STEP 2 - LIGHT
    if (step == 2) {

      glow += 8.0

      if (glow >= 180) {

        glow = 180
        step = 3
      }
    }

    // STEP 3 - RAKHI
    if (step == 3) {

      rakhiSize += 2.3

      if (rakhiSize >= 70) {

        rakhiSize = 70
        sparkleRadius = 60
        step = 4
      }
    }

    // STEP 4 - SPARKLES
    if (step == 4) {

      sparkleRadius += 1.5

      if (sparkleRadius >= 125) {

        sparkleRadius = 125
        step = 5
      }
    }

    // STEP 5 - TITLE
    if (step == 5) {

      titleTimer += 1

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

        titleIndex += 1
      }
    }
  }

  drawScene()

  frame + 1.0
}

// ============================================================
// MOUSE OPEN
// ============================================================

onMouseMove { (x, y) =>

  if (!opened) {

    if (
      x >= -120 &&
      x <= 120 &&
      y >= -50 &&
      y <= 125
    ) {

      opened = true
      step = 1

      lidY = 62
      lidAngle = 0

      glow = 0
      rakhiSize = 0
      sparkleRadius = 0

      titleIndex = 0
      titleTimer = 0

      try {
        playNote(
          72,
          220
        )
      } catch {
        case _: Exception =>
      }
    }
  }
}