\n","generatedCode":"/**** \n* Plugins\n****/ \nvar tween = LK.import(\"@upit/tween.v1\");\n\n/**** \n* Classes\n****/ \n// Playback starts automatically\n// Balloon: Animated colorful balloons falling from the top\nvar Balloon = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar size = 60 + Math.random() * 80; // Random size\n\tvar speedY = 0.8 + Math.random() * 1.2; // Vertical speed\n\tvar speedX = (Math.random() - 0.5) * 2; // Horizontal drift\n\tvar rotationSpeed = (Math.random() - 0.5) * 0.05; // Rotation speed\n\t// Visuals\n\t// Use a more realistic width/height ratio for balloons (e.g. 0.55)\n\tvar balloonWidth = size * 0.55;\n\tvar balloonHeight = size;\n\tvar balloonGraphic = self.attachAsset('balloon', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: balloonWidth,\n\t\theight: balloonHeight\n\t});\n\t// Random color (rainbow)\n\tvar hue = Math.random();\n\tvar rgb = hsvToRgb(hue, 0.9 + Math.random() * 0.1, 0.9 + Math.random() * 0.1);\n\tballoonGraphic.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n\t// HSV to RGB helper (essential for color animations)\n\tfunction hsvToRgb(h, s, v) {\n\t\tvar r, g, b;\n\t\tvar i = Math.floor(h * 6);\n\t\tvar f = h * 6 - i;\n\t\tvar p = v * (1 - s);\n\t\tvar q = v * (1 - f * s);\n\t\tvar t_color = v * (1 - (1 - f) * s);\n\t\tswitch (i % 6) {\n\t\t\tcase 0:\n\t\t\t\tr = v;\n\t\t\t\tg = t_color;\n\t\t\t\tb = p;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tr = q;\n\t\t\t\tg = v;\n\t\t\t\tb = p;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tr = p;\n\t\t\t\tg = v;\n\t\t\t\tb = t_color;\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tr = p;\n\t\t\t\tg = q;\n\t\t\t\tb = v;\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tr = t_color;\n\t\t\t\tg = p;\n\t\t\t\tb = v;\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\tr = v;\n\t\t\t\tg = p;\n\t\t\t\tb = q;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];\n\t}\n\t// Animation\n\tself.update = function () {\n\t\tself.y += speedY;\n\t\tself.x += speedX;\n\t\tself.rotation += rotationSpeed;\n\t\t// Wrap around if off screen (below the dancing people)\n\t\tif (self.y > dancingPeople[0].y + 200) {\n\t\t\t// Wrap below the dancing people\n\t\t\tself.y = -size;\n\t\t\tself.x = Math.random() * 2048; // New random x position\n\t\t\t// Reset size and color for a new balloon\n\t\t\tsize = 60 + Math.random() * 80;\n\t\t\tvar balloonWidth = size * 0.55;\n\t\t\tvar balloonHeight = size;\n\t\t\tballoonGraphic.width = balloonWidth; // Maintain realistic balloon width/height ratio\n\t\t\tballoonGraphic.height = balloonHeight;\n\t\t\tvar hue = Math.random();\n\t\t\tvar rgb = hsvToRgb(hue, 0.9 + Math.random() * 0.1, 0.9 + Math.random() * 0.1);\n\t\t\tballoonGraphic.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n\t\t\tspeedY = 0.8 + Math.random() * 1.2;\n\t\t\tspeedX = (Math.random() - 0.5) * 2;\n\t\t\trotationSpeed = (Math.random() - 0.5) * 0.05;\n\t\t}\n\t};\n\treturn self;\n});\n// ConfettiEffect: Animated confetti falling from the top with multiple types\nvar ConfettiEffect = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar numParticles = 200; // Increased from 120 to 200 for much higher density\n\tvar particles = [];\n\tvar particleMinSize = 3.0; // Slightly larger minimum size\n\tvar particleMaxSize = 12.0; // Increased maximum size\n\tvar speedY = 5; // pixels per second\n\tvar speedX = 2; // horizontal drift\n\t// Define confetti types with more rectangle emphasis\n\tvar confettiTypes = [{\n\t\tasset: 'centerCircle',\n\t\tname: 'circle'\n\t}, {\n\t\tasset: 'crossfaderTrack',\n\t\tname: 'rectangle'\n\t}, {\n\t\tasset: 'crossfaderTrack',\n\t\tname: 'rectangle'\n\t}, {\n\t\tasset: 'crossfaderTrack',\n\t\tname: 'rectangle'\n\t}, {\n\t\tasset: 'crossfaderTrack',\n\t\tname: 'rectangle'\n\t}, {\n\t\tasset: 'beatLight',\n\t\tname: 'star'\n\t}];\n\t// Create confetti particles\n\tfor (var i = 0; i < numParticles; i++) {\n\t\tvar size = particleMinSize + Math.random() * (particleMaxSize - particleMinSize);\n\t\t// Choose random confetti type\n\t\tvar confettiType = confettiTypes[Math.floor(Math.random() * confettiTypes.length)];\n\t\tvar particle;\n\t\tif (confettiType.name === 'rectangle') {\n\t\t\t// Create rectangular confetti with more variety\n\t\t\tvar rectWidth = size * (1.2 + Math.random() * 0.8); // More width variation (1.2x to 2.0x)\n\t\t\tvar rectHeight = size * (0.4 + Math.random() * 0.6); // More height variation (0.4x to 1.0x)\n\t\t\tparticle = LK.getAsset(confettiType.asset, {\n\t\t\t\tanchorX: 0.5,\n\t\t\t\tanchorY: 0.5,\n\t\t\t\twidth: rectWidth,\n\t\t\t\theight: rectHeight\n\t\t\t});\n\t\t} else if (confettiType.name === 'star') {\n\t\t\t// Create star-shaped confetti\n\t\t\tparticle = LK.getAsset(confettiType.asset, {\n\t\t\t\tanchorX: 0.5,\n\t\t\t\tanchorY: 0.5,\n\t\t\t\twidth: size * 0.8,\n\t\t\t\theight: size * 0.8\n\t\t\t});\n\t\t} else {\n\t\t\t// Create circular confetti\n\t\t\tparticle = LK.getAsset(confettiType.asset, {\n\t\t\t\tanchorX: 0.5,\n\t\t\t\tanchorY: 0.5,\n\t\t\t\twidth: size,\n\t\t\t\theight: size\n\t\t\t});\n\t\t}\n\t\t// Random color (rainbow)\n\t\tvar hue = Math.random();\n\t\tvar rgb = hsvToRgb(hue, 0.9 + Math.random() * 0.1, 0.9 + Math.random() * 0.1);\n\t\tparticle.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n\t\t// Random initial position in upper half, above screen for seamless loop\n\t\tvar px = Math.random() * 2048;\n\t\tvar py = -particleMaxSize - Math.random() * 500;\n\t\tparticle.x = px;\n\t\tparticle.y = py;\n\t\tself.addChild(particle);\n\t\tparticles.push({\n\t\t\tobj: particle,\n\t\t\tspeedScale: 0.8 + Math.random() * 0.4,\n\t\t\t// particles fall at slightly different speeds\n\t\t\tphase: Math.random() * Math.PI * 2,\n\t\t\ttype: confettiType.name,\n\t\t\tbaseSize: size,\n\t\t\trotationSpeed: (Math.random() - 0.5) * 0.3 // Random rotation speed\n\t\t});\n\t}\n\t// HSV to RGB helper\n\tfunction hsvToRgb(h, s, v) {\n\t\tvar r, g, b;\n\t\tvar i = Math.floor(h * 6);\n\t\tvar f = h * 6 - i;\n\t\tvar p = v * (1 - s);\n\t\tvar q = v * (1 - f * s);\n\t\tvar t = v * (1 - (1 - f) * s);\n\t\tswitch (i % 6) {\n\t\t\tcase 0:\n\t\t\t\tr = v, g = t, b = p;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tr = q, g = v, b = p;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tr = p, g = v, b = t;\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tr = p, g = q, b = v;\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tr = t, g = p, b = v;\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\tr = v, g = p, b = q;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];\n\t}\n\t// Animation\n\tself.update = function () {\n\t\tvar t = Date.now() * 0.001;\n\t\tfor (var i = 0; i < particles.length; i++) {\n\t\t\tvar p = particles[i];\n\t\t\t// Move particles down with horizontal drift\n\t\t\tp.obj.y += speedY * p.speedScale;\n\t\t\tp.obj.x += speedX * Math.sin(t + p.phase);\n\t\t\t// Wrap around vertically (from bottom to top)\n\t\t\tif (p.obj.y > 2732) {\n\t\t\t\tp.obj.y = -particleMaxSize;\n\t\t\t\tp.obj.x = Math.random() * 2048; // new random x position\n\t\t\t\t// Reset rotation and add tween effect for new particles\n\t\t\t\tp.obj.rotation = 0;\n\t\t\t\ttween(p.obj, {\n\t\t\t\t\trotation: Math.PI * 2 * (Math.random() > 0.5 ? 1 : -1)\n\t\t\t\t}, {\n\t\t\t\t\tduration: 2000 + Math.random() * 3000,\n\t\t\t\t\teasing: tween.linear\n\t\t\t\t});\n\t\t\t}\n\t\t\t// Enhanced rotation based on type\n\t\t\tif (p.type === 'rectangle') {\n\t\t\t\tp.obj.rotation += p.rotationSpeed * 1.5; // Rectangles rotate faster\n\t\t\t} else if (p.type === 'star') {\n\t\t\t\tp.obj.rotation += p.rotationSpeed * 0.8; // Stars rotate slower\n\t\t\t} else {\n\t\t\t\tp.obj.rotation += p.rotationSpeed; // Circles normal rotation\n\t\t\t}\n\t\t\t// Type-specific animations\n\t\t\tif (p.type === 'rectangle') {\n\t\t\t\t// Rectangles flutter and tumble more dramatically\n\t\t\t\tvar flutter = 0.8 + 0.4 * Math.sin(t * 5 + p.phase);\n\t\t\t\tvar tumble = 0.9 + 0.2 * Math.cos(t * 3 + p.phase);\n\t\t\t\tp.obj.scaleX = flutter;\n\t\t\t\tp.obj.scaleY = tumble;\n\t\t\t\t// Add extra horizontal drift for rectangles\n\t\t\t\tp.obj.x += Math.sin(t * 2 + p.phase) * 0.8;\n\t\t\t} else if (p.type === 'star') {\n\t\t\t\t// Stars twinkle\n\t\t\t\tvar twinkle = 0.9 + 0.2 * Math.sin(t * 6 + p.phase);\n\t\t\t\tp.obj.scaleX = twinkle;\n\t\t\t\tp.obj.scaleY = twinkle;\n\t\t\t\t// Add alpha twinkling\n\t\t\t\tp.obj.alpha = 0.8 + 0.2 * Math.sin(t * 5 + p.phase);\n\t\t\t} else {\n\t\t\t\t// Circles flicker size\n\t\t\t\tvar baseSize = p.baseSize;\n\t\t\t\tvar s = baseSize * (0.95 + 0.1 * Math.sin(t * 3 + p.phase));\n\t\t\t\tp.obj.width = s;\n\t\t\t\tp.obj.height = s;\n\t\t\t}\n\t\t}\n\t};\n\treturn self;\n});\n// Crossfader: Controls mix between decks\nvar Crossfader = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// State\n\tself.value = 0.5; // 0 = left, 1 = right\n\tself.dragging = false;\n\t// Visuals\n\tvar track = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\tvar knob = self.attachAsset('crossfaderKnob', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\tknob.y = 0;\n\t// Methods\n\tself.setValue = function (val) {\n\t\tself.value = Math.max(0, Math.min(1, val));\n\t\tknob.x = (self.value - 0.5) * track.width;\n\t};\n\t// Touch events\n\tself.down = function (x, y, obj) {\n\t\tself.dragging = true;\n\t\tself.setValue((x + track.width / 2) / track.width);\n\t};\n\tself.up = function (x, y, obj) {\n\t\tself.dragging = false;\n\t};\n\tself.move = function (x, y, obj) {\n\t\tif (self.dragging) {\n\t\t\tself.setValue((x + track.width / 2) / track.width);\n\t\t}\n\t};\n\treturn self;\n});\n// DancingPerson: Animated dancing people (women and men)\nvar DancingPerson = Container.expand(function (forcedAssetId) {\n\tvar self = Container.call(this);\n\t// Config\n\tvar assetId;\n\tself.isUV = false; // Add a property to track if this is a UV person\n\tif (typeof forcedAssetId === 'string') {\n\t\tassetId = forcedAssetId;\n\t\tself.isUV = forcedAssetId === 'UVW' || forcedAssetId === 'UWM';\n\t} else {\n\t\t// fallback to random if not provided\n\t\tvar assets = ['dancingWoman', 'dancingMan'];\n\t\tassetId = assets[Math.floor(Math.random() * assets.length)];\n\t}\n\t// Visuals\n\tvar personGraphics = self.attachAsset(assetId, {\n\t\tanchorX: 0.5,\n\t\tanchorY: 1.0 // Anchor at the bottom center (feet)\n\t});\n\t// Animation state\n\tself.baseY = 0;\n\tself.phaseOffset = Math.random() * Math.PI * 2; // Random start phase for animation\n\t// Animation\n\tself.update = function () {\n\t\tvar t = Date.now() * 0.002; // Time for animation\n\t\t// Simple bouncing and swaying animation\n\t\tself.y = self.baseY + Math.sin(t * 3 + self.phaseOffset) * 15; // Bounce up/down\n\t\tself.rotation = Math.sin(t * 2 + self.phaseOffset) * 0.08; // Sway left/right\n\t};\n\treturn self;\n});\n// DeckPlatter: Represents a turntable platter\nvar DeckPlatter = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// State\n\tself.isActive = false;\n\tself.isScratching = false;\n\tself.lastAngle = 0;\n\tself.rotationOffset = 0;\n\tself.currentRotation = 0;\n\tself.track = 'A'; // 'A' or 'B'\n\tself.playing = true;\n\tself.scratchSpeed = 0;\n\tself.lastTouchAngle = null;\n\t// Visuals\n\tvar platter = self.attachAsset('deckPlatter', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\tvar highlight = self.attachAsset('deckPlatterHighlight', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\thighlight.alpha = 0;\n\t// Move highlight behind the platter by adding it first, then re-adding platter\n\tself.removeChild(platter);\n\tself.addChild(platter);\n\tvar label = self.attachAsset('deckLabel', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\ty: 350,\n\t\twidth: 90,\n\t\theight: 30\n\t});\n\t// Label text\n\tvar labelTxt = new Text2(self.track, {\n\t\tsize: 40,\n\t\tfill: \"#222\"\n\t});\n\tlabelTxt.anchor.set(0.5, 0.5);\n\tlabel.addChild(labelTxt);\n\t// Beat light\n\tvar beatLight = self.attachAsset('beatLight', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\ty: 490\n\t});\n\tbeatLight.alpha = 0.2;\n\t// Methods\n\tself.setActive = function (active) {\n\t\tself.isActive = active;\n\t\tif (active) {\n\t\t\thighlight.alpha = 0.6;\n\t\t\thighlight.visible = true;\n\t\t\t// Ensure highlight is above platter in display order\n\t\t\tself.removeChild(highlight);\n\t\t\tself.addChild(highlight);\n\t\t\t// Flash effect for better visual feedback\n\t\t\ttween(highlight, {\n\t\t\t\talpha: 0.3\n\t\t\t}, {\n\t\t\t\tduration: 200,\n\t\t\t\teasing: tween.easeOut\n\t\t\t});\n\t\t} else {\n\t\t\thighlight.alpha = 0;\n\t\t\thighlight.visible = false;\n\t\t}\n\t};\n\tself.setTrack = function (track) {\n\t\tself.track = track;\n\t\tlabelTxt.setText(track);\n\t};\n\tself.flashBeat = function () {\n\t\tbeatLight.alpha = 1;\n\t\ttween(beatLight, {\n\t\t\talpha: 0.2\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\teasing: tween.easeOut\n\t\t});\n\t};\n\t// Touch events\n\tself.down = function (x, y, obj) {\n\t\tself.isScratching = true;\n\t\tself.setActive(true);\n\t\t// Calculate angle from center using platter dimensions\n\t\tvar dx = x - platter.width / 2;\n\t\tvar dy = y - platter.height / 2;\n\t\tself.lastTouchAngle = Math.atan2(dy, dx);\n\t\tself.scratchSpeed = 0;\n\t\tLK.getSound('scratch').play();\n\t};\n\tself.up = function (x, y, obj) {\n\t\tself.isScratching = false;\n\t\tself.setActive(false);\n\t\tself.scratchSpeed = 0;\n\t\tself.lastTouchAngle = null;\n\t};\n\tself.move = function (x, y, obj) {\n\t\tif (!self.isScratching) return;\n\t\t// Calculate angle from center using platter dimensions\n\t\tvar dx = x - platter.width / 2;\n\t\tvar dy = y - platter.height / 2;\n\t\tvar angle = Math.atan2(dy, dx);\n\t\tif (self.lastTouchAngle !== null) {\n\t\t\tvar delta = angle - self.lastTouchAngle;\n\t\t\t// Normalize delta\n\t\t\tif (delta > Math.PI) delta -= 2 * Math.PI;\n\t\t\tif (delta < -Math.PI) delta += 2 * Math.PI;\n\t\t\tself.rotationOffset += delta;\n\t\t\tself.scratchSpeed = delta;\n\t\t}\n\t\tself.lastTouchAngle = angle;\n\t};\n\t// Called every tick\n\tself.update = function () {\n\t\t// Determine if this deck should be spinning based on start button state\n\t\tvar shouldSpin = false;\n\t\tif (self.track === 'A' && typeof leftStartButtonOn !== 'undefined' && leftStartButtonOn) {\n\t\t\tshouldSpin = true;\n\t\t} else if (self.track === 'B' && typeof rightStartButtonOn !== 'undefined' && rightStartButtonOn) {\n\t\t\tshouldSpin = true;\n\t\t}\n\t\t// If not scratching, platter rotates at normal speed only if should spin\n\t\tif (!self.isScratching && self.playing && shouldSpin) {\n\t\t\tself.rotationOffset += 0.02; // Normal play speed\n\t\t\tself.scratchSpeed = 0.02;\n\t\t}\n\t\t// Apply rotation\n\t\tself.currentRotation = self.rotationOffset;\n\t\tself.rotation = self.currentRotation;\n\t};\n\treturn self;\n});\n// Discoball: True 3D disco ball illusion with spinning mirrored tiles and shining white light particles\nvar Discoball = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar ballRadius = 150;\n\tvar ballDiameter = ballRadius * 2;\n\tvar numLat = 13; // latitude tiles (vertical)\n\tvar numLon = 24; // longitude tiles (horizontal)\n\tvar tileSize = ballDiameter / numLat * 0.95;\n\tvar tileGap = tileSize * 0.12;\n\tvar tiles = [];\n\tvar shineParticles = [];\n\tvar numShine = 18;\n\tvar shineRadius = ballRadius * 1.08;\n\tvar shineMinAlpha = 0.25;\n\tvar shineMaxAlpha = 0.95;\n\tvar shineMinSize = tileSize * 0.7;\n\tvar shineMaxSize = tileSize * 1.7;\n\tvar spinY = 0; // radians, for y-axis rotation\n\tvar spinSpeed = 0.012;\n\tvar spinDir = 1;\n\t// --- Mirrored Tiles Grid ---\n\t// Render both front and back halves for a full 3D ball illusion\n\tfor (var lat = 0; lat < numLat; lat++) {\n\t\tvar theta = Math.PI * (lat + 0.5) / numLat; // 0 (top) to PI (bottom)\n\t\tvar y = Math.cos(theta) * ballRadius;\n\t\tvar r = Math.sin(theta) * ballRadius;\n\t\tfor (var lon = 0; lon < numLon; lon++) {\n\t\t\tvar phi = 2 * Math.PI * lon / numLon;\n\t\t\t// 3D to 2D projection with y-axis spin\n\t\t\tvar x3d = Math.cos(phi) * r;\n\t\t\tvar z3d = Math.sin(phi) * r;\n\t\t\t// Y-axis spin\n\t\t\tvar x2d = x3d * Math.cos(spinY) - z3d * Math.sin(spinY);\n\t\t\tvar z2d = x3d * Math.sin(spinY) + z3d * Math.cos(spinY);\n\t\t\t// Draw both front and back tiles, but make back tiles dimmer and behind\n\t\t\tfor (var side = 0; side < 2; side++) {\n\t\t\t\t// side 0: front (z2d > 0), side 1: back (z2d < 0)\n\t\t\t\tvar isFront = side === 0;\n\t\t\t\t// Always create both front and back tiles, but only show one at a time\n\t\t\t\tvar tile = LK.getAsset('centerCircle', {\n\t\t\t\t\tanchorX: 0.5,\n\t\t\t\t\tanchorY: 0.5,\n\t\t\t\t\twidth: tileSize,\n\t\t\t\t\theight: tileSize\n\t\t\t\t});\n\t\t\t\t// Mirror color: light gray, with some random sparkle\n\t\t\t\tvar base = 0xbb + Math.floor(Math.random() * 0x22);\n\t\t\t\tvar color = base << 16 | base << 8 | base;\n\t\t\t\ttile.tint = color;\n\t\t\t\t// Back tiles are dimmer and more transparent\n\t\t\t\tif (isFront) {\n\t\t\t\t\ttile.alpha = 0.92 - 0.18 * (lat / numLat) + Math.random() * 0.08;\n\t\t\t\t} else {\n\t\t\t\t\ttile.alpha = 0.32 - 0.10 * (lat / numLat) + Math.random() * 0.04;\n\t\t\t\t}\n\t\t\t\t// Position\n\t\t\t\ttile.x = x2d;\n\t\t\t\ttile.y = y;\n\t\t\t\t// Simulate 3D: scaleX based on z2d\n\t\t\t\ttile.scaleX = 1 + 0.18 * (Math.abs(z2d) / ballRadius);\n\t\t\t\ttile.scaleY = 1;\n\t\t\t\t// For back tiles, send to back (add first), for front tiles, add last\n\t\t\t\tif (isFront) {\n\t\t\t\t\tself.addChild(tile);\n\t\t\t\t} else {\n\t\t\t\t\tself.addChildAt(tile, 0);\n\t\t\t\t}\n\t\t\t\ttiles.push({\n\t\t\t\t\ttile: tile,\n\t\t\t\t\tlat: lat,\n\t\t\t\t\tlon: lon,\n\t\t\t\t\ttheta: theta,\n\t\t\t\t\tphi: phi,\n\t\t\t\t\tisFront: isFront\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\t// --- Specular highlight (white spot) ---\n\t// Removed the white oval particle in front of the discoball\n\t// --- Shining white light particles ---\n\tfor (var i = 0; i < numShine; i++) {\n\t\tvar angle = 2 * Math.PI * i / numShine + Math.random() * 0.2;\n\t\tvar dist = shineRadius * (0.92 + Math.random() * 0.12);\n\t\tvar particle = LK.getAsset('centerCircle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: shineMinSize + Math.random() * (shineMaxSize - shineMinSize),\n\t\t\theight: shineMinSize + Math.random() * (shineMaxSize - shineMinSize)\n\t\t});\n\t\tparticle.tint = 0xffffff;\n\t\tparticle.alpha = shineMinAlpha + Math.random() * (shineMaxAlpha - shineMinAlpha);\n\t\tparticle.x = Math.cos(angle) * dist;\n\t\tparticle.y = Math.sin(angle) * dist;\n\t\tself.addChild(particle);\n\t\tshineParticles.push({\n\t\t\tparticle: particle,\n\t\t\tbaseAngle: angle,\n\t\t\tbaseDist: dist,\n\t\t\tphase: Math.random() * Math.PI * 2\n\t\t});\n\t}\n\t// --- Light beams (background) ---\n\tvar numBeams = 32;\n\tvar beams = [];\n\tvar lightBeamLength = 1200; // Increased from 800 to 1200 for longer beams\n\tfor (var i = 0; i < numBeams; i++) {\n\t\tvar beam = LK.getAsset('crossfaderTrack', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0,\n\t\t\twidth: 8,\n\t\t\theight: lightBeamLength\n\t\t});\n\t\tbeam.tint = 0xffffff;\n\t\tbeam.alpha = 0.12 + Math.random() * 0.28;\n\t\tbeam.rotation = Math.PI * 2 / numBeams * i + Math.random() * 0.1;\n\t\tbeams.push(beam);\n\t\tself.addChild(beam);\n\t}\n\t// --- Animation ---\n\tself.update = function () {\n\t\t// Animate y-axis spin in a full 360-degree circle\n\t\tspinY += spinSpeed * spinDir;\n\t\tif (spinY > Math.PI * 2) spinY -= Math.PI * 2;\n\t\tif (spinY < 0) spinY += Math.PI * 2;\n\t\tself._spinY = spinY; // direct assignment for full rotation\n\t\t// Update mirrored tiles positions for y-axis spin\n\t\tfor (var i = 0; i < tiles.length; i++) {\n\t\t\tvar t = tiles[i];\n\t\t\t// 3D to 2D projection with y-axis spin\n\t\t\tvar x3d = Math.cos(t.phi) * Math.sin(t.theta) * ballRadius;\n\t\t\tvar y3d = Math.cos(t.theta) * ballRadius;\n\t\t\tvar z3d = Math.sin(t.phi) * Math.sin(t.theta) * ballRadius;\n\t\t\t// Y-axis spin\n\t\t\tvar x2d = x3d * Math.cos(self._spinY) - z3d * Math.sin(self._spinY);\n\t\t\tvar z2d = x3d * Math.sin(self._spinY) + z3d * Math.cos(self._spinY);\n\t\t\t// For front tiles, show if z2d > 0; for back tiles, show if z2d < 0\n\t\t\tif (t.isFront && z2d > 0 || !t.isFront && z2d < 0) {\n\t\t\t\tt.tile.visible = true;\n\t\t\t\tt.tile.x = x2d;\n\t\t\t\tt.tile.y = y3d;\n\t\t\t\tt.tile.scaleX = 1 + 0.18 * (Math.abs(z2d) / ballRadius);\n\t\t\t\tt.tile.scaleY = 1;\n\t\t\t\t// Flicker for disco effect\n\t\t\t\tif (t.isFront) {\n\t\t\t\t\tt.tile.alpha = 0.88 - 0.18 * (t.lat / numLat) + Math.random() * 0.09;\n\t\t\t\t} else {\n\t\t\t\t\tt.tile.alpha = 0.28 - 0.10 * (t.lat / numLat) + Math.random() * 0.04;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tt.tile.visible = false;\n\t\t\t}\n\t\t}\n\t\t// Animate highlight to move in a small circle for extra 3D effect\n\t\t// (highlight removed, nothing to animate here)\n\t\tvar t = Date.now() * 0.001;\n\t\t// Animate shine particles\n\t\tfor (var i = 0; i < shineParticles.length; i++) {\n\t\t\tvar s = shineParticles[i];\n\t\t\tvar phase = t * 1.2 + s.phase;\n\t\t\tvar r = s.baseDist + Math.sin(phase) * 12;\n\t\t\ts.particle.x = Math.cos(s.baseAngle + Math.sin(phase) * 0.12) * r;\n\t\t\ts.particle.y = Math.sin(s.baseAngle + Math.cos(phase) * 0.12) * r;\n\t\t\ts.particle.alpha = shineMinAlpha + (shineMaxAlpha - shineMinAlpha) * (0.5 + 0.5 * Math.sin(phase * 2 + i));\n\t\t\tvar size = shineMinSize + (shineMaxSize - shineMinSize) * (0.5 + 0.5 * Math.cos(phase * 1.5 + i));\n\t\t\ts.particle.width = size;\n\t\t\ts.particle.height = size;\n\t\t}\n\t\t// Animate beams (spin and flicker)\n\t\tfor (var i = 0; i < beams.length; i++) {\n\t\t\tvar beam = beams[i];\n\t\t\tbeam.rotation += 0.015;\n\t\t\tbeam.alpha = 0.12 + Math.random() * 0.28;\n\t\t}\n\t};\n\treturn self;\n});\n// EqualizerBars: Animated frequency visualization bars for screens\nvar EqualizerBars = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar numBars = 12;\n\tvar barWidth = 25 * 1.2;\n\tvar barSpacing = 8;\n\tvar maxBarHeight = 100;\n\tvar minBarHeight = 10;\n\tvar bars = [];\n\t// Create equalizer bars\n\tfor (var i = 0; i < numBars; i++) {\n\t\tvar bar = LK.getAsset('crossfaderTrack', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 1.0,\n\t\t\twidth: barWidth,\n\t\t\theight: minBarHeight\n\t\t});\n\t\t// Color based on frequency range (bass=red, mid=yellow, treble=cyan)\n\t\tif (i < 4) {\n\t\t\tbar.tint = 0xff0000; // Bass - red\n\t\t} else if (i < 8) {\n\t\t\tbar.tint = 0xffff00; // Mid - yellow\n\t\t} else {\n\t\t\tbar.tint = 0x00ffff; // Treble - cyan\n\t\t}\n\t\tbar.x = (i - (numBars - 1) / 2) * (barWidth + barSpacing);\n\t\tbar.y = 0;\n\t\tself.addChild(bar);\n\t\tbars.push({\n\t\t\tobj: bar,\n\t\t\tphase: Math.random() * Math.PI * 2,\n\t\t\tbaseHeight: minBarHeight\n\t\t});\n\t}\n\t// Animation\n\tself.update = function () {\n\t\tvar t = Date.now() * 0.001;\n\t\tfor (var i = 0; i < bars.length; i++) {\n\t\t\tvar b = bars[i];\n\t\t\t// Simulate frequency response with different speeds for different frequency ranges\n\t\t\tvar speed = 1.0;\n\t\t\tif (i < 4) speed = 0.8; // Bass moves slower\n\t\t\telse if (i < 8) speed = 1.2; // Mid moves medium\n\t\t\telse speed = 1.8; // Treble moves faster\n\t\t\t// Create realistic frequency bar movement\n\t\t\tvar height = minBarHeight + (maxBarHeight - minBarHeight) * (0.3 + 0.7 * Math.abs(Math.sin(t * speed * 2 + b.phase + i * 0.3)));\n\t\t\tb.obj.height = height;\n\t\t\t// Add beat sync flash effect\n\t\t\tif (beatTimer && beatTimer < 100) {\n\t\t\t\tb.obj.alpha = 0.7 + 0.3 * Math.sin(t * 10 + i);\n\t\t\t} else {\n\t\t\t\tb.obj.alpha = 0.9;\n\t\t\t}\n\t\t}\n\t};\n\treturn self;\n});\n// FXButton: Triggers a sound effect\nvar FXButton = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Visuals\n\tvar btn = self.attachAsset('fxButton', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\tvar txt = new Text2('FX', {\n\t\tsize: 48,\n\t\tfill: \"#fff\"\n\t});\n\ttxt.anchor.set(0.5, 0.5);\n\tbtn.addChild(txt);\n\t// State\n\tself.cooldown = false;\n\t// Touch\n\tself.down = function (x, y, obj) {\n\t\tif (self.cooldown) return;\n\t\tself.cooldown = true;\n\t\tLK.getSound('fx').play();\n\t\ttween(btn, {\n\t\t\tscaleX: 1.2,\n\t\t\tscaleY: 1.2\n\t\t}, {\n\t\t\tduration: 80,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\ttween(btn, {\n\t\t\t\t\tscaleX: 1,\n\t\t\t\t\tscaleY: 1\n\t\t\t\t}, {\n\t\t\t\t\tduration: 120\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\tLK.setTimeout(function () {\n\t\t\tself.cooldown = false;\n\t\t}, 400);\n\t};\n\treturn self;\n});\n// FerrisWheel: Animated slow spinning, color-changing Ferris wheel\nvar FerrisWheel = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tself.wheelRadius = 200;\n\tself.numCabins = 8;\n\tself.spinSpeed = 0.002; // Radians per update for wheelAssembly\n\tself.colorChangeCycleTime = 6000; // ms for a full color cycle for a cabin\n\t// HSV to RGB helper function (essential for color animations)\n\tfunction hsvToRgb(h, s, v) {\n\t\tvar r, g, b;\n\t\tvar i = Math.floor(h * 6);\n\t\tvar f = h * 6 - i;\n\t\tvar p = v * (1 - s);\n\t\tvar q = v * (1 - f * s);\n\t\tvar t_color = v * (1 - (1 - f) * s); // Renamed 't' to avoid conflict\n\t\tswitch (i % 6) {\n\t\t\tcase 0:\n\t\t\t\tr = v;\n\t\t\t\tg = t_color;\n\t\t\t\tb = p;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tr = q;\n\t\t\t\tg = v;\n\t\t\t\tb = p;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tr = p;\n\t\t\t\tg = v;\n\t\t\t\tb = t_color;\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tr = p;\n\t\t\t\tg = q;\n\t\t\t\tb = v;\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tr = t_color;\n\t\t\t\tg = p;\n\t\t\t\tb = v;\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\tr = v;\n\t\t\t\tg = p;\n\t\t\t\tb = q;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];\n\t}\n\t// Wheel structure (hub and spokes) - this part will rotate\n\tself.wheelAssembly = self.addChild(new Container());\n\t// --- Full Circle (Rim) ---\n\t// Approximate a circle by placing many small ellipses around the rim\n\tself.rimSegments = 36;\n\tself.rimRadius = self.wheelRadius;\n\tfor (var i = 0; i < self.rimSegments; i++) {\n\t\tvar rimAngle = Math.PI * 2 / self.rimSegments * i;\n\t\tvar rimX = Math.cos(rimAngle) * self.rimRadius;\n\t\tvar rimY = Math.sin(rimAngle) * self.rimRadius;\n\t\tvar rim = self.wheelAssembly.attachAsset('centerCircle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: 11,\n\t\t\theight: 11,\n\t\t\tx: rimX,\n\t\t\ty: rimY\n\t\t});\n\t\trim.tint = 0xffffff;\n\t\trim.alpha = 0.7;\n\t}\n\t// Central Hub\n\tvar hub = self.wheelAssembly.attachAsset('ferrisHub', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\t// Spokes\n\tfor (var i = 0; i < self.numCabins; i++) {\n\t\tvar angle = Math.PI * 2 / self.numCabins * i;\n\t\tvar spoke = self.wheelAssembly.attachAsset('ferrisSpoke', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0,\n\t\t\t// Anchor at the hub-connection point\n\t\t\theight: self.wheelRadius,\n\t\t\t// Spoke length is the wheel radius\n\t\t\trotation: angle\n\t\t});\n\t}\n\t// Cabins - these will be positioned along the rim and kept upright\n\tself.cabins = [];\n\tfor (var i = 0; i < self.numCabins; i++) {\n\t\tvar cabinAngle = Math.PI * 2 / self.numCabins * i;\n\t\t// Create cabin using LK.getAsset and add it as a child to the FerrisWheel container (self)\n\t\tvar cabin = self.addChild(LK.getAsset('ferrisCabin', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5\n\t\t}));\n\t\tcabin.initialAngle = cabinAngle; // Store its angular position on the wheel\n\t\t// Initial position and color\n\t\tvar xPos = Math.cos(cabinAngle) * self.wheelRadius;\n\t\tvar yPos = Math.sin(cabinAngle) * self.wheelRadius;\n\t\tcabin.x = xPos;\n\t\tcabin.y = yPos;\n\t\tvar initialHue = cabin.initialAngle / (Math.PI * 2) % 1.0;\n\t\tvar initialRgb = hsvToRgb(initialHue, 0.85, 0.95);\n\t\tcabin.tint = initialRgb[0] << 16 | initialRgb[1] << 8 | initialRgb[2];\n\t\tself.cabins.push(cabin);\n\t}\n\tself.update = function () {\n\t\t// Spin the wheel assembly\n\t\tself.wheelAssembly.rotation += self.spinSpeed;\n\t\t// Update cabin positions and colors\n\t\tvar globalTimeFactor = Date.now() % self.colorChangeCycleTime / self.colorChangeCycleTime;\n\t\tfor (var i = 0; i < self.cabins.length; i++) {\n\t\t\tvar cabin = self.cabins[i];\n\t\t\t// Calculate current angle of the cabin attachment point on the rotating wheel\n\t\t\tvar currentAttachmentAngle = cabin.initialAngle + self.wheelAssembly.rotation;\n\t\t\t// Update cabin position relative to the FerrisWheel container's center\n\t\t\tcabin.x = Math.cos(currentAttachmentAngle) * self.wheelRadius;\n\t\t\tcabin.y = Math.sin(currentAttachmentAngle) * self.wheelRadius;\n\t\t\t// Cabins are direct children of 'self' (FerrisWheel container).\n\t\t\t// 'self' itself is not rotating, so cabins remain upright (rotation = 0) by default.\n\t\t\t// Animate color: Cycle hue for each cabin\n\t\t\tvar cabinHue = (cabin.initialAngle / (Math.PI * 2) + globalTimeFactor) % 1.0;\n\t\t\tvar rgb = hsvToRgb(cabinHue, 0.85, 0.95);\n\t\t\tvar newTint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n\t\t\t// Tween for smooth color change\n\t\t\tif (cabin.tint !== newTint) {\n\t\t\t\ttween.stop(cabin, {\n\t\t\t\t\ttint: true\n\t\t\t\t}); // Stop existing tint tweens on this cabin\n\t\t\t\ttween(cabin, {\n\t\t\t\t\ttint: newTint\n\t\t\t\t}, {\n\t\t\t\t\tduration: 300,\n\t\t\t\t\teasing: tween.linear\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n\treturn self;\n});\n// FireworksEffect: Animated fireworks exploding in the upper half of the screen\nvar FireworksEffect = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar numRockets = 8; // Number of simultaneous rockets/explosions - increased from 4 to 8\n\tvar rocketInterval = 800; // ms between new rockets - reduced from 1500 to 800\n\tvar rocketTimer = 0;\n\tvar lastTickTime = Date.now();\n\tvar rockets = [];\n\tvar explosionParticles = [];\n\t// Predefined rainbow colors for explosions\n\tvar beamColors = [0xff0000,\n\t// red\n\t0xff8000,\n\t// orange\n\t0xffff00,\n\t// yellow\n\t0x00ff00,\n\t// green\n\t0x00ffff,\n\t// cyan\n\t0x0000ff,\n\t// blue\n\t0x8000ff,\n\t// violet\n\t0xff00ff // magenta\n\t];\n\t// Explosion particle configuration\n\tvar particleMinSize = 8;\n\tvar particleMaxSize = 20;\n\tvar particleSpeed = 15; // pixels per update\n\tvar particleLifetime = 1000; // ms\n\t// Create an explosion\n\tfunction createExplosion(x, y, color) {\n\t\tvar numParticles = 20 + Math.random() * 10;\n\t\tfor (var i = 0; i < numParticles; i++) {\n\t\t\tvar angle = Math.random() * Math.PI * 2;\n\t\t\tvar speed = particleSpeed * (0.8 + Math.random() * 0.4);\n\t\t\tvar particle = LK.getAsset('centerCircle', {\n\t\t\t\tanchorX: 0.5,\n\t\t\t\tanchorY: 0.5,\n\t\t\t\twidth: (particleMinSize + Math.random() * (particleMaxSize - particleMinSize)) * 0.5,\n\t\t\t\theight: (particleMinSize + Math.random() * (particleMaxSize - particleMinSize)) * 0.5\n\t\t\t});\n\t\t\tparticle.tint = color;\n\t\t\tparticle.alpha = 1.0;\n\t\t\tparticle.x = x;\n\t\t\tparticle.y = y;\n\t\t\tself.addChild(particle);\n\t\t\texplosionParticles.push({\n\t\t\t\tobj: particle,\n\t\t\t\tspeedX: Math.cos(angle) * speed,\n\t\t\t\tspeedY: Math.sin(angle) * speed,\n\t\t\t\tstartTime: Date.now(),\n\t\t\t\tcolor: color\n\t\t\t});\n\t\t}\n\t}\n\t// Animation\n\tself.update = function () {\n\t\tvar now = Date.now();\n\t\tvar delta = now - lastTickTime;\n\t\tlastTickTime = now;\n\t\t// --- Manage rockets ---\n\t\trocketTimer += delta;\n\t\tif (rocketTimer >= rocketInterval && rockets.length < numRockets) {\n\t\t\trocketTimer -= rocketInterval;\n\t\t\t// Launch a new rocket from the bottom\n\t\t\tvar startX = 200 + Math.random() * (2048 - 400);\n\t\t\tvar endY = 200 + Math.random() * (600 - 200); // Explode in upper half\n\t\t\tvar rocket = LK.getAsset('centerCircle', {\n\t\t\t\tanchorX: 0.5,\n\t\t\t\tanchorY: 0.5,\n\t\t\t\twidth: 10,\n\t\t\t\theight: 10\n\t\t\t});\n\t\t\trocket.tint = 0xffffff; // White trail\n\t\t\trocket.alpha = 0.8;\n\t\t\trocket.x = startX;\n\t\t\trocket.y = 2732; // Start from bottom\n\t\t\tself.addChild(rocket);\n\t\t\trockets.push({\n\t\t\t\tobj: rocket,\n\t\t\t\tstartX: startX,\n\t\t\t\tendY: endY,\n\t\t\t\tspeedY: -(2732 - endY) / (rocketInterval * 0.6) * 16,\n\t\t\t\t// Adjust speed based on distance and interval\n\t\t\t\tcolor: beamColors[Math.floor(Math.random() * beamColors.length)],\n\t\t\t\t// Random explosion color from beamColors\n\t\t\t\tlaunchedTime: now\n\t\t\t});\n\t\t}\n\t\t// Update rockets\n\t\tfor (var i = rockets.length - 1; i >= 0; i--) {\n\t\t\tvar rocket = rockets[i];\n\t\t\trocket.obj.y += rocket.speedY * (delta / 16); // Move rocket based on delta\n\t\t\t// Check if rocket reached explosion point\n\t\t\tif (rocket.obj.y <= rocket.endY || now - rocket.launchedTime > rocketInterval * 0.8) {\n\t\t\t\t// Explode also after a certain time\n\t\t\t\tcreateExplosion(rocket.obj.x, rocket.obj.y, rocket.color);\n\t\t\t\trocket.obj.destroy();\n\t\t\t\trockets.splice(i, 1);\n\t\t\t}\n\t\t}\n\t\t// Update explosion particles\n\t\tfor (var i = explosionParticles.length - 1; i >= 0; i--) {\n\t\t\tvar p = explosionParticles[i];\n\t\t\tvar elapsed = now - p.startTime;\n\t\t\tif (elapsed > particleLifetime) {\n\t\t\t\tp.obj.destroy();\n\t\t\t\texplosionParticles.splice(i, 1);\n\t\t\t} else {\n\t\t\t\t// Move particle\n\t\t\t\tp.obj.x += p.speedX * (delta / 16);\n\t\t\t\tp.obj.y += p.speedY * (delta / 16);\n\t\t\t\t// Fade out\n\t\t\t\tp.obj.alpha = 1.0 - elapsed / particleLifetime;\n\t\t\t}\n\t\t}\n\t};\n\treturn self;\n});\n// Flamethrower: Animated flames from the ground\nvar Flamethrower = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Visuals - Flamethrower base\n\tvar base = self.attachAsset('flamethrowerBase', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 1.0,\n\t\tscaleX: 0.5,\n\t\tscaleY: 0.5\n\t});\n\tbase.y = 0; // Position at the base of the container\n\t// Config\n\tvar numParticles = 20;\n\tvar particles = [];\n\tvar particleMinSize = 40;\n\tvar particleMaxSize = 120;\n\tvar speedY = -15; // pixels per second (upwards)\n\tvar speedX = 4; // horizontal flicker/sway\n\tvar particleLifetime = 500; // ms\n\t// HSV to RGB helper\n\tfunction hsvToRgb(h, s, v) {\n\t\tvar r, g, b;\n\t\tvar i = Math.floor(h * 6);\n\t\tvar f = h * 6 - i;\n\t\tvar p = v * (1 - s);\n\t\tvar q = v * (1 - f * s);\n\t\tvar t = v * (1 - (1 - f) * s);\n\t\tswitch (i % 6) {\n\t\t\tcase 0:\n\t\t\t\tr = v, g = t, b = p;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tr = q, g = v, b = p;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tr = p, g = v, b = t;\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tr = p, g = q, b = v;\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tr = t, g = p, b = v;\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\tr = v, g = p, b = q;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];\n\t}\n\t// Create flame particles\n\tself.createFlame = function () {\n\t\tvar baseSize = (particleMinSize + Math.random() * (particleMaxSize - particleMinSize)) * 0.48;\n\t\tvar size = baseSize;\n\t\t// Modify size based on fire effect mode\n\t\tif (typeof fireEffectMode !== 'undefined' && fireEffectMode === 2) {\n\t\t\t// Big flames mode - make particles larger\n\t\t\tsize = baseSize * 2.5;\n\t\t}\n\t\tvar particle = LK.getAsset('centerCircle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: size,\n\t\t\theight: size\n\t\t});\n\t\t// Flame color (yellow to red)\n\t\tvar hue = Math.random() * 0.1 + 0.05; // Hue from 0.05 (reddish-orange) to 0.15 (yellowish-orange)\n\t\tvar rgb = hsvToRgb(hue, 1, 1);\n\t\tparticle.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n\t\t// Initial position at the base of the flamethrower\n\t\t// Position the particle relative to the top-center of the base graphic\n\t\tparticle.x = 0; // Relative to the Flamethrower container's origin\n\t\tparticle.y = -base.height; // Position above the base graphic\n\t\tparticle.alpha = 0.8 + Math.random() * 0.2;\n\t\tself.addChild(particle);\n\t\tparticles.push({\n\t\t\tobj: particle,\n\t\t\tspeedScale: 0.8 + Math.random() * 0.4,\n\t\t\tstartTime: Date.now(),\n\t\t\tbaseSize: size,\n\t\t\tphase: Math.random() * Math.PI * 2\n\t\t});\n\t};\n\t// Animation\n\tself.update = function () {\n\t\tvar now = Date.now();\n\t\tvar delta = now - (self._lastTickTime || now);\n\t\tself._lastTickTime = now;\n\t\t// Create new particles periodically based on fire effect mode\n\t\tvar targetParticleCount = numParticles;\n\t\tif (typeof fireEffectMode !== 'undefined') {\n\t\t\tif (fireEffectMode === 0) {\n\t\t\t\t// Off mode - no flames\n\t\t\t\ttargetParticleCount = 0;\n\t\t\t} else if (fireEffectMode === 2) {\n\t\t\t\t// Big flames mode - more particles\n\t\t\t\ttargetParticleCount = numParticles * 2;\n\t\t\t}\n\t\t}\n\t\tif (particles.length < targetParticleCount) {\n\t\t\tself.createFlame();\n\t\t}\n\t\t// Update particles\n\t\tfor (var i = particles.length - 1; i >= 0; i--) {\n\t\t\tvar p = particles[i];\n\t\t\tvar elapsed = now - p.startTime;\n\t\t\tif (elapsed > particleLifetime) {\n\t\t\t\tp.obj.destroy();\n\t\t\t\tparticles.splice(i, 1);\n\t\t\t} else {\n\t\t\t\t// Move particle upwards with horizontal flicker\n\t\t\t\tp.obj.y += speedY * p.speedScale * (delta / 16);\n\t\t\t\tp.obj.x += speedX * Math.sin(now * 0.003 + p.phase) * p.speedScale * (delta / 16);\n\t\t\t\t// Fade out\n\t\t\t\tp.obj.alpha = (1.0 - elapsed / particleLifetime) * (0.8 + 0.2 * Math.sin(now * 0.004 + p.phase)); // Add flicker to fade\n\t\t\t\t// Scale down over time\n\t\t\t\tvar size = p.baseSize * (1.0 - elapsed / particleLifetime * 0.8);\n\t\t\t\tp.obj.width = size;\n\t\t\t\tp.obj.height = size;\n\t\t\t\t// Animate color slightly towards red as it fades\n\t\t\t\tvar fadeHue = Math.random() * 0.05; // Shift slightly towards red (hue 0)\n\t\t\t\tvar fadeRgb = hsvToRgb(fadeHue, 1, 1);\n\t\t\t\tvar originalTint = p.obj.tint;\n\t\t\t\tvar r1 = originalTint >> 16 & 0xFF;\n\t\t\t\tvar g1 = originalTint >> 8 & 0xFF;\n\t\t\t\tvar b1 = originalTint & 0xFF;\n\t\t\t\tvar r2 = fadeRgb[0];\n\t\t\t\tvar g2 = fadeRgb[1];\n\t\t\t\tvar b2 = fadeRgb[2];\n\t\t\t\tvar blend = elapsed / particleLifetime;\n\t\t\t\tvar r = Math.round(r1 * (1 - blend) + r2 * blend);\n\t\t\t\tvar g = Math.round(g1 * (1 - blend) + g2 * blend);\n\t\t\t\tvar b = Math.round(b1 * (1 - blend) + b2 * blend);\n\t\t\t\tp.obj.tint = r << 16 | g << 8 | b;\n\t\t\t}\n\t\t}\n\t};\n\treturn self;\n});\n// FogEffect: Animated fog in upper half of the map\nvar FogEffect = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar numParticles = 20;\n\tvar particles = [];\n\tvar particleMinSize = 200;\n\tvar particleMaxSize = 800;\n\tvar speedX = 3; // pixels per second, increased horizontal speed\n\tvar speedY = 0.2; // pixels per second, decreased vertical speed\n\tvar particleAlpha = 0.18; // Increased particle alpha for denser fog\n\t// Create fog particles\n\tfor (var i = 0; i < numParticles; i++) {\n\t\tvar size = particleMinSize + Math.random() * (particleMaxSize - particleMinSize);\n\t\tvar particle = LK.getAsset('crossfaderTrack', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: size * 2.0,\n\t\t\t// Make particles significantly wider\n\t\t\theight: size * 0.4 // Make particles much flatter\n\t\t});\n\t\tparticle.tint = 0xffffff; // white fog\n\t\tparticle.alpha = particleAlpha;\n\t\t// Random initial position in upper half, extending slightly beyond bounds for seamless loop\n\t\tvar px = Math.random() * (2048 + particleMaxSize) - particleMaxSize / 2;\n\t\tvar py = 100 + Math.random() * (1366 - 100);\n\t\tparticle.x = px;\n\t\tparticle.y = py;\n\t\tself.addChild(particle);\n\t\tparticles.push({\n\t\t\tobj: particle,\n\t\t\tspeedScale: 0.5 + Math.random() * 1.0,\n\t\t\t// particles move at different speeds\n\t\t\tbaseAlpha: particleAlpha\n\t\t});\n\t}\n\t// Animation\n\tself.update = function () {\n\t\t// Only animate if fog animation is active\n\t\tif (typeof fogAnimationActive !== 'undefined' && !fogAnimationActive) {\n\t\t\t// Hide all particles when fog animation is not active\n\t\t\tfor (var i = 0; i < particles.length; i++) {\n\t\t\t\tvar p = particles[i];\n\t\t\t\tp.obj.alpha = 0;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tvar t = Date.now() * 0.001;\n\t\tfor (var i = 0; i < particles.length; i++) {\n\t\t\tvar p = particles[i];\n\t\t\t// Move particles from right to left\n\t\t\tp.obj.x -= speedX * p.speedScale;\n\t\t\tp.obj.y += speedY * p.speedScale;\n\t\t\t// Wrap around horizontally (from left to right)\n\t\t\tif (p.obj.x < -particleMaxSize / 2) {\n\t\t\t\tp.obj.x = 2048 + particleMaxSize / 2;\n\t\t\t\tp.obj.y = Math.random() * (2732 / 2 - 100) + 100; // new random y position within upper half\n\t\t\t}\n\t\t\t// Animate alpha for subtle flow and density changes\n\t\t\tp.obj.alpha = p.baseAlpha + 0.08 * Math.sin(t * 0.8 + i); // Increased alpha animation range\n\t\t}\n\t};\n\treturn self;\n});\n// KeyboardApp: Simple keyboard app for the tablet\nvar KeyboardApp = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar keyboardWidth = 742;\n\tvar keyboardHeight = 250;\n\tvar keyWidth = 50;\n\tvar keyHeight = 50;\n\tvar keySpacing = 8;\n\tvar keys = [];\n\tvar keyLabels = [['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'], ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'], ['Z', 'X', 'C', 'V', 'B', 'N', 'M']];\n\tvar shiftLabels = [['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'], ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'], ['z', 'x', 'c', 'v', 'b', 'n', 'm']];\n\tvar symbolLabels = [['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'], [',', '-', '.', '/', '+', ':', ';', '<', '>'], ['_', '=', '|', '\\\\', '{', '}', '[', ']'], ['é', 'ú', 'ü', 'ű', 'í', 'ó', 'ö', 'ő', 'á']];\n\tself.isSymbolsMode = false; // Track if symbols mode is active\n\tself.isShiftMode = false; // Track if shift mode is active\n\t// Create keyboard background\n\tvar keyboardBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: keyboardWidth,\n\t\theight: keyboardHeight\n\t});\n\tkeyboardBg.tint = 0x333333;\n\t// Create keys\n\tvar startX = (keyboardWidth - (keyLabels[0].length * (keyWidth + keySpacing) - keySpacing)) / 2;\n\tvar startY = 20;\n\tfor (var row = 0; row < keyLabels.length; row++) {\n\t\tvar rowLabels = keyLabels[row];\n\t\tvar rowStartX = (keyboardWidth - (rowLabels.length * (keyWidth + keySpacing) - keySpacing)) / 2;\n\t\tfor (var col = 0; col < rowLabels.length; col++) {\n\t\t\tvar keyBg = self.attachAsset('crossfaderTrack', {\n\t\t\t\tanchorX: 0.5,\n\t\t\t\tanchorY: 0.5,\n\t\t\t\twidth: keyWidth,\n\t\t\t\theight: keyHeight\n\t\t\t});\n\t\t\tkeyBg.tint = 0x555555;\n\t\t\tkeyBg.x = rowStartX + col * (keyWidth + keySpacing) + keyWidth / 2;\n\t\t\tkeyBg.y = startY + row * (keyHeight + keySpacing) + keyHeight / 2;\n\t\t\tvar keyText = new Text2(rowLabels[col], {\n\t\t\t\tsize: 40,\n\t\t\t\tfill: 0xFFFFFF\n\t\t\t});\n\t\t\tkeyText.anchor.set(0.5, 0.5);\n\t\t\tkeyBg.addChild(keyText);\n\t\t\t// Add basic press feedback\n\t\t\tkeyBg.down = function (x, y, obj) {\n\t\t\t\tself.handleKeyPress(keyText.text); // Pass the key label to a new handler\n\t\t\t\ttween(this, {\n\t\t\t\t\tscaleX: 1.1,\n\t\t\t\t\tscaleY: 1.1\n\t\t\t\t}, {\n\t\t\t\t\tduration: 80\n\t\t\t\t});\n\t\t\t\t// Add orange flashing effect using tint and alpha\n\t\t\t\t// Create a temporary flashing graphic above the key\n\t\t\t\tvar flashGraphic = LK.getAsset('flashRectangle', {\n\t\t\t\t\tanchorX: 0.5,\n\t\t\t\t\tanchorY: 0.5,\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\theight: this.height\n\t\t\t\t});\n\t\t\t\tflashGraphic.alpha = 1.0;\n\t\t\t\t// Position the flash graphic centered on the key\n\t\t\t\tflashGraphic.x = this.x;\n\t\t\t\tflashGraphic.y = this.y;\n\t\t\t\tself.addChild(flashGraphic);\n\t\t\t\t// Fade out and remove the flash graphic\n\t\t\t\ttween(flashGraphic, {\n\t\t\t\t\talpha: 0.0\n\t\t\t\t}, {\n\t\t\t\t\tduration: 200,\n\t\t\t\t\tonFinish: function onFinish() {\n\t\t\t\t\t\tflashGraphic.destroy();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\ttween(this, {\n\t\t\t\t\ttint: 0xff8000,\n\t\t\t\t\talpha: 1.0\n\t\t\t\t}, {\n\t\t\t\t\tduration: 50,\n\t\t\t\t\tonFinish: function () {\n\t\t\t\t\t\ttween(this, {\n\t\t\t\t\t\t\ttint: 0x555555,\n\t\t\t\t\t\t\talpha: 0.8 // Slightly faded normal state\n\t\t\t\t\t\t}, {\n\t\t\t\t\t\t\tduration: 150\n\t\t\t\t\t\t});\n\t\t\t\t\t}.bind(this)\n\t\t\t\t});\n\t\t\t\tLK.getSound('fx').play(); // Play a generic sound\n\t\t\t};\n\t\t\tkeyBg.up = function (x, y, obj) {\n\t\t\t\t// Return to original tint and alpha on release\n\t\t\t\ttween(this, {\n\t\t\t\t\ttint: 0x555555,\n\t\t\t\t\talpha: 0.8 // Slightly faded normal state\n\t\t\t\t}, {\n\t\t\t\t\tduration: 100\n\t\t\t\t});\n\t\t\t\ttween(this, {\n\t\t\t\t\tscaleX: 1.0,\n\t\t\t\t\tscaleY: 1.0\n\t\t\t\t}, {\n\t\t\t\t\tduration: 80\n\t\t\t\t});\n\t\t\t};\n\t\t\tkeys.push(keyBg);\n\t\t}\n\t}\n\t// Add space bar\n\tvar spaceBarWidth = keyWidth * 6 + keySpacing * 5;\n\tvar spaceBarBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: spaceBarWidth * 1.1,\n\t\theight: keyHeight\n\t});\n\tvar spaceGraphic = self.attachAsset('Space', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\tspaceGraphic.width = spaceBarWidth * 1.1;\n\tspaceGraphic.height = keyHeight;\n\tspaceBarBg.addChild(spaceGraphic);\n\tspaceBarBg.tint = 0x555555;\n\tspaceBarBg.x = keyboardWidth / 2;\n\tspaceBarBg.y = startY + keyLabels.length * (keyHeight + keySpacing) + keyHeight / 2;\n\tvar spaceText = new Text2('SPACE', {\n\t\tsize: 40,\n\t\tfill: 0xFFFFFF\n\t});\n\tspaceText.anchor.set(0.5, 0.5);\n\tspaceBarBg.addChild(spaceText);\n\t// Add basic press feedback for space bar\n\tspaceBarBg.down = function (x, y, obj) {\n\t\ttween(this, {\n\t\t\tscaleX: 1.05,\n\t\t\tscaleY: 1.05\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t\t// Add orange flashing effect using tint and alpha\n\t\t// Create a temporary flashing graphic above the spacebar\n\t\tvar flashGraphic = LK.getAsset('flashRectangle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: this.width,\n\t\t\theight: this.height\n\t\t});\n\t\tflashGraphic.alpha = 1.0;\n\t\t// Position the flash graphic centered on the spacebar\n\t\tflashGraphic.x = this.x;\n\t\tflashGraphic.y = this.y;\n\t\tself.addChild(flashGraphic);\n\t\t// Fade out and remove the flash graphic\n\t\ttween(flashGraphic, {\n\t\t\talpha: 0.0\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\tflashGraphic.destroy();\n\t\t\t}\n\t\t});\n\t\ttween(this, {\n\t\t\ttint: 0xff8000,\n\t\t\talpha: 1.0\n\t\t}, {\n\t\t\tduration: 50\n\t\t});\n\t\tLK.getSound('fx').play(); // Play a generic sound\n\t};\n\tspaceBarBg.up = function (x, y, obj) {\n\t\t// Return to original tint and alpha on release\n\t\ttween(this, {\n\t\t\ttint: 0x555555,\n\t\t\talpha: 0.8 // Slightly faded normal state\n\t\t}, {\n\t\t\tduration: 100\n\t\t});\n\t\ttween(this, {\n\t\t\tscaleX: 1.0,\n\t\t\tscaleY: 1.0\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t};\n\tkeys.push(spaceBarBg);\n\t// Add symbols button to the left of the space bar\n\tvar symbolsBarWidth = keyWidth * 2 + keySpacing;\n\tvar symbolsBarBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: symbolsBarWidth,\n\t\theight: keyHeight\n\t});\n\tsymbolsBarBg.tint = 0x555555;\n\tsymbolsBarBg.x = spaceBarBg.x - spaceBarBg.width / 2 - symbolsBarBg.width / 2 - keySpacing - 22;\n\tsymbolsBarBg.y = spaceBarBg.y;\n\tvar symbolsText = new Text2('SYMBOLS', {\n\t\tsize: 30,\n\t\tfill: 0xFFFFFF\n\t});\n\tsymbolsText.anchor.set(0.5, 0.5);\n\tsymbolsBarBg.addChild(symbolsText);\n\t// Add basic press feedback for symbols button\n\tsymbolsBarBg.down = function (x, y, obj) {\n\t\t// Toggle symbols mode\n\t\tself.isSymbolsMode = !self.isSymbolsMode;\n\t\t// If switching to symbols mode, turn off shift mode\n\t\tif (self.isSymbolsMode) {\n\t\t\tself.isShiftMode = false;\n\t\t\t// Find and update the shift button text\n\t\t\tfor (var i = 0; i < keys.length; i++) {\n\t\t\t\tif (keys[i].children.length > 0 && keys[i].children[0] instanceof Text2 && keys[i].children[0].text === 'SHIFT') {\n\t\t\t\t\tkeys[i].children[0].setText('shift');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tself.updateKeyLabels(); // Update the labels\n\t\t// Update symbols button text based on mode\n\t\tsymbolsText.setText(self.isSymbolsMode ? 'ABC' : 'SYMBOLS'); // Update symbols button text based on mode\n\t\ttween(this, {\n\t\t\tscaleX: 1.05,\n\t\t\tscaleY: 1.05\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t\t// Add orange flashing effect using tint and alpha\n\t\t// Create a temporary flashing graphic above the symbols button\n\t\tvar flashGraphic = LK.getAsset('flashRectangle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: this.width,\n\t\t\theight: this.height\n\t\t});\n\t\tflashGraphic.alpha = 1.0;\n\t\t// Position the flash graphic centered on the symbols button\n\t\tflashGraphic.x = this.x;\n\t\tflashGraphic.y = this.y;\n\t\tself.addChild(flashGraphic);\n\t\t// Fade out and remove the flash graphic\n\t\ttween(flashGraphic, {\n\t\t\talpha: 0.0\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\tflashGraphic.destroy();\n\t\t\t}\n\t\t});\n\t\ttween(this, {\n\t\t\ttint: 0xff8000,\n\t\t\talpha: 1.0\n\t\t}, {\n\t\t\tduration: 50\n\t\t});\n\t\tLK.getSound('fx').play(); // Play a generic sound\n\t};\n\tsymbolsBarBg.up = function (x, y, obj) {\n\t\t// Return to original tint and alpha on release\n\t\ttween(this, {\n\t\t\ttint: 0x555555,\n\t\t\talpha: 0.8 // Slightly faded normal state\n\t\t}, {\n\t\t\tduration: 100\n\t\t});\n\t\ttween(this, {\n\t\t\tscaleX: 1.0,\n\t\t\tscaleY: 1.0\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t};\n\tkeys.push(symbolsBarBg);\n\t// Add Shift button above the symbols button\n\tvar shiftBarWidth = keyWidth * 2 + keySpacing;\n\tvar shiftBarBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: shiftBarWidth,\n\t\theight: keyHeight\n\t});\n\tshiftBarBg.tint = 0x555555;\n\tshiftBarBg.x = symbolsBarBg.x;\n\tshiftBarBg.y = symbolsBarBg.y - keyHeight - keySpacing;\n\tvar shiftText = new Text2('SHIFT', {\n\t\tsize: 30,\n\t\tfill: 0xFFFFFF\n\t});\n\tshiftText.anchor.set(0.5, 0.5);\n\tshiftBarBg.addChild(shiftText);\n\t// Add basic press feedback for shift button\n\tshiftBarBg.down = function (x, y, obj) {\n\t\t// Toggle shift mode\n\t\tself.isShiftMode = !self.isShiftMode;\n\t\tself.updateKeyLabels(); // Update the labels\n\t\t// Update shift button text based on mode\n\t\tshiftText.setText(self.isShiftMode ? 'SHIFT' : 'shift'); // Maybe change visual later\n\t\ttween(this, {\n\t\t\tscaleX: 1.05,\n\t\t\tscaleY: 1.05\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t\t// Add orange flashing effect using tint and alpha\n\t\t// Create a temporary flashing graphic above the shift button\n\t\tvar flashGraphic = LK.getAsset('flashRectangle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: this.width,\n\t\t\theight: this.height\n\t\t});\n\t\tflashGraphic.alpha = 1.0;\n\t\t// Position the flash graphic centered on the shift button\n\t\tflashGraphic.x = this.x;\n\t\tflashGraphic.y = this.y;\n\t\tself.addChild(flashGraphic);\n\t\t// Fade out and remove the flash graphic\n\t\ttween(flashGraphic, {\n\t\t\talpha: 0.0\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\tflashGraphic.destroy();\n\t\t\t}\n\t\t});\n\t\ttween(this, {\n\t\t\ttint: 0xff8000,\n\t\t\talpha: 1.0\n\t\t}, {\n\t\t\tduration: 50\n\t\t});\n\t\tLK.getSound('fx').play(); // Play a generic sound\n\t};\n\tshiftBarBg.up = function (x, y, obj) {\n\t\t// Return to original tint and alpha on release\n\t\ttween(this, {\n\t\t\ttint: 0x555555,\n\t\t\talpha: 0.8 // Slightly faded normal state\n\t\t}, {\n\t\t\tduration: 100\n\t\t});\n\t\ttween(this, {\n\t\t\tscaleX: 1.0,\n\t\t\tscaleY: 1.0\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t};\n\tkeys.push(shiftBarBg);\n\t// Add X button above the enter button\n\tvar xBarWidth = keyWidth * 1.5;\n\tvar xBarBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: xBarWidth,\n\t\theight: keyHeight\n\t});\n\txBarBg.tint = 0x555555;\n\txBarBg.x = spaceBarBg.x + spaceBarBg.width / 2 + xBarBg.width / 2 + keySpacing + 15 + 20;\n\txBarBg.y = spaceBarBg.y - keyHeight - keySpacing;\n\tvar xText = new Text2('DELETE', {\n\t\tsize: 28,\n\t\tfill: 0xFFFFFF\n\t});\n\txText.anchor.set(0.5, 0.5);\n\txBarBg.addChild(xText);\n\t// Add basic press feedback for DELETE button\n\txBarBg.down = function (x, y, obj) {\n\t\tself.handleKeyPress('DELETE'); // Handle DELETE/BACKSPACE key press\n\t\ttween(this, {\n\t\t\tscaleX: 1.05,\n\t\t\tscaleY: 1.05\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t\t// Add orange flashing effect using tint and alpha\n\t\t// Create a temporary flashing graphic above the X button\n\t\tvar flashGraphic = LK.getAsset('flashRectangle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: this.width,\n\t\t\theight: this.height\n\t\t});\n\t\tflashGraphic.alpha = 1.0;\n\t\t// Position the flash graphic centered on the X button\n\t\tflashGraphic.x = this.x;\n\t\tflashGraphic.y = this.y;\n\t\tself.addChild(flashGraphic);\n\t\t// Fade out and remove the flash graphic\n\t\ttween(flashGraphic, {\n\t\t\talpha: 0.0\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\tflashGraphic.destroy();\n\t\t\t}\n\t\t});\n\t\ttween(this, {\n\t\t\ttint: 0xff8000,\n\t\t\talpha: 1.0\n\t\t}, {\n\t\t\tduration: 50\n\t\t});\n\t\tLK.getSound('fx').play(); // Play a generic sound\n\t};\n\txBarBg.up = function (x, y, obj) {\n\t\t// Return to original tint and alpha on release\n\t\ttween(this, {\n\t\t\ttint: 0x555555,\n\t\t\talpha: 0.8 // Slightly faded normal state\n\t\t}, {\n\t\t\tduration: 100\n\t\t});\n\t\ttween(this, {\n\t\t\tscaleX: 1.0,\n\t\t\tscaleY: 1.0\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t};\n\tkeys.push(xBarBg);\n\t// Add enter button to the right of the space bar\n\tvar enterBarWidth = keyWidth * 2 + keySpacing;\n\tvar enterBarBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: enterBarWidth,\n\t\theight: keyHeight\n\t});\n\tenterBarBg.tint = 0x555555;\n\tenterBarBg.x = spaceBarBg.x + spaceBarBg.width / 2 + enterBarBg.width / 2 + keySpacing + 15;\n\tenterBarBg.y = spaceBarBg.y;\n\tvar enterText = new Text2('ENTER', {\n\t\tsize: 40,\n\t\tfill: 0xFFFFFF\n\t});\n\tenterText.anchor.set(0.5, 0.5);\n\tenterBarBg.addChild(enterText);\n\t// Add basic press feedback for enter button\n\tenterBarBg.down = function (x, y, obj) {\n\t\ttween(this, {\n\t\t\tscaleX: 1.05,\n\t\t\tscaleY: 1.05\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t\t// Add orange flashing effect using tint and alpha\n\t\t// Create a temporary flashing graphic above the enter button\n\t\tvar flashGraphic = LK.getAsset('flashRectangle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: this.width,\n\t\t\theight: this.height\n\t\t});\n\t\tflashGraphic.alpha = 1.0;\n\t\t// Position the flash graphic centered on the enter button\n\t\tflashGraphic.x = this.x;\n\t\tflashGraphic.y = this.y;\n\t\tself.addChild(flashGraphic);\n\t\t// Fade out and remove the flash graphic\n\t\ttween(flashGraphic, {\n\t\t\talpha: 0.0\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\tflashGraphic.destroy();\n\t\t\t}\n\t\t});\n\t\ttween(this, {\n\t\t\ttint: 0xff8000,\n\t\t\talpha: 1.0\n\t\t}, {\n\t\t\tduration: 50\n\t\t});\n\t\tLK.getSound('fx').play(); // Play a generic sound\n\t};\n\tenterBarBg.up = function (x, y, obj) {\n\t\t// Return to original tint and alpha on release\n\t\ttween(this, {\n\t\t\ttint: 0x555555,\n\t\t\talpha: 0.8 // Slightly faded normal state\n\t\t}, {\n\t\t\tduration: 100\n\t\t});\n\t\ttween(this, {\n\t\t\tscaleX: 1.0,\n\t\t\tscaleY: 1.0\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t};\n\tkeys.push(enterBarBg);\n\t// Method to update key labels based on mode\n\tself.updateKeyLabels = function () {\n\t\tvar currentLabels;\n\t\tif (self.isSymbolsMode) {\n\t\t\tcurrentLabels = symbolLabels;\n\t\t} else if (self.isShiftMode) {\n\t\t\tcurrentLabels = shiftLabels;\n\t\t} else {\n\t\t\tcurrentLabels = keyLabels;\n\t\t}\n\t\tvar labelIndex = 0;\n\t\tfor (var row = 0; row < currentLabels.length; row++) {\n\t\t\tvar rowLabels = currentLabels[row];\n\t\t\tfor (var col = 0; col < rowLabels.length; col++) {\n\t\t\t\tif (labelIndex < keys.length) {\n\t\t\t\t\tvar keyBg = keys[labelIndex];\n\t\t\t\t\t// Find the Text2 child object\n\t\t\t\t\tvar keyText = null;\n\t\t\t\t\tfor (var i = 0; i < keyBg.children.length; i++) {\n\t\t\t\t\t\tif (keyBg.children[i] instanceof Text2) {\n\t\t\t\t\t\t\tkeyText = keyBg.children[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (keyText && keyText.setText) {\n\t\t\t\t\t\tkeyText.setText(rowLabels[col]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlabelIndex++;\n\t\t\t}\n\t\t}\n\t};\n\t// Method to handle key press\n\tself.handleKeyPress = function (key) {\n\t\t// Initialize searchText if it hasn't been already\n\t\tif (typeof searchText === 'undefined') {\n\t\t\tsearchText = new Text2('', {\n\t\t\t\tsize: 28,\n\t\t\t\tfill: 0x888888\n\t\t\t});\n\t\t\tsearchText.anchor.set(0.5, 0.5);\n\t\t\t// Position placeholder, actual position will be set by RekordboxApp\n\t\t\tsearchText.x = 0;\n\t\t\tsearchText.y = 0;\n\t\t}\n\t\tconsole.log(\"Key pressed:\", key);\n\t\t// Add logic here to handle different key presses, e.g., appending to a text input\n\t};\n\tsymbolsBarBg.down = function (x, y, obj) {\n\t\t// Toggle symbols mode\n\t\tself.isSymbolsMode = !self.isSymbolsMode;\n\t\tself.updateKeyLabels(); // Update the labels\n\t\ttween(this, {\n\t\t\tscaleX: 1.05,\n\t\t\tscaleY: 1.05\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t\t// Add orange flashing effect using tint and alpha\n\t\t// Create a temporary flashing graphic above the symbols button\n\t\tvar flashGraphic = LK.getAsset('flashRectangle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: this.width,\n\t\t\theight: this.height\n\t\t});\n\t\tflashGraphic.alpha = 1.0;\n\t\t// Position the flash graphic centered on the symbols button\n\t\tflashGraphic.x = this.x;\n\t\tflashGraphic.y = this.y;\n\t\tself.addChild(flashGraphic);\n\t\t// Fade out and remove the flash graphic\n\t\ttween(flashGraphic, {\n\t\t\talpha: 0.0\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\tflashGraphic.destroy();\n\t\t\t}\n\t\t});\n\t\ttween(this, {\n\t\t\ttint: 0xff8000,\n\t\t\talpha: 1.0\n\t\t}, {\n\t\t\tduration: 50\n\t\t});\n\t\tLK.getSound('fx').play(); // Play a generic sound\n\t};\n\tsymbolsBarBg.up = function (x, y, obj) {\n\t\t// Return to original tint and alpha on release\n\t\ttween(this, {\n\t\t\ttint: 0x555555,\n\t\t\talpha: 0.8 // Slightly faded normal state\n\t\t}, {\n\t\t\tduration: 100\n\t\t});\n\t\ttween(this, {\n\t\t\tscaleX: 1.0,\n\t\t\tscaleY: 1.0\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t};\n\tkeys.push(symbolsBarBg);\n\t// Add enter button to the right of the space bar\n\tvar enterBarWidth = keyWidth * 2 + keySpacing;\n\tvar enterBarBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: enterBarWidth,\n\t\theight: keyHeight\n\t});\n\tenterBarBg.tint = 0x555555;\n\tenterBarBg.x = spaceBarBg.x + spaceBarBg.width / 2 + enterBarBg.width / 2 + keySpacing + 15;\n\tenterBarBg.y = spaceBarBg.y;\n\tvar enterText = new Text2('ENTER', {\n\t\tsize: 40,\n\t\tfill: 0xFFFFFF\n\t});\n\tenterText.anchor.set(0.5, 0.5);\n\tenterBarBg.addChild(enterText);\n\t// Add basic press feedback for enter button\n\tenterBarBg.down = function (x, y, obj) {\n\t\tself.handleKeyPress('ENTER'); // Handle enter key press\n\t\t// Reset shift and symbols mode after enter\n\t\tself.isShiftMode = false;\n\t\tself.isSymbolsMode = false;\n\t\tself.updateKeyLabels();\n\t\t// Find and update the symbols button text\n\t\tfor (var i = 0; i < keys.length; i++) {\n\t\t\tif (keys[i].children.length > 0 && keys[i].children[0] instanceof Text2) {\n\t\t\t\tif (keys[i].children[0].text === 'ABC' || keys[i].children[0].text === 'SYMBOLS') {\n\t\t\t\t\t// Find the symbols button and update its text\n\t\t\t\t\tkeys[i].children[0].setText('SYMBOLS');\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Find and update the shift button text\n\t\tfor (var i = 0; i < keys.length; i++) {\n\t\t\tif (keys[i].children.length > 0 && keys[i].children[0] instanceof Text2 && keys[i].children[0].text === 'SHIFT') {\n\t\t\t\tkeys[i].children[0].setText('shift');\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\ttween(this, {\n\t\t\tscaleX: 1.05,\n\t\t\tscaleY: 1.05\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t\t// Add orange flashing effect using tint and alpha\n\t\t// Create a temporary flashing graphic above the enter button\n\t\tvar flashGraphic = LK.getAsset('flashRectangle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: this.width,\n\t\t\theight: this.height\n\t\t});\n\t\tflashGraphic.alpha = 1.0;\n\t\t// Position the flash graphic centered on the enter button\n\t\tflashGraphic.x = this.x;\n\t\tflashGraphic.y = this.y;\n\t\tself.addChild(flashGraphic);\n\t\t// Fade out and remove the flash graphic\n\t\ttween(flashGraphic, {\n\t\t\talpha: 0.0\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\tflashGraphic.destroy();\n\t\t\t}\n\t\t});\n\t\ttween(this, {\n\t\t\ttint: 0xff8000,\n\t\t\talpha: 1.0\n\t\t}, {\n\t\t\tduration: 50\n\t\t});\n\t\tLK.getSound('fx').play(); // Play a generic sound\n\t};\n\tenterBarBg.up = function (x, y, obj) {\n\t\t// Return to original tint and alpha on release\n\t\ttween(this, {\n\t\t\ttint: 0x555555,\n\t\t\talpha: 0.8 // Slightly faded normal state\n\t\t}, {\n\t\t\tduration: 100\n\t\t});\n\t\ttween(this, {\n\t\t\tscaleX: 1.0,\n\t\t\tscaleY: 1.0\n\t\t}, {\n\t\t\tduration: 80\n\t\t});\n\t};\n\tkeys.push(enterBarBg);\n\treturn self;\n});\n// LaserShow: Realistic party laser show with moving heads and multi-color animated beams\nvar LaserShow = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar numHeads = 6;\n\tvar beamsPerHead = 3;\n\tvar headRadius = 700; // Reduced from 1100 to 700 to move heads closer to the middle\n\tvar centerX = 2048 / 2;\n\tvar centerY = 400;\n\tvar beamLength = 1200; // Reduced from 1600 to 1200 to keep beams inside the new head radius\n\tvar beamWidth = 18;\n\tvar beamAlpha = 0.65;\n\tvar headAlpha = 0.7;\n\tvar heads = [];\n\tvar beams = [];\n\t// Predefined rainbow colors for beams\n\tvar beamColors = [0xff0000,\n\t// red\n\t0xff8000,\n\t// orange\n\t0xffff00,\n\t// yellow\n\t0x00ff00,\n\t// green\n\t0x00ffff,\n\t// cyan\n\t0x0000ff,\n\t// blue\n\t0x8000ff,\n\t// violet\n\t0xff00ff // magenta\n\t];\n\t// Create moving heads and beams\n\tfor (var h = 0; h < numHeads; h++) {\n\t\t// Head position in a semi-circle\n\t\tvar angle = Math.PI * (h + 1) / (numHeads + 1);\n\t\tvar hx = centerX + Math.cos(angle) * headRadius;\n\t\tvar hy = centerY + Math.sin(angle) * 200;\n\t\t// Head (visual: ellipse, colored)\n\t\t// Use rainbowEllipse for gradient rainbow look\n\t\tvar head = LK.getAsset('rainbowEllipse', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\tx: hx,\n\t\t\ty: hy,\n\t\t\twidth: 20,\n\t\t\theight: 20\n\t\t});\n\t\thead.alpha = headAlpha;\n\t\t// Animate color: store initial hue offset for each head\n\t\thead._rainbowHueOffset = h * (360 / numHeads);\n\t\tself.addChild(head);\n\t\theads.push(head);\n\t\t// Beams for this head\n\t\tfor (var b = 0; b < beamsPerHead; b++) {\n\t\t\tvar beam = LK.getAsset('laserBeam', {\n\t\t\t\tanchorX: 0.5,\n\t\t\t\tanchorY: 0,\n\t\t\t\tx: hx,\n\t\t\t\ty: hy,\n\t\t\t\twidth: beamWidth,\n\t\t\t\theight: beamLength\n\t\t\t});\n\t\t\t// Assign color in a rainbow pattern, offset by head and beam\n\t\t\tbeam.tint = beamColors[(h * beamsPerHead + b) % beamColors.length];\n\t\t\tbeam.alpha = beamAlpha;\n\t\t\t// Initial rotation\n\t\t\tbeam.rotation = 0;\n\t\t\tself.addChild(beam);\n\t\t\tbeams.push({\n\t\t\t\tobj: beam,\n\t\t\t\theadIdx: h,\n\t\t\t\tbeamIdx: b,\n\t\t\t\tbaseAngle: angle\n\t\t\t});\n\t\t}\n\t}\n\t// Animate heads and beams\n\tself.update = function () {\n\t\tvar t = Date.now() * 0.001;\n\t\t// Only update head colors every few frames to improve performance\n\t\tif (LK.ticks % 4 === 0) {\n\t\t\t// Animate heads in a subtle up/down and color pulse\n\t\t\tfor (var h = 0; h < heads.length; h++) {\n\t\t\t\tvar head = heads[h];\n\t\t\t\t// Sway up/down\n\t\t\t\thead.y = centerY + Math.sin(Math.PI * (h + 1) / (numHeads + 1)) * 200 + Math.sin(t * 1.2 + h) * 18;\n\t\t\t\t// Pulse alpha\n\t\t\t\thead.alpha = headAlpha + 0.15 * Math.sin(t * 2 + h);\n\t\t\t\t// Animate rainbow color: cycle hue every second\n\t\t\t\t// Full cycle every 1 second (t mod 1.0)\n\t\t\t\tvar hue = (head._rainbowHueOffset + t * 360) % 360 / 360;\n\t\t\t\t// HSV to RGB conversion\n\t\t\t\tvar i = Math.floor(hue * 6);\n\t\t\t\tvar f = hue * 6 - i;\n\t\t\t\tvar q = 1 - f;\n\t\t\t\tvar tcol = 1 - (1 - f);\n\t\t\t\tvar r, g, b;\n\t\t\t\tswitch (i % 6) {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tr = 1, g = tcol, b = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tr = q, g = 1, b = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\tr = 0, g = 1, b = tcol;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\tr = 0, g = q, b = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\tr = tcol, g = 0, b = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\tr = 1, g = 0, b = q;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tvar tint = Math.round(r * 255) << 16 | Math.round(g * 255) << 8 | Math.round(b * 255);\n\t\t\t\t// Only tween if color actually changed\n\t\t\t\tif (head.tint !== tint) {\n\t\t\t\t\thead.tint = tint;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Animate beams: sweep, flicker, and color pulse\n\t\tfor (var i = 0; i < beams.length; i++) {\n\t\t\tvar beamData = beams[i];\n\t\t\tvar beam = beamData.obj;\n\t\t\tvar h = beamData.headIdx;\n\t\t\tvar b = beamData.beamIdx;\n\t\t\tvar baseAngle = beamData.baseAngle;\n\t\t\t// Beam origin follows head\n\t\t\tvar head = heads[h];\n\t\t\tbeam.x = head.x;\n\t\t\tbeam.y = head.y;\n\t\t\t// Check laser show mode (controlled by second effect button)\n\t\t\tif (typeof laserShowMode !== 'undefined' && laserShowMode === 1) {\n\t\t\t\t// Slow laser show mode - beams visible\n\t\t\t\tbeam.visible = true;\n\t\t\t\tvar sweep = Math.sin(t * 1.2 + h + b * 0.5) * 0.3 + Math.sin(t * 0.8 + b) * 0.15;\n\t\t\t\tvar beatPulse = Math.sin(t * 2.8 + h + b) * 0.12;\n\t\t\t\tbeam.rotation = baseAngle - Math.PI / 2 + sweep + beatPulse;\n\t\t\t\t// Slow beam length flicker\n\t\t\t\tvar flicker = 1 + 0.18 * Math.sin(t * 3.5 + h * 2 + b * 1.2 + Math.sin(t * 2.0 + b));\n\t\t\t\tbeam.height = beamLength * flicker;\n\t\t\t\t// Color logic: if UV mode is on, show different colors; if only laser mode, all beams same color\n\t\t\t\tif (typeof uvEffectActive !== 'undefined' && uvEffectActive) {\n\t\t\t\t\t// UV mode active - different colors per beam\n\t\t\t\t\tvar colorIdx = (h * beamsPerHead + b + Math.floor(t * 2.5 + h + b)) % beamColors.length;\n\t\t\t\t\tbeam.tint = beamColors[colorIdx];\n\t\t\t\t} else {\n\t\t\t\t\t// Only laser mode - all beams same color but cycle through gradient\n\t\t\t\t\tvar sameColorIdx = Math.floor(t * 2.5) % beamColors.length;\n\t\t\t\t\tbeam.tint = beamColors[sameColorIdx];\n\t\t\t\t}\n\t\t\t\t// Slow alpha strobe effect\n\t\t\t\tbeam.alpha = beamAlpha + 0.2 * Math.abs(Math.sin(t * 5 + h + b));\n\t\t\t} else if (typeof laserShowMode !== 'undefined' && laserShowMode === 2) {\n\t\t\t\t// Fast laser show mode - beams visible\n\t\t\t\tbeam.visible = true;\n\t\t\t\tvar sweep = Math.sin(t * 2.4 + h + b * 0.9) * 0.5 + Math.sin(t * 1.8 + b) * 0.25;\n\t\t\t\tvar beatPulse = Math.sin(t * 6.0 + h + b) * 0.2;\n\t\t\t\tbeam.rotation = baseAngle - Math.PI / 2 + sweep + beatPulse;\n\t\t\t\t// Fast beam length flicker\n\t\t\t\tvar flicker = 1 + 0.35 * Math.sin(t * 7 + h * 2 + b * 1.8 + Math.sin(t * 3.5 + b));\n\t\t\t\tbeam.height = beamLength * flicker;\n\t\t\t\t// Color logic: if UV mode is on, show different colors; if only laser mode, all beams same color\n\t\t\t\tif (typeof uvEffectActive !== 'undefined' && uvEffectActive) {\n\t\t\t\t\t// UV mode active - different colors per beam\n\t\t\t\t\tvar colorIdx = (h * beamsPerHead + b + Math.floor(t * 6 + h + b)) % beamColors.length;\n\t\t\t\t\tbeam.tint = beamColors[colorIdx];\n\t\t\t\t} else {\n\t\t\t\t\t// Only laser mode - all beams same color but cycle through gradient\n\t\t\t\t\tvar sameColorIdx = Math.floor(t * 6) % beamColors.length;\n\t\t\t\t\tbeam.tint = beamColors[sameColorIdx];\n\t\t\t\t}\n\t\t\t\t// Fast alpha strobe effect\n\t\t\t\tbeam.alpha = beamAlpha + 0.4 * Math.abs(Math.sin(t * 12 + h + b));\n\t\t\t} else {\n\t\t\t\t// Off mode - hide beams completely\n\t\t\t\tbeam.visible = false;\n\t\t\t}\n\t\t}\n\t};\n\treturn self;\n});\n// MoneyParticle: Animated money bills falling from the top\nvar MoneyParticle = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar size = (40 + Math.random() * 30) / 1.2; // Random size between 40-70\n\tvar speedY = 1.2 + Math.random() * 0.8; // Vertical speed\n\tvar speedX = (Math.random() - 0.5) * 1.5; // Horizontal drift\n\tvar rotationSpeed = (Math.random() - 0.5) * 0.03; // Rotation speed\n\t// Create money bill graphic using money asset\n\tvar moneyGraphic = self.attachAsset('money', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: size * 1.8,\n\t\t// Money bills are wider than tall\n\t\theight: size\n\t});\n\t// Keep natural money asset color (remove tint)\n\t// Animation\n\tself.update = function () {\n\t\tself.y += speedY;\n\t\tself.x += speedX;\n\t\tself.rotation += rotationSpeed;\n\t\t// Wrap around if off screen (below the dancing people)\n\t\tif (self.y > dancingPeople[0].y + 200) {\n\t\t\t// Reset to top with new random properties\n\t\t\tself.y = -size;\n\t\t\tself.x = Math.random() * 2048;\n\t\t\t// Reset size and properties for variety\n\t\t\tsize = 40 + Math.random() * 30;\n\t\t\tmoneyGraphic.width = size * 1.8;\n\t\t\tmoneyGraphic.height = size;\n\t\t\tspeedY = 1.2 + Math.random() * 0.8;\n\t\t\tspeedX = (Math.random() - 0.5) * 1.5;\n\t\t\trotationSpeed = (Math.random() - 0.5) * 0.03;\n\t\t\t// Animate scale for sparkle effect instead of tint\n\t\t\ttween(moneyGraphic, {\n\t\t\t\tscaleX: 1.2,\n\t\t\t\tscaleY: 1.2\n\t\t\t}, {\n\t\t\t\tduration: 300,\n\t\t\t\teasing: tween.easeOut,\n\t\t\t\tonFinish: function onFinish() {\n\t\t\t\t\ttween(moneyGraphic, {\n\t\t\t\t\t\tscaleX: 1.0,\n\t\t\t\t\t\tscaleY: 1.0\n\t\t\t\t\t}, {\n\t\t\t\t\t\tduration: 300,\n\t\t\t\t\t\teasing: tween.easeIn\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t};\n\treturn self;\n});\n// PianoRoll: Interactive piano roll for composing music\nvar PianoRoll = Container.expand(function (config) {\n\tvar self = Container.call(this);\n\t// Config\n\tself.config = config;\n\tself.notes = []; // Array to store notes {beatIndex, keyIndex, visual, pitch}\n\tself.instruments = ['Drums', 'Guitar', 'Piano', 'Synthesizer', 'Bass', 'Strings']; // Added more instruments\n\tvar numKeys = Math.floor(config.height / config.noteHeight);\n\tvar keyLabels = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];\n\t// Piano Roll Background\n\tvar pianoRollBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: config.width,\n\t\theight: config.height\n\t});\n\tpianoRollBg.tint = 0x2a2a2a;\n\tpianoRollBg.x = 0; // Relative to container\n\tpianoRollBg.y = 0; // Relative to container\n\t// Piano Keyboard (left side)\n\tvar keyboardBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: config.keyboardWidth,\n\t\theight: config.height\n\t});\n\tkeyboardBg.tint = 0x000000;\n\tkeyboardBg.x = 0; // Relative to container\n\tkeyboardBg.y = 0; // Relative to container\n\t// Create piano keys\n\tvar keys = [];\n\tfor (var i = 0; i < numKeys; i++) {\n\t\tvar keyY = i * config.noteHeight;\n\t\tvar keyNote = keyLabels[i % 12];\n\t\tvar isBlackKey = keyNote.indexOf('#') !== -1;\n\t\tvar key = self.attachAsset('crossfaderTrack', {\n\t\t\tanchorX: 0,\n\t\t\tanchorY: 0,\n\t\t\twidth: config.keyboardWidth - 2,\n\t\t\theight: config.noteHeight - 1\n\t\t});\n\t\tkey.tint = isBlackKey ? 0x333333 : 0xFFFFFF;\n\t\tkey.x = 1;\n\t\tkey.y = keyY;\n\t\tself.addChild(key);\n\t\t// Key label\n\t\tvar keyText = new Text2(keyNote + Math.floor(i / 12 + 3), {\n\t\t\tsize: 16,\n\t\t\tfill: isBlackKey ? 0xFFFFFF : 0x000000\n\t\t});\n\t\tkeyText.anchor.set(0, 0.5);\n\t\tkeyText.x = key.x + 5;\n\t\tkeyText.y = key.y + config.noteHeight / 2;\n\t\tself.addChild(keyText);\n\t\t// Key interaction\n\t\tkey.keyIndex = i;\n\t\tkey.note = keyNote + Math.floor(i / 12 + 3);\n\t\tkey.down = function (x, y, obj) {\n\t\t\t// Play note sound - placeholder for now\n\t\t\tconsole.log(\"Key pressed:\", this.note);\n\t\t\t// Visual feedback\n\t\t\tvar originalTint = this.tint;\n\t\t\tthis.tint = 0xFF6600;\n\t\t\tvar keyRef = this;\n\t\t\tLK.setTimeout(function () {\n\t\t\t\tkeyRef.tint = originalTint;\n\t\t\t}, 200);\n\t\t};\n\t\tkeys.push(key);\n\t}\n\t// Grid lines\n\tvar gridContainer = new Container();\n\tself.addChild(gridContainer);\n\tvar totalBars = 16; // Example: 16 bars\n\tvar beatsPerBar = 4; // Example: 4 beats per bar\n\tvar timelineWidth = config.width - config.keyboardWidth;\n\tvar beatWidth = timelineWidth / (totalBars * beatsPerBar);\n\t// Horizontal grid lines (for each note)\n\tfor (var i = 0; i <= numKeys; i++) {\n\t\tvar gridY = i * config.noteHeight;\n\t\tvar hLine = LK.getAsset('crossfaderTrack', {\n\t\t\tanchorX: 0,\n\t\t\tanchorY: 0,\n\t\t\twidth: timelineWidth,\n\t\t\theight: 1\n\t\t});\n\t\thLine.tint = config.gridColor;\n\t\thLine.x = config.keyboardWidth;\n\t\thLine.y = gridY;\n\t\tgridContainer.addChild(hLine);\n\t}\n\t// Vertical grid lines (for each beat)\n\tfor (var i = 0; i <= totalBars * beatsPerBar; i++) {\n\t\tvar gridX = config.keyboardWidth + i * beatWidth;\n\t\tvar vLine = LK.getAsset('crossfaderTrack', {\n\t\t\tanchorX: 0,\n\t\t\tanchorY: 0,\n\t\t\twidth: 1,\n\t\t\theight: config.height\n\t\t});\n\t\tvLine.tint = i % beatsPerBar === 0 ? 0x555555 : config.gridColor;\n\t\tvLine.x = gridX;\n\t\tvLine.y = 0; // Relative to container\n\t\tgridContainer.addChild(vLine);\n\t}\n\t// Note placement area for interaction\n\tvar noteArea = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: timelineWidth,\n\t\theight: config.height\n\t});\n\tnoteArea.tint = 0x1a1a1a;\n\tnoteArea.alpha = 0.001; // Make it almost transparent but interactive\n\tnoteArea.x = config.keyboardWidth;\n\tnoteArea.y = 0; // Relative to container\n\tself.addChild(noteArea);\n\t// Variables for dragging instrument voices\n\tvar draggedInstrument = null;\n\tvar dragOffset = {\n\t\tx: 0,\n\t\ty: 0\n\t};\n\t// Instrument voice selection (using instruments from SongMakerApp)\n\tvar instrumentVoices = self.config.instruments || ['Drums', 'Guitar', 'Piano', 'Synthesizer', 'Bass', 'Strings'];\n\tvar instrumentButtons = [];\n\tvar instrumentButtonY = 50; // Position buttons relative to instrumentsToolsContainer\n\tvar instrumentsPerRow = 4; // Number of instrument buttons per row\n\tvar buttonSpacing = 20;\n\tfor (var i = 0; i < instrumentVoices.length; i++) {\n\t\tvar button = self.attachAsset('crossfaderTrack', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: 150,\n\t\t\theight: 60\n\t\t});\n\t\tvar row = Math.floor(i / instrumentsPerRow);\n\t\tvar col = i % instrumentsPerRow;\n\t\tbutton.tint = config.noteColors[i % config.noteColors.length];\n\t\t// Position buttons relative to the instrumentsToolsContainer\n\t\tbutton.x = config.keyboardWidth + 100 + col * (button.width + buttonSpacing + 80); // Add extra 80px spacing\n\t\tbutton.y = instrumentButtonY + row * (button.height + buttonSpacing); // Arrange in rows\n\t\tself.addChild(button);\n\t\tvar buttonText = new Text2(instrumentVoices[i], {\n\t\t\tsize: 80,\n\t\t\tfill: 0xFFFFFF\n\t\t});\n\t\tbuttonText.anchor.set(0.5, 0.5);\n\t\tbutton.addChild(buttonText);\n\t\tbutton.instrumentVoice = instrumentVoices[i];\n\t\tbutton.down = function (x, y, obj) {\n\t\t\tdraggedInstrument = {\n\t\t\t\tvoice: this.instrumentVoice,\n\t\t\t\tcolor: this.tint\n\t\t\t};\n\t\t\tdragOffset.x = x;\n\t\t\tdragOffset.y = y;\n\t\t};\n\t\tinstrumentButtons.push(button);\n\t}\n\tself.move = function (x, y, obj) {\n\t\tif (draggedInstrument) {\n\t\t\t// Convert global touch coordinates to local coordinates relative to PianoRoll container\n\t\t\tvar globalPoint = obj && obj.position ? obj.position : {\n\t\t\t\tx: x,\n\t\t\t\ty: y\n\t\t\t}; // Get global position from event object with fallback\n\t\t\tvar localPoint = self.toLocal(globalPoint);\n\t\t\t// Create a temporary visual representation of the dragged note/instrument voice\n\t\t\tif (!self.draggedNoteVisual) {\n\t\t\t\tself.draggedNoteVisual = LK.getAsset('crossfaderTrack', {\n\t\t\t\t\tanchorX: 0,\n\t\t\t\t\tanchorY: 0,\n\t\t\t\t\twidth: beatWidth - 2,\n\t\t\t\t\theight: config.noteHeight - 2\n\t\t\t\t});\n\t\t\t\tself.draggedNoteVisual.alpha = 0.7;\n\t\t\t\tself.addChild(self.draggedNoteVisual);\n\t\t\t}\n\t\t\tself.draggedNoteVisual.tint = draggedInstrument.color;\n\t\t\tself.draggedNoteVisual.x = localPoint.x - dragOffset.x + config.keyboardWidth; // Adjust for drag offset and keyboard width\n\t\t\tself.draggedNoteVisual.y = localPoint.y - dragOffset.y; // Adjust for drag offset\n\t\t}\n\t};\n\tself.up = function (x, y, obj) {\n\t\tif (draggedInstrument) {\n\t\t\t// Convert global touch coordinates to local coordinates relative to PianoRoll container\n\t\t\tvar globalPoint = obj && obj.position ? obj.position : {\n\t\t\t\tx: x,\n\t\t\t\ty: y\n\t\t\t}; // Get global position from event object with fallback\n\t\t\tvar localPoint = self.toLocal(globalPoint);\n\t\t\t// Calculate grid position based on the release position, relative to the noteArea's origin\n\t\t\tvar releaseX = localPoint.x - config.keyboardWidth;\n\t\t\tvar releaseY = localPoint.y;\n\t\t\tvar beatIndex = Math.floor(releaseX / beatWidth);\n\t\t\tvar keyIndex = Math.floor(releaseY / config.noteHeight);\n\t\t\t// Check if release position is within the note area\n\t\t\tif (releaseX >= 0 && releaseX < timelineWidth && releaseY >= 0 && releaseY < config.height) {\n\t\t\t\tif (beatIndex >= 0 && beatIndex < totalBars * beatsPerBar && keyIndex >= 0 && keyIndex < numKeys) {\n\t\t\t\t\t// Check if a note of this instrument already exists at this position\n\t\t\t\t\tvar existingNoteIndex = -1;\n\t\t\t\t\tfor (var i = 0; i < self.notes.length; i++) {\n\t\t\t\t\t\tif (self.notes[i].beatIndex === beatIndex && self.notes[i].keyIndex === keyIndex && self.notes[i].instrument === draggedInstrument.voice) {\n\t\t\t\t\t\t\texistingNoteIndex = i;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (existingNoteIndex !== -1) {\n\t\t\t\t\t\t// Remove existing note of the same instrument\n\t\t\t\t\t\tself.removeChild(self.notes[existingNoteIndex].visual);\n\t\t\t\t\t\tself.notes.splice(existingNoteIndex, 1);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Create new note\n\t\t\t\t\t\tvar noteX = config.keyboardWidth + beatIndex * beatWidth;\n\t\t\t\t\t\tvar noteY = keyIndex * config.noteHeight;\n\t\t\t\t\t\tvar noteVisual = LK.getAsset('crossfaderTrack', {\n\t\t\t\t\t\t\tanchorX: 0,\n\t\t\t\t\t\t\tanchorY: 0,\n\t\t\t\t\t\t\twidth: beatWidth - 2,\n\t\t\t\t\t\t\theight: config.noteHeight - 2\n\t\t\t\t\t\t});\n\t\t\t\t\t\tnoteVisual.tint = draggedInstrument.color;\n\t\t\t\t\t\tnoteVisual.x = noteX + 1;\n\t\t\t\t\t\tnoteVisual.y = noteY + 1;\n\t\t\t\t\t\tself.addChild(noteVisual);\n\t\t\t\t\t\tvar note = {\n\t\t\t\t\t\t\tbeatIndex: beatIndex,\n\t\t\t\t\t\t\tkeyIndex: keyIndex,\n\t\t\t\t\t\t\tvisual: noteVisual,\n\t\t\t\t\t\t\tpitch: keyLabels[keyIndex % 12] + Math.floor(keyIndex / 12 + 3),\n\t\t\t\t\t\t\tinstrument: draggedInstrument.voice // Store the instrument voice\n\t\t\t\t\t\t};\n\t\t\t\t\t\tself.notes.push(note);\n\t\t\t\t\t\t// Play sound for the placed note (placeholder - map instrument voice to sound)\n\t\t\t\t\t\tconsole.log(\"Placed note:\", note);\n\t\t\t\t\t\tLK.getSound('fx').play(); // Generic sound for now\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Remove the dragged note visual\n\t\t\tif (self.draggedNoteVisual) {\n\t\t\t\tself.removeChild(self.draggedNoteVisual);\n\t\t\t\tself.draggedNoteVisual = null;\n\t\t\t}\n\t\t\tdraggedInstrument = null;\n\t\t\tdragOffset = {\n\t\t\t\tx: 0,\n\t\t\t\ty: 0\n\t\t\t};\n\t\t}\n\t};\n\treturn self;\n});\n// RekordboxApp: Full-featured rekordbox application interface for the tablet\nvar RekordboxApp = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tself.currentScreen = 'browser'; // 'browser', 'playlist', 'settings', 'performance'\n\tself.selectedTrackIndex = 0;\n\tself.selectedCategoryIndex = 0;\n\tself.currentCategory = 'all';\n\t// Track database\n\tself.tracks = [{\n\t\tname: 'Summer Vibes',\n\t\tartist: 'DJ Alex',\n\t\tbpm: 128,\n\t\tkey: 'Am',\n\t\tgenre: 'House'\n\t}, {\n\t\tname: 'Night Drive',\n\t\tartist: 'Luna Beat',\n\t\tbpm: 132,\n\t\tkey: 'Fm',\n\t\tgenre: 'Techno'\n\t}, {\n\t\tname: 'Electric Dreams',\n\t\tartist: 'Synth Master',\n\t\tbpm: 140,\n\t\tkey: 'Gm',\n\t\tgenre: 'Electronic'\n\t}, {\n\t\tname: 'Deep Ocean',\n\t\tartist: 'Wave Runner',\n\t\tbpm: 124,\n\t\tkey: 'Dm',\n\t\tgenre: 'Deep House'\n\t}, {\n\t\tname: 'City Lights',\n\t\tartist: 'Urban Sound',\n\t\tbpm: 126,\n\t\tkey: 'Em',\n\t\tgenre: 'Progressive'\n\t}, {\n\t\tname: 'Midnight Express',\n\t\tartist: 'Beat Factory',\n\t\tbpm: 130,\n\t\tkey: 'Cm',\n\t\tgenre: 'Techno'\n\t}, {\n\t\tname: 'Tropical Storm',\n\t\tartist: 'Island Beats',\n\t\tbpm: 118,\n\t\tkey: 'Bm',\n\t\tgenre: 'Tropical'\n\t}, {\n\t\tname: 'Neon Pulse',\n\t\tartist: 'Cyber DJ',\n\t\tbpm: 135,\n\t\tkey: 'F#m',\n\t\tgenre: 'Electro'\n\t}, {\n\t\tname: 'Sunset Boulevard',\n\t\tartist: 'Coast Drive',\n\t\tbpm: 122,\n\t\tkey: 'Am',\n\t\tgenre: 'Chill'\n\t}, {\n\t\tname: 'Bass Revolution',\n\t\tartist: 'Low End Theory',\n\t\tbpm: 128,\n\t\tkey: 'Dm',\n\t\tgenre: 'Bass'\n\t}, {\n\t\tname: 'Street Anthem',\n\t\tartist: 'MC Flow',\n\t\tbpm: 90,\n\t\tkey: 'Em',\n\t\tgenre: 'Hip-Hop'\n\t}, {\n\t\tname: 'Island Rhythm',\n\t\tartist: 'Rasta King',\n\t\tbpm: 75,\n\t\tkey: 'Am',\n\t\tgenre: 'Reggae'\n\t}, {\n\t\tname: 'Smooth Jazz Night',\n\t\tartist: 'Jazz Collective',\n\t\tbpm: 110,\n\t\tkey: 'Bbm',\n\t\tgenre: 'Jazz'\n\t}, {\n\t\tname: 'Symphony No. 9',\n\t\tartist: 'Classical Ensemble',\n\t\tbpm: 120,\n\t\tkey: 'Dm',\n\t\tgenre: 'Classical'\n\t}, {\n\t\tname: 'Rock The House',\n\t\tartist: 'Thunder Strike',\n\t\tbpm: 140,\n\t\tkey: 'Em',\n\t\tgenre: 'EDM'\n\t}, {\n\t\tname: 'Pop Star',\n\t\tartist: 'Chart Topper',\n\t\tbpm: 125,\n\t\tkey: 'Am',\n\t\tgenre: 'Pop'\n\t}, {\n\t\tname: 'Floating Dreams',\n\t\tartist: 'Ambient Explorer',\n\t\tbpm: 80,\n\t\tkey: 'Fm',\n\t\tgenre: 'Ambient'\n\t}, {\n\t\tname: 'Drop The Beat',\n\t\tartist: 'Dubstep Master',\n\t\tbpm: 140,\n\t\tkey: 'Gm',\n\t\tgenre: 'Dubstep'\n\t}, {\n\t\tname: 'Trap Nation',\n\t\tartist: 'Trap Lord',\n\t\tbpm: 75,\n\t\tkey: 'Cm',\n\t\tgenre: 'Trap'\n\t}, {\n\t\tname: 'Liquid Motion',\n\t\tartist: 'DNB Producer',\n\t\tbpm: 175,\n\t\tkey: 'Am',\n\t\tgenre: 'Drum & Bass'\n\t}];\n\tself.categories = ['CATEGORY', 'All Tracks', 'House', 'Techno', 'EDM', 'Electronic', 'Disco', 'Latin', 'POP', 'Hip-Hop'];\n\tself.visibleTrackStart = 0;\n\tself.maxVisibleTracks = 8;\n\t// Create main container for app content\n\tvar appContainer = self.addChild(new Container());\n\t// Header bar\n\tvar headerBar = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: 742,\n\t\theight: 50\n\t});\n\theaderBar.tint = 0x1a1a1a;\n\tappContainer.addChild(headerBar);\n\t// TRACKLIST logo/title\n\tvar titleText = new Text2('TRACKLIST', {\n\t\tsize: 56,\n\t\tfill: 0xFF6600\n\t});\n\ttitleText.anchor.set(0, 0.5);\n\ttitleText.x = 10;\n\ttitleText.y = 25;\n\tappContainer.addChild(titleText);\n\t// Screen indicator\n\tvar screenIndicator = new Text2('BROWSER', {\n\t\tsize: 40,\n\t\tfill: 0xFFFFFF\n\t});\n\tscreenIndicator.anchor.set(1, 0.5);\n\tscreenIndicator.x = 722;\n\tscreenIndicator.y = 25;\n\tappContainer.addChild(screenIndicator);\n\t// Sidebar for categories\n\tvar sidebar = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: 180,\n\t\theight: 400\n\t});\n\tsidebar.tint = 0x2a2a2a;\n\tsidebar.y = 60;\n\tappContainer.addChild(sidebar);\n\t// Main content area\n\tvar contentArea = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: 542,\n\t\theight: 400\n\t});\n\tcontentArea.tint = 0x1a1a1a;\n\tcontentArea.x = 190;\n\tcontentArea.y = 60;\n\tappContainer.addChild(contentArea);\n\t// Category items in sidebar\n\tself.categoryItems = [];\n\tfor (var i = 0; i < self.categories.length; i++) {\n\t\tvar categoryBg = LK.getAsset('crossfaderTrack', {\n\t\t\tanchorX: 0,\n\t\t\tanchorY: 0,\n\t\t\twidth: 170,\n\t\t\theight: 35\n\t\t});\n\t\tcategoryBg.tint = i === self.selectedCategoryIndex ? 0x444444 : 0x333333;\n\t\tcategoryBg.x = 5;\n\t\tcategoryBg.y = 70 + i * 40;\n\t\tappContainer.addChild(categoryBg);\n\t\tvar categoryText = new Text2(self.categories[i], {\n\t\t\tsize: 28,\n\t\t\tfill: i === self.selectedCategoryIndex ? \"#ff6600\" : \"#cccccc\"\n\t\t});\n\t\tcategoryText.anchor.set(0, 0.5);\n\t\tcategoryText.x = 15;\n\t\tcategoryText.y = 87 + i * 40 - 2 - 5;\n\t\tappContainer.addChild(categoryText);\n\t\tself.categoryItems.push({\n\t\t\tbg: categoryBg,\n\t\t\ttext: categoryText\n\t\t});\n\t}\n\t// Track list headers\n\t// Category texts will be initialized with proper fill colors in updateDisplay method\n\tvar headerTrack = new Text2('TRACK', {\n\t\tsize: 28,\n\t\tfill: 0x888888\n\t});\n\theaderTrack.anchor.set(0, 0);\n\theaderTrack.x = 200;\n\theaderTrack.y = 70;\n\tappContainer.addChild(headerTrack);\n\tvar headerArtist = new Text2('ARTIST', {\n\t\tsize: 28,\n\t\tfill: 0x888888\n\t});\n\theaderArtist.anchor.set(0, 0);\n\theaderArtist.x = 413; // Increased x-position\n\theaderArtist.y = 70;\n\tappContainer.addChild(headerArtist);\n\tvar headerBPM = new Text2('BPM', {\n\t\tsize: 28,\n\t\tfill: 0x888888\n\t});\n\theaderBPM.anchor.set(0, 0);\n\theaderBPM.x = 610; // Increased x-position and moved left by 10 units\n\theaderBPM.y = 70;\n\tappContainer.addChild(headerBPM);\n\tvar headerKey = new Text2('KEY', {\n\t\tsize: 28,\n\t\tfill: 0x888888\n\t});\n\theaderKey.anchor.set(0, 0);\n\theaderKey.x = 620 + 40 + 17; // Increased x-position by adding 17 units to the previous elements x + width\n\theaderKey.y = 70;\n\tappContainer.addChild(headerKey);\n\t// Track list items\n\tself.trackItems = [];\n\tfor (var i = 0; i < self.maxVisibleTracks; i++) {\n\t\tvar trackBg = LK.getAsset('crossfaderTrack', {\n\t\t\tanchorX: 0,\n\t\t\tanchorY: 0,\n\t\t\twidth: 532,\n\t\t\theight: 35\n\t\t});\n\t\ttrackBg.tint = 0x252525;\n\t\ttrackBg.x = 195;\n\t\ttrackBg.y = 95 + i * 40;\n\t\tvar trackText = new Text2('', {\n\t\t\tsize: 28,\n\t\t\tfill: 0xFFFFFF\n\t\t});\n\t\ttrackText.anchor.set(0, 0.5);\n\t\ttrackText.x = 200;\n\t\ttrackText.y = 112 + i * 40 + 17 + 30;\n\t\tvar artistText = new Text2('', {\n\t\t\tsize: 28,\n\t\t\t//{ O}\n\t\t\tfill: 0xCCCCCC //{ P}\n\t\t}); //{ Q}\n\t\tartistText.anchor.set(0, 0.5);\n\t\tartistText.x = 380 + 25 + 10; // Increased x-position//{ O}\n\t\tartistText.y = 112 + i * 40 + 17 + 30;\n\t\tvar bpmText = new Text2('', {\n\t\t\tsize: 28,\n\t\t\t//{ R}\n\t\t\tfill: 0xAAAAAA //{ S}\n\t\t}); //{ T}\n\t\tbpmText.anchor.set(0, 0.5);\n\t\tbpmText.x = 620; // Increased x-position\n\t\tbpmText.y = 112 + i * 40 + 17 + 30;\n\t\tvar keyText = new Text2('', {\n\t\t\tsize: 28,\n\t\t\t//{ U}\n\t\t\tfill: 0xAAAAAA //{ V}\n\t\t}); //{ W}\n\t\tkeyText.anchor.set(0, 0.5);\n\t\tkeyText.x = 620 + 40 + 17; // Increased x-position by adding 17 units to the previous elements x + width\n\t\tkeyText.y = 112 + i * 40 + 17 + 30;\n\t\tself.trackItems.push({\n\t\t\tbg: trackBg,\n\t\t\ttrack: trackText,\n\t\t\tartist: artistText,\n\t\t\tbpm: bpmText,\n\t\t\tkey: keyText\n\t\t});\n\t\t// Store original tint\n\t\tself.trackItems[i].bg.originalTint = trackBg.tint;\n\t}\n\t// Add all backgrounds first to ensure they are at the back\n\tfor (var i = 0; i < self.maxVisibleTracks; i++) {\n\t\tappContainer.addChild(self.trackItems[i].bg);\n\t}\n\t// Then add all text elements so they are rendered on top\n\tfor (var i = 0; i < self.maxVisibleTracks; i++) {\n\t\tvar item = self.trackItems[i];\n\t\tappContainer.addChild(item.track);\n\t\tappContainer.addChild(item.artist);\n\t\tappContainer.addChild(item.bpm);\n\t\tappContainer.addChild(item.key);\n\t}\n\t// Bottom status bar\n\tvar statusBar = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: 742,\n\t\theight: 30\n\t});\n\tstatusBar.tint = 0x333333;\n\tstatusBar.y = 470;\n\tappContainer.addChild(statusBar);\n\tvar statusText = new Text2('Use arrow keys to navigate', {\n\t\tsize: 24,\n\t\tfill: 0xCCCCCC\n\t});\n\tstatusText.anchor.set(0, 0.5);\n\tstatusText.x = 235;\n\tstatusText.y = 485;\n\tappContainer.addChild(statusText);\n\t// Search bar background\n\tvar searchBarBg = LK.getAsset('Searchbarbg', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: 512,\n\t\theight: 40\n\t});\n\tsearchBarBg.tint = 0xffffff;\n\tsearchBarBg.x = 457 + 10; // Adjusted for center anchor and moved right by 12 units\n\tsearchBarBg.y = 125; // Adjusted for center anchor\n\tself.addChild(searchBarBg); // Add directly to self instead of appContainer for independent positioning\n\t// Search bar text\n\tvar searchText = new Text2('Search tracks...', {\n\t\tsize: 28,\n\t\tfill: 0x888888\n\t});\n\tsearchText.anchor.set(0.5, 0.5);\n\tsearchText.x = 457; // Centered with search bar background and moved right by 12 units\n\tsearchText.y = 125; // Centered with search bar background\n\tself.addChild(searchText); // Add directly to self instead of appContainer for independent positioning\n\t// Track count info\n\tself.trackCountText = new Text2('', {\n\t\tsize: 24,\n\t\tfill: 0x888888\n\t});\n\tself.trackCountText.anchor.set(1, 0.5);\n\tself.trackCountText.x = 732;\n\tself.trackCountText.y = 485;\n\tappContainer.addChild(self.trackCountText);\n\t// Methods\n\tself.updateDisplay = function () {\n\t\t// Update categories\n\t\tfor (var i = 0; i < self.categoryItems.length; i++) {\n\t\t\tvar isSelected = i === self.selectedCategoryIndex;\n\t\t\tself.categoryItems[i].bg.tint = isSelected ? 0x444444 : 0x333333;\n\t\t\tif (self.categoryItems[i].text) {\n\t\t\t\tself.categoryItems[i].text.fill = isSelected ? \"#ff8000\" : \"#cccccc\";\n\t\t\t}\n\t\t}\n\t\t// Filter tracks based on category\n\t\tvar filteredTracks = self.tracks;\n\t\tif (self.selectedCategoryIndex > 1) {\n\t\t\t// Filter by specific genre, skipping 'CATEGORY' and 'All Tracks'\n\t\t\tvar genre = self.categories[self.selectedCategoryIndex];\n\t\t\tfilteredTracks = self.tracks.filter(function (track) {\n\t\t\t\treturn track.genre === genre;\n\t\t\t});\n\t\t} else if (self.selectedCategoryIndex === 1) {\n\t\t\t// 'All Tracks' category - show all tracks\n\t\t\tfilteredTracks = self.tracks;\n\t\t} else {\n\t\t\t// 'CATEGORY' category - show no tracks\n\t\t\tfilteredTracks = [];\n\t\t}\n\t\t// Update track list\n\t\tfor (var i = 0; i < self.maxVisibleTracks; i++) {\n\t\t\tvar trackIndex = self.visibleTrackStart + i;\n\t\t\tvar item = self.trackItems[i];\n\t\t\tif (trackIndex < filteredTracks.length) {\n\t\t\t\tvar track = filteredTracks[trackIndex];\n\t\t\t\tvar isSelected = trackIndex === self.selectedTrackIndex;\n\t\t\t\titem.bg.tint = isSelected ? 0xff8000 : i % 2 === 0 ? 0x252525 : 0x2a2a2a;\n\t\t\t\titem.track.setText(track.name.length > 20 ? track.name.substring(0, 17) + '...' : track.name);\n\t\t\t\titem.artist.setText(track.artist.length > 15 ? track.artist.substring(0, 12) + '...' : track.artist);\n\t\t\t\titem.bpm.setText(track.bpm.toString());\n\t\t\t\titem.key.setText(track.key);\n\t\t\t\tif (item.track) {\n\t\t\t\t\titem.track.fill = isSelected ? \"#ff8000\" : \"#cccccc\";\n\t\t\t\t}\n\t\t\t\titem.artist.fill = isSelected ? \"#ffffff\" : \"#aaaaaa\";\n\t\t\t\titem.bpm.fill = isSelected ? \"#ffffff\" : \"#999999\";\n\t\t\t\titem.key.fill = isSelected ? \"#ffffff\" : \"#999999\";\n\t\t\t\titem.bg.visible = true;\n\t\t\t\titem.track.visible = true;\n\t\t\t\titem.artist.visible = true;\n\t\t\t\titem.bpm.visible = true;\n\t\t\t\titem.key.visible = true;\n\t\t\t} else {\n\t\t\t\titem.bg.visible = false;\n\t\t\t\titem.track.visible = false;\n\t\t\t\titem.artist.visible = false;\n\t\t\t\titem.bpm.visible = false;\n\t\t\t\titem.key.visible = false;\n\t\t\t}\n\t\t}\n\t\t// Update track count\n\t\tself.trackCountText.setText(filteredTracks.length + ' tracks');\n\t\t// Update screen indicator\n\t\tscreenIndicator.setText(self.currentScreen.toUpperCase());\n\t};\n\tself.navigateUp = function () {\n\t\tif (self.selectedTrackIndex > 0) {\n\t\t\tself.selectedTrackIndex--;\n\t\t\tif (self.selectedTrackIndex < self.visibleTrackStart) {\n\t\t\t\tself.visibleTrackStart = self.selectedTrackIndex;\n\t\t\t}\n\t\t\tself.updateDisplay();\n\t\t}\n\t};\n\tself.navigateDown = function () {\n\t\tvar maxTracks = self.tracks.length - 1;\n\t\tif (self.selectedTrackIndex < maxTracks) {\n\t\t\tself.selectedTrackIndex++;\n\t\t\tif (self.selectedTrackIndex >= self.visibleTrackStart + self.maxVisibleTracks) {\n\t\t\t\tself.visibleTrackStart = self.selectedTrackIndex - self.maxVisibleTracks + 1;\n\t\t\t}\n\t\t\tself.updateDisplay();\n\t\t}\n\t};\n\tself.navigateLeft = function () {\n\t\tif (self.selectedCategoryIndex > 0) {\n\t\t\tself.selectedCategoryIndex--;\n\t\t\tself.selectedTrackIndex = 0;\n\t\t\tself.visibleTrackStart = 0;\n\t\t\tself.updateDisplay();\n\t\t}\n\t};\n\tself.navigateRight = function () {\n\t\tif (self.selectedCategoryIndex < self.categories.length - 1) {\n\t\t\tself.selectedCategoryIndex++;\n\t\t\tself.selectedTrackIndex = 0;\n\t\t\tself.visibleTrackStart = 0;\n\t\t\tself.updateDisplay();\n\t\t}\n\t};\n\tself.selectTrack = function () {\n\t\tvar filteredTracks = self.tracks;\n\t\tif (self.selectedCategoryIndex > 1) {\n\t\t\t// Filter by specific genre, skipping 'CATEGORY' and 'All Tracks'\n\t\t\tvar genre = self.categories[self.selectedCategoryIndex];\n\t\t\tfilteredTracks = self.tracks.filter(function (track) {\n\t\t\t\treturn track.genre === genre;\n\t\t\t});\n\t\t} else if (self.selectedCategoryIndex === 1) {\n\t\t\t// 'All Tracks' category - show all tracks\n\t\t\tfilteredTracks = self.tracks;\n\t\t} else {\n\t\t\t// 'CATEGORY' category - show no tracks\n\t\t\tfilteredTracks = [];\n\t\t}\n\t\tif (self.selectedTrackIndex < filteredTracks.length) {\n\t\t\tvar selectedTrack = filteredTracks[self.selectedTrackIndex];\n\t\t\t// Flash effect to show selection\n\t\t\ttween(self.trackItems[self.selectedTrackIndex - self.visibleTrackStart].bg, {\n\t\t\t\ttint: 0x00ff00\n\t\t\t}, {\n\t\t\t\tduration: 150,\n\t\t\t\tonFinish: function onFinish() {\n\t\t\t\t\ttween(self.trackItems[self.selectedTrackIndex - self.visibleTrackStart].bg, {\n\t\t\t\t\t\ttint: self.trackItems[self.selectedTrackIndex - self.visibleTrackStart].bg.originalTint || (self.selectedTrackIndex - self.visibleTrackStart) % 2 === 0 ? 0x252525 : 0x2a2a2a\n\t\t\t\t\t}, {\n\t\t\t\t\t\tduration: 150\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t\t// Play a selection sound\n\t\t\tLK.getSound('fx').play();\n\t\t\t// Add score for track selection\n\t\t\tif (typeof score !== 'undefined') {\n\t\t\t\tscore += 25;\n\t\t\t\tcombo += 1;\n\t\t\t}\n\t\t}\n\t};\n\t// Make search bar draggable\n\tsearchBarBg.down = function (x, y, obj) {\n\t\tself.searchBarDragging = true;\n\t\tself.searchBarOffset = {\n\t\t\tx: x - searchBarBg.x,\n\t\t\ty: y - searchBarBg.y\n\t\t};\n\t};\n\tsearchBarBg.up = function (x, y, obj) {\n\t\tself.searchBarDragging = false;\n\t\tself.searchBarOffset = null;\n\t};\n\tsearchBarBg.move = function (x, y, obj) {\n\t\tif (self.searchBarDragging && self.searchBarOffset) {\n\t\t\tsearchBarBg.x = x - self.searchBarOffset.x;\n\t\t\tsearchBarBg.y = y - self.searchBarOffset.y;\n\t\t\t// Keep search text aligned with background\n\t\t\tsearchText.x = searchBarBg.x;\n\t\t\tsearchText.y = searchBarBg.y;\n\t\t}\n\t};\n\t// Initialize display\n\tself.updateDisplay();\n\treturn self;\n});\n// SmokeDiffuser: Animated smoke diffuser with rising smoke puffs\nvar SmokeDiffuser = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Visuals - Diffuser base (small ellipse)\n\tvar base = self.attachAsset('centerCircle', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 1.0,\n\t\twidth: 60,\n\t\theight: 30,\n\t\ty: 0\n\t});\n\tbase.tint = 0x888888;\n\tbase.alpha = 0.85;\n\t// Config\n\tvar numParticles = 60; // Increased number of particles for denser smoke\n\tvar particles = [];\n\tvar particleMinSize = 48;\n\tvar particleMaxSize = 96;\n\tvar speedY = -3.5; // pixels per frame (upwards)\n\tvar speedX = 0.7; // horizontal drift\n\tvar particleLifetime = 2500; // ms // Increased particle lifetime\n\t// HSV to RGB helper\n\tfunction hsvToRgb(h, s, v) {\n\t\tvar r, g, b;\n\t\tvar i = Math.floor(h * 6);\n\t\tvar f = h * 6 - i;\n\t\tvar p = v * (1 - s);\n\t\tvar q = v * (1 - f * s);\n\t\tvar t_color = v * (1 - (1 - f) * s);\n\t\tswitch (i % 6) {\n\t\t\tcase 0:\n\t\t\t\tr = v;\n\t\t\t\tg = t_color;\n\t\t\t\tb = p;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tr = q;\n\t\t\t\tg = v;\n\t\t\t\tb = p;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tr = p;\n\t\t\t\tg = v;\n\t\t\t\tb = t_color;\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tr = p;\n\t\t\t\tg = q;\n\t\t\t\tb = v;\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tr = t_color;\n\t\t\t\tg = p;\n\t\t\t\tb = v;\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\tr = v;\n\t\t\t\tg = p;\n\t\t\t\tb = q;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];\n\t}\n\tself.createSmoke = function () {\n\t\tvar size = particleMinSize + Math.random() * (particleMaxSize - particleMinSize);\n\t\tvar puff = LK.getAsset('centerCircle', {\n\t\t\tanchorX: 0.5,\n\t\t\tanchorY: 0.5,\n\t\t\twidth: size,\n\t\t\theight: size\n\t\t});\n\t\t// Smoke color depends on UV effect state\n\t\tif (typeof uvEffectActive !== 'undefined' && uvEffectActive) {\n\t\t\t// Colorful UV smoke\n\t\t\tvar hue = Math.random();\n\t\t\tvar rgb = hsvToRgb(hue, 0.9 + Math.random() * 0.1, 0.9 + Math.random() * 0.1);\n\t\t\tpuff.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n\t\t} else {\n\t\t\t// Normal smoke color: light gray, some randomization\n\t\t\tvar gray = 180 + Math.floor(Math.random() * 40);\n\t\t\tpuff.tint = gray << 16 | gray << 8 | gray;\n\t\t}\n\t\tpuff.alpha = 0.32 + Math.random() * 0.18;\n\t\t// Start at base, with slight random x offset\n\t\tpuff.x = Math.random() * 16 - 8;\n\t\tpuff.y = -base.height + Math.random() * 8;\n\t\tself.addChild(puff);\n\t\tparticles.push({\n\t\t\tobj: puff,\n\t\t\tspeedScale: 0.8 + Math.random() * 0.5,\n\t\t\tstartTime: Date.now(),\n\t\t\tbaseSize: size,\n\t\t\tphase: Math.random() * Math.PI * 2\n\t\t});\n\t};\n\t// Animation\n\tself.update = function () {\n\t\tvar now = Date.now();\n\t\t// Only emit smoke if smokeEffectActive is true\n\t\tif (typeof smokeEffectActive !== 'undefined' && smokeEffectActive) {\n\t\t\t// Create new puffs if needed\n\t\t\tif (particles.length < numParticles) {\n\t\t\t\tself.createSmoke();\n\t\t\t}\n\t\t}\n\t\t// Update puffs\n\t\tfor (var i = particles.length - 1; i >= 0; i--) {\n\t\t\tvar p = particles[i];\n\t\t\tvar elapsed = now - p.startTime;\n\t\t\tif (elapsed > particleLifetime) {\n\t\t\t\tp.obj.destroy();\n\t\t\t\tparticles.splice(i, 1);\n\t\t\t} else {\n\t\t\t\t// Move upwards, drift sideways\n\t\t\t\tp.obj.y += speedY * p.speedScale;\n\t\t\t\tp.obj.x += speedX * Math.sin(now * 0.001 + p.phase) * p.speedScale;\n\t\t\t\t// Fade out and grow\n\t\t\t\tp.obj.alpha = (1.0 - elapsed / particleLifetime) * (0.32 + 0.18 * Math.sin(now * 0.002 + p.phase));\n\t\t\t\tvar size = p.baseSize * (1.0 + elapsed / particleLifetime * 0.7);\n\t\t\t\tp.obj.width = size;\n\t\t\t\tp.obj.height = size;\n\t\t\t}\n\t\t}\n\t};\n\treturn self;\n});\nvar SongMakerApp = Container.expand(function () {\n\tvar self = Container.call(this);\n\t// Config\n\tvar appWidth = 2048;\n\tvar appHeight = 2732;\n\t// Background\n\tvar background = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: appWidth,\n\t\theight: appHeight\n\t});\n\tbackground.tint = 0x1a1a1a; // Dark background\n\t// App Title\n\tvar titleText = new Text2('SONG MAKER', {\n\t\tsize: 100,\n\t\tfill: 0xFF6600\n\t});\n\ttitleText.anchor.set(0.5, 0);\n\ttitleText.x = appWidth / 2;\n\ttitleText.y = 100;\n\tself.addChild(titleText);\n\t// Piano Roll Configuration\n\tvar pianoRollConfig = {\n\t\tx: 50,\n\t\ty: 250,\n\t\twidth: appWidth - 100,\n\t\theight: 1600,\n\t\tnoteHeight: 25,\n\t\tnoteColors: [0xFF6600, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF],\n\t\tgridColor: 0x333333,\n\t\tkeyboardWidth: 120,\n\t\ttimelineHeight: 80,\n\t\tinstruments: ['Drums', 'Guitar', 'Piano', 'Synthesizer', 'Bass', 'Strings']\n\t};\n\t// Create piano roll instance\n\tvar pianoRoll = new PianoRoll(pianoRollConfig);\n\tpianoRoll.x = pianoRollConfig.x; // Position the container\n\tpianoRoll.y = pianoRollConfig.y; // Position the container\n\tself.addChild(pianoRoll);\n\t// Access notes array from the pianoRoll instance\n\tvar notes = pianoRoll.notes; // This variable is now accessible\n\tvar beatWidth = (pianoRollConfig.width - pianoRollConfig.keyboardWidth) / (16 * 4); // Recalculate beatWidth based on pianoRollConfig\n\t// Instruments tools container\n\t// Instruments tools container\n\tvar instrumentsToolsY = pianoRollConfig.y + pianoRollConfig.height + 50;\n\tvar instrumentsToolsHeight = 200; // Define height for instruments tools\n\tvar instrumentsToolsContainer = self.addChild(new Container());\n\tinstrumentsToolsContainer.x = pianoRollConfig.x;\n\tinstrumentsToolsContainer.y = instrumentsToolsY;\n\tvar instrumentsToolsBg = instrumentsToolsContainer.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: pianoRollConfig.width,\n\t\theight: instrumentsToolsHeight\n\t});\n\tinstrumentsToolsBg.tint = 0x333333;\n\tinstrumentsToolsBg.x = 0; // Relative to container\n\tinstrumentsToolsBg.y = 0; // Relative to container\n\t// Transport controls\n\tvar transportY = instrumentsToolsY + instrumentsToolsHeight + 50; // Position transport controls below instruments tools\n\tvar transportBg = self.attachAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: pianoRollConfig.width,\n\t\theight: 100\n\t});\n\ttransportBg.tint = 0x333333;\n\ttransportBg.x = pianoRollConfig.x;\n\ttransportBg.y = transportY;\n\tself.addChild(transportBg);\n\t// Play button\n\tvar playButton = self.attachAsset('Startbutton', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\tplayButton.x = pianoRollConfig.x + 100;\n\tplayButton.y = transportY + 50;\n\tplayButton.scaleX = 0.5;\n\tplayButton.scaleY = 0.5;\n\tself.addChild(playButton);\n\tvar isPlaying = false;\n\tvar playbackPosition = 0;\n\tvar playbackTimer = null;\n\tplayButton.down = function (x, y, obj) {\n\t\tisPlaying = !isPlaying;\n\t\tif (isPlaying) {\n\t\t\t// Start playback\n\t\t\tplayButton.tint = 0x00FF00;\n\t\t\tplaybackTimer = LK.setInterval(function () {\n\t\t\t\t// Update playback position\n\t\t\t\tplaybackPosition = (playbackPosition + 1) % (16 * 4); // Use totalBars * beatsPerBar\n\t\t\t\t// Play notes at current position\n\t\t\t\tfor (var i = 0; i < notes.length; i++) {\n\t\t\t\t\tif (notes[i].beatIndex === playbackPosition) {\n\t\t\t\t\t\t// Play sound associated with the instrument voice\n\t\t\t\t\t\t// This needs a mapping from instrument voice to a sound asset ID\n\t\t\t\t\t\t// For now, playing a generic sound\n\t\t\t\t\t\tLK.getSound('fx').play();\n\t\t\t\t\t\t// Flash the note\n\t\t\t\t\t\tvar originalTint = notes[i].visual.tint;\n\t\t\t\t\t\tnotes[i].visual.tint = 0xFFFFFF;\n\t\t\t\t\t\tvar noteRef = notes[i];\n\t\t\t\t\t\tLK.setTimeout(function () {\n\t\t\t\t\t\t\tnoteRef.visual.tint = originalTint;\n\t\t\t\t\t\t}, 100);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 250); // 240 BPM (250ms per beat)\n\t\t} else {\n\t\t\t// Stop playback\n\t\t\tplayButton.tint = 0xFFFFFF;\n\t\t\tif (playbackTimer) {\n\t\t\t\tLK.clearInterval(playbackTimer);\n\t\t\t\tplaybackTimer = null;\n\t\t\t}\n\t\t}\n\t};\n\t// Stop button\n\tvar stopButton = self.attachAsset('Cuebutton', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\tstopButton.x = pianoRollConfig.x + 200;\n\tstopButton.y = transportY + 50;\n\tstopButton.scaleX = 0.5;\n\tstopButton.scaleY = 0.5;\n\tself.addChild(stopButton);\n\tstopButton.down = function (x, y, obj) {\n\t\tisPlaying = false;\n\t\tplaybackPosition = 0;\n\t\tplayButton.tint = 0xFFFFFF;\n\t\tif (playbackTimer) {\n\t\t\tLK.clearInterval(playbackTimer);\n\t\t\tplaybackTimer = null;\n\t\t}\n\t};\n\t// Clear button\n\tvar clearButton = self.attachAsset('Effect', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\tclearButton.x = pianoRollConfig.x + 300;\n\tclearButton.y = transportY + 50;\n\tclearButton.scaleX = 0.8;\n\tclearButton.scaleY = 0.8;\n\tself.addChild(clearButton);\n\tvar clearText = new Text2('CLEAR', {\n\t\tsize: 24,\n\t\tfill: 0xFFFFFF\n\t});\n\tclearText.anchor.set(0.5, 0.5);\n\tclearText.x = clearButton.x;\n\tclearText.y = clearButton.y;\n\tself.addChild(clearText);\n\tclearButton.down = function (x, y, obj) {\n\t\t// Clear all notes\n\t\tfor (var i = 0; i < notes.length; i++) {\n\t\t\tself.removeChild(notes[i].visual);\n\t\t}\n\t\tnotes = []; // Clear the notes array\n\t\t// Visual feedback\n\t\ttween(clearButton, {\n\t\t\tscaleX: 0.6,\n\t\t\tscaleY: 0.6\n\t\t}, {\n\t\t\tduration: 100,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\ttween(clearButton, {\n\t\t\t\t\tscaleX: 0.8,\n\t\t\t\t\tscaleY: 0.8\n\t\t\t\t}, {\n\t\t\t\t\tduration: 100\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t};\n\t// Tempo display\n\tvar tempoText = new Text2('BPM: 240', {\n\t\tsize: 32,\n\t\tfill: 0xFFFFFF\n\t});\n\ttempoText.anchor.set(0, 0.5);\n\ttempoText.x = pianoRollConfig.x + 450;\n\ttempoText.y = transportY + 50;\n\tself.addChild(tempoText);\n\treturn self;\n});\n\n/**** \n* Initialize Game\n****/ \nvar game = new LK.Game({\n\tbackgroundColor: 0x000000\n});\n\n/**** \n* Game Code\n****/ \n// --- Reflectors (behind discoball) ---\n// Add a vertical crossfader track\nvar reflectors = [];\nvar numReflectors = 7;\nvar reflectorSpacing = 2048 / (numReflectors + 1);\nvar reflectorY = 80; // Top, but below menu area\n// Create reflectors but do not add to game yet\nfor (var i = 0; i < numReflectors; i++) {\n\tvar rx = reflectorSpacing * (i + 1);\n\tvar reflector = LK.getAsset('centerCircle', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: 60,\n\t\theight: 60\n\t});\n\treflector.tint = 0xffffff;\n\treflector.alpha = 0.0;\n\treflector.x = rx;\n\treflector.y = reflectorY;\n\treflectors.push(reflector);\n}\n// --- Discoball (top of screen) ---\n// Asset for dancing woman\n// Asset for dancing man\nvar discoball = new Discoball();\n// Add reflectors behind discoball in display order\nfor (var i = 0; i < reflectors.length; i++) {\n\tgame.addChild(reflectors[i]);\n}\n// Insert discoball after reflectors so it appears above them\ngame.addChild(discoball);\ndiscoball.x = 2048 / 2;\ndiscoball.y = 200 - 69; // Move discoball up by 69 units\ndiscoball.scaleX = 0.8;\ndiscoball.scaleY = 0.8;\n// --- Extra white particles for upper half sparkle effect ---\nvar extraWhiteParticles = [];\nvar numExtraParticles = 32;\nfor (var i = 0; i < numExtraParticles; i++) {\n\t// Random position in upper half, avoid top 100px (menu)\n\tvar px = 100 + Math.random() * (2048 - 200);\n\tvar py = 120 + Math.random() * (1366 - 220);\n\tvar size = 8 + Math.random() * 10;\n\tvar particle = LK.getAsset('centerCircle', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: size,\n\t\theight: size\n\t});\n\tparticle.tint = 0xffffff;\n\tparticle.alpha = 0.18 + Math.random() * 0.22;\n\tparticle.x = px;\n\tparticle.y = py;\n\tgame.addChild(particle);\n\textraWhiteParticles.push({\n\t\tobj: particle,\n\t\tbaseX: px,\n\t\tbaseY: py,\n\t\tphase: Math.random() * Math.PI * 2,\n\t\tbaseAlpha: particle.alpha,\n\t\tbaseSize: size\n\t});\n}\n// Animate extra particles in game.update\n// --- Fog Effect (upper half) ---\nvar fogEffect = new FogEffect();\ngame.addChild(fogEffect);\nfogEffect.y = 0; // Position at the top of the screen\n// --- Confetti Effect (upper half) ---\nvar confettiEffect = new ConfettiEffect();\ngame.addChild(confettiEffect);\nconfettiEffect.y = 0; // Position at the top of the screen\n// --- DJDeck Asset (center of map) ---\nvar djDeck = LK.getAsset('desk', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\twidth: 2048,\n\theight: 2020 * (2048 / 2040) // maintain aspect ratio\n});\ngame.addChild(djDeck);\ndjDeck.x = 2048 / 2;\ndjDeck.y = 2732 / 2 + 333 + 12 + 12; // Move the DJ deck down by 357 units\n// --- Rim Assets (both sides of djdeck) ---\nvar rimLeft = LK.getAsset('rim', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\nrimLeft.x = djDeck.x - djDeck.width / 2 + rimLeft.width / 2 + 49;\nrimLeft.y = djDeck.y;\nvar rimRight = LK.getAsset('rim', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\nrimRight.x = djDeck.x + djDeck.width / 2 - rimRight.width / 2 - 150 + 108;\nrimRight.y = djDeck.y;\n// Add rim assets after djdeck to ensure they appear above in display order\ngame.addChild(rimLeft);\ngame.addChild(rimRight);\n// Move rim assets above djdeck in display order\nvar djdeckIndex = game.children.indexOf(djDeck);\nif (djdeckIndex !== -1) {\n\tgame.setChildIndex(rimLeft, djdeckIndex + 1);\n\tgame.setChildIndex(rimRight, djdeckIndex + 2);\n}\n// Remove and re-add rim assets to ensure they're above djdeckAsset in display order\nif (game.children.indexOf(rimLeft) !== -1) {\n\tgame.removeChild(rimLeft);\n}\nif (game.children.indexOf(rimRight) !== -1) {\n\tgame.removeChild(rimRight);\n}\ngame.addChild(rimLeft);\ngame.addChild(rimRight);\n// --- Dancing People ---\nvar dancingPeople = [];\nvar numPeople = 8;\nvar peopleAreaY = djDeck.y - djDeck.height / 2 - 200 + 200 + 69; // Position above the DJ deck, moved down by 200 units, then down by 69 more\nvar peopleAreaWidth = 1600 - 25 * (numPeople - 1); // Area width for dancing people, reduced to move people closer\nvar startX = 2048 / 2 - peopleAreaWidth / 2 - 77;\nvar personSpacing = peopleAreaWidth / (numPeople - 1);\nfor (var i = 0; i < numPeople; i++) {\n\t// Alternate: even index = woman, odd index = man\n\tvar genderAsset = i % 2 === 0 ? 'dancingWoman' : 'dancingMan';\n\tvar person = new DancingPerson(genderAsset);\n\tperson.x = startX + i * personSpacing;\n\tperson.baseY = peopleAreaY; // Set the base Y position for animation\n\tgame.addChild(person);\n\tdancingPeople.push(person);\n}\n// --- Laser Show (upper half) ---\nvar laserShow = new LaserShow();\ngame.addChild(laserShow);\nlaserShow.y = -456; // Move laser effect up by 456 units (333 + 123)\n// --- Fireworks Effect (upper half) ---\nvar fireworksEffect = new FireworksEffect();\ngame.addChild(fireworksEffect);\nfireworksEffect.y = 0; // Position at the top of the screen\n// --- Additional Fireworks Effects for more density in upper half ---\nvar fireworksEffect2 = new FireworksEffect();\ngame.addChild(fireworksEffect2);\nfireworksEffect2.y = 0; // Position at the top of the screen\nfireworksEffect2.x = 500; // Offset position for varied launch points\nvar fireworksEffect3 = new FireworksEffect();\ngame.addChild(fireworksEffect3);\nfireworksEffect3.y = 0; // Position at the top of the screen\nfireworksEffect3.x = -300; // Different offset position\nvar fireworksEffect4 = new FireworksEffect();\ngame.addChild(fireworksEffect4);\nfireworksEffect4.y = 0; // Position at the top of the screen\nfireworksEffect4.x = 800; // Another offset position\n// --- Balloons (falling from top) ---\nvar balloons = [];\nvar numBalloons = 50; // Increased number of balloons\nfor (var i = 0; i < numBalloons; i++) {\n\tvar balloon = new Balloon();\n\t// Position balloons initially above the screen\n\tballoon.y = -300 - Math.random() * 1000; // Start higher up for more variety\n\tballoon.x = Math.random() * 2048;\n\tgame.addChild(balloon);\n\tballoons.push(balloon);\n}\n// --- Money Particles (falling from top) ---\nvar moneyParticles = [];\nvar numMoneyParticles = 25; // Number of money bills falling\nfor (var i = 0; i < numMoneyParticles; i++) {\n\tvar money = new MoneyParticle();\n\t// Position money initially above the screen with staggered timing\n\tmoney.y = -100 - Math.random() * 800;\n\tmoney.x = Math.random() * 2048;\n\tgame.addChild(money);\n\tmoneyParticles.push(money);\n\t// Add initial sparkle effect with tween\n\ttween(money, {\n\t\talpha: 0.7\n\t}, {\n\t\tduration: 1000 + Math.random() * 1000,\n\t\teasing: tween.easeInOut,\n\t\tonFinish: function () {\n\t\t\ttween(this, {\n\t\t\t\talpha: 1.0\n\t\t\t}, {\n\t\t\t\tduration: 1000 + Math.random() * 1000,\n\t\t\t\teasing: tween.easeInOut\n\t\t\t});\n\t\t}.bind(money)\n\t});\n}\n// --- Ferris Wheel (upper half) ---\nvar ferrisWheel = new FerrisWheel();\ngame.addChild(ferrisWheel);\nferrisWheel.x = 2048 / 2 - 400;\nferrisWheel.y = 450; // Positioned in the upper-middle part of the screen\nferrisWheel.scaleX = 0.8;\nferrisWheel.scaleY = 0.8;\n// --- DJ Deck Asset ---\nvar djDeck = LK.getAsset('desk', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\twidth: 2048,\n\theight: 2020 * (2048 / 2040) // maintain aspect ratio\n});\ngame.addChild(djDeck);\ndjDeck.x = 2048 / 2;\ndjDeck.y = 2732 / 2 + 333 + 12 + 12; // Move the DJ deck down by 357 units\n// No dark overlay is present, so nothing to remove.\n// --- Second Line Dancing People (append to existing array) ---\n// Don't recreate the array, just append to existing dancingPeople array\nvar numPeople = 8;\nvar peopleAreaY = djDeck.y - djDeck.height / 2 - 200 + 200 + 69; // Position above the DJ deck, moved down by 200 units, then down by 69 more\nvar peopleAreaWidth = 1600 - 25 * (numPeople - 1); // Area width for dancing people, reduced to move people closer\nvar startX = 2048 / 2 - peopleAreaWidth / 2;\nvar personSpacing = peopleAreaWidth / (numPeople - 1);\nfor (var i = 0; i < numPeople; i++) {\n\tvar person = new DancingPerson(); // Use default random asset initially\n\tperson.x = startX + i * personSpacing;\n\tperson.baseY = peopleAreaY; // Set the base Y position for animation\n\tgame.addChild(person);\n\tdancingPeople.push(person);\n}\n// --- Smoke Diffuser (left of people line) ---\n// Add global smokeEffectActive variable to control smoke emission\nvar smokeEffectActive = false;\nvar fogAnimationActive = false;\nvar fogTimeout = null;\n// --- Add 6 smoke diffusers spread out to the left of the people line, spaced 300 units apart, all moved right by 32 units ---\nvar smokeDiffusers = [];\nfor (var i = 0; i <= 5; i++) {\n\tvar sd = new SmokeDiffuser();\n\tsd.x = startX - 80 + 32 + i * 300;\n\tsd.y = peopleAreaY + 18 - 50; // Align base with people feet, moved up by 50 units\n\tgame.addChild(sd);\n\tsmokeDiffusers.push(sd);\n}\n// --- Flamethrower ---\nvar flamethrower = new Flamethrower();\n// Position the flamethrower to the right of the dancing people line\nflamethrower.x = startX + peopleAreaWidth + 100 + 77 + 7; // Move flamethrower right by 84 units (77+7)\n// Move the flamethrower down so the flame aligns with the top of the base, then up by 100 units\nflamethrower.y = peopleAreaY + (flamethrower.height ? flamethrower.height * 0.5 : 75) - 100; // 75 is half of base height (150*0.5), fallback if height is not set\ngame.addChild(flamethrower);\n// --- Second Flamethrower (left edge) ---\nvar flamethrowerLeft = new Flamethrower();\n// Place at the left edge, aligned with the people line\nflamethrowerLeft.x = startX - 200; // Move left flamethrower left by 100 more units\nflamethrowerLeft.y = peopleAreaY + (flamethrowerLeft.height ? flamethrowerLeft.height * 0.5 : 75) - 100; // Move base up by 100 units\ngame.addChild(flamethrowerLeft);\n// Ensure ferriswheel, cabins, and rim dots are always under the dancing people in display order\nfor (var i = 0; i < dancingPeople.length; i++) {\n\t// Find the minimum index among all dancing people\n\tvar minIndex = game.children.length;\n\tfor (var j = 0; j < dancingPeople.length; j++) {\n\t\tvar idx = game.children.indexOf(dancingPeople[j]);\n\t\tif (idx !== -1 && idx < minIndex) minIndex = idx;\n\t}\n\t// Move ferrisWheel itself below all dancing people\n\tif (game.children.indexOf(ferrisWheel) > minIndex) {\n\t\tgame.setChildIndex(ferrisWheel, minIndex);\n\t}\n\t// Move all cabins below all dancing people\n\tif (ferrisWheel.cabins) {\n\t\tfor (var c = 0; c < ferrisWheel.cabins.length; c++) {\n\t\t\tvar cabin = ferrisWheel.cabins[c];\n\t\t\tif (game.children.indexOf(cabin) > minIndex) {\n\t\t\t\tgame.setChildIndex(cabin, minIndex);\n\t\t\t}\n\t\t}\n\t}\n\t// Move all rim dots (centerCircle assets attached to wheelAssembly) below all dancing people\n\tif (ferrisWheel.wheelAssembly && ferrisWheel.wheelAssembly.children) {\n\t\tfor (var w = 0; w < ferrisWheel.wheelAssembly.children.length; w++) {\n\t\t\tvar rimDot = ferrisWheel.wheelAssembly.children[w];\n\t\t\t// Only move rim dots (centerCircle assets, not hub or spokes)\n\t\t\tif (rimDot && rimDot.assetId === 'centerCircle') {\n\t\t\t\t// The rim dots are not direct children of game, but of wheelAssembly, so nothing to do here for game order\n\t\t\t\t// If in future, rim dots are added to game, ensure they are below dancing people\n\t\t\t}\n\t\t}\n\t}\n\t// Now, ensure this dancing person is above ferrisWheel and all its parts\n\tvar maxFerrisIndex = game.children.indexOf(ferrisWheel);\n\tif (ferrisWheel.cabins) {\n\t\tfor (var c = 0; c < ferrisWheel.cabins.length; c++) {\n\t\t\tvar idx = game.children.indexOf(ferrisWheel.cabins[c]);\n\t\t\tif (idx > maxFerrisIndex) maxFerrisIndex = idx;\n\t\t}\n\t}\n\t// (Rim dots are not direct children of game, so not included)\n\tgame.setChildIndex(dancingPeople[i], maxFerrisIndex + 1);\n}\n// Ensure balloons are behind the dancing people but in front of the DJ deck\nvar minDancingPeopleIndex = game.children.length;\nfor (var i = 0; i < dancingPeople.length; i++) {\n\tvar idx = game.children.indexOf(dancingPeople[i]);\n\tif (idx !== -1 && idx < minDancingPeopleIndex) minDancingPeopleIndex = idx;\n}\nvar djDeckIndex = game.children.indexOf(djdeckAsset); // Use djdeckAsset which is the visible asset\nif (balloons) {\n\tfor (var i = 0; i < balloons.length; i++) {\n\t\tvar balloon = balloons[i];\n\t\tvar balloonIndex = game.children.indexOf(balloon);\n\t\tif (balloonIndex !== -1) {\n\t\t\t// Position balloons just behind the dancing people (minIndex - 1)\n\t\t\t// But also ensure they are in front of the djdeckAsset (djDeckIndex + 1)\n\t\t\tvar targetIndex = Math.max(djDeckIndex + 1, minDancingPeopleIndex - 1);\n\t\t\t// Make sure the targetIndex is valid\n\t\t\tif (targetIndex < game.children.length) {\n\t\t\t\tgame.setChildIndex(balloon, targetIndex);\n\t\t\t} else {\n\t\t\t\t// If target index is out of bounds, place it just before the dancing people\n\t\t\t\tgame.setChildIndex(balloon, minDancingPeopleIndex > 0 ? minDancingPeopleIndex - 1 : 0);\n\t\t\t}\n\t\t}\n\t}\n}\n// --- Decks ---\n// Sound effects (dummy, as actual music is handled by LK)\n// Beat lights\n// FX Button\n// Crossfader\n// Deck platters (turntables)\n// --- Layout constants ---\nvar deckY = 1366; // Move decks to vertical center of 2732px screen\nvar deckSpacing = 1000;\nvar crossfaderY = 2300;\nvar fxButtonY = 2200;\n// --- Decks ---\nvar leftDeck = new DeckPlatter();\nleftDeck.setTrack('A');\ngame.addChild(leftDeck);\nleftDeck.x = 2048 / 2 - deckSpacing / 2;\nleftDeck.y = deckY;\nvar rightDeck = new DeckPlatter();\nrightDeck.setTrack('B');\ngame.addChild(rightDeck);\nrightDeck.x = 2048 / 2 + deckSpacing / 2;\nrightDeck.y = deckY;\n// --- Crossfader ---\nvar crossfader = new Crossfader();\ncrossfader.x = 2048 / 2;\ncrossfader.y = crossfaderY + 333 - 124 + 100;\ngame.addChild(crossfader);\ngame.setChildIndex(crossfader, game.children.length - 1); // Ensure knob is on top\ncrossfader.setValue(0.5);\n// --- FX Button ---\nvar fxButton = new FXButton();\ngame.addChild(fxButton);\nfxButton.x = 2048 / 2 - 150;\nfxButton.y = fxButtonY;\n// --- Score / Combo / Energy ---\nvar energy = 50; // 0-100\nvar combo = 0;\nvar score = 0;\n// Energy bar\nvar energyBarBg = LK.getAsset('crossfaderTrack', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\twidth: 600,\n\theight: 40\n});\nenergyBarBg.tint = 0x222222;\nenergyBarBg.y = 0;\nvar energyBar = LK.getAsset('crossfaderTrack', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\twidth: 600,\n\theight: 40\n});\nenergyBar.tint = 0x00ff00;\nenergyBar.y = 0;\nvar energyBarContainer = new Container();\nenergyBarContainer.addChild(energyBarBg);\nenergyBarContainer.addChild(energyBar);\nenergyBarContainer.x = 2048 / 2;\nenergyBarContainer.y = 200;\nLK.gui.top.addChild(energyBarContainer);\n// --- DJDeck Asset (center of map) ---\nvar djdeckAsset = LK.getAsset('djdeck', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(djdeckAsset);\ndjdeckAsset.x = 2048 / 2;\ndjdeckAsset.y = 2732 / 2 + 300 + 23 - 5 - 15 - 5;\n// Scale djdeck to fit the screen width properly\ndjdeckAsset.width = 2048;\ndjdeckAsset.height = djdeckAsset.height * (2048 / djdeckAsset.width);\n// Ensure rim assets are above djdeckAsset in display order\nvar djdeckAssetIndex = game.children.indexOf(djdeckAsset);\nif (djdeckAssetIndex !== -1) {\n\tvar rimLeftIndex = game.children.indexOf(rimLeft);\n\tvar rimRightIndex = game.children.indexOf(rimRight);\n\tif (rimLeftIndex !== -1 && rimLeftIndex <= djdeckAssetIndex) {\n\t\tvar targetIndexLeft = djdeckAssetIndex + 1;\n\t\tif (targetIndexLeft < game.children.length) {\n\t\t\tgame.setChildIndex(rimLeft, targetIndexLeft);\n\t\t} else {\n\t\t\t// If target index is out of bounds, move to last position\n\t\t\tgame.setChildIndex(rimLeft, game.children.length - 1);\n\t\t}\n\t\t// Update djdeckAssetIndex after moving rimLeft\n\t\tdjdeckAssetIndex = game.children.indexOf(djdeckAsset);\n\t}\n\tif (rimRightIndex !== -1 && rimRightIndex <= djdeckAssetIndex) {\n\t\t// Get fresh index for rimLeft after potential move\n\t\tvar currentRimLeftIndex = game.children.indexOf(rimLeft);\n\t\tvar targetIndex = Math.max(djdeckAssetIndex + 1, currentRimLeftIndex + 1);\n\t\tif (targetIndex < game.children.length) {\n\t\t\tgame.setChildIndex(rimRight, targetIndex);\n\t\t} else {\n\t\t\t// If target index is out of bounds, move to last position\n\t\t\tgame.setChildIndex(rimRight, game.children.length - 1);\n\t\t}\n\t}\n}\n// --- Sampletable Asset (center of map) ---\nvar sampletableAsset = LK.getAsset('sampletable', {\n\tanchorX: 0.5,\n\tanchorY: 1.0\n});\ngame.addChild(sampletableAsset);\nsampletableAsset.x = 2048 / 2;\nsampletableAsset.y = 2732;\n// --- Crossfader ---\n// Remove and re-add crossfader to ensure it's above the sampletable\nif (game.children.indexOf(crossfader) !== -1) {\n\tgame.removeChild(crossfader);\n}\ngame.addChild(crossfader);\n// --- FX Button ---\n// Remove and re-add fxButton to ensure it's above the sampletable\nif (game.children.indexOf(fxButton) !== -1) {\n\tgame.removeChild(fxButton);\n}\ngame.addChild(fxButton);\n// --- Samplebutton Asset (left side corner of sampletable) ---\nvar samplebuttonAsset = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAsset);\nsamplebuttonAsset.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset.width / 2 + 50 - 4;\nsamplebuttonAsset.y = sampletableAsset.y - samplebuttonAsset.height / 2 - 50;\n// Add functionality to first samplebutton\nsamplebuttonAsset.down = function (x, y, obj) {\n\t// Play sample1 sound\n\tLK.getSound('sample1').play();\n\t// Visual feedback - scale animation\n\ttween(samplebuttonAsset, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAsset, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect\n\tLK.effects.flashObject(samplebuttonAsset, 0xff0000, 300);\n};\n// --- Second Samplebutton Asset (reusing existing asset for memory efficiency) ---\nvar samplebuttonAsset2 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAsset2);\nsamplebuttonAsset2.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset2.width / 2 + 200 - 4;\nsamplebuttonAsset2.y = sampletableAsset.y - samplebuttonAsset2.height / 2 - 50;\n// --- Third Samplebutton Asset ---\nvar samplebuttonAsset3 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAsset3);\nsamplebuttonAsset3.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset3.width / 2 + 350;\nsamplebuttonAsset3.y = sampletableAsset.y - samplebuttonAsset3.height / 2 - 50;\n// Add functionality to third samplebutton\nsamplebuttonAsset3.down = function (x, y, obj) {\n\t// Play sample3 sound\n\tLK.getSound('sample3').play();\n\t// Visual feedback - color flash animation\n\ttween(samplebuttonAsset3, {\n\t\ttint: 0x0000ff\n\t}, {\n\t\tduration: 150,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAsset3, {\n\t\t\t\ttint: 0xffffff\n\t\t\t}, {\n\t\t\t\tduration: 150\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with blue color\n\tLK.effects.flashObject(samplebuttonAsset3, 0x0000ff, 300);\n\tscore += 50;\n\tcombo += 1;\n};\n// --- Fourth Samplebutton Asset ---\nvar samplebuttonAsset4 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAsset4);\nsamplebuttonAsset4.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset4.width / 2 + 500 - 4;\nsamplebuttonAsset4.y = sampletableAsset.y - samplebuttonAsset4.height / 2 - 50;\n// Add functionality to fourth samplebutton\nsamplebuttonAsset4.down = function (x, y, obj) {\n\t// Play sample4 sound\n\tLK.getSound('sample4').play();\n\t// Visual feedback - pulse animation\n\ttween(samplebuttonAsset4, {\n\t\talpha: 0.3\n\t}, {\n\t\tduration: 80,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAsset4, {\n\t\t\t\talpha: 1.0\n\t\t\t}, {\n\t\t\t\tduration: 80\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with purple color\n\tLK.effects.flashObject(samplebuttonAsset4, 0xff00ff, 300);\n\tscore += 50;\n\tcombo += 1;\n};\n// --- Second Line Samplebuttons (Above First Line) ---\n// --- First Samplebutton Second Line ---\nvar samplebuttonAsset5 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAsset5);\nsamplebuttonAsset5.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset5.width / 2 + 50 - 4;\nsamplebuttonAsset5.y = sampletableAsset.y - samplebuttonAsset5.height / 2 - 250;\n// Add functionality to fifth samplebutton\nsamplebuttonAsset5.down = function (x, y, obj) {\n\t// Play sample1 sound with different effect\n\tLK.getSound('sample1').play();\n\t// Visual feedback - scale animation\n\ttween(samplebuttonAsset5, {\n\t\tscaleX: 1.3,\n\t\tscaleY: 1.3\n\t}, {\n\t\tduration: 200,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAsset5, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 200\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with cyan color\n\tLK.effects.flashObject(samplebuttonAsset5, 0x00ffff, 300);\n\tscore += 75;\n\tcombo += 1;\n};\n// --- Second Samplebutton Second Line ---\nvar samplebuttonAsset6 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAsset6);\nsamplebuttonAsset6.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset6.width / 2 + 200 - 4;\nsamplebuttonAsset6.y = sampletableAsset.y - samplebuttonAsset6.height / 2 - 250;\n// Add functionality to sixth samplebutton\nsamplebuttonAsset6.down = function (x, y, obj) {\n\t// Play sample2 sound with different effect\n\tLK.getSound('sample2').play();\n\t// Visual feedback - scale animation\n\ttween(samplebuttonAsset6, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 150,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAsset6, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 150\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with magenta color\n\tLK.effects.flashObject(samplebuttonAsset6, 0xff00ff, 300);\n\tscore += 75;\n\tcombo += 1;\n};\n// --- Third Samplebutton Second Line ---\nvar samplebuttonAsset7 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAsset7);\nsamplebuttonAsset7.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset7.width / 2 + 350 - 4;\nsamplebuttonAsset7.y = sampletableAsset.y - samplebuttonAsset7.height / 2 - 250;\n// Add functionality to seventh samplebutton\nsamplebuttonAsset7.down = function (x, y, obj) {\n\t// Play sample3 sound with different effect\n\tLK.getSound('sample3').play();\n\t// Visual feedback - pulsing tint animation\n\ttween(samplebuttonAsset7, {\n\t\ttint: 0xffff00,\n\t\tscaleX: 0.8,\n\t\tscaleY: 0.8\n\t}, {\n\t\tduration: 120,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAsset7, {\n\t\t\t\ttint: 0xffffff,\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 120\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with yellow color\n\tLK.effects.flashObject(samplebuttonAsset7, 0xffff00, 300);\n\tscore += 75;\n\tcombo += 1;\n};\n// --- Fourth Samplebutton Second Line ---\nvar samplebuttonAsset8 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAsset8);\nsamplebuttonAsset8.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset8.width / 2 + 500 - 4;\nsamplebuttonAsset8.y = sampletableAsset.y - samplebuttonAsset8.height / 2 - 250;\n// Add functionality to eighth samplebutton\nsamplebuttonAsset8.down = function (x, y, obj) {\n\t// Play sample4 sound with different effect\n\tLK.getSound('sample4').play();\n\t// Visual feedback - alpha fade\n\ttween(samplebuttonAsset8, {\n\t\talpha: 0.5\n\t}, {\n\t\tduration: 300,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAsset8, {\n\t\t\t\talpha: 1.0\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with orange color\n\tLK.effects.flashObject(samplebuttonAsset8, 0xff8000, 300);\n\tscore += 75;\n\tcombo += 1;\n};\n// Add different functionality to second samplebutton\nsamplebuttonAsset2.down = function (x, y, obj) {\n\t// Play sample2 sound (different from first button)\n\tLK.getSound('sample2').play();\n\t// Visual feedback - scale animation\n\ttween(samplebuttonAsset2, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAsset2, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with different color\n\tLK.effects.flashObject(samplebuttonAsset2, 0x00ff00, 300);\n\t// Add score bonus for using sample buttons\n\tscore += 50;\n\tcombo += 1;\n};\n// --- Right Side Sample Buttons (First Line) ---\n// --- First Samplebutton Right Side First Line ---\nvar samplebuttonAssetR1 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAssetR1);\nsamplebuttonAssetR1.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR1.width / 2 - 50 + 4;\nsamplebuttonAssetR1.y = sampletableAsset.y - samplebuttonAssetR1.height / 2 - 50;\n// Add functionality to first right side samplebutton\nsamplebuttonAssetR1.down = function (x, y, obj) {\n\t// Play sample1 sound\n\tLK.getSound('sample1').play();\n\t// Visual feedback - scale animation\n\ttween(samplebuttonAssetR1, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAssetR1, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect\n\tLK.effects.flashObject(samplebuttonAssetR1, 0xff0000, 300);\n};\n// --- Second Samplebutton Right Side First Line ---\nvar samplebuttonAssetR2 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAssetR2);\nsamplebuttonAssetR2.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR2.width / 2 - 200 + 4;\nsamplebuttonAssetR2.y = sampletableAsset.y - samplebuttonAssetR2.height / 2 - 50;\n// Add functionality to second right side samplebutton\nsamplebuttonAssetR2.down = function (x, y, obj) {\n\t// Play sample2 sound\n\tLK.getSound('sample2').play();\n\t// Visual feedback - scale animation\n\ttween(samplebuttonAssetR2, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAssetR2, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with different color\n\tLK.effects.flashObject(samplebuttonAssetR2, 0x00ff00, 300);\n\t// Add score bonus for using sample buttons\n\tscore += 50;\n\tcombo += 1;\n};\n// --- Third Samplebutton Right Side First Line ---\nvar samplebuttonAssetR3 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAssetR3);\nsamplebuttonAssetR3.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR3.width / 2 - 350 + 4;\nsamplebuttonAssetR3.y = sampletableAsset.y - samplebuttonAssetR3.height / 2 - 50;\n// Add functionality to third right side samplebutton\nsamplebuttonAssetR3.down = function (x, y, obj) {\n\t// Play sample3 sound\n\tLK.getSound('sample3').play();\n\t// Visual feedback - color flash animation\n\ttween(samplebuttonAssetR3, {\n\t\ttint: 0x0000ff\n\t}, {\n\t\tduration: 150,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAssetR3, {\n\t\t\t\ttint: 0xffffff\n\t\t\t}, {\n\t\t\t\tduration: 150\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with blue color\n\tLK.effects.flashObject(samplebuttonAssetR3, 0x0000ff, 300);\n\tscore += 50;\n\tcombo += 1;\n};\n// --- Left Deck Asset ---\nvar leftDeckAsset = LK.getAsset('Deck', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(leftDeckAsset);\nleftDeckAsset.x = rimLeft.x;\nleftDeckAsset.y = rimLeft.y;\n// --- Right Deck Asset ---\nvar rightDeckAsset = LK.getAsset('Deck', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightDeckAsset);\nrightDeckAsset.x = rimRight.x;\nrightDeckAsset.y = rimRight.y;\n// --- Right Side Sample Buttons (Second Line) ---\n// --- First Samplebutton Right Side Second Line ---\nvar samplebuttonAssetR5 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAssetR5);\nsamplebuttonAssetR5.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR5.width / 2 - 50 + 4;\nsamplebuttonAssetR5.y = sampletableAsset.y - samplebuttonAssetR5.height / 2 - 250;\n// Add functionality to fifth right side samplebutton\nsamplebuttonAssetR5.down = function (x, y, obj) {\n\t// Play sample1 sound with different effect\n\tLK.getSound('sample1').play();\n\t// Visual feedback - scale animation\n\ttween(samplebuttonAssetR5, {\n\t\tscaleX: 1.3,\n\t\tscaleY: 1.3\n\t}, {\n\t\tduration: 200,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAssetR5, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 200\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with cyan color\n\tLK.effects.flashObject(samplebuttonAssetR5, 0x00ffff, 300);\n\tscore += 75;\n\tcombo += 1;\n};\n// --- Second Samplebutton Right Side Second Line ---\nvar samplebuttonAssetR6 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAssetR6);\nsamplebuttonAssetR6.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR6.width / 2 - 200 + 4;\nsamplebuttonAssetR6.y = sampletableAsset.y - samplebuttonAssetR6.height / 2 - 250;\n// Add functionality to sixth right side samplebutton\nsamplebuttonAssetR6.down = function (x, y, obj) {\n\t// Play sample2 sound with different effect\n\tLK.getSound('sample2').play();\n\t// Visual feedback - scale animation\n\ttween(samplebuttonAssetR6, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 150,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAssetR6, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 150\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with magenta color\n\tLK.effects.flashObject(samplebuttonAssetR6, 0xff00ff, 300);\n\tscore += 75;\n\tcombo += 1;\n};\n// --- Third Samplebutton Right Side Second Line ---\nvar samplebuttonAssetR7 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAssetR7);\nsamplebuttonAssetR7.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR7.width / 2 - 350 + 4;\nsamplebuttonAssetR7.y = sampletableAsset.y - samplebuttonAssetR7.height / 2 - 250;\n// Add functionality to seventh right side samplebutton\nsamplebuttonAssetR7.down = function (x, y, obj) {\n\t// Play sample3 sound with different effect\n\tLK.getSound('sample3').play();\n\t// Visual feedback - pulsing tint animation\n\ttween(samplebuttonAssetR7, {\n\t\ttint: 0xffff00,\n\t\tscaleX: 0.8,\n\t\tscaleY: 0.8\n\t}, {\n\t\tduration: 120,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAssetR7, {\n\t\t\t\ttint: 0xffffff,\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 120\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with yellow color\n\tLK.effects.flashObject(samplebuttonAssetR7, 0xffff00, 300);\n\tscore += 75;\n\tcombo += 1;\n};\n// --- Fourth Samplebutton Right Side Second Line ---\nvar samplebuttonAssetR8 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAssetR8);\nsamplebuttonAssetR8.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR8.width / 2 - 500 + 4;\nsamplebuttonAssetR8.y = sampletableAsset.y - samplebuttonAssetR8.height / 2 - 250;\n// --- MASTER Asset ---\nvar masterAsset = LK.getAsset('MASTER', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(masterAsset);\nmasterAsset.x = samplebuttonAssetR8.x - samplebuttonAssetR8.width / 2 - masterAsset.width / 2 - 50 - 100; // Position to the left of samplebuttonAssetR8, moved left by 50 units\nmasterAsset.y = samplebuttonAssetR8.y; // Align vertically with samplebuttonAssetR8\n// Add logo asset between the fx and master button\nvar logoAsset = LK.getAsset('Logo', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(logoAsset);\nlogoAsset.x = crossfader.x;\nlogoAsset.y = crossfader.y + crossfader.height / 2 + 30; // Position under the crossfader\n// Add white B letter under master button\nvar masterButtonBText = new Text2('B', {\n\tsize: 48,\n\tfill: 0xFFFFFF // White color\n});\nmasterButtonBText.anchor.set(0.5, 0.5);\nmasterButtonBText.x = masterAsset.x + 150;\nmasterButtonBText.y = masterAsset.y + masterAsset.height / 2 + 20; // Position under the button\ngame.addChild(masterButtonBText);\n// Add functionality to master asset\nmasterAsset.down = function (x, y, obj) {\n\t// Visual feedback - scale animation\n\ttween(masterAsset, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(masterAsset, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with white color\n\tLK.effects.flashObject(masterAsset, 0xffffff, 300);\n\t// Add score bonus\n\tscore += 100;\n\tcombo += 1;\n};\n// --- Fourth Samplebutton Right Side First Line ---\nvar samplebuttonAssetR4 = LK.getAsset('samplebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(samplebuttonAssetR4);\nsamplebuttonAssetR4.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR4.width / 2 - 500 + 4;\nsamplebuttonAssetR4.y = sampletableAsset.y - samplebuttonAssetR4.height / 2 - 50;\n// Add functionality to fourth right side samplebutton\nsamplebuttonAssetR4.down = function (x, y, obj) {\n\t// Play sample4 sound\n\tLK.getSound('sample4').play();\n\t// Visual feedback - pulse animation\n\ttween(samplebuttonAssetR4, {\n\t\talpha: 0.3\n\t}, {\n\t\tduration: 80,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAssetR4, {\n\t\t\t\talpha: 1.0\n\t\t\t}, {\n\t\t\t\tduration: 80\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with purple color\n\tLK.effects.flashObject(samplebuttonAssetR4, 0xff00ff, 300);\n\tscore += 50;\n\tcombo += 1;\n};\n// Add functionality to eighth right side samplebutton\nsamplebuttonAssetR8.down = function (x, y, obj) {\n\t// Play sample4 sound with different effect\n\tLK.getSound('sample4').play();\n\t// Visual feedback - alpha fade\n\ttween(samplebuttonAssetR8, {\n\t\talpha: 0.5\n\t}, {\n\t\tduration: 300,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(samplebuttonAssetR8, {\n\t\t\t\talpha: 1.0\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with orange color\n\tLK.effects.flashObject(samplebuttonAssetR8, 0xff8000, 300);\n\tscore += 75;\n\tcombo += 1;\n};\n// --- Digital Clock (center of map) ---\nvar digitalClockTxt = new Text2('', {\n\tsize: 30,\n\tfill: \"#fff\"\n});\ndigitalClockTxt.anchor.set(0.5, 0.5);\ndigitalClockTxt.x = 2048 / 2;\ndigitalClockTxt.y = 2732 / 2 - 500;\ngame.addChild(digitalClockTxt);\n// Helper to format time as HH:MM:SS\nfunction formatTime(date) {\n\tvar h = date.getHours();\n\tvar m = date.getMinutes();\n\tvar s = date.getSeconds();\n\tfunction pad(n) {\n\t\treturn n < 10 ? '0' + n : n;\n\t}\n\treturn pad(h) + ':' + pad(m) + ':' + pad(s);\n}\n// Score text\nvar scoreTxt = new Text2('Score: 0', {\n\tsize: 80,\n\tfill: \"#fff\"\n});\nscoreTxt.anchor.set(0.5, 0);\nLK.gui.top.addChild(scoreTxt);\nscoreTxt.x = 2048 / 2;\nscoreTxt.y = 300;\n// Combo text\nvar comboTxt = new Text2('', {\n\tsize: 60,\n\tfill: \"#ff0\"\n});\ncomboTxt.anchor.set(0.5, 0);\nLK.gui.top.addChild(comboTxt);\ncomboTxt.x = 2048 / 2;\ncomboTxt.y = 400;\n// --- State ---\nvar dragging = null; // Which control is being dragged\nvar lastTouchObj = null;\n// --- Beat simulation ---\nvar beatInterval = 600; // ms per beat\nvar beatTimer = 0;\nvar lastTickTime = Date.now();\n// --- Music ---\nLK.playMusic('trackA', {\n\tloop: true\n});\nLK.playMusic('trackB', {\n\tloop: true\n});\n// HSV to RGB helper for background color\nfunction hsvToRgb(h, s, v) {\n\tvar r, g, b;\n\tvar i = Math.floor(h * 6);\n\tvar f = h * 6 - i;\n\tvar p = v * (1 - s);\n\tvar q = v * (1 - f * s);\n\tvar t = v * (1 - (1 - f) * s);\n\tswitch (i % 6) {\n\t\tcase 0:\n\t\t\tr = v, g = t, b = p;\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tr = q, g = v, b = p;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tr = p, g = v, b = t;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tr = p, g = q, b = v;\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tr = t, g = p, b = v;\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\tr = v, g = p, b = q;\n\t\t\tbreak;\n\t}\n\treturn [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];\n}\nvar trackAVol = 1;\nvar trackBVol = 1;\n// --- Touch handling ---\nfunction getTouchedControl(x, y) {\n\t// Check decks\n\tvar lx = leftDeck.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t})).x;\n\tvar ly = leftDeck.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t})).y;\n\tif (Math.pow(lx - leftDeck.width / 2, 2) + Math.pow(ly - leftDeck.height / 2, 2) < 200 * 200) return leftDeck;\n\tvar rx = rightDeck.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t})).x;\n\tvar ry = rightDeck.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t})).y;\n\tif (Math.pow(rx - rightDeck.width / 2, 2) + Math.pow(ry - rightDeck.height / 2, 2) < 200 * 200) return rightDeck;\n\t// Crossfader\n\tvar cf = crossfader.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (cf.x > 0 && cf.x < crossfader.width && cf.y > 0 && cf.y < crossfader.height) return crossfader;\n\t// FX Button\n\tvar fx = fxButton.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(fx.x - fxButton.width / 2, 2) + Math.pow(fx.y - fxButton.height / 2, 2) < 60 * 60) return fxButton;\n\t// Check first samplebutton\n\tvar sb1 = samplebuttonAsset.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sb1.x - samplebuttonAsset.width / 2, 2) + Math.pow(sb1.y - samplebuttonAsset.height / 2, 2) < 75 * 75) return samplebuttonAsset;\n\t// Check second samplebutton\n\tvar sb2 = samplebuttonAsset2.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sb2.x - samplebuttonAsset2.width / 2, 2) + Math.pow(sb2.y - samplebuttonAsset2.height / 2, 2) < 75 * 75) return samplebuttonAsset2;\n\t// Check third samplebutton\n\tvar sb3 = samplebuttonAsset3.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sb3.x - samplebuttonAsset3.width / 2, 2) + Math.pow(sb3.y - samplebuttonAsset3.height / 2, 2) < 75 * 75) return samplebuttonAsset3;\n\t// Check fourth samplebutton\n\tvar sb4 = samplebuttonAsset4.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sb4.x - samplebuttonAsset4.width / 2, 2) + Math.pow(sb4.y - samplebuttonAsset4.height / 2, 2) < 75 * 75) return samplebuttonAsset4;\n\t// Check second line sample buttons\n\t// Check fifth samplebutton (second line, first button)\n\tvar sb5 = samplebuttonAsset5.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sb5.x - samplebuttonAsset5.width / 2, 2) + Math.pow(sb5.y - samplebuttonAsset5.height / 2, 2) < 75 * 75) return samplebuttonAsset5;\n\t// Check sixth samplebutton (second line, second button)\n\tvar sb6 = samplebuttonAsset6.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sb6.x - samplebuttonAsset6.width / 2, 2) + Math.pow(sb6.y - samplebuttonAsset6.height / 2, 2) < 75 * 75) return samplebuttonAsset6;\n\t// Check seventh samplebutton (second line, third button)\n\tvar sb7 = samplebuttonAsset7.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sb7.x - samplebuttonAsset7.width / 2, 2) + Math.pow(sb7.y - samplebuttonAsset7.height / 2, 2) < 75 * 75) return samplebuttonAsset7;\n\t// Check eighth samplebutton (second line, fourth button)\n\tvar sb8 = samplebuttonAsset8.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sb8.x - samplebuttonAsset8.width / 2, 2) + Math.pow(sb8.y - samplebuttonAsset8.height / 2, 2) < 75 * 75) return samplebuttonAsset8;\n\t// Check right side sample buttons\n\t// Check first right side samplebutton (first line)\n\tvar sbR1 = samplebuttonAssetR1.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sbR1.x - samplebuttonAssetR1.width / 2, 2) + Math.pow(sbR1.y - samplebuttonAssetR1.height / 2, 2) < 75 * 75) return samplebuttonAssetR1;\n\t// Check second right side samplebutton (first line)\n\tvar sbR2 = samplebuttonAssetR2.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sbR2.x - samplebuttonAssetR2.width / 2, 2) + Math.pow(sbR2.y - samplebuttonAssetR2.height / 2, 2) < 75 * 75) return samplebuttonAssetR2;\n\t// Check third right side samplebutton (first line)\n\tvar sbR3 = samplebuttonAssetR3.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sbR3.x - samplebuttonAssetR3.width / 2, 2) + Math.pow(sbR3.y - samplebuttonAssetR3.height / 2, 2) < 75 * 75) return samplebuttonAssetR3;\n\t// Check fourth right side samplebutton (first line)\n\tvar sbR4 = samplebuttonAssetR4.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sbR4.x - samplebuttonAssetR4.width / 2, 2) + Math.pow(sbR4.y - samplebuttonAssetR4.height / 2, 2) < 75 * 75) return samplebuttonAssetR4;\n\t// Check fifth right side samplebutton (second line)\n\tvar sbR5 = samplebuttonAssetR5.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sbR5.x - samplebuttonAssetR5.width / 2, 2) + Math.pow(sbR5.y - samplebuttonAssetR5.height / 2, 2) < 75 * 75) return samplebuttonAssetR5;\n\t// Check sixth right side samplebutton (second line)\n\tvar sbR6 = samplebuttonAssetR6.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sbR6.x - samplebuttonAssetR6.width / 2, 2) + Math.pow(sbR6.y - samplebuttonAssetR6.height / 2, 2) < 75 * 75) return samplebuttonAssetR6;\n\t// Check seventh right side samplebutton (second line)\n\tvar sbR7 = samplebuttonAssetR7.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sbR7.x - samplebuttonAssetR7.width / 2, 2) + Math.pow(sbR7.y - samplebuttonAssetR7.height / 2, 2) < 75 * 75) return samplebuttonAssetR7;\n\t// Check eighth right side samplebutton (second line)\n\tvar sbR8 = samplebuttonAssetR8.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(sbR8.x - samplebuttonAssetR8.width / 2, 2) + Math.pow(sbR8.y - samplebuttonAssetR8.height / 2, 2) < 75 * 75) return samplebuttonAssetR8;\n\t// Check right loop exit button\n\tvar rightLoopExitLocal = rightLoopExitButton.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(rightLoopExitLocal.x - rightLoopExitButton.width / 2, 2) + Math.pow(rightLoopExitLocal.y - rightLoopExitButton.height / 2, 2) < 50 * 50) return rightLoopExitButton;\n\t// Check right in button\n\tvar rightInLocal = rightInButton.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(rightInLocal.x - rightInButton.width / 2, 2) + Math.pow(rightInLocal.y - rightInButton.height / 2, 2) < 50 * 50) return rightInButton;\n\t// Check right out button\n\tvar rightOutLocal = rightOutButton.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(rightOutLocal.x - rightOutButton.width / 2, 2) + Math.pow(rightOutLocal.y - rightOutButton.height / 2, 2) < 50 * 50) return rightOutButton;\n\t// Check left start button\n\tvar leftStartLocal = leftStartButton.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(leftStartLocal.x - leftStartButton.width / 2, 2) + Math.pow(leftStartLocal.y - leftStartButton.height / 2, 2) < 100 * 100) return leftStartButton;\n\t// Check right start button\n\tvar rightStartLocal = rightStartButton.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(rightStartLocal.x - rightStartButton.width / 2, 2) + Math.pow(rightStartLocal.y - rightStartButton.height / 2, 2) < 100 * 100) return rightStartButton;\n\t// Check left cue button\n\tvar leftCueLocal = leftCueButton.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(leftCueLocal.x - leftCueButton.width / 2, 2) + Math.pow(leftCueLocal.y - leftCueButton.height / 2, 2) < 50 * 50) return leftCueButton;\n\t// Check right cue button\n\tvar rightCueLocal = rightCueButton.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(rightCueLocal.x - rightCueButton.width / 2, 2) + Math.pow(rightCueLocal.y - rightCueButton.height / 2, 2) < 50 * 50) return rightCueButton;\n\t// Check vertical crossfader track\n\tvar verticalCfLocal = verticalCrossfaderTrack.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (verticalCfLocal.x > 0 && verticalCfLocal.x < verticalCrossfaderTrack.width && verticalCfLocal.y > 0 && verticalCfLocal.y < verticalCrossfaderTrack.height) return verticalCrossfaderTrack;\n\t// Check second vertical crossfader track\n\tvar verticalCfLocal2 = verticalCrossfaderTrack2.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (verticalCfLocal2.x > 0 && verticalCfLocal2.x < verticalCrossfaderTrack2.width && verticalCfLocal2.y > 0 && verticalCfLocal2.y < verticalCrossfaderTrack2.height) return verticalCrossfaderTrack2;\n\t// Check filter knobs\n\tvar lfh = leftFilterKnobHigh.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(lfh.x - leftFilterKnobHigh.width / 2, 2) + Math.pow(lfh.y - leftFilterKnobHigh.height / 2, 2) < 60 * 60) return leftFilterKnobHigh;\n\tvar lfm = leftFilterKnobMid.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(lfm.x - leftFilterKnobMid.width / 2, 2) + Math.pow(lfm.y - leftFilterKnobMid.height / 2, 2) < 60 * 60) return leftFilterKnobMid;\n\tvar lfl = leftFilterKnobLow.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(lfl.x - leftFilterKnobLow.width / 2, 2) + Math.pow(lfl.y - leftFilterKnobLow.height / 2, 2) < 60 * 60) return leftFilterKnobLow;\n\tvar rfh = rightFilterKnobHigh.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(rfh.x - rightFilterKnobHigh.width / 2, 2) + Math.pow(rfh.y - rightFilterKnobHigh.height / 2, 2) < 60 * 60) return rightFilterKnobHigh;\n\tvar rfm = rightFilterKnobMid.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(rfm.x - rightFilterKnobMid.width / 2, 2) + Math.pow(rfm.y - rightFilterKnobMid.height / 2, 2) < 60 * 60) return rightFilterKnobMid;\n\tvar rfl = rightFilterKnobLow.toLocal(game.toGlobal({\n\t\tx: x,\n\t\ty: y\n\t}));\n\tif (Math.pow(rfl.x - rightFilterKnobLow.width / 2, 2) + Math.pow(rfl.y - rightFilterKnobLow.height / 2, 2) < 60 * 60) return rightFilterKnobLow;\n}\ngame.down = function (x, y, obj) {\n\tvar control = getTouchedControl(x, y);\n\tdragging = control;\n\tlastTouchObj = obj;\n\tif (control && control.down) {\n\t\t// Convert to local\n\t\tvar local = control.toLocal(game.toGlobal({\n\t\t\tx: x,\n\t\t\ty: y\n\t\t}));\n\t\tcontrol.down(local.x, local.y, obj);\n\t}\n\tlastTouchObj = obj; // Keep track of the object that was touched down\n};\ngame.up = function (x, y, obj) {\n\tif (dragging && dragging.up) {\n\t\tvar local = dragging.toLocal(game.toGlobal({\n\t\t\tx: x,\n\t\t\ty: y\n\t\t}));\n\t\tdragging.up(local.x, local.y, obj);\n\t}\n\t// Reset filter knob drag state for vertical drag mode\n\tif (dragging === leftFilterKnobHigh || dragging === leftFilterKnobMid || dragging === leftFilterKnobLow || dragging === rightFilterKnobHigh || dragging === rightFilterKnobMid || dragging === rightFilterKnobLow) {\n\t\tif (typeof dragging._lastY !== \"undefined\") delete dragging._lastY;\n\t\tif (typeof dragging._rotationValue !== \"undefined\") delete dragging._rotationValue;\n\t}\n\t// Only set dragging to null if the released object was the one being dragged\n\tif (dragging === getTouchedControl(x, y) || !getTouchedControl(x, y)) {\n\t\t// Check if released on the same object or empty space\n\t\tdragging = null;\n\t}\n\tlastTouchObj = null;\n};\ngame.move = function (x, y, obj) {\n\tif (dragging) {\n\t\tvar local = dragging.toLocal(game.toGlobal({\n\t\t\tx: x,\n\t\t\ty: y\n\t\t}));\n\t\tif (dragging === verticalCrossfaderTrack) {\n\t\t\t// Use the object's own move method for consistent behavior\n\t\t\tdragging.move(local.x, local.y, obj);\n\t\t} else if (dragging === verticalCrossfaderTrack2) {\n\t\t\t// Use the object's own move method for consistent behavior\n\t\t\tdragging.move(local.x, local.y, obj);\n\t\t} else if (dragging === leftFilterKnobHigh || dragging === leftFilterKnobMid || dragging === leftFilterKnobLow || dragging === rightFilterKnobHigh || dragging === rightFilterKnobMid || dragging === rightFilterKnobLow) {\n\t\t\t// --- Filter knob rotation logic: vertical drag (up = right, down = left) ---\n\t\t\t// Store lastY on the knob for delta calculation\n\t\t\tif (typeof dragging._lastY === \"undefined\") {\n\t\t\t\tdragging._lastY = local.y;\n\t\t\t\tdragging._rotationValue = dragging.rotation || 0; // Store current rotation in radians\n\t\t\t}\n\t\t\t// Calculate vertical movement delta\n\t\t\tvar deltaY = local.y - dragging._lastY;\n\t\t\t// Sensitivity: how much vertical movement for full rotation (in px)\n\t\t\tvar sensitivity = 120; // 120px drag = full range (-150deg to +150deg)\n\t\t\t// Calculate rotation change: up = right (increase), down = left (decrease)\n\t\t\tvar deltaRotation = -deltaY * (Math.PI * 5 / 6) / sensitivity; // 5/6 PI = 150deg\n\t\t\t// Clamp rotation to -150deg to +150deg\n\t\t\tvar minRotation = -Math.PI * 5 / 6;\n\t\t\tvar maxRotation = Math.PI * 5 / 6;\n\t\t\tdragging._rotationValue = Math.max(minRotation, Math.min(maxRotation, (dragging._rotationValue || 0) + deltaRotation));\n\t\t\tdragging.rotation = dragging._rotationValue;\n\t\t\t// Update lastY for next move\n\t\t\tdragging._lastY = local.y;\n\t\t} else if (dragging.move) {\n\t\t\t// Handle move for other objects that have a move method\n\t\t\tdragging.move(local.x, local.y, obj);\n\t\t}\n\t}\n};\n// --- Start Button State Variables ---\nvar leftStartButtonOn = false;\nvar rightStartButtonOn = false;\n// --- Deck Spinning State Variables ---\nvar leftDeckSpinning = false;\nvar rightDeckSpinning = false;\n// --- Left Start Button ---\nvar leftStartButton = LK.getAsset('Startbutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(leftStartButton);\nleftStartButton.x = rimLeft.x - 200;\nleftStartButton.y = rimLeft.y + rimLeft.height / 2 + leftStartButton.height / 2 + 20;\n// --- Left Cue Button ---\nvar leftCueButton = LK.getAsset('Cuebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(leftCueButton);\nleftCueButton.x = leftStartButton.x + leftStartButton.width / 2 + leftCueButton.width / 2 + 20 + 200 - 20;\nleftCueButton.y = leftStartButton.y;\n// Add functionality to left start button\nleftStartButton.down = function (x, y, obj) {\n\t// Visual feedback - scale animation\n\ttween(leftStartButton, {\n\t\tscaleX: 1.3,\n\t\tscaleY: 1.3\n\t}, {\n\t\tduration: 150,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(leftStartButton, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 150\n\t\t\t});\n\t\t}\n\t});\n\t// Toggle button state\n\tleftStartButtonOn = !leftStartButtonOn;\n\t// Stop any existing tween first\n\ttween.stop(leftStartButton, {\n\t\ttint: true\n\t});\n\tif (leftStartButtonOn) {\n\t\t// Turn on green light effect\n\t\ttween(leftStartButton, {\n\t\t\ttint: 0x00ff00\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\t// Create pulsing green light effect\n\t\t\t\tfunction createPulse() {\n\t\t\t\t\tif (leftStartButtonOn) {\n\t\t\t\t\t\t// Only continue pulsing if still on\n\t\t\t\t\t\ttween(leftStartButton, {\n\t\t\t\t\t\t\ttint: 0x88ff88\n\t\t\t\t\t\t}, {\n\t\t\t\t\t\t\tduration: 800,\n\t\t\t\t\t\t\teasing: tween.easeInOut,\n\t\t\t\t\t\t\tonFinish: function onFinish() {\n\t\t\t\t\t\t\t\tif (leftStartButtonOn) {\n\t\t\t\t\t\t\t\t\t// Only continue pulsing if still on\n\t\t\t\t\t\t\t\t\ttween(leftStartButton, {\n\t\t\t\t\t\t\t\t\t\ttint: 0x00ff00\n\t\t\t\t\t\t\t\t\t}, {\n\t\t\t\t\t\t\t\t\t\tduration: 800,\n\t\t\t\t\t\t\t\t\t\teasing: tween.easeInOut,\n\t\t\t\t\t\t\t\t\t\tonFinish: createPulse\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcreatePulse();\n\t\t\t}\n\t\t});\n\t} else {\n\t\t// Turn off light effect - return to normal tint\n\t\ttween(leftStartButton, {\n\t\t\ttint: 0xffffff\n\t\t}, {\n\t\t\tduration: 200\n\t\t});\n\t}\n\t// Start/stop left deck\n\tleftDeck.playing = !leftDeck.playing;\n\t// Start/stop left deck spinning\n\tleftDeckSpinning = !leftDeckSpinning;\n\tif (leftDeckSpinning) {\n\t\t// Start continuous clockwise spinning synchronized with deckplatter\n\t\tvar _spinLeftDeck = function spinLeftDeck() {\n\t\t\tif (leftDeckSpinning) {\n\t\t\t\t// Synchronize deck asset rotation with deckplatter rotation speed\n\t\t\t\t// Deckplatter rotates at 0.02 radians per frame (60fps), so full rotation takes ~314 frames (~5.23 seconds)\n\t\t\t\t// To match this, deck asset should complete rotation in same time\n\t\t\t\ttween(leftDeckAsset, {\n\t\t\t\t\trotation: leftDeckAsset.rotation + Math.PI * 2\n\t\t\t\t}, {\n\t\t\t\t\tduration: 5233,\n\t\t\t\t\teasing: tween.linear,\n\t\t\t\t\tonFinish: _spinLeftDeck\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\t_spinLeftDeck();\n\t} else {\n\t\t// Stop spinning by stopping any rotation tweens\n\t\ttween.stop(leftDeckAsset, {\n\t\t\trotation: true\n\t\t});\n\t}\n\t// Play beat sound\n\tLK.getSound('beat').play();\n\t// Add score bonus\n\tscore += 100;\n\tcombo += 1;\n};\n// --- Right Start Button ---\nvar rightStartButton = LK.getAsset('Startbutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightStartButton);\nrightStartButton.x = rimRight.x - 200;\nrightStartButton.y = rimRight.y + rimRight.height / 2 + rightStartButton.height / 2 + 20;\n// --- Right Cue Button ---\nvar rightCueButton = LK.getAsset('Cuebutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightCueButton);\nrightCueButton.x = rightStartButton.x + rightStartButton.width / 2 + rightCueButton.width / 2 + 20 + 200 - 20 - 5 - 5;\nrightCueButton.y = rightStartButton.y;\n// Add functionality to right start button\nrightStartButton.down = function (x, y, obj) {\n\t// Visual feedback - scale animation\n\ttween(rightStartButton, {\n\t\tscaleX: 1.3,\n\t\tscaleY: 1.3\n\t}, {\n\t\tduration: 150,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(rightStartButton, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 150\n\t\t\t});\n\t\t}\n\t});\n\t// Toggle button state\n\trightStartButtonOn = !rightStartButtonOn;\n\t// Stop any existing tween first\n\ttween.stop(rightStartButton, {\n\t\ttint: true\n\t});\n\tif (rightStartButtonOn) {\n\t\t// Turn on green light effect\n\t\ttween(rightStartButton, {\n\t\t\ttint: 0x00ff00\n\t\t}, {\n\t\t\tduration: 200,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\t// Create pulsing green light effect\n\t\t\t\tfunction createPulse() {\n\t\t\t\t\tif (rightStartButtonOn) {\n\t\t\t\t\t\t// Only continue pulsing if still on\n\t\t\t\t\t\ttween(rightStartButton, {\n\t\t\t\t\t\t\ttint: 0x88ff88\n\t\t\t\t\t\t}, {\n\t\t\t\t\t\t\tduration: 800,\n\t\t\t\t\t\t\teasing: tween.easeInOut,\n\t\t\t\t\t\t\tonFinish: function onFinish() {\n\t\t\t\t\t\t\t\tif (rightStartButtonOn) {\n\t\t\t\t\t\t\t\t\t// Only continue pulsing if still on\n\t\t\t\t\t\t\t\t\ttween(rightStartButton, {\n\t\t\t\t\t\t\t\t\t\ttint: 0x00ff00\n\t\t\t\t\t\t\t\t\t}, {\n\t\t\t\t\t\t\t\t\t\tduration: 800,\n\t\t\t\t\t\t\t\t\t\teasing: tween.easeInOut,\n\t\t\t\t\t\t\t\t\t\tonFinish: createPulse\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcreatePulse();\n\t\t\t}\n\t\t});\n\t} else {\n\t\t// Turn off light effect - return to normal tint\n\t\ttween(rightStartButton, {\n\t\t\ttint: 0xffffff\n\t\t}, {\n\t\t\tduration: 200\n\t\t});\n\t}\n\t// Start/stop right deck\n\trightDeck.playing = !rightDeck.playing;\n\t// Start/stop right deck spinning\n\trightDeckSpinning = !rightDeckSpinning;\n\tif (rightDeckSpinning) {\n\t\t// Start continuous clockwise spinning synchronized with deckplatter\n\t\tvar _spinRightDeck = function spinRightDeck() {\n\t\t\tif (rightDeckSpinning) {\n\t\t\t\t// Synchronize deck asset rotation with deckplatter rotation speed\n\t\t\t\t// Deckplatter rotates at 0.02 radians per frame (60fps), so full rotation takes ~314 frames (~5.23 seconds)\n\t\t\t\t// To match this, deck asset should complete rotation in same time\n\t\t\t\ttween(rightDeckAsset, {\n\t\t\t\t\trotation: rightDeckAsset.rotation + Math.PI * 2\n\t\t\t\t}, {\n\t\t\t\t\tduration: 5233,\n\t\t\t\t\teasing: tween.linear,\n\t\t\t\t\tonFinish: _spinRightDeck\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t\t_spinRightDeck();\n\t} else {\n\t\t// Stop spinning by stopping any rotation tweens\n\t\ttween.stop(rightDeckAsset, {\n\t\t\trotation: true\n\t\t});\n\t}\n\t// Play beat sound\n\tLK.getSound('beat').play();\n\t// Add score bonus\n\tscore += 100;\n\tcombo += 1;\n};\n// Add functionality to left cue button\nleftCueButton.down = function (x, y, obj) {\n\t// Visual feedback - scale animation\n\ttween(leftCueButton, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(leftCueButton, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with cyan color\n\tLK.effects.flashObject(leftCueButton, 0x00ffff, 300);\n\t// Reset left deck to start position\n\tleftDeck.rotationOffset = 0;\n\tleftDeck.currentRotation = 0;\n\tleftDeck.rotation = 0;\n\t// Play scratch sound\n\tLK.getSound('scratch').play();\n\t// Add score bonus\n\tscore += 50;\n\tcombo += 1;\n};\n// Add functionality to right cue button\nrightCueButton.down = function (x, y, obj) {\n\t// Visual feedback - scale animation\n\ttween(rightCueButton, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(rightCueButton, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with magenta color\n\tLK.effects.flashObject(rightCueButton, 0xff00ff, 300);\n\t// Reset right deck to start position\n\trightDeck.rotationOffset = 0;\n\trightDeck.currentRotation = 0;\n\trightDeck.rotation = 0;\n\t// Play scratch sound\n\tLK.getSound('scratch').play();\n\t// Add score bonus\n\tscore += 50;\n\tcombo += 1;\n};\n// Center left deck platter to the left deck center\nleftDeck.x = leftDeckAsset.x;\nleftDeck.y = leftDeckAsset.y - 3;\n// Center right deck platter to the right deck center\nrightDeck.x = rightDeckAsset.x;\nrightDeck.y = rightDeckAsset.y - 3;\n// --- Screens above decks ---\n// Left deck screen\nvar leftDeckScreen = LK.getAsset('screen', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(leftDeckScreen);\nleftDeckScreen.x = leftDeckAsset.x;\nleftDeckScreen.y = leftDeckAsset.y - leftDeckAsset.height / 2 - leftDeckScreen.height / 2 - 50 - 200;\n// Right deck screen\nvar rightDeckScreen = LK.getAsset('screen', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightDeckScreen);\nrightDeckScreen.x = rightDeckAsset.x;\nrightDeckScreen.y = rightDeckAsset.y - rightDeckAsset.height / 2 - rightDeckScreen.height / 2 - 50 - 200;\n// --- Effect Buttons Above Screens ---\nvar effectButtons = [];\nvar effectButtonSpacing = 220;\nvar effectButtonY = leftDeckScreen.y - leftDeckScreen.height / 2 - 80 - 55;\n// Create 6 effect buttons (3 above each screen)\nfor (var i = 0; i < 6; i++) {\n\tvar effectButton = LK.getAsset('Effect', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5\n\t});\n\tgame.addChild(effectButton);\n\t// Position 3 buttons above left screen, 3 above right screen\n\tif (i < 3) {\n\t\t// Left side buttons\n\t\teffectButton.x = leftDeckScreen.x - effectButtonSpacing + i * effectButtonSpacing;\n\t} else {\n\t\t// Right side buttons\n\t\teffectButton.x = rightDeckScreen.x - effectButtonSpacing + (i - 3) * effectButtonSpacing;\n\t}\n\teffectButton.y = effectButtonY;\n\t// Add 'FIRE' text above the first effect button (i === 0)\n\tif (i === 0) {\n\t\tvar fireText = new Text2('FIRE', {\n\t\t\tsize: 36,\n\t\t\tfill: 0xFFFFFF\n\t\t});\n\t\tfireText.anchor.set(0.5, 0.5);\n\t\tfireText.x = effectButton.x;\n\t\tfireText.y = effectButton.y - effectButton.height / 2 - 80;\n\t\tgame.addChild(fireText);\n\t}\n\t// Add 'LASER' text above the second effect button (i === 1)\n\tif (i === 1) {\n\t\tvar laserText = new Text2('LASER', {\n\t\t\tsize: 36,\n\t\t\tfill: 0xFFFFFF\n\t\t});\n\t\tlaserText.anchor.set(0.5, 0.5);\n\t\tlaserText.x = effectButton.x;\n\t\tlaserText.y = effectButton.y - effectButton.height / 2 - 80;\n\t\tgame.addChild(laserText);\n\t}\n\t// Add 'LIGHT' text above the third effect button (i === 2)\n\tif (i === 2) {\n\t\tvar lightText = new Text2('LIGHT', {\n\t\t\tsize: 36,\n\t\t\tfill: 0xFFFFFF\n\t\t});\n\t\tlightText.anchor.set(0.5, 0.5);\n\t\tlightText.x = effectButton.x;\n\t\tlightText.y = effectButton.y - effectButton.height / 2 - 80;\n\t\tgame.addChild(lightText);\n\t\t// Store the third effect button for later access\n\t\teffectButtons[i] = effectButton;\n\t}\n\t// Add 'SMOKE' text above the fourth effect button (i === 3)\n\tif (i === 3) {\n\t\tvar smokeText = new Text2('SMOKE', {\n\t\t\tsize: 36,\n\t\t\tfill: 0xFFFFFF\n\t\t});\n\t\tsmokeText.anchor.set(0.5, 0.5);\n\t\tsmokeText.x = effectButton.x;\n\t\tsmokeText.y = effectButton.y - effectButton.height / 2 - 80;\n\t\tgame.addChild(smokeText);\n\t}\n\t// Add 'UV' text above the fifth effect button (i === 4)\n\tif (i === 4) {\n\t\tvar uvText = new Text2('UV', {\n\t\t\tsize: 36,\n\t\t\tfill: 0xFFFFFF\n\t\t});\n\t\tuvText.anchor.set(0.5, 0.5);\n\t\tuvText.x = effectButton.x;\n\t\tuvText.y = effectButton.y - effectButton.height / 2 - 80;\n\t\tgame.addChild(uvText);\n\t}\n\t// Add 'GIFTS' text above the sixth effect button (i === 5)\n\tif (i === 5) {\n\t\tvar giftsText = new Text2('GIFTS', {\n\t\t\tsize: 36,\n\t\t\tfill: 0xFFFFFF\n\t\t});\n\t\tgiftsText.anchor.set(0.5, 0.5);\n\t\tgiftsText.x = effectButton.x;\n\t\tgiftsText.y = effectButton.y - effectButton.height / 2 - 80;\n\t\tgame.addChild(giftsText);\n\t}\n\t// Scale up effect button by 1.5\n\ttween(effectButton, {\n\t\tscaleX: 1.5,\n\t\tscaleY: 1.5\n\t}, {\n\t\tduration: 300,\n\t\teasing: tween.easeOut\n\t});\n\t// Add up handler for SMOKE button (index 3)\n\tif (i === 3) {\n\t\teffectButton.down = function (x, y, obj) {\n\t\t\tsmokeEffectActive = true;\n\t\t\tfogAnimationActive = true;\n\t\t\t// Clear any existing fog timeout\n\t\t\tif (fogTimeout) {\n\t\t\t\tLK.clearTimeout(fogTimeout);\n\t\t\t\tfogTimeout = null;\n\t\t\t}\n\t\t\ttween(this, {\n\t\t\t\tscaleX: 1.7,\n\t\t\t\tscaleY: 1.7\n\t\t\t}, {\n\t\t\t\tduration: 150,\n\t\t\t\tonFinish: function () {\n\t\t\t\t\ttween(this, {\n\t\t\t\t\t\tscaleX: 1.5,\n\t\t\t\t\t\tscaleY: 1.5\n\t\t\t\t\t}, {\n\t\t\t\t\t\tduration: 150\n\t\t\t\t\t});\n\t\t\t\t}.bind(this)\n\t\t\t});\n\t\t\tLK.getSound('fx').play();\n\t\t\tLK.effects.flashObject(this, 0x888888, 200);\n\t\t};\n\t\teffectButton.up = function (x, y, obj) {\n\t\t\tsmokeEffectActive = false;\n\t\t\t// Start 4 second countdown to turn off fog animation\n\t\t\tfogTimeout = LK.setTimeout(function () {\n\t\t\t\tfogAnimationActive = false;\n\t\t\t\tfogTimeout = null;\n\t\t\t}, 4000);\n\t\t\t// Optionally, provide a quick scale feedback on release\n\t\t\ttween(this, {\n\t\t\t\tscaleX: 1.5,\n\t\t\t\tscaleY: 1.5\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t};\n\t} else {\n\t\t// Add functionality to other effect buttons\n\t\teffectButton.down = function (x, y, obj) {\n\t\t\t// Visual feedback - scale animation that returns to 1.5 instead of 1.0\n\t\t\ttween(this, {\n\t\t\t\tscaleX: 1.7,\n\t\t\t\tscaleY: 1.7\n\t\t\t}, {\n\t\t\t\tduration: 150,\n\t\t\t\tonFinish: function () {\n\t\t\t\t\ttween(this, {\n\t\t\t\t\t\tscaleX: 1.5,\n\t\t\t\t\t\tscaleY: 1.5\n\t\t\t\t\t}, {\n\t\t\t\t\t\tduration: 150\n\t\t\t\t\t});\n\t\t\t\t}.bind(this)\n\t\t\t});\n\t\t\t// Play FX sound\n\t\t\tLK.getSound('fx').play();\n\t\t\t// Flash effect with random color\n\t\t\tvar colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];\n\t\t\tvar randomColor = colors[Math.floor(Math.random() * colors.length)];\n\t\t\tLK.effects.flashObject(this, randomColor, 400);\n\t\t\t// Add score bonus\n\t\t\tscore += 75;\n\t\t\tcombo += 1;\n\t\t};\n\t}\n\t// If this is the first effect button (index 0) - FIRE button\n\tif (i === 0) {\n\t\teffectButton.down = function (x, y, obj) {\n\t\t\t// Visual feedback - scale animation that returns to 1.5 instead of 1.0\n\t\t\ttween(this, {\n\t\t\t\tscaleX: 1.7,\n\t\t\t\tscaleY: 1.7\n\t\t\t}, {\n\t\t\t\tduration: 150,\n\t\t\t\tonFinish: function () {\n\t\t\t\t\ttween(this, {\n\t\t\t\t\t\tscaleX: 1.5,\n\t\t\t\t\t\tscaleY: 1.5\n\t\t\t\t\t}, {\n\t\t\t\t\t\tduration: 150\n\t\t\t\t\t});\n\t\t\t\t}.bind(this)\n\t\t\t});\n\t\t\t// Play FX sound\n\t\t\tLK.getSound('fx').play();\n\t\t\t// Cycle through fire effect modes: 0 (off) -> 1 (normal) -> 2 (big) -> 0 (off)\n\t\t\tfireEffectMode = (fireEffectMode + 1) % 3;\n\t\t\t// Flash effect with different colors based on mode\n\t\t\tvar fireColors;\n\t\t\tif (fireEffectMode === 0) {\n\t\t\t\t// Off mode - gray color\n\t\t\t\tfireColors = [0x888888];\n\t\t\t} else if (fireEffectMode === 1) {\n\t\t\t\t// Normal mode - orange colors\n\t\t\t\tfireColors = [0xff8000, 0xff4400, 0xffaa00];\n\t\t\t} else {\n\t\t\t\t// Big flames mode - red colors\n\t\t\t\tfireColors = [0xff0000, 0xff4444, 0xff8888];\n\t\t\t}\n\t\t\tvar randomColor = fireColors[Math.floor(Math.random() * fireColors.length)];\n\t\t\tLK.effects.flashObject(this, randomColor, 400);\n\t\t\t// Add score bonus\n\t\t\tscore += 75;\n\t\t\tcombo += 1;\n\t\t};\n\t}\n\teffectButtons.push(effectButton);\n\t// If this is the second effect button (index 1) - LASER button\n\tif (i === 1) {\n\t\teffectButton.down = function (x, y, obj) {\n\t\t\t// Visual feedback - scale animation that returns to 1.5 instead of 1.0\n\t\t\ttween(this, {\n\t\t\t\tscaleX: 1.7,\n\t\t\t\tscaleY: 1.7\n\t\t\t}, {\n\t\t\t\tduration: 150,\n\t\t\t\tonFinish: function () {\n\t\t\t\t\ttween(this, {\n\t\t\t\t\t\tscaleX: 1.5,\n\t\t\t\t\t\tscaleY: 1.5\n\t\t\t\t\t}, {\n\t\t\t\t\t\tduration: 150\n\t\t\t\t\t});\n\t\t\t\t}.bind(this)\n\t\t\t});\n\t\t\t// Play FX sound\n\t\t\tLK.getSound('fx').play();\n\t\t\t// Cycle through laser show modes: 0 (off) -> 1 (slow) -> 2 (fast) -> 0 (off)\n\t\t\tlaserShowMode = (laserShowMode + 1) % 3;\n\t\t\t// Flash effect with different colors based on mode\n\t\t\tvar laserColors;\n\t\t\tif (laserShowMode === 0) {\n\t\t\t\t// Off mode - gray color\n\t\t\t\tlaserColors = [0x888888];\n\t\t\t} else if (laserShowMode === 1) {\n\t\t\t\t// Slow mode - blue colors\n\t\t\t\tlaserColors = [0x0000ff, 0x4444ff, 0x8888ff];\n\t\t\t} else {\n\t\t\t\t// Fast mode - rainbow colors\n\t\t\t\tlaserColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];\n\t\t\t}\n\t\t\tvar randomColor = laserColors[Math.floor(Math.random() * laserColors.length)];\n\t\t\tLK.effects.flashObject(this, randomColor, 400);\n\t\t\t// Add score bonus\n\t\t\tscore += 75;\n\t\t\tcombo += 1;\n\t\t};\n\t}\n\t// If this is the third effect button (index 2)\n\tif (i === 2) {\n\t\teffectButton.down = function (x, y, obj) {\n\t\t\t// Visual feedback - scale animation that returns to 1.5 instead of 1.0\n\t\t\ttween(this, {\n\t\t\t\tscaleX: 1.7,\n\t\t\t\tscaleY: 1.7\n\t\t\t}, {\n\t\t\t\tduration: 150,\n\t\t\t\tonFinish: function () {\n\t\t\t\t\ttween(this, {\n\t\t\t\t\t\tscaleX: 1.5,\n\t\t\t\t\t\tscaleY: 1.5\n\t\t\t\t\t}, {\n\t\t\t\t\t\tduration: 150\n\t\t\t\t\t});\n\t\t\t\t}.bind(this)\n\t\t\t});\n\t\t\t// Play FX sound\n\t\t\tLK.getSound('fx').play();\n\t\t\t// Flash effect with random color\n\t\t\tvar colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];\n\t\t\tvar randomColor = colors[Math.floor(Math.random() * colors.length)];\n\t\t\tLK.effects.flashObject(this, randomColor, 400);\n\t\t\t// Add score bonus\n\t\t\tscore += 75;\n\t\t\tcombo += 1;\n\t\t\t// Toggle RGB flashing state\n\t\t\tisRgbFlashingActive = !isRgbFlashingActive;\n\t\t};\n\t}\n\t// Define variable to track the gifts button mode\n\tvar giftsMode = 0; // 0: off, 1: balloons, 2: money, 3: fireworks\n\t// Reference the gifts effect button\n\tvar giftsEffectButton;\n\t// If this is the fifth effect button (index 4) - UV button\n\tif (i === 4) {\n\t\teffectButton.down = function (x, y, obj) {\n\t\t\t// Visual feedback - scale animation that returns to 1.5 instead of 1.0\n\t\t\ttween(this, {\n\t\t\t\tscaleX: 1.7,\n\t\t\t\tscaleY: 1.7\n\t\t\t}, {\n\t\t\t\tduration: 150,\n\t\t\t\tonFinish: function () {\n\t\t\t\t\ttween(this, {\n\t\t\t\t\t\tscaleX: 1.5,\n\t\t\t\t\t\tscaleY: 1.5\n\t\t\t\t\t}, {\n\t\t\t\t\t\tduration: 150\n\t\t\t\t\t});\n\t\t\t\t}.bind(this)\n\t\t\t});\n\t\t\t// Play FX sound\n\t\t\tLK.getSound('fx').play();\n\t\t\t// Toggle UV effect state\n\t\t\tuvEffectActive = !uvEffectActive;\n\t\t\t// Flash effect with different colors based on mode\n\t\t\tvar flashColor = uvEffectActive ? 0x8000ff : 0x888888; // Purple for ON, gray for OFF\n\t\t\tLK.effects.flashObject(this, flashColor, 400);\n\t\t\t// Add score bonus\n\t\t\tscore += 75;\n\t\t\tcombo += 1;\n\t\t};\n\t\t// Add a reference to the UV button for flashing in update\n\t\teffectButtons[4] = effectButton;\n\t}\n\t// If this is the sixth effect button (index 5) - GIFTS button\n\tif (i === 5) {\n\t\tgiftsEffectButton = effectButton; // Store reference to gifts button\n\t\teffectButton.down = function (x, y, obj) {\n\t\t\t// Cycle through gift modes\n\t\t\tgiftsMode = (giftsMode + 1) % 4;\n\t\t\t// Visual feedback - scale animation\n\t\t\ttween(this, {\n\t\t\t\tscaleX: 1.7,\n\t\t\t\tscaleY: 1.7\n\t\t\t}, {\n\t\t\t\tduration: 150,\n\t\t\t\tonFinish: function () {\n\t\t\t\t\ttween(this, {\n\t\t\t\t\t\tscaleX: 1.5,\n\t\t\t\t\t\tscaleY: 1.5\n\t\t\t\t\t}, {\n\t\t\t\t\t\tduration: 150\n\t\t\t\t\t});\n\t\t\t\t}.bind(this)\n\t\t\t});\n\t\t\t// Play FX sound\n\t\t\tLK.getSound('fx').play();\n\t\t\t// Add score bonus\n\t\t\tscore += 100;\n\t\t\tcombo += 1;\n\t\t};\n\t}\n}\n// Tablet between the two screens\nvar tabletAsset = LK.getAsset('tablet', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(tabletAsset);\n// Ensure screens exist before positioning tablet\nif (typeof leftDeckScreen !== 'undefined' && typeof rightDeckScreen !== 'undefined') {\n\ttabletAsset.x = (leftDeckScreen.x + rightDeckScreen.x) / 2;\n\ttabletAsset.y = leftDeckScreen.y + 77 + 35 - 20;\n} else {\n\t// Fallback positioning if screens are not defined\n\ttabletAsset.x = 2048 / 2;\n\ttabletAsset.y = 1366;\n}\n// Create rekordbox app instance\nvar rekordboxApp = new RekordboxApp();\ngame.addChild(rekordboxApp);\n// Position and scale rekordbox app to fit tablet screen\nrekordboxApp.x = tabletAsset.x - tabletAsset.width / 2 + 20 + 30;\nrekordboxApp.y = tabletAsset.y - tabletAsset.height / 2 + 20 - 200 - 25;\n// Create keyboard app instance\nvar keyboardApp = new KeyboardApp();\ngame.addChild(keyboardApp);\n// Position and scale keyboard app under the tracklist\nkeyboardApp.x = rekordboxApp.x - 777; // Align with rekordbox app and move left by 777 units\nkeyboardApp.y = rekordboxApp.y + rekordboxApp.height + 10 + 777 - 300 + 200 - 100 - 100; // Position below tracklist with spacing and move down by 777 units, then up by 300, then down by 200, then up by 100, then up by 100\nkeyboardApp.scaleX = rekordboxApp.scaleX * 1.1; // Match scale and adjust slightly\nkeyboardApp.scaleY = keyboardApp.scaleX; // Maintain aspect ratio\nkeyboardApp.visible = false; // Hide the keyboard initially\n// Scale up keyboard app to 3x size using tween animation\ntween(keyboardApp, {\n\tscaleX: 3.0,\n\tscaleY: 3.0\n}, {\n\tduration: 500,\n\teasing: tween.easeOut\n});\n// Scale down to better fit the tablet asset by 1.1\ntween(rekordboxApp, {\n\tscaleX: 0.95 / 1.1,\n\tscaleY: 0.95 / 1.1\n}, {\n\tduration: 500,\n\teasing: tween.easeOut\n});\n// Add tablet press functionality to pop up fullscreen tracklist\ntabletAsset.down = function (x, y, obj) {\n\t// Create fullscreen tracklist popup\n\tvar fullscreenTracklist = new RekordboxApp();\n\t// Add to game at top layer\n\tgame.addChild(fullscreenTracklist);\n\tkeyboardApp.visible = true; // Show the keyboard app\n\t// Ensure keyboard is above the overlay and tracklist\n\tgame.addChild(keyboardApp);\n\t// Position fullscreen - center on screen and move to top\n\tfullscreenTracklist.x = 2048 / 2 - 371 - 600; // Half of app width (742/2)\n\tfullscreenTracklist.y = 0 + 269; // Move to top of tablet height\n\t// Scale to fullscreen size\n\tfullscreenTracklist.scaleX = 2.5 * 1.05;\n\tfullscreenTracklist.scaleY = 2.5 * 1.05;\n\t// Create semi-transparent background overlay\n\tvar overlay = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: 2048,\n\t\theight: 2732\n\t});\n\toverlay.tint = 0x000000;\n\toverlay.alpha = 0.7;\n\toverlay.x = 0;\n\toverlay.y = 0;\n\t// Add overlay behind the app\n\tgame.addChild(overlay);\n\tgame.setChildIndex(overlay, game.children.indexOf(fullscreenTracklist) - 1);\n\t// Add X (close window) button to the full screen song maker app top right corner\n\tvar closeButton = LK.getAsset('X', {\n\t\tanchorX: 1.0,\n\t\tanchorY: 0.0\n\t});\n\tcloseButton.scaleX = 2.0;\n\tcloseButton.scaleY = 2.0;\n\tcloseButton.x = 2048 - 20; // 20px from right edge\n\tcloseButton.y = 20; // 20px from top edge\n\tgame.addChild(closeButton);\n\t// Add close functionality to the X button\n\tcloseButton.down = function (x, y, obj) {\n\t\t// Remove fullscreen song maker app, overlay, and close button\n\t\tif (game.children.indexOf(fullscreenTracklist) !== -1) {\n\t\t\tgame.removeChild(fullscreenTracklist);\n\t\t}\n\t\tif (game.children.indexOf(overlay) !== -1) {\n\t\t\tgame.removeChild(overlay);\n\t\t}\n\t\tif (game.children.indexOf(closeButton) !== -1) {\n\t\t\tgame.removeChild(closeButton);\n\t\t}\n\t\tkeyboardApp.visible = false; // Hide the keyboard app\n\t};\n\t// Add close functionality when clicking overlay\n\toverlay.down = function (x, y, obj) {\n\t\t// Remove fullscreen tracklist and overlay\n\t\tif (game.children.indexOf(fullscreenTracklist) !== -1) {\n\t\t\tgame.removeChild(fullscreenTracklist);\n\t\t}\n\t\tif (game.children.indexOf(overlay) !== -1) {\n\t\t\tgame.removeChild(overlay);\n\t\t}\n\t\tif (game.children.indexOf(closeButton) !== -1) {\n\t\t\tgame.removeChild(closeButton);\n\t\t}\n\t\tkeyboardApp.visible = false; // Hide the keyboard app\n\t};\n\t// Visual feedback for tablet press\n\ttween(tabletAsset, {\n\t\tscaleX: 1.1,\n\t\tscaleY: 1.1\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(tabletAsset, {\n\t\t\t\tscaleX: 1.0,\n\t\t\t\tscaleY: 1.0\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Play sound effect\n\tLK.getSound('fx').play();\n};\n// --- IN Button under tablet screen ---\nvar inButton = LK.getAsset('in', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(inButton);\ninButton.x = tabletAsset.x - 700 - 200 - 12;\ninButton.y = tabletAsset.y + tabletAsset.height / 2 + inButton.height / 2 + 20 - 300 + 77;\n// Add whitegray text: ADJUST above in buttons\nvar adjustTextLeft = new Text2('ADJUST', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\nadjustTextLeft.anchor.set(0.5, 0.5);\nadjustTextLeft.x = inButton.x + 107;\nadjustTextLeft.y = inButton.y - inButton.height / 2 - 20; // Position above the button\ngame.addChild(adjustTextLeft);\n// Add whitegray text: IN under in buttons\nvar inTextLeft = new Text2('IN', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\ninTextLeft.anchor.set(0.5, 0.5);\ninTextLeft.x = inButton.x;\ninTextLeft.y = inButton.y + inButton.height / 2 + 20; // Position under the button\ngame.addChild(inTextLeft);\n// Add functionality to IN button\ninButton.down = function (x, y, obj) {\n\t// Stop any existing flashing effect first\n\ttween.stop(inButton, {\n\t\ttint: true\n\t});\n\t// Start flashing orange light effect\n\tfunction createOrangeFlash() {\n\t\ttween(inButton, {\n\t\t\ttint: 0xff8000 // Orange color\n\t\t}, {\n\t\t\tduration: 300,\n\t\t\teasing: tween.easeInOut,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\ttween(inButton, {\n\t\t\t\t\ttint: 0xffffff // Back to white/normal\n\t\t\t\t}, {\n\t\t\t\t\tduration: 300,\n\t\t\t\t\teasing: tween.easeInOut,\n\t\t\t\t\tonFinish: createOrangeFlash // Continue flashing\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\tcreateOrangeFlash();\n\t// Add score bonus\n\tscore += 25;\n\tcombo += 1;\n};\n// --- OUT Button under tablet screen ---\nvar outButton = LK.getAsset('Out', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(outButton);\noutButton.x = tabletAsset.x + 700 + 200;\noutButton.y = tabletAsset.y + tabletAsset.height / 2 + outButton.height / 2 + 20 - 300 + 77;\n// --- Right IN Button to the left of right OUT button ---\nvar rightInButton = LK.getAsset('in', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightInButton);\nrightInButton.x = outButton.x - 192 - 200 - 12;\nrightInButton.y = outButton.y;\n// Create right ADJUST text now that rightInButton is defined\nvar adjustTextRight = new Text2('ADJUST', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\nadjustTextRight.anchor.set(0.5, 0.5);\nadjustTextRight.x = rightInButton.x + 107;\nadjustTextRight.y = rightInButton.y - rightInButton.height / 2 - 20; // Position above the button\ngame.addChild(adjustTextRight);\n// Add whitegray text: IN under right in buttons\nvar inTextRight = new Text2('IN', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\ninTextRight.anchor.set(0.5, 0.5);\ninTextRight.x = rightInButton.x;\ninTextRight.y = rightInButton.y + rightInButton.height / 2 + 20; // Position under the button\ngame.addChild(inTextRight);\n// Add functionality to right IN button\nrightInButton.down = function (x, y, obj) {\n\t// Stop any existing flashing effect first\n\ttween.stop(rightInButton, {\n\t\ttint: true\n\t});\n\t// Start flashing orange light effect\n\tfunction createOrangeFlash() {\n\t\ttween(rightInButton, {\n\t\t\ttint: 0xff8000 // Orange color\n\t\t}, {\n\t\t\tduration: 300,\n\t\t\teasing: tween.easeInOut,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\ttween(rightInButton, {\n\t\t\t\t\ttint: 0xffffff // Back to white/normal\n\t\t\t\t}, {\n\t\t\t\t\tduration: 300,\n\t\t\t\t\teasing: tween.easeInOut,\n\t\t\t\t\tonFinish: createOrangeFlash // Continue flashing\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\tcreateOrangeFlash();\n\t// Add score bonus\n\tscore += 25;\n\tcombo += 1;\n};\n// --- OUT Button above left deck ---\nvar outButtonLeft = LK.getAsset('Out', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(outButtonLeft);\noutButtonLeft.x = leftDeckAsset.x + 192 - 200;\noutButtonLeft.y = inButton.y;\n// --- Loop Exit Button on the right side of left out button ---\nvar loopExitButton = LK.getAsset('LoopExit', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(loopExitButton);\nloopExitButton.x = outButtonLeft.x + 150 + 50;\nloopExitButton.y = outButtonLeft.y;\n// Add whitegray text: OUT under left out button\nvar outTextLeft = new Text2('OUT', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\noutTextLeft.anchor.set(0.5, 0.5);\noutTextLeft.x = outButtonLeft.x;\noutTextLeft.y = inTextLeft.y - 3; // Position at same height as IN text, moved up by 3 units\ngame.addChild(outTextLeft);\n// Add whitegray text: LOOP between left out button and left loop exit button\nvar loopTextLeft = new Text2('LOOP', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\nloopTextLeft.anchor.set(0.5, 0.5);\nloopTextLeft.x = (outButtonLeft.x + loopExitButton.x) / 2;\nloopTextLeft.y = adjustTextLeft.y; // Position at same height as ADJUST text\ngame.addChild(loopTextLeft);\n// Add whitegray text: EXIT under left loop exit button\nvar exitTextLeft = new Text2('EXIT', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\nexitTextLeft.anchor.set(0.5, 0.5);\nexitTextLeft.x = loopExitButton.x;\nexitTextLeft.y = loopExitButton.y + loopExitButton.height / 2 + 20; // Position under the button\ngame.addChild(exitTextLeft);\n// Add functionality to loop exit button\nloopExitButton.down = function (x, y, obj) {\n\t// Visual feedback - scale animation\n\ttween(loopExitButton, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(loopExitButton, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with purple color\n\tLK.effects.flashObject(loopExitButton, 0x8000ff, 300);\n\t// Add score bonus\n\tscore += 30;\n\tcombo += 1;\n};\n// Add functionality to left OUT button\noutButtonLeft.down = function (x, y, obj) {\n\t// Stop any existing flashing effect first\n\ttween.stop(outButtonLeft, {\n\t\ttint: true\n\t});\n\t// Stop flashing the corresponding 'in' button\n\ttween.stop(inButton, {\n\t\ttint: true\n\t});\n\tinButton.tint = 0xffffff; // Reset tint to normal\n\t// Start flashing orange light effect\n\tfunction createOrangeFlash() {\n\t\ttween(outButtonLeft, {\n\t\t\ttint: 0xff8000 // Orange color\n\t\t}, {\n\t\t\tduration: 300,\n\t\t\teasing: tween.easeInOut,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\ttween(outButtonLeft, {\n\t\t\t\t\ttint: 0xffffff // Back to white/normal\n\t\t\t\t}, {\n\t\t\t\t\tduration: 300,\n\t\t\t\t\teasing: tween.easeInOut,\n\t\t\t\t\tonFinish: createOrangeFlash // Continue flashing\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\tcreateOrangeFlash();\n\t// Add score bonus\n\tscore += 25;\n\tcombo += 1;\n};\n// --- Right OUT Button ---\nvar rightOutButton = LK.getAsset('Out', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightOutButton);\nrightOutButton.x = rightDeckAsset.x + 192 - 200;\nrightOutButton.y = inButton.y;\n// --- Right Loop Exit Button next to right out button ---\nvar rightLoopExitButton = LK.getAsset('LoopExit', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightLoopExitButton);\nrightLoopExitButton.x = rightOutButton.x + 150 + 50 + 5;\nrightLoopExitButton.y = rightOutButton.y;\n// Add functionality to right loop exit button\nrightLoopExitButton.down = function (x, y, obj) {\n\t// Visual feedback - scale animation\n\ttween(rightLoopExitButton, {\n\t\tscaleX: 1.2,\n\t\tscaleY: 1.2\n\t}, {\n\t\tduration: 100,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(rightLoopExitButton, {\n\t\t\t\tscaleX: 1,\n\t\t\t\tscaleY: 1\n\t\t\t}, {\n\t\t\t\tduration: 100\n\t\t\t});\n\t\t}\n\t});\n\t// Flash effect with purple color\n\tLK.effects.flashObject(rightLoopExitButton, 0x8000ff, 300);\n\t// Add score bonus\n\tscore += 30;\n\tcombo += 1;\n};\n// Add whitegray text: OUT under right out button\nvar outTextRight = new Text2('OUT', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\noutTextRight.anchor.set(0.5, 0.5);\noutTextRight.x = rightOutButton.x;\noutTextRight.y = inTextRight.y - 3; // Position at same height as IN text, moved up by 3 units\ngame.addChild(outTextRight);\n// Add whitegray text: LOOP between right out button and right loop exit button\nvar loopTextRight = new Text2('LOOP', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\nloopTextRight.anchor.set(0.5, 0.5);\nloopTextRight.x = (rightOutButton.x + rightLoopExitButton.x) / 2;\nloopTextRight.y = adjustTextRight.y; // Position at same height as ADJUST text\ngame.addChild(loopTextRight);\n// Add whitegray text: EXIT under right loop exit button\nvar exitTextRight = new Text2('EXIT', {\n\tsize: 24,\n\tfill: 0xCCCCCC // Whitegray color\n});\nexitTextRight.anchor.set(0.5, 0.5);\nexitTextRight.x = rightLoopExitButton.x;\nexitTextRight.y = rightLoopExitButton.y + rightLoopExitButton.height / 2 + 20; // Position under the button\ngame.addChild(exitTextRight);\n// Add functionality to right OUT button\nrightOutButton.down = function (x, y, obj) {\n\t// Stop any existing flashing effect first\n\ttween.stop(rightOutButton, {\n\t\ttint: true\n\t});\n\t// Stop flashing the corresponding 'in' button\n\ttween.stop(rightInButton, {\n\t\ttint: true\n\t});\n\trightInButton.tint = 0xffffff; // Reset tint to normal\n\t// Start flashing orange light effect\n\tfunction createOrangeFlash() {\n\t\ttween(rightOutButton, {\n\t\t\ttint: 0xff8000 // Orange color\n\t\t}, {\n\t\t\tduration: 300,\n\t\t\teasing: tween.easeInOut,\n\t\t\tonFinish: function onFinish() {\n\t\t\t\ttween(rightOutButton, {\n\t\t\t\t\ttint: 0xffffff // Back to white/normal\n\t\t\t\t}, {\n\t\t\t\t\tduration: 300,\n\t\t\t\t\teasing: tween.easeInOut,\n\t\t\t\t\tonFinish: createOrangeFlash // Continue flashing\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\tcreateOrangeFlash();\n\t// Add score bonus\n\tscore += 25;\n\tcombo += 1;\n};\n// --- Connecting Lines between In and Out Buttons ---\n// Line between inButton and outButtonLeft\nvar lineInToOutLeft = LK.getAsset('crossfaderTrack', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\twidth: Math.abs(outButtonLeft.x - inButton.x) - 120,\n\theight: 3\n});\ngame.addChild(lineInToOutLeft);\nlineInToOutLeft.x = (inButton.x + outButtonLeft.x) / 2;\nlineInToOutLeft.y = inButton.y;\nlineInToOutLeft.tint = 0x888888; // Gray color\n// Line between rightInButton and rightOutButton\nvar lineRightInToOut = LK.getAsset('crossfaderTrack', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\twidth: Math.abs(rightOutButton.x - rightInButton.x) - 120,\n\theight: 3\n});\ngame.addChild(lineRightInToOut);\nlineRightInToOut.x = (rightInButton.x + rightOutButton.x) / 2;\nlineRightInToOut.y = rightInButton.y;\nlineRightInToOut.tint = 0x888888; // Gray color\n// Add white notches for horizontal crossfader (top side)\nvar horizontalCrossfaderTrack = crossfader; // Use the existing crossfader\nvar notchSpacingHorizontal = horizontalCrossfaderTrack.width / 10; // 10 notches\nfor (var i = 0; i <= 10; i++) {\n\tvar notch = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: 3,\n\t\t// Notch width\n\t\theight: 20 // Notch height\n\t});\n\tnotch.tint = 0xFFFFFF; // White color\n\tnotch.x = horizontalCrossfaderTrack.x - horizontalCrossfaderTrack.width / 2 + i * notchSpacingHorizontal; // Position along the top edge\n\tnotch.y = horizontalCrossfaderTrack.y - 20; // Position above the track\n\tgame.addChild(notch);\n}\n// Add white notches for horizontal crossfader (bottom side)\nvar horizontalCrossfaderTrack = crossfader; // Use the existing crossfader\nvar notchSpacingHorizontal = horizontalCrossfaderTrack.width / 10; // 10 notches\nfor (var i = 0; i <= 10; i++) {\n\tvar notch = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: 3,\n\t\t// Notch width\n\t\theight: 20 // Notch height\n\t});\n\tnotch.tint = 0xFFFFFF; // White color\n\tnotch.x = horizontalCrossfaderTrack.x - horizontalCrossfaderTrack.width / 2 + i * notchSpacingHorizontal; // Position along the top edge\n\tnotch.y = horizontalCrossfaderTrack.y + 20; // Position below the track\n\tgame.addChild(notch);\n}\n// Horizontal crossfader knob is already managed by the crossfader object\n// Add a vertical crossfader track\nvar verticalCrossfaderTrack = LK.getAsset('crossfaderTrack', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\twidth: 12,\n\theight: 500\n});\n// Ensure horizontal crossfader knob is above the notches\ngame.addChild(crossfader);\ncrossfader.x = 2048 / 2;\ncrossfader.y = crossfaderY + 333 - 124 + 100;\ncrossfader.setValue(0.5);\n// Add a vertical crossfader track\nvar verticalCrossfaderTrack = LK.getAsset('crossfaderTrack', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\twidth: 12,\n\theight: 500\n});\ngame.addChild(verticalCrossfaderTrack);\nverticalCrossfaderTrack.x = djdeckAsset.x - 250;\nverticalCrossfaderTrack.y = djdeckAsset.y - 100 + 400;\nverticalCrossfaderTrack.tint = 0xFFFFFF;\n// Add white notches for scaling\nvar notchSpacing = verticalCrossfaderTrack.height / 10; // 10 notches\nfor (var i = 0; i <= 10; i++) {\n\tvar notch = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: 20,\n\t\t// Notch width\n\t\theight: 3 // Notch height\n\t});\n\tnotch.tint = 0xFFFFFF; // White color\n\tnotch.x = verticalCrossfaderTrack.x + 20; // Position to the right of the track\n\tnotch.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 + i * notchSpacing;\n\tgame.addChild(notch);\n}\n// Add white notches for scaling on the other side of the track\nfor (var i = 0; i <= 10; i++) {\n\tvar notch = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: 20,\n\t\theight: 3\n\t});\n\tnotch.tint = 0xFFFFFF;\n\tnotch.x = verticalCrossfaderTrack.x - 20; // Position to the left of the track\n\tnotch.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 + i * notchSpacing;\n\tgame.addChild(notch);\n}\n// Add a knob onto the vertical crossfader track\nvar verticalCrossfaderKnob = LK.getAsset('crossfaderKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\trotation: Math.PI / 2\n});\nverticalCrossfaderKnob.x = verticalCrossfaderTrack.x;\nverticalCrossfaderKnob.y = verticalCrossfaderTrack.y;\n// Add a knob onto the vertical crossfader track\nvar verticalCrossfaderKnob = LK.getAsset('crossfaderKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\trotation: Math.PI / 2\n});\nverticalCrossfaderKnob.x = verticalCrossfaderTrack.x;\nverticalCrossfaderKnob.y = verticalCrossfaderTrack.y;\ngame.addChild(verticalCrossfaderKnob);\n// Ensure knob is above the notches by bringing it to the top of the children list of game\ngame.setChildIndex(verticalCrossfaderKnob, game.children.length - 1);\n// Add white \"-\" text under the left vertical crossfader\nvar leftCrossfaderMinusText = new Text2('-', {\n\tsize: 40,\n\tfill: 0xFFFFFF // White color\n});\nleftCrossfaderMinusText.scaleX = 4.0; // Increased width by 2x\nleftCrossfaderMinusText.scaleY = 2.0; // Increased height by 2x\nleftCrossfaderMinusText.anchor.set(0.5, 0.5);\nleftCrossfaderMinusText.x = verticalCrossfaderTrack.x;\nleftCrossfaderMinusText.y = verticalCrossfaderTrack.y + verticalCrossfaderTrack.height / 2 + 30; // Position under the crossfader\ngame.addChild(leftCrossfaderMinusText);\n// Add white \"+\" text above the left vertical crossfader\nvar leftCrossfaderPlusText = new Text2('+', {\n\tsize: 40,\n\tfill: 0xFFFFFF // White color\n});\nleftCrossfaderPlusText.anchor.set(0.5, 0.5);\nleftCrossfaderPlusText.x = verticalCrossfaderTrack.x;\nleftCrossfaderPlusText.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 - 30; // Position above the crossfader\ngame.addChild(leftCrossfaderPlusText);\n// Add white TEMPO text above the left vertical crossfader plus sign\nvar leftCrossfaderTempoText = new Text2('TEMPO', {\n\tsize: 30,\n\tfill: 0xFFFFFF // White color\n});\nleftCrossfaderTempoText.anchor.set(0.5, 0.5);\nleftCrossfaderTempoText.x = verticalCrossfaderTrack.x;\nleftCrossfaderTempoText.y = leftCrossfaderPlusText.y - 40; // Position above the plus sign\ngame.addChild(leftCrossfaderTempoText);\n// Add a second vertical crossfader track\nvar verticalCrossfaderTrack2 = LK.getAsset('crossfaderTrack', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\twidth: 12,\n\theight: 500\n});\ngame.addChild(verticalCrossfaderTrack2);\nverticalCrossfaderTrack2.x = djdeckAsset.x + 250; // Position on the right side\nverticalCrossfaderTrack2.y = djdeckAsset.y - 100 + 400;\nverticalCrossfaderTrack2.tint = 0xFFFFFF;\n// Add white notches for scaling\nvar notchSpacing = verticalCrossfaderTrack2.height / 10; // 10 notches\nfor (var i = 0; i <= 10; i++) {\n\tvar notch = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: 20,\n\t\t// Notch width\n\t\theight: 3 // Notch height\n\t});\n\tnotch.tint = 0xFFFFFF; // White color\n\tnotch.x = verticalCrossfaderTrack2.x - 20; // Position to the left of the track\n\tnotch.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 + i * notchSpacing;\n\tgame.addChild(notch);\n}\n// Add white notches for scaling on the other side of the track\nfor (var i = 0; i <= 10; i++) {\n\tvar notch = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0.5,\n\t\tanchorY: 0.5,\n\t\twidth: 20,\n\t\theight: 3\n\t});\n\tnotch.tint = 0xFFFFFF;\n\tnotch.x = verticalCrossfaderTrack2.x + 20; // Position to the right of the track\n\tnotch.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 + i * notchSpacing;\n\tgame.addChild(notch);\n}\n// Add a knob onto the second vertical crossfader track\nvar verticalCrossfaderKnob2 = LK.getAsset('crossfaderKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\trotation: Math.PI / 2\n});\nverticalCrossfaderKnob2.x = verticalCrossfaderTrack2.x;\nverticalCrossfaderKnob2.y = verticalCrossfaderTrack2.y;\n// Add a knob onto the second vertical crossfader track\nvar verticalCrossfaderKnob2 = LK.getAsset('crossfaderKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5,\n\trotation: Math.PI / 2\n});\nverticalCrossfaderKnob2.x = verticalCrossfaderTrack2.x;\nverticalCrossfaderKnob2.y = verticalCrossfaderTrack2.y;\ngame.addChild(verticalCrossfaderKnob2);\n// Ensure knob is above the notches by bringing it to the top of the children list of game\ngame.setChildIndex(verticalCrossfaderKnob2, game.children.length - 1);\n// Add white Balance text under the horizontal crossfader\n// Add white \"-\" text under the right vertical crossfader\nvar rightCrossfaderMinusText = new Text2('-', {\n\tsize: 40,\n\tfill: 0xFFFFFF // White color\n});\nrightCrossfaderMinusText.scaleX = 4.0; // Increased width by 2x\nrightCrossfaderMinusText.scaleY = 2.0; // Increased height by 2x\nrightCrossfaderMinusText.anchor.set(0.5, 0.5);\nrightCrossfaderMinusText.x = verticalCrossfaderTrack2.x;\nrightCrossfaderMinusText.y = verticalCrossfaderTrack2.y + verticalCrossfaderTrack2.height / 2 + 30; // Position under the crossfader\ngame.addChild(rightCrossfaderMinusText);\n// Add white \"+\" text above the right vertical crossfader\nvar rightCrossfaderPlusText = new Text2('+', {\n\tsize: 40,\n\tfill: 0xFFFFFF // White color\n});\nrightCrossfaderPlusText.anchor.set(0.5, 0.5);\nrightCrossfaderPlusText.x = verticalCrossfaderTrack2.x;\nrightCrossfaderPlusText.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 - 30; // Position above the crossfader\ngame.addChild(rightCrossfaderPlusText);\n// Add white TEMPO text above the right vertical crossfader plus sign\nvar rightCrossfaderTempoText = new Text2('TEMPO', {\n\tsize: 30,\n\tfill: 0xFFFFFF // White color\n});\nrightCrossfaderTempoText.anchor.set(0.5, 0.5);\nrightCrossfaderTempoText.x = verticalCrossfaderTrack2.x;\nrightCrossfaderTempoText.y = rightCrossfaderPlusText.y - 40; // Position above the plus sign\ngame.addChild(rightCrossfaderTempoText);\n// Add filter knobs\nvar leftFilterKnobHigh = LK.getAsset('filterKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(leftFilterKnobHigh);\nleftFilterKnobHigh.anchor.set(0.5, 0.5);\nleftFilterKnobHigh.x = leftDeckAsset.x + 190 + 400 + 12;\nleftFilterKnobHigh.y = leftDeckAsset.y - 100 + 25 + 130;\n// Add white HIGH text under the HIGH filter knob\nvar highTextLeft = new Text2('HIGH', {\n\tsize: 24,\n\tfill: 0xFFFFFF // White color\n});\nhighTextLeft.anchor.set(0.5, 0.5);\nhighTextLeft.x = leftFilterKnobHigh.x;\nhighTextLeft.y = leftFilterKnobHigh.y + leftFilterKnobHigh.height / 2 + 20; // Position under the knob\ngame.addChild(highTextLeft);\n// Add white FILTER text above the HIGH filter knobs, horizontally between them\nvar filterTextLeft = new Text2('FILTER', {\n\tsize: 30,\n\tfill: 0xFFFFFF // White color\n});\nfilterTextLeft.anchor.set(0.5, 0.5);\nfilterTextLeft.x = leftFilterKnobHigh.x + 100; // Position text to the right of the knob for horizontal alignment\nfilterTextLeft.y = leftFilterKnobHigh.y - leftFilterKnobHigh.height / 2 - 40 + 130 - 120; // Position above the knob\ngame.addChild(filterTextLeft);\ntween(leftFilterKnobHigh, {\n\tscaleX: 1.2,\n\tscaleY: 1.2\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar leftFilterKnobMid = LK.getAsset('filterKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(leftFilterKnobMid);\nleftFilterKnobMid.anchor.set(0.5, 0.5);\nleftFilterKnobMid.x = leftDeckAsset.x + 190 + 400 + 12;\nleftFilterKnobMid.y = leftDeckAsset.y + 30 + 30 + 30 + 30 + 50 + 30 + 30 + 12;\ntween(leftFilterKnobMid, {\n\tscaleX: 1.2,\n\tscaleY: 1.2\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar leftFilterKnobLow = LK.getAsset('filterKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(leftFilterKnobLow);\nleftFilterKnobLow.anchor.set(0.5, 0.5);\nleftFilterKnobLow.x = leftDeckAsset.x + 190 + 400 + 12;\nleftFilterKnobLow.y = leftDeckAsset.y + 100 + 120 + 120 + 77;\n// Add white LOW text under the LOW filter knob\nvar lowTextLeft = new Text2('LOW', {\n\tsize: 24,\n\tfill: 0xFFFFFF // White color\n});\nlowTextLeft.anchor.set(0.5, 0.5);\nlowTextLeft.x = leftFilterKnobLow.x;\nlowTextLeft.y = leftFilterKnobLow.y + leftFilterKnobLow.height / 2 + 20; // Position under the knob\ngame.addChild(lowTextLeft);\ntween(leftFilterKnobLow, {\n\tscaleX: 1.2,\n\tscaleY: 1.2\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar rightFilterKnobHigh = LK.getAsset('filterKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightFilterKnobHigh);\nrightFilterKnobHigh.anchor.set(0.5, 0.5);\nrightFilterKnobHigh.x = rightDeckAsset.x - 190 - 400 - 12;\nrightFilterKnobHigh.y = rightDeckAsset.y - 100 + 25 + 130;\n// Add white HIGH text under the HIGH filter knobs (Right side)\nvar highTextRight = new Text2('HIGH', {\n\tsize: 24,\n\tfill: 0xFFFFFF // White color\n});\nhighTextRight.anchor.set(0.5, 0.5);\nhighTextRight.x = rightFilterKnobHigh.x;\nhighTextRight.y = rightFilterKnobHigh.y + rightFilterKnobHigh.height / 2 + 20; // Position under the knob\ngame.addChild(highTextRight);\n// Add white FILTER text above the HIGH filter knobs, horizontally between them (Right side)\nvar filterTextRight = new Text2('FILTER', {\n\tsize: 30,\n\tfill: 0xFFFFFF // White color\n});\nfilterTextRight.anchor.set(0.5, 0.5);\nfilterTextRight.x = rightFilterKnobHigh.x - 100; // Position text to the left of the knob for horizontal alignment\nfilterTextRight.y = rightFilterKnobHigh.y - rightFilterKnobHigh.height / 2 - 40 + 130 - 120; // Position above the knob\ngame.addChild(filterTextRight);\ntween(rightFilterKnobHigh, {\n\tscaleX: 1.2,\n\tscaleY: 1.2\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar rightFilterKnobMid = LK.getAsset('filterKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightFilterKnobMid);\nrightFilterKnobMid.anchor.set(0.5, 0.5);\nrightFilterKnobMid.x = rightDeckAsset.x - 190 - 400 - 12;\nrightFilterKnobMid.y = rightDeckAsset.y + 30 + 30 + 30 + 30 + 50 + 30 + 30 + 12;\ntween(rightFilterKnobMid, {\n\tscaleX: 1.2,\n\tscaleY: 1.2\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar rightFilterKnobLow = LK.getAsset('filterKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ngame.addChild(rightFilterKnobLow);\nrightFilterKnobLow.anchor.set(0.5, 0.5);\nrightFilterKnobLow.x = rightDeckAsset.x - 190 - 400 - 12;\nrightFilterKnobLow.y = rightDeckAsset.y + 100 + 120 + 120 + 77;\n// Add white LOW text under the LOW filter knob (Right side)\nvar lowTextRight = new Text2('LOW', {\n\tsize: 24,\n\tfill: 0xFFFFFF // White color\n});\nlowTextRight.anchor.set(0.5, 0.5);\nlowTextRight.x = rightFilterKnobLow.x;\nlowTextRight.y = rightFilterKnobLow.y + rightFilterKnobLow.height / 2 + 20; // Position under the knob\ngame.addChild(lowTextRight);\ntween(rightFilterKnobLow, {\n\tscaleX: 1.2,\n\tscaleY: 1.2\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nfunction setupFilterKnobInteraction(knob) {\n\tknob.down = function (x, y, obj) {\n\t\ttween.stop(this);\n\t\t// Scale down the previously selected filter knob if it exists and is not the current one\n\t\tif (lastSelectedFilterKnob && lastSelectedFilterKnob !== this) {\n\t\t\ttween.stop(lastSelectedFilterKnob);\n\t\t\ttween(lastSelectedFilterKnob, {\n\t\t\t\tscaleX: 1.2,\n\t\t\t\tscaleY: 1.2\n\t\t\t}, {\n\t\t\t\tduration: 100,\n\t\t\t\teasing: tween.easeOut\n\t\t\t});\n\t\t}\n\t\tlastSelectedFilterKnob = this;\n\t\ttween(this, {\n\t\t\tscaleX: 2.4,\n\t\t\tscaleY: 2.4\n\t\t}, {\n\t\t\tduration: 100,\n\t\t\teasing: tween.easeOut\n\t\t});\n\t};\n\tknob.up = function (x, y, obj) {\n\t\ttween.stop(this);\n\t\t// Do not scale down on up, keep enlarged\n\t};\n}\nsetupFilterKnobInteraction(leftFilterKnobHigh);\nsetupFilterKnobInteraction(leftFilterKnobMid);\nsetupFilterKnobInteraction(leftFilterKnobLow);\nsetupFilterKnobInteraction(rightFilterKnobHigh);\nsetupFilterKnobInteraction(rightFilterKnobMid);\nsetupFilterKnobInteraction(rightFilterKnobLow);\n// --- Vertical crossfader state ---\nvar verticalCrossfaderValue = 0.5; // 0 = top, 1 = bottom\nvar verticalCrossfaderDragging = false;\n// Second vertical crossfader state\nvar verticalCrossfaderValue2 = 0.5; // 0 = top, 1 = bottom\nvar verticalCrossfaderDragging2 = false;\nvar isRgbFlashingActive = false; // State variable for RGB flashing effect\nvar laserShowMode = 0; // Laser show state: 0 = off, 1 = slow, 2 = fast\nvar fireEffectMode = 0; // Fire effect state: 0 = off, 1 = normal flames, 2 = big flames\nvar lastSelectedFilterKnob = null; // Variable to track the last selected filter knob.\nvar uvEffectActive = false; // UV effect state: false = off, true = on\nvar uvBackgroundColorTween = null; // Variable to hold the background color tween\n// Add vertical crossfader functionality with improved touch detection\nverticalCrossfaderTrack.down = function (x, y, obj) {\n\tverticalCrossfaderDragging = true;\n\t// Use relative position within track bounds for precise control\n\tvar relativeY = (y + verticalCrossfaderTrack.height / 2) / verticalCrossfaderTrack.height;\n\tverticalCrossfaderValue = Math.max(0, Math.min(1, relativeY));\n\t// Update knob position smoothly\n\tverticalCrossfaderKnob.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 + verticalCrossfaderValue * verticalCrossfaderTrack.height;\n};\nverticalCrossfaderTrack.up = function (x, y, obj) {\n\tverticalCrossfaderDragging = false;\n};\nverticalCrossfaderTrack.move = function (x, y, obj) {\n\tif (verticalCrossfaderDragging) {\n\t\t// Use relative position within track bounds for precise control\n\t\tvar relativeY = (y + verticalCrossfaderTrack.height / 2) / verticalCrossfaderTrack.height;\n\t\tverticalCrossfaderValue = Math.max(0, Math.min(1, relativeY));\n\t\t// Update knob position smoothly\n\t\tverticalCrossfaderKnob.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 + verticalCrossfaderValue * verticalCrossfaderTrack.height;\n\t}\n};\n// Add vertical crossfader functionality for the second crossfader with improved touch detection\nverticalCrossfaderTrack2.down = function (x, y, obj) {\n\tverticalCrossfaderDragging2 = true;\n\t// Use relative position within track bounds for precise control\n\tvar relativeY = (y + verticalCrossfaderTrack2.height / 2) / verticalCrossfaderTrack2.height;\n\tverticalCrossfaderValue2 = Math.max(0, Math.min(1, relativeY));\n\t// Update knob position smoothly\n\tverticalCrossfaderKnob2.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 + verticalCrossfaderValue2 * verticalCrossfaderTrack2.height;\n};\nverticalCrossfaderTrack2.up = function (x, y, obj) {\n\tverticalCrossfaderDragging2 = false;\n};\nverticalCrossfaderTrack2.move = function (x, y, obj) {\n\tif (verticalCrossfaderDragging2) {\n\t\t// Use relative position within track bounds for precise control\n\t\tvar relativeY = (y + verticalCrossfaderTrack2.height / 2) / verticalCrossfaderTrack2.height;\n\t\tverticalCrossfaderValue2 = Math.max(0, Math.min(1, relativeY));\n\t\t// Update knob position smoothly\n\t\tverticalCrossfaderKnob2.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 + verticalCrossfaderValue2 * verticalCrossfaderTrack2.height;\n\t}\n};\nvar leftEqualizer = new EqualizerBars();\ngame.addChild(leftEqualizer);\nleftEqualizer.x = leftDeckScreen.x;\nleftEqualizer.y = leftDeckScreen.y + 50;\n// Add equalizer to right deck screen\nvar rightEqualizer = new EqualizerBars();\ngame.addChild(rightEqualizer);\nrightEqualizer.x = rightDeckScreen.x;\nrightEqualizer.y = rightDeckScreen.y + 50;\n// Ensure deck platters are always at the top of the display order\nif (game.children.indexOf(leftDeck) !== -1) {\n\tgame.setChildIndex(leftDeck, game.children.length - 1);\n}\nif (game.children.indexOf(rightDeck) !== -1) {\n\tgame.setChildIndex(rightDeck, game.children.length - 1);\n}\n// --- Game update ---\ngame.update = function () {\n\t// Update discoball animation\n\tdiscoball.update();\n\t// Update fog effect animation\n\tfogEffect.update();\n\t// Update confetti effect animation\n\tconfettiEffect.update();\n\t// Update balloons animation\n\tif (balloons) {\n\t\tfor (var i = 0; i < balloons.length; i++) {\n\t\t\tballoons[i].update();\n\t\t}\n\t}\n\t// Update money particles animation\n\tif (moneyParticles) {\n\t\tfor (var i = 0; i < moneyParticles.length; i++) {\n\t\t\tmoneyParticles[i].update();\n\t\t}\n\t}\n\t// Update first dancing people line animations (first set created)\n\tfor (var i = 0; i < Math.min(dancingPeople.length, 8); i++) {\n\t\tvar person = dancingPeople[i];\n\t\t// Check if UV effect is active\n\t\tif (uvEffectActive) {\n\t\t\t// If not already a UV person, swap to UV asset\n\t\t\tif (!person.isUV) {\n\t\t\t\tvar uvAssetId = i % 2 === 0 ? 'UVW' : 'UWM';\n\t\t\t\tvar currentScaleX = person.scale.x;\n\t\t\t\tvar currentScaleY = person.scale.y;\n\t\t\t\tvar currentRotation = person.rotation;\n\t\t\t\tvar currentAlpha = person.alpha;\n\t\t\t\tvar currentX = person.x;\n\t\t\t\tvar currentY = person.y;\n\t\t\t\tvar currentBaseY = person.baseY;\n\t\t\t\tvar currentPhaseOffset = person.phaseOffset;\n\t\t\t\t// Remove the old graphic child\n\t\t\t\tif (person.children.length > 0) {\n\t\t\t\t\tperson.removeChildAt(0);\n\t\t\t\t}\n\t\t\t\t// Add the new UV graphic child\n\t\t\t\tvar uvGraphic = person.attachAsset(uvAssetId, {\n\t\t\t\t\tanchorX: 0.5,\n\t\t\t\t\tanchorY: 1.0\n\t\t\t\t});\n\t\t\t\t// Restore previous transform and animation properties\n\t\t\t\tperson.scale.set(currentScaleX, currentScaleY);\n\t\t\t\tperson.rotation = currentRotation;\n\t\t\t\tperson.alpha = currentAlpha;\n\t\t\t\tperson.x = currentX;\n\t\t\t\tperson.y = currentY;\n\t\t\t\tperson.baseY = currentBaseY;\n\t\t\t\tperson.phaseOffset = currentPhaseOffset;\n\t\t\t\tperson.isUV = true;\n\t\t\t}\n\t\t} else {\n\t\t\t// If UV effect is off and it's a UV person, swap back to normal asset\n\t\t\tif (person.isUV) {\n\t\t\t\tvar normalAssetId = i % 2 === 0 ? 'dancingWoman' : 'dancingMan';\n\t\t\t\tvar currentScaleX = person.scale.x;\n\t\t\t\tvar currentScaleY = person.scale.y;\n\t\t\t\tvar currentRotation = person.rotation;\n\t\t\t\tvar currentAlpha = person.alpha;\n\t\t\t\tvar currentX = person.x;\n\t\t\t\tvar currentY = person.y;\n\t\t\t\tvar currentBaseY = person.baseY;\n\t\t\t\tvar currentPhaseOffset = person.phaseOffset;\n\t\t\t\t// Remove the old graphic child\n\t\t\t\tif (person.children.length > 0) {\n\t\t\t\t\tperson.removeChildAt(0);\n\t\t\t\t}\n\t\t\t\t// Add the new normal graphic child\n\t\t\t\tvar normalGraphic = person.attachAsset(normalAssetId, {\n\t\t\t\t\tanchorX: 0.5,\n\t\t\t\t\tanchorY: 1.0\n\t\t\t\t});\n\t\t\t\t// Restore previous transform and animation properties\n\t\t\t\tperson.scale.set(currentScaleX, currentScaleY);\n\t\t\t\tperson.rotation = currentRotation;\n\t\t\t\tperson.alpha = currentAlpha;\n\t\t\t\tperson.x = currentX;\n\t\t\t\tperson.y = currentY;\n\t\t\t\tperson.baseY = currentBaseY;\n\t\t\t\tperson.phaseOffset = currentPhaseOffset;\n\t\t\t\tperson.isUV = false;\n\t\t\t}\n\t\t}\n\t\tperson.update();\n\t}\n\t// Update second dancing people line animations (second set created) - swap with UV assets when UV is active\n\tfor (var i = 8; i < dancingPeople.length; i++) {\n\t\tvar person = dancingPeople[i];\n\t\t// Check if UV effect is active\n\t\tif (uvEffectActive) {\n\t\t\t// If not already a UV person, swap to UV asset\n\t\t\tif (!person.isUV) {\n\t\t\t\tvar uvAssetId = (i - 8) % 2 === 0 ? 'UVW' : 'UWM';\n\t\t\t\tvar currentScaleX = person.scale.x;\n\t\t\t\tvar currentScaleY = person.scale.y;\n\t\t\t\tvar currentRotation = person.rotation;\n\t\t\t\tvar currentAlpha = person.alpha;\n\t\t\t\tvar currentX = person.x;\n\t\t\t\tvar currentY = person.y;\n\t\t\t\tvar currentBaseY = person.baseY;\n\t\t\t\tvar currentPhaseOffset = person.phaseOffset;\n\t\t\t\t// Remove the old graphic child\n\t\t\t\tif (person.children.length > 0) {\n\t\t\t\t\tperson.removeChildAt(0);\n\t\t\t\t}\n\t\t\t\t// Add the new UV graphic child\n\t\t\t\tvar uvGraphic = person.attachAsset(uvAssetId, {\n\t\t\t\t\tanchorX: 0.5,\n\t\t\t\t\tanchorY: 1.0\n\t\t\t\t});\n\t\t\t\t// Restore previous transform and animation properties\n\t\t\t\tperson.scale.set(currentScaleX, currentScaleY);\n\t\t\t\tperson.rotation = currentRotation;\n\t\t\t\tperson.alpha = currentAlpha;\n\t\t\t\tperson.x = currentX;\n\t\t\t\tperson.y = currentY;\n\t\t\t\tperson.baseY = currentBaseY;\n\t\t\t\tperson.phaseOffset = currentPhaseOffset;\n\t\t\t\tperson.isUV = true;\n\t\t\t}\n\t\t} else {\n\t\t\t// If UV effect is off and it's a UV person, swap back to normal asset\n\t\t\tif (person.isUV) {\n\t\t\t\tvar normalAssetId = (i - 8) % 2 === 0 ? 'dancingWoman' : 'dancingMan';\n\t\t\t\tvar currentScaleX = person.scale.x;\n\t\t\t\tvar currentScaleY = person.scale.y;\n\t\t\t\tvar currentRotation = person.rotation;\n\t\t\t\tvar currentAlpha = person.alpha;\n\t\t\t\tvar currentX = person.x;\n\t\t\t\tvar currentY = person.y;\n\t\t\t\tvar currentBaseY = person.baseY;\n\t\t\t\tvar currentPhaseOffset = person.phaseOffset;\n\t\t\t\t// Remove the old graphic child\n\t\t\t\tif (person.children.length > 0) {\n\t\t\t\t\tperson.removeChildAt(0);\n\t\t\t\t}\n\t\t\t\t// Add the new normal graphic child\n\t\t\t\tvar normalGraphic = person.attachAsset(normalAssetId, {\n\t\t\t\t\tanchorX: 0.5,\n\t\t\t\t\tanchorY: 1.0\n\t\t\t\t});\n\t\t\t\t// Restore previous transform and animation properties\n\t\t\t\tperson.scale.set(currentScaleX, currentScaleY);\n\t\t\t\tperson.rotation = currentRotation;\n\t\t\t\tperson.alpha = currentAlpha;\n\t\t\t\tperson.x = currentX;\n\t\t\t\tperson.y = currentY;\n\t\t\t\tperson.baseY = currentBaseY;\n\t\t\t\tperson.phaseOffset = currentPhaseOffset;\n\t\t\t\tperson.isUV = false;\n\t\t\t}\n\t\t}\n\t\tperson.update();\n\t}\n\t// Animate extra white particles (subtle sparkle and movement)\n\tif (extraWhiteParticles) {\n\t\tvar t = Date.now() * 0.001;\n\t\tfor (var i = 0; i < extraWhiteParticles.length; i++) {\n\t\t\tvar p = extraWhiteParticles[i];\n\t\t\t// Subtle float and twinkle\n\t\t\tp.obj.x = p.baseX + Math.sin(t * 1.2 + p.phase + i) * 8;\n\t\t\tp.obj.y = p.baseY + Math.cos(t * 1.1 + p.phase + i * 0.7) * 6;\n\t\t\tp.obj.alpha = p.baseAlpha + 0.10 * Math.sin(t * 2.2 + p.phase + i * 0.5);\n\t\t\tvar s = p.baseSize * (0.95 + 0.12 * Math.sin(t * 1.7 + p.phase + i));\n\t\t\tp.obj.width = s;\n\t\t\tp.obj.height = s;\n\t\t}\n\t}\n\t// Animate flashing white reflectors\n\tif (reflectors) {\n\t\tvar t = Date.now() * 0.001;\n\t\tfor (var i = 0; i < reflectors.length; i++) {\n\t\t\t// Staggered flash, each reflector flashes in sequence\n\t\t\tvar phase = t * 2.2 + i * 0.5;\n\t\t\t// Use a sharp pulse for flash, then fade out\n\t\t\tvar flash = Math.max(0, Math.sin(phase));\n\t\t\t// Sharpen the flash curve for a strobe effect\n\t\t\tflash = Math.pow(flash, 6);\n\t\t\treflectors[i].alpha = 0.18 + 0.82 * flash;\n\t\t\t// Animate as perfect circles for extra pop (half size base)\n\t\t\tvar size = 60 + 20 * flash;\n\t\t\t// Prevent reflectors from covering the discoball\n\t\t\t// Compute distance from reflector to discoball center\n\t\t\tvar dx = reflectors[i].x - discoball.x;\n\t\t\tvar dy = reflectors[i].y - discoball.y;\n\t\t\tvar dist = Math.sqrt(dx * dx + dy * dy);\n\t\t\t// Discoball's visible radius (scaled)\n\t\t\tvar discoballRadius = 150 * discoball.scaleX; // matches Discoball class\n\t\t\t// If reflector would overlap discoball, shrink it so it cannot cover\n\t\t\tif (dist < discoballRadius + size / 2) {\n\t\t\t\t// Max allowed size so edge of reflector does not enter discoball\n\t\t\t\tvar maxSize = Math.max(0, 2 * (dist - discoballRadius));\n\t\t\t\tif (size > maxSize) size = maxSize;\n\t\t\t\tif (size < 0) size = 0;\n\t\t\t}\n\t\t\treflectors[i].width = size;\n\t\t\treflectors[i].height = size;\n\t\t}\n\t}\n\t// Update laser show animation\n\tlaserShow.update();\n\t// Update fireworks effect animation\n\tfireworksEffect.update();\n\tfireworksEffect2.update();\n\tfireworksEffect3.update();\n\tfireworksEffect4.update();\n\t// Update Ferris wheel animation\n\tif (typeof ferrisWheel !== 'undefined' && ferrisWheel.update) {\n\t\t// Defensive check\n\t\tferrisWheel.update();\n\t}\n\t// Update smoke diffuser animation\n\t// --- Synchronize all smoke diffusers so they emit smoke puffs at the same time ---\n\tif (typeof smokeDiffusers !== 'undefined' && smokeDiffusers.length > 0) {\n\t\t// Use the first smoke diffuser as the \"master\" for timing\n\t\tvar now = Date.now();\n\t\t// All diffusers share the same \"now\" and will create puffs in sync\n\t\tfor (var i = 0; i < smokeDiffusers.length; i++) {\n\t\t\tvar sd = smokeDiffusers[i];\n\t\t\t// Patch: override the update method to use the same \"now\" for all\n\t\t\tif (sd && typeof sd.update === 'function') {\n\t\t\t\t// Save original Date.now\n\t\t\t\tvar origDateNow = Date.now;\n\t\t\t\tDate.now = function () {\n\t\t\t\t\treturn now;\n\t\t\t\t};\n\t\t\t\tsd.update();\n\t\t\t\tDate.now = origDateNow;\n\t\t\t}\n\t\t}\n\t}\n\t// Update flamethrower animation\n\tif (typeof flamethrower !== 'undefined' && flamethrower.update) {\n\t\tflamethrower.update();\n\t}\n\t// Update decks\n\tleftDeck.update();\n\trightDeck.update();\n\t// Update equalizers\n\tleftEqualizer.update();\n\trightEqualizer.update();\n\t// Simulate beat\n\tvar now = Date.now();\n\tbeatTimer += now - lastTickTime;\n\tlastTickTime = now;\n\tif (beatTimer >= beatInterval) {\n\t\tbeatTimer -= beatInterval;\n\t\tleftDeck.flashBeat();\n\t\trightDeck.flashBeat();\n\t\tLK.getSound('beat').play();\n\t\t// Energy drops if not scratching or mixing\n\t\tif (!leftDeck.isScratching && !rightDeck.isScratching && crossfader.value > 0.2 && crossfader.value < 0.8) {\n\t\t\tenergy -= 2;\n\t\t\tcombo = 0;\n\t\t} else {\n\t\t\t// Combo up if scratching or crossfading\n\t\t\tcombo += 1;\n\t\t\tscore += 10 * combo;\n\t\t\tenergy += 2;\n\t\t\tif (energy > 100) energy = 100;\n\t\t}\n\t\tif (energy < 0) energy = 0;\n\t\t// Update visuals\n\t\tscoreTxt.setText('Score: ' + score);\n\t\tif (combo > 1) {\n\t\t\tcomboTxt.setText('Combo x' + combo);\n\t\t} else {\n\t\t\tcomboTxt.setText('');\n\t\t}\n\t}\n\t// Update energy bar\n\tenergyBar.width = 600 * (energy / 100);\n\t// Crossfader logic: adjust music volumes\n\ttrackAVol = 1 - crossfader.value;\n\ttrackBVol = crossfader.value;\n\t// (In a real game, would set music volumes here, but LK handles music globally.)\n\t// End game if energy is 0\n\tif (energy <= 0) {\n\t\t// Game over event disabled\n\t}\n\t// Animate background color\n\tvar time = Date.now() * 0.0005; // Time for animation\n\tvar hue = time * 360 % 360; // Cycle through hues over time\n\tvar rgb = hsvToRgb(hue / 360, 0.6, 0.5); // Convert HSV to RGB (adjust saturation and value for desired effect)\n\t// Only animate the background color if RGB flashing is active on the third effect button\n\tif (isRgbFlashingActive) {\n\t\tgame.setBackgroundColor(rgb[0] << 16 | rgb[1] << 8 | rgb[2]);\n\t} else if (uvEffectActive) {\n\t\t// If UV effect is active, flash between indigo blue and purple\n\t\tvar uvTime = Date.now() * 0.002; // Faster flashing for UV\n\t\tvar uvHue = uvTime * 360 % 360;\n\t\t// Cycle between indigo (around 240 hue) and purple (around 270 hue)\n\t\tvar targetHue = 240 + Math.sin(uvTime * Math.PI * 2) * 30;\n\t\ttargetHue = (targetHue + 360) % 360;\n\t\tvar uvRgb = hsvToRgb(targetHue / 360, 0.8, 0.7); // Adjust saturation and value for UV colors\n\t\tgame.setBackgroundColor(uvRgb[0] << 16 | uvRgb[1] << 8 | uvRgb[2]);\n\t} else {\n\t\t// If neither is active, set a default background color\n\t\tgame.setBackgroundColor(0x000000); // Or any other default color\n\t}\n\t// Win condition disabled\n\t// --- Update Digital Clock ---\n\tif (typeof digitalClockTxt !== 'undefined') {\n\t\tvar now = new Date();\n\t\tdigitalClockTxt.setText(formatTime(now));\n\t}\n\t// Display laser flashing effect on the second effect button's frame based on mode\n\tif (effectButtons[1]) {\n\t\tif (laserShowMode === 0) {\n\t\t\t// Off mode - normal white tint\n\t\t\teffectButtons[1].tint = 0xFFFFFF;\n\t\t} else if (laserShowMode === 1) {\n\t\t\t// Slow mode - slow blue pulsing\n\t\t\tvar time = Date.now() * 0.0008; // Slow pulsing\n\t\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\t\tvar blueValue = Math.floor(intensity * 255);\n\t\t\teffectButtons[1].tint = 0x4444ff | blueValue << 8 | blueValue;\n\t\t} else if (laserShowMode === 2) {\n\t\t\t// Fast mode - slower rainbow cycling\n\t\t\tvar time = Date.now() * 0.0008; // Slower cycling (reduced from 0.002)\n\t\t\tvar laserColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];\n\t\t\tvar colorIndex = Math.floor(time * 3) % laserColors.length; // Slower color cycling (reduced from 8 to 3)\n\t\t\teffectButtons[1].tint = laserColors[colorIndex];\n\t\t}\n\t}\n\t// Display fire effect flashing on the first effect button's frame based on mode\n\tif (effectButtons[0]) {\n\t\tif (fireEffectMode === 0) {\n\t\t\t// Off mode - normal white tint\n\t\t\teffectButtons[0].tint = 0xFFFFFF;\n\t\t} else if (fireEffectMode === 1) {\n\t\t\t// Normal flames mode - orange flashing\n\t\t\tvar time = Date.now() * 0.002; // Medium speed flashing\n\t\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\t\tvar redValue = Math.floor(255);\n\t\t\tvar greenValue = Math.floor(intensity * 128 + 64); // Orange tint\n\t\t\tvar blueValue = 0;\n\t\t\teffectButtons[0].tint = redValue << 16 | greenValue << 8 | blueValue;\n\t\t} else if (fireEffectMode === 2) {\n\t\t\t// Big flames mode - red flashing\n\t\t\tvar time = Date.now() * 0.003; // Faster flashing\n\t\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\t\tvar redValue = Math.floor(255);\n\t\t\tvar greenValue = Math.floor(intensity * 64); // More red tint\n\t\t\tvar blueValue = Math.floor(intensity * 64);\n\t\t\teffectButtons[0].tint = redValue << 16 | greenValue << 8 | blueValue;\n\t\t}\n\t}\n\t// Display RGB flashing effect on the third effect button's frame if active\n\tif (isRgbFlashingActive && effectButtons[2]) {\n\t\tvar time = Date.now() * 0.0005; // Time for animation, even slower\n\t\tvar hue = time * 360 % 360; // Cycle through hues\n\t\tvar rgb = hsvToRgb(hue / 360, 1.0, 1.0); // Full saturation and value for vibrant flash\n\t\teffectButtons[2].tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n\t} else if (effectButtons[2]) {\n\t\t// If not active, set the tint back to white\n\t\teffectButtons[2].tint = 0xFFFFFF;\n\t}\n\t// --- UV button continuous purple flashing effect ---\n\tif (effectButtons[4]) {\n\t\tif (uvEffectActive) {\n\t\t\t// Animate between indigo and purple\n\t\t\tvar uvBtnTime = Date.now() * 0.0015; // Slightly faster for button, but slower flashing for button\n\t\t\t// Indigo: #4B0082 (0x4B0082), Purple: #8000FF (0x8000FF)\n\t\t\tvar t = 0.5 + 0.5 * Math.sin(uvBtnTime * Math.PI * 2);\n\t\t\t// Interpolate RGB\n\t\t\tvar r = Math.round(0x4B * (1 - t) + 0x80 * t);\n\t\t\tvar g = Math.round(0x00 * (1 - t) + 0x00 * t);\n\t\t\tvar b = Math.round(0x82 * (1 - t) + 0xFF * t);\n\t\t\teffectButtons[4].tint = r << 16 | g << 8 | b;\n\t\t} else {\n\t\t\teffectButtons[4].tint = 0xFFFFFF;\n\t\t}\n\t}\n\t// Manage gifts effects based on giftsMode\n\tif (balloons) {\n\t\tfor (var i = 0; i < balloons.length; i++) {\n\t\t\tballoons[i].update();\n\t\t\t// Only show balloons if giftsMode is 1 (balloons mode)\n\t\t\tballoons[i].visible = giftsMode === 1;\n\t\t}\n\t}\n\tif (moneyParticles) {\n\t\tfor (var i = 0; i < moneyParticles.length; i++) {\n\t\t\tmoneyParticles[i].update();\n\t\t\t// Only show money particles if giftsMode is 2 (money mode)\n\t\t\tmoneyParticles[i].visible = giftsMode === 2;\n\t\t}\n\t}\n\t// Manage fireworks visibility (fireworks are spread across multiple instances)\n\tif (fireworksEffect) fireworksEffect.visible = giftsMode === 3;\n\tif (fireworksEffect2) fireworksEffect2.visible = giftsMode === 3;\n\tif (fireworksEffect3) fireworksEffect3.visible = giftsMode === 3;\n\tif (fireworksEffect4) fireworksEffect4.visible = giftsMode === 3;\n\t// Update fireworks effect animation only if visible\n\tif (fireworksEffect && fireworksEffect.visible) fireworksEffect.update();\n\tif (fireworksEffect2 && fireworksEffect2.visible) fireworksEffect2.update();\n\tif (fireworksEffect3 && fireworksEffect3.visible) fireworksEffect3.update();\n\tif (fireworksEffect4 && fireworksEffect4.visible) fireworksEffect4.update();\n\t// Update gifts button visual feedback based on mode\n\tif (giftsEffectButton) {\n\t\ttween.stop(giftsEffectButton, {\n\t\t\ttint: true\n\t\t}); // Stop any previous tint tweens\n\t\tif (giftsMode === 0) {\n\t\t\t// Off mode - no light (white tint)\n\t\t\tgiftsEffectButton.tint = 0xFFFFFF;\n\t\t} else if (giftsMode === 1) {\n\t\t\t// Balloons mode - flashing pink\n\t\t\tvar time = Date.now() * 0.002; // Medium speed flashing\n\t\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\t\tvar pinkValue = Math.floor(intensity * 255);\n\t\t\tgiftsEffectButton.tint = 0xFF00FF | pinkValue << 8 | pinkValue; // Magenta/Pink\n\t\t} else if (giftsMode === 2) {\n\t\t\t// Money mode - green color\n\t\t\tgiftsEffectButton.tint = 0x00FF00; // Green\n\t\t} else if (giftsMode === 3) {\n\t\t\t// Fireworks mode - flashing gold\n\t\t\tvar time = Date.now() * 0.002; // Medium speed flashing\n\t\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\t\tvar goldR = Math.floor(intensity * 255);\n\t\t\tvar goldG = Math.floor(intensity * 215);\n\t\t\tvar goldB = Math.floor(intensity * 0);\n\t\t\tgiftsEffectButton.tint = goldR << 16 | goldG << 8 | goldB; // Gold/Yellowish\n\t\t}\n\t}\n};\ntabletAsset.x = (leftDeckScreen.x + rightDeckScreen.x) / 2;\ntabletAsset.y = leftDeckScreen.y + 77 + 35 - 20 - 200 - 35;\n// --- Arrow Buttons under Tablet ---\nvar arrowButtonSpacing = 150;\nvar arrowButtonY = tabletAsset.y + tabletAsset.height / 2 + 80;\nvar leftArrowButton = LK.getAsset('Leftarrow', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\nleftArrowButton.x = tabletAsset.x - arrowButtonSpacing * 1.5 - 50 - 5 - 5 - 1;\nleftArrowButton.y = arrowButtonY;\ngame.addChild(leftArrowButton);\n// Scale up left arrow button by 1.3\ntween(leftArrowButton, {\n\tscaleX: 1.3,\n\tscaleY: 1.3\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar upArrowButton = LK.getAsset('UParrow', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\nupArrowButton.x = tabletAsset.x + arrowButtonSpacing * 1.5 - 50 - 5 - 12 - 5 - 1;\nupArrowButton.y = arrowButtonY;\ngame.addChild(upArrowButton);\n// Scale up up arrow button by 1.3\ntween(upArrowButton, {\n\tscaleX: 1.3,\n\tscaleY: 1.3\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar downArrowButton = LK.getAsset('Downarrow', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\ndownArrowButton.x = tabletAsset.x + arrowButtonSpacing * 0.5 - 50 - 5 - 12 - 5 - 1;\ndownArrowButton.y = arrowButtonY;\ngame.addChild(downArrowButton);\n// Scale up down arrow button by 1.3\ntween(downArrowButton, {\n\tscaleX: 1.3,\n\tscaleY: 1.3\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar rightArrowButton = LK.getAsset('Rightarrow', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\nrightArrowButton.x = tabletAsset.x - arrowButtonSpacing * 0.5 - 50 - 5 - 12 - 5 - 1;\nrightArrowButton.y = arrowButtonY;\ngame.addChild(rightArrowButton);\n// Scale up right arrow button by 1.3\ntween(rightArrowButton, {\n\tscaleX: 1.3,\n\tscaleY: 1.3\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar okButton = LK.getAsset('OKbutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\n// Place OK button to the right of the right arrow button with the same spacing as between arrow buttons\nokButton.x = upArrowButton.x + arrowButtonSpacing - 12 - 5 - 1 + 2 + 2;\nokButton.y = arrowButtonY;\ngame.addChild(okButton);\n// Scale up OK button by 1.3 to match arrow buttons\ntween(okButton, {\n\tscaleX: 1.3,\n\tscaleY: 1.3\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\n// Add edit button under the OK button\nvar editButton = LK.getAsset('editbutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\neditButton.x = okButton.x;\neditButton.y = okButton.y + okButton.height + 20; // Position 20 units under the OK button\ngame.addChild(editButton);\n// Scale up edit button by 1.3 to match arrow buttons\ntween(editButton, {\n\tscaleX: 1.3,\n\tscaleY: 1.3\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\n// --- Pulse Button Effect State ---\nvar pulseButtonEffect = 1.0; // 1.0 = normal, <1.0 = decreased\n// Helper to decrease pulse effect\nfunction decreasePulseButtonEffect() {\n\tpulseButtonEffect = 0.5;\n\t// Optionally, restore after a short time for visual feedback\n\tLK.setTimeout(function () {\n\t\tpulseButtonEffect = 1.0;\n\t}, 200);\n}\n// --- Add decrease pulse effect to arrow and OK buttons ---\nleftArrowButton.down = function (x, y, obj) {\n\tdecreasePulseButtonEffect();\n\t// Navigate left in rekordbox app\n\tif (typeof rekordboxApp !== 'undefined') {\n\t\trekordboxApp.navigateLeft();\n\t}\n\t// Visual feedback\n\ttween(leftArrowButton, {\n\t\tscaleX: 1.1,\n\t\tscaleY: 1.1\n\t}, {\n\t\tduration: 80,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(leftArrowButton, {\n\t\t\t\tscaleX: 1.3,\n\t\t\t\tscaleY: 1.3\n\t\t\t}, {\n\t\t\t\tduration: 120\n\t\t\t});\n\t\t}\n\t});\n};\nrightArrowButton.down = function (x, y, obj) {\n\tdecreasePulseButtonEffect();\n\t// Navigate right in rekordbox app\n\tif (typeof rekordboxApp !== 'undefined') {\n\t\trekordboxApp.navigateRight();\n\t}\n\ttween(rightArrowButton, {\n\t\tscaleX: 1.1,\n\t\tscaleY: 1.1\n\t}, {\n\t\tduration: 80,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(rightArrowButton, {\n\t\t\t\tscaleX: 1.3,\n\t\t\t\tscaleY: 1.3\n\t\t\t}, {\n\t\t\t\tduration: 120\n\t\t\t});\n\t\t}\n\t});\n};\nupArrowButton.down = function (x, y, obj) {\n\tdecreasePulseButtonEffect();\n\t// Navigate up in rekordbox app\n\tif (typeof rekordboxApp !== 'undefined') {\n\t\trekordboxApp.navigateUp();\n\t}\n\ttween(upArrowButton, {\n\t\tscaleX: 1.1,\n\t\tscaleY: 1.1\n\t}, {\n\t\tduration: 80,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(upArrowButton, {\n\t\t\t\tscaleX: 1.3,\n\t\t\t\tscaleY: 1.3\n\t\t\t}, {\n\t\t\t\tduration: 120\n\t\t\t});\n\t\t}\n\t});\n};\ndownArrowButton.down = function (x, y, obj) {\n\tdecreasePulseButtonEffect();\n\t// Navigate down in rekordbox app\n\tif (typeof rekordboxApp !== 'undefined') {\n\t\trekordboxApp.navigateDown();\n\t}\n\ttween(downArrowButton, {\n\t\tscaleX: 1.1,\n\t\tscaleY: 1.1\n\t}, {\n\t\tduration: 80,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(downArrowButton, {\n\t\t\t\tscaleX: 1.3,\n\t\t\t\tscaleY: 1.3\n\t\t\t}, {\n\t\t\t\tduration: 120\n\t\t\t});\n\t\t}\n\t});\n};\nokButton.down = function (x, y, obj) {\n\tdecreasePulseButtonEffect();\n\t// Select track in rekordbox app\n\tif (typeof rekordboxApp !== 'undefined' && rekordboxApp.selectTrack) {\n\t\trekordboxApp.selectTrack();\n\t}\n\ttween(okButton, {\n\t\tscaleX: 1.1,\n\t\tscaleY: 1.1\n\t}, {\n\t\tduration: 80,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(okButton, {\n\t\t\t\tscaleX: 1.3,\n\t\t\t\tscaleY: 1.3\n\t\t\t}, {\n\t\t\t\tduration: 120\n\t\t\t});\n\t\t}\n\t});\n};\n// Add functionality to edit button\neditButton.down = function (x, y, obj) {\n\tdecreasePulseButtonEffect();\n\t// Create fullscreen song maker app\n\tvar songMakerApp = new SongMakerApp();\n\tgame.addChild(songMakerApp);\n\t// Create semi-transparent background overlay\n\tvar overlay = LK.getAsset('crossfaderTrack', {\n\t\tanchorX: 0,\n\t\tanchorY: 0,\n\t\twidth: 2048,\n\t\theight: 2732\n\t});\n\toverlay.tint = 0x000000;\n\toverlay.alpha = 0.7;\n\toverlay.x = 0;\n\toverlay.y = 0;\n\t// Add overlay behind the app\n\tgame.addChild(overlay);\n\tgame.setChildIndex(overlay, game.children.indexOf(songMakerApp) - 1);\n\t// Add X (close window) button to the full screen song maker app top right corner\n\tvar closeButton = LK.getAsset('X', {\n\t\tanchorX: 1.0,\n\t\tanchorY: 0.0\n\t});\n\tcloseButton.scaleX = 2.0;\n\tcloseButton.scaleY = 2.0;\n\tcloseButton.x = 2048 - 20; // 20px from right edge\n\tcloseButton.y = 20; // 20px from top edge\n\tgame.addChild(closeButton);\n\t// Add close functionality to the X button\n\tcloseButton.down = function (x, y, obj) {\n\t\t// Remove fullscreen song maker app, overlay, and close button\n\t\tif (game.children.indexOf(songMakerApp) !== -1) {\n\t\t\tgame.removeChild(songMakerApp);\n\t\t}\n\t\tif (game.children.indexOf(overlay) !== -1) {\n\t\t\tgame.removeChild(overlay);\n\t\t}\n\t\tif (game.children.indexOf(closeButton) !== -1) {\n\t\t\tgame.removeChild(closeButton);\n\t\t}\n\t};\n\t// Add close functionality when clicking overlay\n\toverlay.down = function (x, y, obj) {\n\t\t// Remove fullscreen song maker app and overlay\n\t\tif (game.children.indexOf(songMakerApp) !== -1) {\n\t\t\tgame.removeChild(songMakerApp);\n\t\t}\n\t\tif (game.children.indexOf(overlay) !== -1) {\n\t\t\tgame.removeChild(overlay);\n\t\t}\n\t\tif (game.children.indexOf(closeButton) !== -1) {\n\t\t\tgame.removeChild(closeButton);\n\t\t}\n\t};\n\ttween(editButton, {\n\t\tscaleX: 1.1,\n\t\tscaleY: 1.1\n\t}, {\n\t\tduration: 80,\n\t\tonFinish: function onFinish() {\n\t\t\ttween(editButton, {\n\t\t\t\tscaleX: 1.3,\n\t\t\t\tscaleY: 1.3\n\t\t\t}, {\n\t\t\t\tduration: 120\n\t\t\t});\n\t\t}\n\t});\n};\n// Update second dancing people line animations (second set created) - swap with UV assets when UV is active\nfor (var i = 8; i < dancingPeople.length; i++) {\n\tvar person = dancingPeople[i];\n\t// Check if UV effect is active\n\tif (uvEffectActive) {\n\t\t// If not already a UV person, swap to UV asset\n\t\tif (!person.isUV) {\n\t\t\tvar uvAssetId = (i - 8) % 2 === 0 ? 'UVW' : 'UWM';\n\t\t\tvar currentScaleX = person.scale.x;\n\t\t\tvar currentScaleY = person.scale.y;\n\t\t\tvar currentRotation = person.rotation;\n\t\t\tvar currentAlpha = person.alpha;\n\t\t\tvar currentX = person.x;\n\t\t\tvar currentY = person.y;\n\t\t\tvar currentBaseY = person.baseY;\n\t\t\tvar currentPhaseOffset = person.phaseOffset;\n\t\t\t// Remove the old graphic child\n\t\t\tif (person.children.length > 0) {\n\t\t\t\tperson.removeChildAt(0);\n\t\t\t}\n\t\t\t// Add the new UV graphic child\n\t\t\tvar uvGraphic = person.attachAsset(uvAssetId, {\n\t\t\t\tanchorX: 0.5,\n\t\t\t\tanchorY: 1.0\n\t\t\t});\n\t\t\t// Restore previous transform and animation properties\n\t\t\tperson.scale.set(currentScaleX, currentScaleY);\n\t\t\tperson.rotation = currentRotation;\n\t\t\tperson.alpha = currentAlpha;\n\t\t\tperson.x = currentX;\n\t\t\tperson.y = currentY;\n\t\t\tperson.baseY = currentBaseY;\n\t\t\tperson.phaseOffset = currentPhaseOffset;\n\t\t\tperson.isUV = true;\n\t\t}\n\t} else {\n\t\t// If UV effect is off and it's a UV person, swap back to normal asset\n\t\tif (person.isUV) {\n\t\t\tvar normalAssetId = (i - 8) % 2 === 0 ? 'dancingWoman' : 'dancingMan';\n\t\t\tvar currentScaleX = person.scale.x;\n\t\t\tvar currentScaleY = person.scale.y;\n\t\t\tvar currentRotation = person.rotation;\n\t\t\tvar currentAlpha = person.alpha;\n\t\t\tvar currentX = person.x;\n\t\t\tvar currentY = person.y;\n\t\t\tvar currentBaseY = person.baseY;\n\t\t\tvar currentPhaseOffset = person.phaseOffset;\n\t\t\t// Remove the old graphic child\n\t\t\tif (person.children.length > 0) {\n\t\t\t\tperson.removeChildAt(0);\n\t\t\t}\n\t\t\t// Add the new normal graphic child\n\t\t\tvar normalGraphic = person.attachAsset(normalAssetId, {\n\t\t\t\tanchorX: 0.5,\n\t\t\t\tanchorY: 1.0\n\t\t\t});\n\t\t\t// Restore previous transform and animation properties\n\t\t\tperson.scale.set(currentScaleX, currentScaleY);\n\t\t\tperson.rotation = currentRotation;\n\t\t\tperson.alpha = currentAlpha;\n\t\t\tperson.x = currentX;\n\t\t\tperson.y = currentY;\n\t\t\tperson.baseY = currentBaseY;\n\t\t\tperson.phaseOffset = currentPhaseOffset;\n\t\t\tperson.isUV = false;\n\t\t}\n\t}\n\tperson.update();\n}\n// Animate extra white particles (subtle sparkle and movement)\nif (extraWhiteParticles) {\n\tvar t = Date.now() * 0.001;\n\tfor (var i = 0; i < extraWhiteParticles.length; i++) {\n\t\tvar p = extraWhiteParticles[i];\n\t\t// Subtle float and twinkle\n\t\tp.obj.x = p.baseX + Math.sin(t * 1.2 + p.phase + i) * 8;\n\t\tp.obj.y = p.baseY + Math.cos(t * 1.1 + p.phase + i * 0.7) * 6;\n\t\tp.obj.alpha = p.baseAlpha + 0.10 * Math.sin(t * 2.2 + p.phase + i * 0.5);\n\t\tvar s = p.baseSize * (0.95 + 0.12 * Math.sin(t * 1.7 + p.phase + i));\n\t\tp.obj.width = s;\n\t\tp.obj.height = s;\n\t}\n}\n// Animate flashing white reflectors\nif (reflectors) {\n\tvar t = Date.now() * 0.001;\n\tfor (var i = 0; i < reflectors.length; i++) {\n\t\t// Staggered flash, each reflector flashes in sequence\n\t\tvar phase = t * 2.2 + i * 0.5;\n\t\t// Use a sharp pulse for flash, then fade out\n\t\tvar flash = Math.max(0, Math.sin(phase));\n\t\t// Sharpen the flash curve for a strobe effect\n\t\tflash = Math.pow(flash, 6);\n\t\treflectors[i].alpha = 0.18 + 0.82 * flash;\n\t\t// Animate as perfect circles for extra pop (half size base)\n\t\tvar size = 60 + 20 * flash;\n\t\t// Prevent reflectors from covering the discoball\n\t\t// Compute distance from reflector to discoball center\n\t\tvar dx = reflectors[i].x - discoball.x;\n\t\tvar dy = reflectors[i].y - discoball.y;\n\t\tvar dist = Math.sqrt(dx * dx + dy * dy);\n\t\t// Discoball's visible radius (scaled)\n\t\tvar discoballRadius = 150 * discoball.scaleX; // matches Discoball class\n\t\t// If reflector would overlap discoball, shrink it so it cannot cover\n\t\tif (dist < discoballRadius + size / 2) {\n\t\t\t// Max allowed size so edge of reflector does not enter discoball\n\t\t\tvar maxSize = Math.max(0, 2 * (dist - discoballRadius));\n\t\t\tif (size > maxSize) size = maxSize;\n\t\t\tif (size < 0) size = 0;\n\t\t}\n\t\treflectors[i].width = size;\n\t\treflectors[i].height = size;\n\t}\n}\n// Update laser show animation\nlaserShow.update();\n// Update fireworks effect animation\nfireworksEffect.update();\nfireworksEffect2.update();\nfireworksEffect3.update();\nfireworksEffect4.update();\n// Update Ferris wheel animation\nif (typeof ferrisWheel !== 'undefined' && ferrisWheel.update) {\n\t// Defensive check\n\tferrisWheel.update();\n}\n// Update smoke diffuser animation\n// --- Synchronize all smoke diffusers so they emit smoke puffs at the same time ---\nif (typeof smokeDiffusers !== 'undefined' && smokeDiffusers.length > 0) {\n\t// Use the first smoke diffuser as the \"master\" for timing\n\tvar now = Date.now();\n\t// All diffusers share the same \"now\" and will create puffs in sync\n\tfor (var i = 0; i < smokeDiffusers.length; i++) {\n\t\tvar sd = smokeDiffusers[i];\n\t\t// Patch: override the update method to use the same \"now\" for all\n\t\tif (sd && typeof sd.update === 'function') {\n\t\t\t// Save original Date.now\n\t\t\tvar origDateNow = Date.now;\n\t\t\tDate.now = function () {\n\t\t\t\treturn now;\n\t\t\t};\n\t\t\tsd.update();\n\t\t\tDate.now = origDateNow;\n\t\t}\n\t}\n}\n// Update flamethrower animation\nif (typeof flamethrower !== 'undefined' && flamethrower.update) {\n\tflamethrower.update();\n}\n// Update decks\nleftDeck.update();\nrightDeck.update();\n// Update equalizers\nleftEqualizer.update();\nrightEqualizer.update();\n// Simulate beat\nvar now = Date.now();\nbeatTimer += now - lastTickTime;\nlastTickTime = now;\nif (beatTimer >= beatInterval) {\n\tbeatTimer -= beatInterval;\n\tleftDeck.flashBeat();\n\trightDeck.flashBeat();\n\tLK.getSound('beat').play();\n\t// Energy drops if not scratching or mixing\n\tif (!leftDeck.isScratching && !rightDeck.isScratching && crossfader.value > 0.2 && crossfader.value < 0.8) {\n\t\tenergy -= 2;\n\t\tcombo = 0;\n\t} else {\n\t\t// Combo up if scratching or crossfading\n\t\tcombo += 1;\n\t\tscore += 10 * combo;\n\t\tenergy += 2;\n\t\tif (energy > 100) energy = 100;\n\t}\n\tif (energy < 0) energy = 0;\n\t// Update visuals\n\tscoreTxt.setText('Score: ' + score);\n\tif (combo > 1) {\n\t\tcomboTxt.setText('Combo x' + combo);\n\t} else {\n\t\tcomboTxt.setText('');\n\t}\n}\n// Update energy bar\nenergyBar.width = 600 * (energy / 100);\n// Crossfader logic: adjust music volumes\ntrackAVol = 1 - crossfader.value;\ntrackBVol = crossfader.value;\n// (In a real game, would set music volumes here, but LK handles music globally.)\n// End game if energy is 0\nif (energy <= 0) {\n\t// Game over event disabled\n}\n// Animate background color\nvar time = Date.now() * 0.0005; // Time for animation\nvar hue = time * 360 % 360; // Cycle through hues over time\nvar rgb = hsvToRgb(hue / 360, 0.6, 0.5); // Convert HSV to RGB (adjust saturation and value for desired effect)\n// Only animate the background color if RGB flashing is active on the third effect button\nif (isRgbFlashingActive) {\n\tgame.setBackgroundColor(rgb[0] << 16 | rgb[1] << 8 | rgb[2]);\n} else if (uvEffectActive) {\n\t// If UV effect is active, flash between indigo blue and purple\n\tvar uvTime = Date.now() * 0.002; // Faster flashing for UV\n\tvar uvHue = uvTime * 360 % 360;\n\t// Cycle between indigo (around 240 hue) and purple (around 270 hue)\n\tvar targetHue = 240 + Math.sin(uvTime * Math.PI * 2) * 30;\n\ttargetHue = (targetHue + 360) % 360;\n\tvar uvRgb = hsvToRgb(targetHue / 360, 0.8, 0.7); // Adjust saturation and value for UV colors\n\tgame.setBackgroundColor(uvRgb[0] << 16 | uvRgb[1] << 8 | uvRgb[2]);\n} else {\n\t// If neither is active, set a default background color\n\tgame.setBackgroundColor(0x000000); // Or any other default color\n}\n// Win condition disabled\n// --- Update Digital Clock ---\nif (typeof digitalClockTxt !== 'undefined') {\n\tvar now = new Date();\n\tdigitalClockTxt.setText(formatTime(now));\n}\n// Display laser flashing effect on the second effect button's frame based on mode\nif (effectButtons[1]) {\n\tif (laserShowMode === 0) {\n\t\t// Off mode - normal white tint\n\t\teffectButtons[1].tint = 0xFFFFFF;\n\t} else if (laserShowMode === 1) {\n\t\t// Slow mode - slow blue pulsing\n\t\tvar time = Date.now() * 0.0008; // Slow pulsing\n\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\tvar blueValue = Math.floor(intensity * 255);\n\t\teffectButtons[1].tint = 0x4444ff | blueValue << 8 | blueValue;\n\t} else if (laserShowMode === 2) {\n\t\t// Fast mode - slower rainbow cycling\n\t\tvar time = Date.now() * 0.0008; // Slower cycling (reduced from 0.002)\n\t\tvar laserColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];\n\t\tvar colorIndex = Math.floor(time * 3) % laserColors.length; // Slower color cycling (reduced from 8 to 3)\n\t\teffectButtons[1].tint = laserColors[colorIndex];\n\t}\n}\n// Display fire effect flashing on the first effect button's frame based on mode\nif (effectButtons[0]) {\n\tif (fireEffectMode === 0) {\n\t\t// Off mode - normal white tint\n\t\teffectButtons[0].tint = 0xFFFFFF;\n\t} else if (fireEffectMode === 1) {\n\t\t// Normal flames mode - orange flashing\n\t\tvar time = Date.now() * 0.002; // Medium speed flashing\n\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\tvar redValue = Math.floor(255);\n\t\tvar greenValue = Math.floor(intensity * 128 + 64); // Orange tint\n\t\tvar blueValue = 0;\n\t\teffectButtons[0].tint = redValue << 16 | greenValue << 8 | blueValue;\n\t} else if (fireEffectMode === 2) {\n\t\t// Big flames mode - red flashing\n\t\tvar time = Date.now() * 0.003; // Faster flashing\n\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\tvar redValue = Math.floor(255);\n\t\tvar greenValue = Math.floor(intensity * 64); // More red tint\n\t\tvar blueValue = Math.floor(intensity * 64);\n\t\teffectButtons[0].tint = redValue << 16 | greenValue << 8 | blueValue;\n\t}\n}\n// Display RGB flashing effect on the third effect button's frame if active\nif (isRgbFlashingActive && effectButtons[2]) {\n\tvar time = Date.now() * 0.0005; // Time for animation, even slower\n\tvar hue = time * 360 % 360; // Cycle through hues\n\tvar rgb = hsvToRgb(hue / 360, 1.0, 1.0); // Full saturation and value for vibrant flash\n\teffectButtons[2].tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];\n} else if (effectButtons[2]) {\n\t// If not active, set the tint back to white\n\teffectButtons[2].tint = 0xFFFFFF;\n}\n// --- UV button continuous purple flashing effect ---\nif (effectButtons[4]) {\n\tif (uvEffectActive) {\n\t\t// Animate between indigo and purple\n\t\tvar uvBtnTime = Date.now() * 0.0015; // Slightly faster for button, but slower flashing for button\n\t\t// Indigo: #4B0082 (0x4B0082), Purple: #8000FF (0x8000FF)\n\t\tvar t = 0.5 + 0.5 * Math.sin(uvBtnTime * Math.PI * 2);\n\t\t// Interpolate RGB\n\t\tvar r = Math.round(0x4B * (1 - t) + 0x80 * t);\n\t\tvar g = Math.round(0x00 * (1 - t) + 0x00 * t);\n\t\tvar b = Math.round(0x82 * (1 - t) + 0xFF * t);\n\t\teffectButtons[4].tint = r << 16 | g << 8 | b;\n\t} else {\n\t\teffectButtons[4].tint = 0xFFFFFF;\n\t}\n}\n// Manage gifts effects based on giftsMode\nif (balloons) {\n\tfor (var i = 0; i < balloons.length; i++) {\n\t\tballoons[i].update();\n\t\t// Only show balloons if giftsMode is 1 (balloons mode)\n\t\tballoons[i].visible = giftsMode === 1;\n\t}\n}\nif (moneyParticles) {\n\tfor (var i = 0; i < moneyParticles.length; i++) {\n\t\tmoneyParticles[i].update();\n\t\t// Only show money particles if giftsMode is 2 (money mode)\n\t\tmoneyParticles[i].visible = giftsMode === 2;\n\t}\n}\n// Manage fireworks visibility (fireworks are spread across multiple instances)\nif (fireworksEffect) fireworksEffect.visible = giftsMode === 3;\nif (fireworksEffect2) fireworksEffect2.visible = giftsMode === 3;\nif (fireworksEffect3) fireworksEffect3.visible = giftsMode === 3;\nif (fireworksEffect4) fireworksEffect4.visible = giftsMode === 3;\n// Update fireworks effect animation only if visible\nif (fireworksEffect && fireworksEffect.visible) fireworksEffect.update();\nif (fireworksEffect2 && fireworksEffect2.visible) fireworksEffect2.update();\nif (fireworksEffect3 && fireworksEffect3.visible) fireworksEffect3.update();\nif (fireworksEffect4 && fireworksEffect4.visible) fireworksEffect4.update();\n// Update gifts button visual feedback based on mode\nif (giftsEffectButton) {\n\ttween.stop(giftsEffectButton, {\n\t\ttint: true\n\t}); // Stop any previous tint tweens\n\tif (giftsMode === 0) {\n\t\t// Off mode - no light (white tint)\n\t\tgiftsEffectButton.tint = 0xFFFFFF;\n\t} else if (giftsMode === 1) {\n\t\t// Balloons mode - flashing pink\n\t\tvar time = Date.now() * 0.002; // Medium speed flashing\n\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\tvar pinkValue = Math.floor(intensity * 255);\n\t\tgiftsEffectButton.tint = 0xFF00FF | pinkValue << 8 | pinkValue; // Magenta/Pink\n\t} else if (giftsMode === 2) {\n\t\t// Money mode - green color\n\t\tgiftsEffectButton.tint = 0x00FF00; // Green\n\t} else if (giftsMode === 3) {\n\t\t// Fireworks mode - flashing gold\n\t\tvar time = Date.now() * 0.002; // Medium speed flashing\n\t\tvar intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);\n\t\tvar goldR = Math.floor(intensity * 255);\n\t\tvar goldG = Math.floor(intensity * 215);\n\t\tvar goldB = Math.floor(intensity * 0);\n\t\tgiftsEffectButton.tint = goldR << 16 | goldG << 8 | goldB; // Gold/Yellowish\n\t}\n}\nokButton.y = arrowButtonY + 12 + 30 - 25; // Move OK button down by 30 units\ngame.addChild(okButton);\nleftArrowButton.x = tabletAsset.x - arrowButtonSpacing * 1.5 - 50 - 5 - 5 - 1;\nleftArrowButton.y = arrowButtonY + 12 + 30 - 25; // Move left arrow down by 30 units\ngame.addChild(leftArrowButton);\nupArrowButton.x = tabletAsset.x + arrowButtonSpacing * 1.5 - 50 - 5 - 12 - 5 - 1;\nupArrowButton.y = arrowButtonY + 12 + 30 - 25; // Move up arrow down by 30 units\ngame.addChild(upArrowButton);\ndownArrowButton.x = tabletAsset.x + arrowButtonSpacing * 0.5 - 50 - 5 - 12 - 5 - 1;\ndownArrowButton.y = arrowButtonY + 12 + 30 - 25; // Move down arrow down by 30 units\ngame.addChild(downArrowButton);\nrightArrowButton.x = tabletAsset.x - arrowButtonSpacing * 0.5 - 50 - 5 - 12 - 5 - 1;\nrightArrowButton.y = arrowButtonY + 12 + 30 - 25; // Move right arrow down by 30 units\ngame.addChild(rightArrowButton);\n// Update edit button position in update loop\nif (typeof editButton !== 'undefined' && typeof okButton !== 'undefined') {\n\teditButton.x = okButton.x;\n\teditButton.y = okButton.y + okButton.height + 20 + 12 - 25 + 20 + 20; // Move down by 12 units + 20 units\n}\nvar editButton = LK.getAsset('editbutton', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\nfxButton.y = fxButtonY + 200 + 10;\n// Add white A letter under fx button\nvar fxButtonAText = new Text2('A', {\n\tsize: 48,\n\tfill: 0xFFFFFF // White color\n});\nfxButtonAText.anchor.set(0.5, 0.5);\nfxButtonAText.x = fxButton.x - 150;\nfxButtonAText.y = fxButton.y + fxButton.height / 2 + 20 + 90 + 12; // Position under the button, moved down by 90 units, then down by 12 units\ngame.addChild(fxButtonAText);\nleftFilterKnobMid.y = leftDeckAsset.y + 30 + 30 + 30 + 30 + 50 + 30 + 30 + 12;\n// Add white MID text under the MID filter knob\nvar midTextLeft = new Text2('MID', {\n\tsize: 24,\n\tfill: 0xFFFFFF // White color\n});\nmidTextLeft.anchor.set(0.5, 0.5);\nmidTextLeft.x = leftFilterKnobMid.x;\nmidTextLeft.y = leftFilterKnobMid.y + leftFilterKnobMid.height / 2 + 20; // Position under the knob\ngame.addChild(midTextLeft);\ntween(leftFilterKnobMid, {\n\tscaleX: 1.2,\n\tscaleY: 1.2\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar leftFilterKnobLow = LK.getAsset('filterKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\nrightFilterKnobMid.y = rightDeckAsset.y + 30 + 30 + 30 + 30 + 50 + 30 + 30 + 12;\n// Add white MID text under the MID filter knob (Right side)\nvar midTextRight = new Text2('MID', {\n\tsize: 24,\n\tfill: 0xFFFFFF // White color\n});\nmidTextRight.anchor.set(0.5, 0.5);\nmidTextRight.x = rightFilterKnobMid.x;\nmidTextRight.y = rightFilterKnobMid.y + rightFilterKnobMid.height / 2 + 20; // Position under the knob\ngame.addChild(midTextRight);\ntween(rightFilterKnobMid, {\n\tscaleX: 1.2,\n\tscaleY: 1.2\n}, {\n\tduration: 300,\n\teasing: tween.easeOut\n});\nvar rightFilterKnobLow = LK.getAsset('filterKnob', {\n\tanchorX: 0.5,\n\tanchorY: 0.5\n});\nlogoAsset.x = crossfader.x;\nlogoAsset.y = crossfader.y + crossfader.height / 2 + 30 - 350 - 40; // Position under the crossfader, moved up by 350 units;\nlogoAsset.x = crossfader.x;\nlogoAsset.y = crossfader.y + crossfader.height / 2 + 30 - 350 - 40 - 50; // Position under the crossfader, moved up by 350 units;;\nmasterButtonBText.x = masterAsset.x + 150;\nmasterButtonBText.y = masterAsset.y + masterAsset.height / 2 + 20 + 100; // Position under the button, moved down by 100 units\nmasterButtonBText.y = masterAsset.y + masterAsset.height / 2 + 20 + 100 + 10; // Position under the button, moved down by 100 units, moved down by 10 units;\ngame.addChild(masterButtonBText);\nfxButtonAText.y = fxButton.y + fxButton.height / 2 + 20 + 90 + 12 + 10 + 10; // Position under the button, moved down by 90 units, then down by 12 units, then down by 10 units, then down by 10 units;"} Upit | Learn about creating the game Best DJ with gen AI