Code Sketch


navya tembhurne
By: Mhalsakant School
Category: Programming
clear()
setBackground(Color(7, 4, 20))

// ============================================================================
// ULTRA LUXURY RAKSHA BANDHAN EXPERIENCE
// Advanced Scala Graphics Animation Engine
// ============================================================================


// ============================================================================
// 1. CONSTANTS
// ============================================================================

val PI = 3.141592653589793

val SCREEN_W = 900.0
val SCREEN_H = 650.0

val MAX_GOLD_PARTICLES = 55
val MAX_STARS = 45
val MAX_PETALS = 28
val MAX_HEARTS = 12

val FIREWORK_1 = 36
val FIREWORK_2 = 28
val FIREWORK_3 = 18

val MAX_FIREWORK_RADIUS = 270.0


// ============================================================================
// 2. PERSONALIZATION
// ============================================================================

val sisterName = "Navya"

val titleText = "HAPPY RAKSHABANDHAN"

val subtitleText =
  "BEST SISTER EVER NAVYA"

val blessingText =
  "May your life be filled with happiness, peace, and eternal joy!"


// ============================================================================
// 3. BASIC UTILITIES
// ============================================================================

def rad(degrees: Double): Double = {
  degrees * PI / 180.0
}

def sinWave(
  t: Double,
  speed: Double,
  amount: Double
): Double = {

  Math.sin(rad(t * speed)) * amount
}

def cosWave(
  t: Double,
  speed: Double,
  amount: Double
): Double = {

  Math.cos(rad(t * speed)) * amount
}


// ============================================================================
// 4. GLOBAL STATE
// ============================================================================

var opened = false

var hoverBox = false

var animationFrame = 0.0

// Gift
var giftLidY = 55.0
var giftLidRotation = 0.0
var giftScale = 1.0

// Fireworks
var firework1 = 0.0
var firework2 = 0.0
var firework3 = 0.0

// Rakhi
var rakhiAngle = 0.0
var rakhiOuterAngle = 0.0

// Text
var titleIndex = 0
var subtitleIndex = 0
var blessingIndex = 0

var typeCounter = 0

// Celebration
var celebrationProgress = 0.0

// Glow
var globalGlow = 0.0

// Particle animation
var particleTime = 0.0


// ============================================================================
// 5. SAFE MIDI ENGINE
// ============================================================================

var midiEnabled = true
var midiCounter = 0
var melodyIndex = 0

val melody = Array(
  60, 64, 67, 72,
  71, 67, 69, 72,
  76, 74, 72, 67,
  64, 67, 72, 76,
  77, 76, 72, 69,
  72, 67, 64, 60
)

def safeMusic(): Unit = {

  if (!midiEnabled) {
    return
  }

  midiCounter += 1

  if (midiCounter % 8 == 0) {

    try {

      playNote(
        melody(melodyIndex),
        260
      )

      melodyIndex =
        (melodyIndex + 1) %
        melody.length

    } catch {

      case _: javax.sound.midi.MidiUnavailableException =>
        midiEnabled = false

      case _: Exception =>
        midiEnabled = false
    }
  }
}


// ============================================================================
// 6. BACKGROUND GRADIENT-LIKE LAYERS
// ============================================================================

def drawBackgroundGlow(): Unit = {

  val pulse =
    20 + sinWave(animationFrame, 2.0, 10)

  val glow1 =
    Picture.circle(620 + pulse)

  glow1.setFillColor(
    Color(40, 5, 75)
  )

  glow1.setPosition(
    0,
    40
  )

  draw(glow1)


  val glow2 =
    Picture.circle(470 + pulse)

  glow2.setFillColor(
    Color(70, 5, 60)
  )

  glow2.setPosition(
    0,
    40
  )

  draw(glow2)


  val centerGlow =
    Picture.circle(330 + pulse)

  centerGlow.setFillColor(
    Color(100, 10, 70)
  )

  centerGlow.setPosition(
    0,
    40
  )

  draw(centerGlow)
}


// ============================================================================
// 7. STAR FIELD
// ============================================================================

def renderStars(): Unit = {

  for (i <- 0 until MAX_STARS) {

    val x =
      ((i * 97) % 820) - 410

    val y =
      ((i * 53) % 570) - 285

    val brightness =
      130 +
      Math.abs(
        sinWave(
          animationFrame + i * 17,
          5.0,
          110
        )
      )

    val size =
      2 +
      Math.abs(
        sinWave(
          animationFrame + i,
          4.0,
          2
        )
      )

    val star =
      Picture.circle(size)

    star.setFillColor(
      Color(
        255,
        245,
        190,
        Math.min(255, brightness.toInt)
      )
    )

    star.setPosition(
      x,
      y
    )

    draw(star)
  }
}


// ============================================================================
// 8. FLOATING GOLD PARTICLES
// ============================================================================

def renderFloatingParticles(): Unit = {

  for (i <- 0 until MAX_GOLD_PARTICLES) {

    val baseX =
      ((i * 73) % 760) - 380

    val baseY =
      ((i * 41) % 520) - 260

    val x =
      baseX +
      sinWave(
        animationFrame + i * 11,
        1.8,
        20
      )

    val y =
      baseY +
      cosWave(
        animationFrame + i * 9,
        1.3,
        18
      )

    val size =
      2 +
      Math.abs(
        sinWave(
          animationFrame + i * 3,
          5,
          2
        )
      )

    val particle =
      Picture.circle(size)

    if (i % 3 == 0) {

      particle.setFillColor(
        Color(255, 215, 0)
      )

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

      particle.setFillColor(
        Color(255, 105, 180)
      )

    } else {

      particle.setFillColor(
        Color(120, 240, 255)
      )
    }

    particle.setPosition(
      x,
      y
    )

    draw(particle)
  }
}


// ============================================================================
// 9. DECORATIVE NEON BORDER
// ============================================================================

def renderNeonBorder(): Unit = {

  val pulse =
    Math.abs(
      sinWave(
        animationFrame,
        3.0,
        2
      )
    )

  val border =
    Picture.rectangle(
      780 + pulse,
      540 + pulse
    )

  border.setFillColor(
    Color(15, 5, 30)
  )

  border.setPenColor(
    Color(255, 215, 0)
  )

  border.setPenThickness(3)

  border.setPosition(
    -390,
    -270
  )

  draw(border)


  val inner =
    Picture.rectangle(
      750,
      510
    )

  inner.setFillColor(
    Color(15, 5, 30)
  )

  inner.setPenColor(
    Color(255, 70, 150)
  )

  inner.setPenThickness(1)

  inner.setPosition(
    -375,
    -255
  )

  draw(inner)
}


// ============================================================================
// 10. CROWN
// ============================================================================

def renderCrown(
  cx: Double,
  cy: Double
): Unit = {

  val crownGlow =
    Picture.circle(45)

  crownGlow.setFillColor(
    Color(120, 20, 80)
  )

  crownGlow.setPosition(
    cx,
    cy
  )

  draw(crownGlow)


  val crown =
    Picture.text(
      "?",
      45
    )

  crown.setPenColor(
    Color(255, 215, 0)
  )

  crown.setPosition(
    cx - 22,
    cy - 20
  )

  draw(crown)
}


// ============================================================================
// 11. GIFT BOX GLOW
// ============================================================================

def renderGiftGlow(): Unit = {

  val glow =
    15 +
    Math.abs(
      sinWave(
        animationFrame,
        4,
        10
      )
    )

  val boxGlow =
    Picture.rectangle(
      240 + glow,
      180 + glow
    )

  boxGlow.setFillColor(
    Color(100, 5, 50)
  )

  boxGlow.setPosition(
    -120 - glow / 2,
    -90 - glow / 2
  )

  draw(boxGlow)
}


// ============================================================================
// 12. ADVANCED GIFT BOX
// ============================================================================

def renderGiftBox(): Unit = {

  if (!opened || giftLidY < 230) {

    renderGiftGlow()


    // Main box
    val box =
      Picture.rectangle(
        200,
        140
      )

    box.setFillColor(
      Color(175, 10, 45)
    )

    box.setPenColor(
      Color(255, 215, 0)
    )

    box.setPenThickness(4)

    box.setPosition(
      -100,
      -80
    )

    draw(box)


    // Dark side
    val side =
      Picture.rectangle(
        18,
        140
      )

    side.setFillColor(
      Color(120, 5, 30)
    )

    side.setPosition(
      82,
      -80
    )

    draw(side)


    // Vertical ribbon
    val ribbonV =
      Picture.rectangle(
        34,
        140
      )

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

    ribbonV.setPosition(
      -17,
      -80
    )

    draw(ribbonV)


    // Ribbon highlight
    val ribbonHighlight =
      Picture.rectangle(
        6,
        140
      )

    ribbonHighlight.setFillColor(
      Color(255, 255, 220)
    )

    ribbonHighlight.setPosition(
      -12,
      -80
    )

    draw(ribbonHighlight)


    // Horizontal ribbon
    val ribbonH =
      Picture.rectangle(
        200,
        34
      )

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

    ribbonH.setPosition(
      -100,
      -17
    )

    draw(ribbonH)


    // Lid
    val lid =
      Picture.rectangle(
        225,
        50
      )

    lid.setFillColor(
      Color(220, 20, 60)
    )

    lid.setPenColor(
      Color(255, 230, 120)
    )

    lid.setPenThickness(4)

    lid.setPosition(
      -112,
      giftLidY
    )

    lid.rotate(
      giftLidRotation
    )

    draw(lid)


    // Lid ribbon
    val lidRibbon =
      Picture.rectangle(
        40,
        50
      )

    lidRibbon.setFillColor(
      Color(255, 215, 0)
    )

    lidRibbon.setPosition(
      -20,
      giftLidY
    )

    lidRibbon.rotate(
      giftLidRotation
    )

    draw(lidRibbon)


    // Bow
    if (!opened) {

      val bowLeft =
        Picture.circle(27)

      bowLeft.setFillColor(
        Color(255, 40, 100)
      )

      bowLeft.setPosition(
        -25,
        78
      )

      draw(bowLeft)


      val bowRight =
        Picture.circle(27)

      bowRight.setFillColor(
        Color(255, 40, 100)
      )

      bowRight.setPosition(
        25,
        78
      )

      draw(bowRight)


      val bowCenter =
        Picture.circle(15)

      bowCenter.setFillColor(
        Color(255, 215, 0)
      )

      bowCenter.setPosition(
        0,
        78
      )

      draw(bowCenter)
    }


    // Instructions
    if (!opened) {

      val instruction =
        Picture.text(
          "CLICK / MOVE OVER THE GIFT",
          16
        )

      instruction.setPenColor(
        Color(255, 215, 0)
      )

      instruction.setPosition(
        -155,
        -150
      )

      draw(instruction)
    }
  }
}


// ============================================================================
// 13. FIREWORK TRAILS
// ============================================================================

def renderFireworkLayer(
  radius: Double,
  count: Int,
  offset: Double,
  particleSize: Double
): Unit = {

  for (i <- 0 until count) {

    val angle =
      (360.0 / count) * i +
      offset

    val r =
      rad(angle)

    val x =
      radius * Math.cos(r)

    val y =
      radius * Math.sin(r) + 45

    // Trail
    val trail =
      Picture.circle(
        particleSize * 0.55
      )

    trail.setFillColor(
      Color(255, 215, 0, 100)
    )

    trail.setPosition(
      x * 0.92,
      y * 0.92
    )

    draw(trail)


    // Particle
    val particle =
      Picture.circle(
        particleSize
      )

    if (i % 4 == 0) {

      particle.setFillColor(
        Color(255, 215, 0)
      )

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

      particle.setFillColor(
        Color(255, 70, 160)
      )

    } else if (i % 4 == 2) {

      particle.setFillColor(
        Color(50, 240, 255)
      )

    } else {

      particle.setFillColor(
        Color(255, 255, 255)
      )
    }

    particle.setPosition(
      x,
      y
    )

    draw(particle)
  }
}


// ============================================================================
// 14. FIREWORKS
// ============================================================================

def renderFireworks(): Unit = {

  if (opened) {

    renderFireworkLayer(
      firework1,
      FIREWORK_1,
      animationFrame * 1.2,
      7
    )

    renderFireworkLayer(
      firework2,
      FIREWORK_2,
      animationFrame * -1.5 + 20,
      5
    )

    renderFireworkLayer(
      firework3,
      FIREWORK_3,
      animationFrame * 2.0 + 40,
      4
    )
  }
}


// ============================================================================
// 15. PETAL / CONFETTI SHOWER
// ============================================================================

def renderPetals(): Unit = {

  if (opened) {

    for (i <- 0 until MAX_PETALS) {

      val baseX =
        ((i * 61) % 760) - 380

      val fall =
        ((animationFrame * (1.5 + (i % 4))) +
          i * 55) % 540

      val x =
        baseX +
        sinWave(
          animationFrame + i * 15,
          2,
          25
        )

      val y =
        270 - fall

      val petal =
        Picture.circle(
          3 + (i % 3)
        )

      if (i % 3 == 0) {

        petal.setFillColor(
          Color(255, 80, 140)
        )

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

        petal.setFillColor(
          Color(255, 215, 0)
        )

      } else {

        petal.setFillColor(
          Color(100, 230, 255)
        )
      }

      petal.setPosition(
        x,
        y
      )

      draw(petal)
    }
  }
}


// ============================================================================
// 16. FLOATING HEARTS
// ============================================================================

def renderHearts(): Unit = {

  if (opened) {

    for (i <- 0 until MAX_HEARTS) {

      val x =
        ((i * 91) % 700) - 350

      val y =
        -260 +
        ((animationFrame * 1.2 +
          i * 60) % 500)

      val floatX =
        x +
        sinWave(
          animationFrame + i * 20,
          2,
          15
        )

      val heart =
        Picture.text(
          "?",
          18 + (i % 3) * 4
        )

      heart.setPenColor(
        if (i % 2 == 0)
          Color(255, 80, 130)
        else
          Color(255, 215, 0)
      )

      heart.setPosition(
        floatX,
        y
      )

      draw(heart)
    }
  }
}


// ============================================================================
// 17. ADVANCED RAKHI
// ============================================================================

def renderRakhi(
  cx: Double,
  cy: Double
): Unit = {

  // Threads
  val leftThread =
    Picture.rectangle(
      175,
      7
    )

  leftThread.setFillColor(
    Color(255, 30, 90)
  )

  leftThread.setPosition(
    cx - 210,
    cy
  )

  draw(leftThread)


  val rightThread =
    Picture.rectangle(
      175,
      7
    )

  rightThread.setFillColor(
    Color(255, 30, 90)
  )

  rightThread.setPosition(
    cx + 35,
    cy
  )

  draw(rightThread)


  // Outer golden beads
  for (i <- 0 until 16) {

    val angle =
      i * 22.5 +
      rakhiOuterAngle

    val rr =
      rad(angle)

    val radius =
      67 +
      sinWave(
        animationFrame + i,
        3,
        3
      )

    val x =
      cx +
      radius * Math.cos(rr)

    val y =
      cy +
      radius * Math.sin(rr)

    val bead =
      Picture.circle(5)

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

    bead.setPosition(
      x,
      y
    )

    draw(bead)
  }


  // Outer dial
  val outer =
    Picture.circle(52)

  outer.setFillColor(
    Color(190, 10, 50)
  )

  outer.setPenColor(
    Color(255, 215, 0)
  )

  outer.setPenThickness(4)

  outer.setPosition(
    cx,
    cy
  )

  draw(outer)


  // Pearl ring
  for (i <- 0 until 10) {

    val angle =
      i * 36 +
      rakhiAngle

    val rr =
      rad(angle)

    val x =
      cx + 39 * Math.cos(rr)

    val y =
      cy + 39 * Math.sin(rr)

    val pearl =
      Picture.circle(4)

    pearl.setFillColor(
      Color(255, 255, 235)
    )

    pearl.setPosition(
      x,
      y
    )

    draw(pearl)
  }


  // Gold middle
  val gold =
    Picture.circle(32)

  gold.setFillColor(
    Color(255, 215, 0)
  )

  gold.setPenColor(
    Color(255, 255, 255)
  )

  gold.setPenThickness(2)

  gold.setPosition(
    cx,
    cy
  )

  draw(gold)


  // Blue gemstone
  val gem =
    Picture.circle(17)

  gem.setFillColor(
    Color(0, 190, 230)
  )

  gem.setPosition(
    cx,
    cy
  )

  draw(gem)


  // Gem shine
  val shine =
    Picture.circle(5)

  shine.setFillColor(
    Color(255, 255, 255)
  )

  shine.setPosition(
    cx - 5,
    cy + 5
  )

  draw(shine)


  // Rotating center star
  val star =
    Picture.text(
      "?",
      25
    )

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

  star.setPosition(
    cx - 12,
    cy - 13
  )

  draw(star)
}


// ============================================================================
// 18. CARD
// ============================================================================

def renderCard(): Unit = {

  if (giftLidY >= 190) {

    // Card glow
    val cardGlow =
      Picture.rectangle(
        570,
        390
      )

    cardGlow.setFillColor(
      Color(90, 5, 65)
    )

    cardGlow.setPosition(
      -285,
      -195
    )

    draw(cardGlow)


    // Card
    val card =
      Picture.rectangle(
        550,
        370
      )

    card.setFillColor(
      Color(17, 8, 36)
    )

    card.setPenColor(
      Color(255, 215, 0)
    )

    card.setPenThickness(4)

    card.setPosition(
      -275,
      -185
    )

    draw(card)


    // Inner border
    val inner =
      Picture.rectangle(
        525,
        345
      )

    inner.setFillColor(
      Color(17, 8, 36)
    )

    inner.setPenColor(
      Color(255, 80, 150)
    )

    inner.setPenThickness(1)

    inner.setPosition(
      -262,
      -172
    )

    draw(inner)


    // Corners
    renderCrown(
      -225,
      135
    )

    renderCrown(
      225,
      135
    )


    // Rakhi
    renderRakhi(
      0,
      45
    )


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

    val safeTitle =
      Math.min(
        titleIndex,
        titleText.length
      )

    val shownTitle =
      titleText.substring(
        0,
        safeTitle
      )


    val title =
      Picture.text(
        shownTitle,
        25
      )

    title.setPenColor(
      Color(255, 215, 0)
    )

    title.setPosition(
      -190,
      125
    )

    draw(title)


    // --------------------------------------------------------------
    // SUBTITLE
    // --------------------------------------------------------------

    if (titleIndex >= titleText.length) {

      val safeSub =
        Math.min(
          subtitleIndex,
          subtitleText.length
        )

      val shownSub =
        subtitleText.substring(
          0,
          safeSub
        )


      val sub =
        Picture.text(
          shownSub,
          20
        )

      sub.setPenColor(
        Color(255, 105, 180)
      )

      sub.setPosition(
        -160,
        -55
      )

      draw(sub)
    }


    // --------------------------------------------------------------
    // BLESSING
    // --------------------------------------------------------------

    if (subtitleIndex >= subtitleText.length) {

      val safeBlessing =
        Math.min(
          blessingIndex,
          blessingText.length
        )

      val shownBlessing =
        blessingText.substring(
          0,
          safeBlessing
        )


      val blessing =
        Picture.text(
          shownBlessing,
          13
        )

      blessing.setPenColor(
        Color(245, 245, 255)
      )

      blessing.setPosition(
        -235,
        -105
      )

      draw(blessing)
    }


    // Bottom decoration
    val bottom =
      Picture.text(
        "WITH LOVE ? ALWAYS",
        13
      )

    bottom.setPenColor(
      Color(255, 215, 0)
    )

    bottom.setPosition(
      -105,
      -145
    )

    draw(bottom)
  }
}


// ============================================================================
// 19. CELEBRATION BURST
// ============================================================================

def renderCelebrationBurst(): Unit = {

  if (opened && celebrationProgress < 100) {

    for (i <- 0 until 40) {

      val angle =
        (360.0 / 40) * i

      val rr =
        rad(angle)

      val radius =
        celebrationProgress * 3

      val x =
        radius * Math.cos(rr)

      val y =
        radius * Math.sin(rr) + 40

      val p =
        Picture.circle(
          3 + (i % 3)
        )

      if (i % 4 == 0) {

        p.setFillColor(
          Color(255, 215, 0)
        )

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

        p.setFillColor(
          Color(255, 80, 150)
        )

      } else if (i % 4 == 2) {

        p.setFillColor(
          Color(0, 230, 255)
        )

      } else {

        p.setFillColor(
          Color(255, 255, 255)
        )
      }

      p.setPosition(
        x,
        y
      )

      draw(p)
    }
  }
}


// ============================================================================
// 20. MASTER SCENE
// ============================================================================

def renderScene(): Unit = {

  erasePictures()

  drawBackgroundGlow()

  renderStars()

  renderNeonBorder()

  if (!opened) {

    renderGiftBox()

    renderFloatingParticles()

  } else {

    renderPetals()

    renderHearts()

    renderFireworks()

    renderCelebrationBurst()

    renderCard()
  }
}


// ============================================================================
// 21. INITIAL SCENE
// ============================================================================

renderScene()


// ============================================================================
// 22. MASTER ANIMATION LOOP
// ============================================================================

animateWithState(0.0) { frame =>

  animationFrame = frame

  particleTime += 1

  // ------------------------------------------------------------
  // MUSIC
  // ------------------------------------------------------------

  if (opened) {
    safeMusic()
  }


  // ------------------------------------------------------------
  // GIFT OPENING
  // ------------------------------------------------------------

  if (opened) {

    if (giftLidY < 235) {

      giftLidY += 9

      giftLidRotation += 6
    }


    // ----------------------------------------------------------
    // Firework growth
    // ----------------------------------------------------------

    if (
      firework1 <
      MAX_FIREWORK_RADIUS
    ) {

      firework1 += 8
    }


    if (
      firework1 > 35 &&
      firework2 <
      MAX_FIREWORK_RADIUS - 30
    ) {

      firework2 += 6.5
    }


    if (
      firework2 > 45 &&
      firework3 <
      MAX_FIREWORK_RADIUS - 65
    ) {

      firework3 += 5
    }


    // ----------------------------------------------------------
    // Rakhi
    // ----------------------------------------------------------

    rakhiAngle =
      (rakhiAngle + 3.5) % 360

    rakhiOuterAngle =
      (rakhiOuterAngle - 2.0) % 360


    // ----------------------------------------------------------
    // Celebration
    // ----------------------------------------------------------

    if (celebrationProgress < 100) {

      celebrationProgress += 2.2
    }


    // ----------------------------------------------------------
    // Typewriter
    // ----------------------------------------------------------

    typeCounter += 1

    if (typeCounter % 3 == 0) {

      if (
        titleIndex <
        titleText.length
      ) {

        titleIndex += 1

      } else if (
        subtitleIndex <
        subtitleText.length
      ) {

        subtitleIndex += 1

      } else if (
        blessingIndex <
        blessingText.length
      ) {

        blessingIndex += 1
      }
    }
  }


  // ------------------------------------------------------------
  // REDRAW
  // ------------------------------------------------------------

  renderScene()

  frame + 1.0
}


// ============================================================================
// 23. OPEN GIFT
// ============================================================================

def openGift(): Unit = {

  if (!opened) {

    opened = true

    giftLidY = 55
    giftLidRotation = 0

    firework1 = 10
    firework2 = 5
    firework3 = 0

    rakhiAngle = 0
    rakhiOuterAngle = 0

    titleIndex = 0
    subtitleIndex = 0
    blessingIndex = 0

    typeCounter = 0

    celebrationProgress = 0
  }
}


// ============================================================================
// 24. MOUSE MOVE
// ============================================================================

onMouseMove { (x, y) =>

  if (!opened) {

    hoverBox =
      x >= -120 &&
      x <= 120 &&
      y >= -100 &&
      y <= 130


    if (hoverBox) {
      openGift()
    }
  }
}


// ============================================================================
// 25. MOUSE CLICK
// ============================================================================

onMouseClick { (x, y) =>

  if (!opened) {

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

      openGift()
    }
  }
}