User prompt
Move the fog button down by 77 units
User prompt
Move the fog button left by 777 units
User prompt
Move the fog button under the pause button
User prompt
Add fog button under the pause button.
User prompt
Add fog button asset to the game.
User prompt
Add fog button asset to the game. Place fog button asseet under the pause button.
User prompt
Add fog button under the pause button
User prompt
Please fix the bug: 'fogButton.children[0].children[0].setText is not a function' in or related to this line: 'fogButton.children[0].children[0].setText('FOG'); // Access the Text2 object inside the FXButton's children' Line Number: 808
User prompt
Add fog button tunder the pause button
User prompt
Make bigger fog
User prompt
Change the fog looking for a more realistic discofog
User prompt
Change the fog looking for a more realistic discofog
User prompt
Add FogEffect class for animated fog in upper half of the map ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Turn off the game over event from the game
User prompt
Add animated fog effect to the upper half of the map
User prompt
Move up lasershow by 123 units
User prompt
Make lasershow wider
User prompt
Add more little bit white particles to the upper half of the screen
User prompt
Make discoball lights longers
User prompt
Increase discoball light power a little bit
User prompt
Increase discoball light powera little bit
User prompt
Increase discoball light power
User prompt
Increase discoball light power a little
User prompt
Increase discoball light power
User prompt
Lasershow's head dot should be Color Changing ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Crossfader: Controls mix between decks
var Crossfader = Container.expand(function () {
	var self = Container.call(this);
	// State
	self.value = 0.5; // 0 = left, 1 = right
	self.dragging = false;
	// Visuals
	var track = self.attachAsset('crossfaderTrack', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var knob = self.attachAsset('crossfaderKnob', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	knob.y = 0;
	// Methods
	self.setValue = function (val) {
		self.value = Math.max(0, Math.min(1, val));
		knob.x = (self.value - 0.5) * (track.width - knob.width);
	};
	// Touch events
	self.down = function (x, y, obj) {
		self.dragging = true;
		self.setValue(x / track.width);
	};
	self.up = function (x, y, obj) {
		self.dragging = false;
	};
	self.move = function (x, y, obj) {
		if (self.dragging) {
			self.setValue(x / track.width);
		}
	};
	return self;
});
// DeckPlatter: Represents a turntable platter
var DeckPlatter = Container.expand(function () {
	var self = Container.call(this);
	// State
	self.isActive = false;
	self.isScratching = false;
	self.lastAngle = 0;
	self.rotationOffset = 0;
	self.currentRotation = 0;
	self.track = 'A'; // 'A' or 'B'
	self.playing = true;
	self.scratchSpeed = 0;
	self.lastTouchAngle = null;
	// Visuals
	var platter = self.attachAsset('deckPlatter', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var highlight = self.attachAsset('deckPlatterHighlight', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	highlight.alpha = 0;
	var label = self.attachAsset('deckLabel', {
		anchorX: 0.5,
		anchorY: 0.5,
		y: 140
	});
	// Label text
	var labelTxt = new Text2(self.track, {
		size: 40,
		fill: "#222"
	});
	labelTxt.anchor.set(0.5, 0.5);
	label.addChild(labelTxt);
	// Beat light
	var beatLight = self.attachAsset('beatLight', {
		anchorX: 0.5,
		anchorY: 0.5,
		y: -140
	});
	beatLight.alpha = 0.2;
	// Methods
	self.setActive = function (active) {
		self.isActive = active;
		highlight.alpha = active ? 0.4 : 0;
	};
	self.setTrack = function (track) {
		self.track = track;
		labelTxt.setText(track);
	};
	self.flashBeat = function () {
		beatLight.alpha = 1;
		tween(beatLight, {
			alpha: 0.2
		}, {
			duration: 200,
			easing: tween.easeOut
		});
	};
	// Touch events
	self.down = function (x, y, obj) {
		self.isScratching = true;
		self.setActive(true);
		// Calculate angle from center
		var dx = x - self.width / 2;
		var dy = y - self.height / 2;
		self.lastTouchAngle = Math.atan2(dy, dx);
		self.scratchSpeed = 0;
		LK.getSound('scratch').play();
	};
	self.up = function (x, y, obj) {
		self.isScratching = false;
		self.setActive(false);
		self.scratchSpeed = 0;
		self.lastTouchAngle = null;
	};
	self.move = function (x, y, obj) {
		if (!self.isScratching) return;
		// Calculate angle from center
		var dx = x - self.width / 2;
		var dy = y - self.height / 2;
		var angle = Math.atan2(dy, dx);
		if (self.lastTouchAngle !== null) {
			var delta = angle - self.lastTouchAngle;
			// Normalize delta
			if (delta > Math.PI) delta -= 2 * Math.PI;
			if (delta < -Math.PI) delta += 2 * Math.PI;
			self.rotationOffset += delta;
			self.scratchSpeed = delta;
		}
		self.lastTouchAngle = angle;
	};
	// Called every tick
	self.update = function () {
		// If not scratching, platter rotates at normal speed
		if (!self.isScratching && self.playing) {
			self.rotationOffset += 0.02; // Normal play speed
			self.scratchSpeed = 0.02;
		}
		// Apply rotation
		self.currentRotation = self.rotationOffset;
		self.rotation = self.currentRotation;
	};
	return self;
});
// Discoball: True 3D disco ball illusion with spinning mirrored tiles and shining white light particles
var Discoball = Container.expand(function () {
	var self = Container.call(this);
	// Config
	var ballRadius = 150;
	var ballDiameter = ballRadius * 2;
	var numLat = 13; // latitude tiles (vertical)
	var numLon = 24; // longitude tiles (horizontal)
	var tileSize = ballDiameter / numLat * 0.95;
	var tileGap = tileSize * 0.12;
	var tiles = [];
	var shineParticles = [];
	var numShine = 18;
	var shineRadius = ballRadius * 1.08;
	var shineMinAlpha = 0.25;
	var shineMaxAlpha = 0.95;
	var shineMinSize = tileSize * 0.7;
	var shineMaxSize = tileSize * 1.7;
	var spinY = 0; // radians, for y-axis rotation
	var spinSpeed = 0.012;
	var spinDir = 1;
	// --- Mirrored Tiles Grid ---
	for (var lat = 0; lat < numLat; lat++) {
		var theta = Math.PI * (lat + 0.5) / numLat; // 0 (top) to PI (bottom)
		var y = Math.cos(theta) * ballRadius;
		var r = Math.sin(theta) * ballRadius;
		for (var lon = 0; lon < numLon; lon++) {
			var phi = 2 * Math.PI * lon / numLon;
			// 3D to 2D projection with y-axis spin
			var x3d = Math.cos(phi) * r;
			var z3d = Math.sin(phi) * r;
			// Y-axis spin
			var x2d = x3d * Math.cos(spinY) - z3d * Math.sin(spinY);
			var z2d = x3d * Math.sin(spinY) + z3d * Math.cos(spinY);
			// Only draw front-facing tiles (z2d > 0)
			if (z2d > 0) {
				var tile = LK.getAsset('centerCircle', {
					anchorX: 0.5,
					anchorY: 0.5,
					width: tileSize,
					height: tileSize
				});
				// Mirror color: light gray, with some random sparkle
				var base = 0xbb + Math.floor(Math.random() * 0x22);
				var color = base << 16 | base << 8 | base;
				tile.tint = color;
				tile.alpha = 0.92 - 0.18 * (lat / numLat) + Math.random() * 0.08;
				// Position
				tile.x = x2d;
				tile.y = y;
				// Simulate 3D: scaleX based on z2d
				tile.scaleX = 1 + 0.18 * (z2d / ballRadius);
				tile.scaleY = 1;
				self.addChild(tile);
				tiles.push({
					tile: tile,
					lat: lat,
					lon: lon,
					theta: theta,
					phi: phi
				});
			}
		}
	}
	// --- Specular highlight (white spot) ---
	var highlight = LK.getAsset('centerCircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: ballRadius * 0.7,
		height: ballRadius * 0.36
	});
	highlight.tint = 0xffffff;
	highlight.alpha = 0.7;
	highlight.x = -ballRadius * 0.32;
	highlight.y = -ballRadius * 0.38;
	self.addChild(highlight);
	// --- Shining white light particles ---
	for (var i = 0; i < numShine; i++) {
		var angle = 2 * Math.PI * i / numShine + Math.random() * 0.2;
		var dist = shineRadius * (0.92 + Math.random() * 0.12);
		var particle = LK.getAsset('centerCircle', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: shineMinSize + Math.random() * (shineMaxSize - shineMinSize),
			height: shineMinSize + Math.random() * (shineMaxSize - shineMinSize)
		});
		particle.tint = 0xffffff;
		particle.alpha = shineMinAlpha + Math.random() * (shineMaxAlpha - shineMinAlpha);
		particle.x = Math.cos(angle) * dist;
		particle.y = Math.sin(angle) * dist;
		self.addChild(particle);
		shineParticles.push({
			particle: particle,
			baseAngle: angle,
			baseDist: dist,
			phase: Math.random() * Math.PI * 2
		});
	}
	// --- Light beams (background) ---
	var numBeams = 32;
	var beams = [];
	var lightBeamLength = 1200; // Increased from 800 to 1200 for longer beams
	for (var i = 0; i < numBeams; i++) {
		var beam = LK.getAsset('crossfaderTrack', {
			anchorX: 0.5,
			anchorY: 0,
			width: 8,
			height: lightBeamLength
		});
		beam.tint = 0xffffff;
		beam.alpha = 0.12 + Math.random() * 0.28;
		beam.rotation = Math.PI * 2 / numBeams * i + Math.random() * 0.1;
		beams.push(beam);
		self.addChild(beam);
	}
	// --- Animation ---
	function animateSpinY() {
		// Animate spinY between -PI/2 and PI/2 for y-axis illusion
		var target = spinDir > 0 ? Math.PI / 2 : -Math.PI / 2;
		tween(self, {
			_spinY: target
		}, {
			duration: 1600,
			easing: tween.linear,
			onUpdate: function onUpdate() {
				// nothing, handled in update
			},
			onFinish: function onFinish() {
				spinDir *= -1;
				animateSpinY();
			}
		});
	}
	self._spinY = 0;
	animateSpinY();
	self.update = function () {
		// Animate y-axis spin
		spinY += spinSpeed * spinDir;
		if (spinY > Math.PI / 2) spinY = -Math.PI / 2;
		if (spinY < -Math.PI / 2) spinY = Math.PI / 2;
		self._spinY += (spinY - self._spinY) * 0.18; // smooth
		// Update mirrored tiles positions for y-axis spin
		for (var i = 0; i < tiles.length; i++) {
			var t = tiles[i];
			// 3D to 2D projection with y-axis spin
			var x3d = Math.cos(t.phi) * Math.sin(t.theta) * ballRadius;
			var y3d = Math.cos(t.theta) * ballRadius;
			var z3d = Math.sin(t.phi) * Math.sin(t.theta) * ballRadius;
			// Y-axis spin
			var x2d = x3d * Math.cos(self._spinY) - z3d * Math.sin(self._spinY);
			var z2d = x3d * Math.sin(self._spinY) + z3d * Math.cos(self._spinY);
			// Only show front-facing tiles
			if (z2d > 0) {
				t.tile.visible = true;
				t.tile.x = x2d;
				t.tile.y = y3d;
				t.tile.scaleX = 1 + 0.18 * (z2d / ballRadius);
				t.tile.scaleY = 1;
				// Flicker for disco effect
				t.tile.alpha = 0.88 - 0.18 * (t.lat / numLat) + Math.random() * 0.09;
			} else {
				t.tile.visible = false;
			}
		}
		// Animate highlight to move in a small circle for extra 3D effect
		var t = Date.now() * 0.001;
		highlight.x = -ballRadius * 0.32 + Math.cos(t * 1.2) * ballRadius * 0.13;
		highlight.y = -ballRadius * 0.38 + Math.sin(t * 1.2) * ballRadius * 0.09;
		// Animate shine particles
		for (var i = 0; i < shineParticles.length; i++) {
			var s = shineParticles[i];
			var phase = t * 1.2 + s.phase;
			var r = s.baseDist + Math.sin(phase) * 12;
			s.particle.x = Math.cos(s.baseAngle + Math.sin(phase) * 0.12) * r;
			s.particle.y = Math.sin(s.baseAngle + Math.cos(phase) * 0.12) * r;
			s.particle.alpha = shineMinAlpha + (shineMaxAlpha - shineMinAlpha) * (0.5 + 0.5 * Math.sin(phase * 2 + i));
			var size = shineMinSize + (shineMaxSize - shineMinSize) * (0.5 + 0.5 * Math.cos(phase * 1.5 + i));
			s.particle.width = size;
			s.particle.height = size;
		}
		// Animate beams (spin and flicker)
		for (var i = 0; i < beams.length; i++) {
			var beam = beams[i];
			beam.rotation += 0.015;
			beam.alpha = 0.12 + Math.random() * 0.28;
		}
	};
	return self;
});
// EqualizerWaves: Animated equalizer bars/waves for visual feedback
var EqualizerWaves = Container.expand(function () {
	var self = Container.call(this);
	// Config
	var numBars = 32;
	var barWidth = 40;
	var barSpacing = 16;
	var barMaxHeight = 220;
	var barMinHeight = 40;
	var bars = [];
	// Create bars
	for (var i = 0; i < numBars; i++) {
		var bar = LK.getAsset('crossfaderTrack', {
			anchorX: 0.5,
			anchorY: 1.0,
			width: barWidth,
			height: barMinHeight,
			x: i * (barWidth + barSpacing),
			y: 0
		});
		// Rainbow gradient: hue from 0 to 360 across bars
		var hue = Math.floor(i / numBars * 360);
		var rgb = hsvToRgb(hue / 360, 1, 1);
		bar.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
		// No dark overlay or background is added to the equalizer.
		self.addChild(bar);
		bars.push(bar);
	}
	// HSV to RGB helper
	function hsvToRgb(h, s, v) {
		var r, g, b;
		var i = Math.floor(h * 6);
		var f = h * 6 - i;
		var p = v * (1 - s);
		var q = v * (1 - f * s);
		var t = v * (1 - (1 - f) * s);
		switch (i % 6) {
			case 0:
				r = v, g = t, b = p;
				break;
			case 1:
				r = q, g = v, b = p;
				break;
			case 2:
				r = p, g = v, b = t;
				break;
			case 3:
				r = p, g = q, b = v;
				break;
			case 4:
				r = t, g = p, b = v;
				break;
			case 5:
				r = v, g = p, b = q;
				break;
		}
		return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
	}
	// Center and scale down the whole equalizer to half size
	self.width = numBars * (barWidth + barSpacing) * 0.5;
	self.height = barMaxHeight * 0.5;
	self.scaleX = 0.5;
	self.scaleY = 0.5;
	self.x = 2048 / 2 - self.width / 2;
	self.y = 600; // Upper half of screen, below GUI
	// Animation state
	self.phase = [];
	for (var j = 0; j < numBars; j++) {
		self.phase[j] = Math.random() * Math.PI * 2;
	}
	// Animate bars
	self.update = function () {
		var t = Date.now() * 0.002;
		for (var i = 0; i < numBars; i++) {
			// Simulate music: combine sine waves and random
			var wave = Math.sin(t + self.phase[i]) * 0.5 + 0.5;
			var beatPulse = (Math.sin(t * 2 + i * 0.2) * 0.5 + 0.5) * 0.5;
			var randomPulse = Math.random() * 0.15;
			var h = barMinHeight + (barMaxHeight - barMinHeight) * (wave * 0.6 + beatPulse * 0.3 + randomPulse);
			bars[i].height = h;
		}
	};
	return self;
});
// FXButton: Triggers a sound effect
var FXButton = Container.expand(function () {
	var self = Container.call(this);
	// Visuals
	var btn = self.attachAsset('fxButton', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var txt = new Text2('FX', {
		size: 48,
		fill: "#fff"
	});
	txt.anchor.set(0.5, 0.5);
	btn.addChild(txt);
	// State
	self.cooldown = false;
	// Touch
	self.down = function (x, y, obj) {
		if (self.cooldown) return;
		self.cooldown = true;
		LK.getSound('fx').play();
		tween(btn, {
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 80,
			onFinish: function onFinish() {
				tween(btn, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 120
				});
			}
		});
		LK.setTimeout(function () {
			self.cooldown = false;
		}, 400);
	};
	return self;
});
// FogEffect: Animated fog in upper half of the map
var FogEffect = Container.expand(function () {
	var self = Container.call(this);
	// Config
	var numParticles = 60;
	var particles = [];
	var particleMinSize = 200;
	var particleMaxSize = 800;
	var speedX = 3; // pixels per second, increased horizontal speed
	var speedY = 0.2; // pixels per second, decreased vertical speed
	var particleAlpha = 0.18; // Increased particle alpha for denser fog
	// Create fog particles
	for (var i = 0; i < numParticles; i++) {
		var size = particleMinSize + Math.random() * (particleMaxSize - particleMinSize);
		var particle = LK.getAsset('crossfaderTrack', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: size * 2.0,
			// Make particles significantly wider
			height: size * 0.4 // Make particles much flatter
		});
		particle.tint = 0xffffff; // white fog
		particle.alpha = particleAlpha;
		// Random initial position in upper half, extending slightly beyond bounds for seamless loop
		var px = Math.random() * (2048 + particleMaxSize) - particleMaxSize / 2;
		var py = 100 + Math.random() * (1366 - 100);
		particle.x = px;
		particle.y = py;
		self.addChild(particle);
		particles.push({
			obj: particle,
			speedScale: 0.5 + Math.random() * 1.0,
			// particles move at different speeds
			baseAlpha: particleAlpha
		});
	}
	// Animation
	self.update = function () {
		var t = Date.now() * 0.001;
		for (var i = 0; i < particles.length; i++) {
			var p = particles[i];
			// Move particles
			p.obj.x += speedX * p.speedScale;
			p.obj.y += speedY * p.speedScale;
			// Wrap around horizontally
			if (p.obj.x > 2048 + particleMaxSize / 2) {
				p.obj.x = -particleMaxSize / 2;
				p.obj.y = 100 + Math.random() * (1366 - 300); // new random y position within upper half
			}
			// Animate alpha for subtle flow and density changes
			p.obj.alpha = p.baseAlpha + 0.08 * Math.sin(t * 0.8 + i); // Increased alpha animation range
		}
	};
	return self;
});
// LaserShow: Realistic party laser show with moving heads and multi-color animated beams
var LaserShow = Container.expand(function () {
	var self = Container.call(this);
	// Config
	var numHeads = 6;
	var beamsPerHead = 3;
	var headRadius = 1100; // Increased from 800 to 1100 for wider spread
	var centerX = 2048 / 2;
	var centerY = 400;
	var beamLength = 1600; // Increased from 1200 to 1600 for longer beams
	var beamWidth = 18;
	var beamAlpha = 0.65;
	var headAlpha = 0.7;
	var heads = [];
	var beams = [];
	// Predefined rainbow colors for beams
	var beamColors = [0xff0000,
	// red
	0xff8000,
	// orange
	0xffff00,
	// yellow
	0x00ff00,
	// green
	0x00ffff,
	// cyan
	0x0000ff,
	// blue
	0x8000ff,
	// violet
	0xff00ff // magenta
	];
	// Create moving heads and beams
	for (var h = 0; h < numHeads; h++) {
		// Head position in a semi-circle
		var angle = Math.PI * (h + 1) / (numHeads + 1);
		var hx = centerX + Math.cos(angle) * headRadius;
		var hy = centerY + Math.sin(angle) * 200;
		// Head (visual: ellipse, colored)
		// Use rainbowEllipse for gradient rainbow look
		var head = LK.getAsset('rainbowEllipse', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: hx,
			y: hy,
			width: 20,
			height: 20
		});
		head.alpha = headAlpha;
		// Animate color: store initial hue offset for each head
		head._rainbowHueOffset = h * (360 / numHeads);
		self.addChild(head);
		heads.push(head);
		// Beams for this head
		for (var b = 0; b < beamsPerHead; b++) {
			var beam = LK.getAsset('crossfaderTrack', {
				anchorX: 0.5,
				anchorY: 0,
				x: hx,
				y: hy,
				width: beamWidth,
				height: beamLength
			});
			// Assign color in a rainbow pattern, offset by head and beam
			beam.tint = beamColors[(h * beamsPerHead + b) % beamColors.length];
			beam.alpha = beamAlpha;
			// Initial rotation
			beam.rotation = 0;
			self.addChild(beam);
			beams.push({
				obj: beam,
				headIdx: h,
				beamIdx: b,
				baseAngle: angle
			});
		}
	}
	// Animate heads and beams
	self.update = function () {
		var t = Date.now() * 0.001;
		// Animate heads in a subtle up/down and color pulse
		for (var h = 0; h < heads.length; h++) {
			var head = heads[h];
			// Sway up/down
			head.y = centerY + Math.sin(Math.PI * (h + 1) / (numHeads + 1)) * 200 + Math.sin(t * 1.2 + h) * 18;
			// Pulse alpha
			head.alpha = headAlpha + 0.15 * Math.sin(t * 2 + h);
			// Animate rainbow color: cycle hue every second
			// Full cycle every 1 second (t mod 1.0)
			var hue = (head._rainbowHueOffset + t * 360) % 360 / 360;
			// HSV to RGB conversion
			var i = Math.floor(hue * 6);
			var f = hue * 6 - i;
			var q = 1 - f;
			var tcol = 1 - (1 - f);
			var r, g, b;
			switch (i % 6) {
				case 0:
					r = 1, g = tcol, b = 0;
					break;
				case 1:
					r = q, g = 1, b = 0;
					break;
				case 2:
					r = 0, g = 1, b = tcol;
					break;
				case 3:
					r = 0, g = q, b = 1;
					break;
				case 4:
					r = tcol, g = 0, b = 1;
					break;
				case 5:
					r = 1, g = 0, b = q;
					break;
			}
			var tint = Math.round(r * 255) << 16 | Math.round(g * 255) << 8 | Math.round(b * 255);
			// Tween the head tint for smooth color change
			tween(head, {
				tint: tint
			}, {
				duration: 120,
				easing: tween.linear
			});
		}
		// Animate beams: sweep, flicker, and color pulse
		for (var i = 0; i < beams.length; i++) {
			var beamData = beams[i];
			var beam = beamData.obj;
			var h = beamData.headIdx;
			var b = beamData.beamIdx;
			var baseAngle = beamData.baseAngle;
			// Beam origin follows head
			var head = heads[h];
			beam.x = head.x;
			beam.y = head.y;
			// Animate beam angle: base + sweeping + per-beam offset
			var sweep = Math.sin(t * 1.1 + h + b * 0.7) * 0.25 + Math.sin(t * 0.7 + b) * 0.12;
			var beatPulse = Math.sin(t * 2.5 + h + b) * 0.08;
			beam.rotation = baseAngle - Math.PI / 2 + sweep + beatPulse;
			// Animate beam length for flicker
			var flicker = 1 + 0.12 * Math.sin(t * 3 + h * 2 + b * 1.5 + Math.sin(t * 1.5 + b));
			beam.height = beamLength * flicker;
			// Animate color pulse (simulate RGB laser color mixing)
			var colorIdx = (h * beamsPerHead + b + Math.floor(t * 2 + h + b)) % beamColors.length;
			beam.tint = beamColors[colorIdx];
			// Animate alpha for strobe effect
			beam.alpha = beamAlpha + 0.15 * Math.abs(Math.sin(t * 4 + h + b));
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
// --- Discoball (top of screen) ---
var discoball = new Discoball();
game.addChild(discoball);
discoball.x = 2048 / 2;
discoball.y = 200; // Position at the top of the screen
discoball.scaleX = 0.8;
discoball.scaleY = 0.8;
// --- Extra white particles for upper half sparkle effect ---
var extraWhiteParticles = [];
var numExtraParticles = 32;
for (var i = 0; i < numExtraParticles; i++) {
	// Random position in upper half, avoid top 100px (menu)
	var px = 100 + Math.random() * (2048 - 200);
	var py = 120 + Math.random() * (1366 - 220);
	var size = 8 + Math.random() * 10;
	var particle = LK.getAsset('centerCircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: size,
		height: size
	});
	particle.tint = 0xffffff;
	particle.alpha = 0.18 + Math.random() * 0.22;
	particle.x = px;
	particle.y = py;
	game.addChild(particle);
	extraWhiteParticles.push({
		obj: particle,
		baseX: px,
		baseY: py,
		phase: Math.random() * Math.PI * 2,
		baseAlpha: particle.alpha,
		baseSize: size
	});
}
// Animate extra particles in game.update
// --- Fog Effect (upper half) ---
var fogEffect = new FogEffect();
game.addChild(fogEffect);
fogEffect.y = 0; // Position at the top of the screen
// --- Laser Show (upper half) ---
var laserShow = new LaserShow();
game.addChild(laserShow);
laserShow.y = -456; // Move laser effect up by 456 units (333 + 123)
// --- DJ Deck Asset ---
var djDeck = LK.getAsset('djDeck', {
	anchorX: 0.5,
	anchorY: 0.5
});
game.addChild(djDeck);
djDeck.x = 2048 / 2;
djDeck.y = 2732 / 2 + 333; // Move the DJ deck down by 333 units
// No dark overlay is present, so nothing to remove.
// --- Decks --- 
// Sound effects (dummy, as actual music is handled by LK)
// Beat lights
// FX Button
// Crossfader
// Deck platters (turntables)
// --- Layout constants ---
var deckY = 1366; // Move decks to vertical center of 2732px screen
var deckSpacing = 1000;
var crossfaderY = 1800;
var fxButtonY = 2200;
// --- Equalizer Waves (upper half) ---
var equalizer = new EqualizerWaves();
game.addChild(equalizer);
// --- Decks ---
var leftDeck = new DeckPlatter();
leftDeck.setTrack('A');
game.addChild(leftDeck);
leftDeck.x = 2048 / 2 - deckSpacing / 2;
leftDeck.y = deckY;
var rightDeck = new DeckPlatter();
rightDeck.setTrack('B');
game.addChild(rightDeck);
rightDeck.x = 2048 / 2 + deckSpacing / 2;
rightDeck.y = deckY;
// --- Crossfader ---
var crossfader = new Crossfader();
game.addChild(crossfader);
crossfader.x = 2048 / 2;
crossfader.y = crossfaderY;
crossfader.setValue(0.5);
// --- FX Button ---
var fxButton = new FXButton();
game.addChild(fxButton);
fxButton.x = 2048 / 2;
fxButton.y = fxButtonY;
// --- Score / Combo / Energy ---
var energy = 50; // 0-100
var combo = 0;
var score = 0;
// Energy bar
var energyBarBg = LK.getAsset('crossfaderTrack', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 600,
	height: 40
});
energyBarBg.tint = 0x222222;
energyBarBg.y = 0;
var energyBar = LK.getAsset('crossfaderTrack', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 600,
	height: 40
});
energyBar.tint = 0x00ff00;
energyBar.y = 0;
var energyBarContainer = new Container();
energyBarContainer.addChild(energyBarBg);
energyBarContainer.addChild(energyBar);
energyBarContainer.x = 2048 / 2;
energyBarContainer.y = 200;
LK.gui.top.addChild(energyBarContainer);
// --- Fog Button under pause button (top left, but not in 0,0 area) ---
var fogButton = LK.getAsset('fogButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
fogButton.x = 100 + 60 - 777; // Move left by 777 units
fogButton.y = 100 + 60 + 77; // Move down by 77 units
LK.gui.top.addChild(fogButton);
// Score text
var scoreTxt = new Text2('Score: 0', {
	size: 80,
	fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.x = 2048 / 2;
scoreTxt.y = 300;
// Combo text
var comboTxt = new Text2('', {
	size: 60,
	fill: "#ff0"
});
comboTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(comboTxt);
comboTxt.x = 2048 / 2;
comboTxt.y = 400;
// --- State ---
var dragging = null; // Which control is being dragged
var lastTouchObj = null;
// --- Beat simulation ---
var beatInterval = 600; // ms per beat
var beatTimer = 0;
var lastTickTime = Date.now();
// --- Music ---
LK.playMusic('trackA', {
	loop: true
});
LK.playMusic('trackB', {
	loop: true
});
var trackAVol = 1;
var trackBVol = 1;
// --- Touch handling ---
function getTouchedControl(x, y) {
	// Check decks
	var lx = leftDeck.toLocal(game.toGlobal({
		x: x,
		y: y
	})).x;
	var ly = leftDeck.toLocal(game.toGlobal({
		x: x,
		y: y
	})).y;
	if (Math.pow(lx - leftDeck.width / 2, 2) + Math.pow(ly - leftDeck.height / 2, 2) < 200 * 200) return leftDeck;
	var rx = rightDeck.toLocal(game.toGlobal({
		x: x,
		y: y
	})).x;
	var ry = rightDeck.toLocal(game.toGlobal({
		x: x,
		y: y
	})).y;
	if (Math.pow(rx - rightDeck.width / 2, 2) + Math.pow(ry - rightDeck.height / 2, 2) < 200 * 200) return rightDeck;
	// Crossfader
	var cf = crossfader.toLocal(game.toGlobal({
		x: x,
		y: y
	}));
	if (cf.x > 0 && cf.x < crossfader.width && cf.y > 0 && cf.y < crossfader.height) return crossfader;
	// FX Button
	var fx = fxButton.toLocal(game.toGlobal({
		x: x,
		y: y
	}));
	if (Math.pow(fx.x - fxButton.width / 2, 2) + Math.pow(fx.y - fxButton.height / 2, 2) < 60 * 60) return fxButton;
	return null;
}
game.down = function (x, y, obj) {
	var control = getTouchedControl(x, y);
	dragging = control;
	lastTouchObj = obj;
	if (control && control.down) {
		// Convert to local
		var local = control.toLocal(game.toGlobal({
			x: x,
			y: y
		}));
		control.down(local.x, local.y, obj);
	}
};
game.up = function (x, y, obj) {
	if (dragging && dragging.up) {
		var local = dragging.toLocal(game.toGlobal({
			x: x,
			y: y
		}));
		dragging.up(local.x, local.y, obj);
	}
	dragging = null;
	lastTouchObj = null;
};
game.move = function (x, y, obj) {
	if (dragging && dragging.move) {
		var local = dragging.toLocal(game.toGlobal({
			x: x,
			y: y
		}));
		dragging.move(local.x, local.y, obj);
	}
};
// --- Game update ---
game.update = function () {
	// Update discoball animation
	discoball.update();
	// Update fog effect animation
	fogEffect.update();
	// Animate extra white particles (subtle sparkle and movement)
	if (extraWhiteParticles) {
		var t = Date.now() * 0.001;
		for (var i = 0; i < extraWhiteParticles.length; i++) {
			var p = extraWhiteParticles[i];
			// Subtle float and twinkle
			p.obj.x = p.baseX + Math.sin(t * 1.2 + p.phase + i) * 8;
			p.obj.y = p.baseY + Math.cos(t * 1.1 + p.phase + i * 0.7) * 6;
			p.obj.alpha = p.baseAlpha + 0.10 * Math.sin(t * 2.2 + p.phase + i * 0.5);
			var s = p.baseSize * (0.95 + 0.12 * Math.sin(t * 1.7 + p.phase + i));
			p.obj.width = s;
			p.obj.height = s;
		}
	}
	// Update equalizer animation
	equalizer.update();
	// Update laser show animation
	laserShow.update();
	// Update decks
	leftDeck.update();
	rightDeck.update();
	// Simulate beat
	var now = Date.now();
	beatTimer += now - lastTickTime;
	lastTickTime = now;
	if (beatTimer >= beatInterval) {
		beatTimer -= beatInterval;
		leftDeck.flashBeat();
		rightDeck.flashBeat();
		LK.getSound('beat').play();
		// Energy drops if not scratching or mixing
		if (!leftDeck.isScratching && !rightDeck.isScratching && crossfader.value > 0.2 && crossfader.value < 0.8) {
			energy -= 2;
			combo = 0;
		} else {
			// Combo up if scratching or crossfading
			combo += 1;
			score += 10 * combo;
			energy += 2;
			if (energy > 100) energy = 100;
		}
		if (energy < 0) energy = 0;
		// Update visuals
		scoreTxt.setText('Score: ' + score);
		if (combo > 1) {
			comboTxt.setText('Combo x' + combo);
		} else {
			comboTxt.setText('');
		}
	}
	// Update energy bar
	energyBar.width = 600 * (energy / 100);
	// Crossfader logic: adjust music volumes
	trackAVol = 1 - crossfader.value;
	trackBVol = crossfader.value;
	// (In a real game, would set music volumes here, but LK handles music globally.)
	// End game if energy is 0
	if (energy <= 0) {
		// Game over event disabled
	}
	// Win if score is high
	if (score >= 5000) {
		LK.effects.flashScreen(0x00ff00, 1000);
		LK.showYouWin();
	}
}; ===================================================================
--- original.js
+++ change.js
@@ -801,9 +801,9 @@
 	anchorX: 0.5,
 	anchorY: 0.5
 });
 fogButton.x = 100 + 60 - 777; // Move left by 777 units
-fogButton.y = 100 + 60; // 100px from top edge, 60px is half height
+fogButton.y = 100 + 60 + 77; // Move down by 77 units
 LK.gui.top.addChild(fogButton);
 // Score text
 var scoreTxt = new Text2('Score: 0', {
 	size: 80,
 
 
 Photorealistic Ferris cabin, sideview
 
 
 
 
 
 Grey circle with transparent inner place, front view
 there are 4 piece of holes in the image, repair it
 
 
 
 photorealistic grey Tablet lying down on dj deck, front view. The screen should be dark monocrome screen in power of mode without text.
 
 
 Photorealistic transparent rectange dj deck sample button with white rounded corners, front view. No text needed on image
 Transparent ballon shape.
 
 Replace arrow to OK text
 Dancing woman in a white top filled with multi-colored UV ink palm prints. UV luminous bracelet on the arm
 
 Photorealistic dollar, front view
 Dancing man in a white shirt filled with multi-colored UV ink palm prints. UV luminous bracelet on the arm
 
 White thin pencil in 45 degrees instead of arrow.
 Replace arrow to white X
 Change the orange filling color from the middle to black
 
 simple grey colored DJZ logo
 REPLACE THE PENCIL WITH WHITE MENU TEXT
 Replace pencil with white REC text, but no other changes!
1
Music
trackA
Music
trackB
Music
sample1
Sound effect
sample2
Sound effect
sample3
Sound effect
sample4
Sound effect
Sample5
Sound effect
sample6
Sound effect
sample7
Sound effect
sample8
Sound effect
sample9
Sound effect
sample10
Sound effect
sample11
Sound effect
sample12
Sound effect
sample13
Sound effect
sample14
Sound effect
sample15
Sound effect
sample16
Sound effect