User prompt
Ensure player can turn on and off smokemachines via SMOKE effect button
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'y')' in or related to this line: 'digitalClockTxt.y = tabletAsset.y + tabletAsset.height / 2 + 100;' Line Number: 2453
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'y')' in or related to this line: 'digitalClockTxt.y = tabletAsset.y + tabletAsset.height / 2 + 100;' Line Number: 2453
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'y')' in or related to this line: 'digitalClockTxt.y = tabletAsset.y + tabletAsset.height / 2 + 100;' Line Number: 2453
User prompt
Time is upper in display than tablet
User prompt
Add UV PARTY to the upper half of the map if UV effect button is pressed once.
User prompt
Add soap foam tothe upper hall of the screen
User prompt
Add UV text above the 5m effect button
User prompt
Smoke effect button has 3 mode. First is off, when button is not active. in this mode turn off smokemachines. Second mode is the default smoke density. In Third mode increase smoke height, and density.
User prompt
You just turned off the smokemachines but it should working ad fire bitton snd flamethrower mode eventm
User prompt
Smoke effect button has 3 mode. First is off, when button is not active. in this mode turn off smokemachines. Second mode is the default smoke density. In Third mode increase smoke height, and density. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add 'SMOKE' text above 4. Effect button
User prompt
Repair ballons looking. They are too wide
User prompt
Use ballon asset to ensure realistic ballon shape. 🎈
User prompt
Add ballon asset to the list.
User prompt
Ensure ballons has realistic ballon shape 🎈
User prompt
Add a lot of different colored ballon falling from the top of the screen to behind dancing beople ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a lot of rectangle confetti to the upper half of the map ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Increase flame height for mode 2 (big flames) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Increase flame in flamethrower 3. Mode ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ensure fire effect button 3 mode: first is turn off the flamethrower event, second is turn on flamethrower effect, third is making big fireflames. In second mode flashing the first effect button frame orange, in the third mode flashing the effect button red. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
2. Effect Button flashing is too fast in fast mode ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hide lasershow's beams while 2. Laser effect button is not flashing ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hurry up
User prompt
Ensure the 2. Laser button has 3 mode by pressing and repressing, first is off when lasershow and lasershow's beams are inactive, second is slow lasershow, third is fast lasershow. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Playback starts automatically
// Balloon: Animated colorful balloons falling from the top
var Balloon = Container.expand(function () {
var self = Container.call(this);
// Config
var size = 60 + Math.random() * 80; // Random size
var speedY = 0.8 + Math.random() * 1.2; // Vertical speed
var speedX = (Math.random() - 0.5) * 2; // Horizontal drift
var rotationSpeed = (Math.random() - 0.5) * 0.05; // Rotation speed
// Visuals
// Use a more realistic width/height ratio for balloons (e.g. 0.55)
var balloonWidth = size * 0.55;
var balloonHeight = size;
var balloonGraphic = self.attachAsset('balloon', {
anchorX: 0.5,
anchorY: 0.5,
width: balloonWidth,
height: balloonHeight
});
// Random color (rainbow)
var hue = Math.random();
var rgb = hsvToRgb(hue, 0.9 + Math.random() * 0.1, 0.9 + Math.random() * 0.1);
balloonGraphic.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
// HSV to RGB helper (essential for color animations)
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_color = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0:
r = v;
g = t_color;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t_color;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t_color;
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)];
}
// Animation
self.update = function () {
self.y += speedY;
self.x += speedX;
self.rotation += rotationSpeed;
// Wrap around if off screen (below the dancing people)
if (self.y > dancingPeople[0].y + 200) {
// Wrap below the dancing people
self.y = -size;
self.x = Math.random() * 2048; // New random x position
// Reset size and color for a new balloon
size = 60 + Math.random() * 80;
var balloonWidth = size * 0.55;
var balloonHeight = size;
balloonGraphic.width = balloonWidth; // Maintain realistic balloon width/height ratio
balloonGraphic.height = balloonHeight;
var hue = Math.random();
var rgb = hsvToRgb(hue, 0.9 + Math.random() * 0.1, 0.9 + Math.random() * 0.1);
balloonGraphic.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
speedY = 0.8 + Math.random() * 1.2;
speedX = (Math.random() - 0.5) * 2;
rotationSpeed = (Math.random() - 0.5) * 0.05;
}
};
return self;
});
// ConfettiEffect: Animated confetti falling from the top with multiple types
var ConfettiEffect = Container.expand(function () {
var self = Container.call(this);
// Config
var numParticles = 200; // Increased from 120 to 200 for much higher density
var particles = [];
var particleMinSize = 3.0; // Slightly larger minimum size
var particleMaxSize = 12.0; // Increased maximum size
var speedY = 5; // pixels per second
var speedX = 2; // horizontal drift
// Define confetti types with more rectangle emphasis
var confettiTypes = [{
asset: 'centerCircle',
name: 'circle'
}, {
asset: 'crossfaderTrack',
name: 'rectangle'
}, {
asset: 'crossfaderTrack',
name: 'rectangle'
}, {
asset: 'crossfaderTrack',
name: 'rectangle'
}, {
asset: 'crossfaderTrack',
name: 'rectangle'
}, {
asset: 'beatLight',
name: 'star'
}];
// Create confetti particles
for (var i = 0; i < numParticles; i++) {
var size = particleMinSize + Math.random() * (particleMaxSize - particleMinSize);
// Choose random confetti type
var confettiType = confettiTypes[Math.floor(Math.random() * confettiTypes.length)];
var particle;
if (confettiType.name === 'rectangle') {
// Create rectangular confetti with more variety
var rectWidth = size * (1.2 + Math.random() * 0.8); // More width variation (1.2x to 2.0x)
var rectHeight = size * (0.4 + Math.random() * 0.6); // More height variation (0.4x to 1.0x)
particle = LK.getAsset(confettiType.asset, {
anchorX: 0.5,
anchorY: 0.5,
width: rectWidth,
height: rectHeight
});
} else if (confettiType.name === 'star') {
// Create star-shaped confetti
particle = LK.getAsset(confettiType.asset, {
anchorX: 0.5,
anchorY: 0.5,
width: size * 0.8,
height: size * 0.8
});
} else {
// Create circular confetti
particle = LK.getAsset(confettiType.asset, {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size
});
}
// Random color (rainbow)
var hue = Math.random();
var rgb = hsvToRgb(hue, 0.9 + Math.random() * 0.1, 0.9 + Math.random() * 0.1);
particle.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
// Random initial position in upper half, above screen for seamless loop
var px = Math.random() * 2048;
var py = -particleMaxSize - Math.random() * 500;
particle.x = px;
particle.y = py;
self.addChild(particle);
particles.push({
obj: particle,
speedScale: 0.8 + Math.random() * 0.4,
// particles fall at slightly different speeds
phase: Math.random() * Math.PI * 2,
type: confettiType.name,
baseSize: size,
rotationSpeed: (Math.random() - 0.5) * 0.3 // Random rotation speed
});
}
// 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)];
}
// Animation
self.update = function () {
var t = Date.now() * 0.001;
for (var i = 0; i < particles.length; i++) {
var p = particles[i];
// Move particles down with horizontal drift
p.obj.y += speedY * p.speedScale;
p.obj.x += speedX * Math.sin(t + p.phase);
// Wrap around vertically (from bottom to top)
if (p.obj.y > 2732) {
p.obj.y = -particleMaxSize;
p.obj.x = Math.random() * 2048; // new random x position
// Reset rotation and add tween effect for new particles
p.obj.rotation = 0;
tween(p.obj, {
rotation: Math.PI * 2 * (Math.random() > 0.5 ? 1 : -1)
}, {
duration: 2000 + Math.random() * 3000,
easing: tween.linear
});
}
// Enhanced rotation based on type
if (p.type === 'rectangle') {
p.obj.rotation += p.rotationSpeed * 1.5; // Rectangles rotate faster
} else if (p.type === 'star') {
p.obj.rotation += p.rotationSpeed * 0.8; // Stars rotate slower
} else {
p.obj.rotation += p.rotationSpeed; // Circles normal rotation
}
// Type-specific animations
if (p.type === 'rectangle') {
// Rectangles flutter and tumble more dramatically
var flutter = 0.8 + 0.4 * Math.sin(t * 5 + p.phase);
var tumble = 0.9 + 0.2 * Math.cos(t * 3 + p.phase);
p.obj.scaleX = flutter;
p.obj.scaleY = tumble;
// Add extra horizontal drift for rectangles
p.obj.x += Math.sin(t * 2 + p.phase) * 0.8;
} else if (p.type === 'star') {
// Stars twinkle
var twinkle = 0.9 + 0.2 * Math.sin(t * 6 + p.phase);
p.obj.scaleX = twinkle;
p.obj.scaleY = twinkle;
// Add alpha twinkling
p.obj.alpha = 0.8 + 0.2 * Math.sin(t * 5 + p.phase);
} else {
// Circles flicker size
var baseSize = p.baseSize;
var s = baseSize * (0.95 + 0.1 * Math.sin(t * 3 + p.phase));
p.obj.width = s;
p.obj.height = s;
}
}
};
return self;
});
// 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;
};
// Touch events
self.down = function (x, y, obj) {
self.dragging = true;
self.setValue((x + track.width / 2) / 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 / 2) / track.width);
}
};
return self;
});
// DancingPerson: Animated dancing people (women and men)
var DancingPerson = Container.expand(function (forcedAssetId) {
var self = Container.call(this);
// Config
var assetId;
if (typeof forcedAssetId === 'string') {
assetId = forcedAssetId;
} else {
// fallback to random if not provided
var assets = ['dancingWoman', 'dancingMan'];
assetId = assets[Math.floor(Math.random() * assets.length)];
}
// Visuals
var personGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 1.0 // Anchor at the bottom center (feet)
});
// Animation state
self.baseY = 0;
self.phaseOffset = Math.random() * Math.PI * 2; // Random start phase for animation
// Animation
self.update = function () {
var t = Date.now() * 0.002; // Time for animation
// Simple bouncing and swaying animation
self.y = self.baseY + Math.sin(t * 3 + self.phaseOffset) * 15; // Bounce up/down
self.rotation = Math.sin(t * 2 + self.phaseOffset) * 0.08; // Sway left/right
};
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;
// Move highlight behind the platter by adding it first, then re-adding platter
self.removeChild(platter);
self.addChild(platter);
var label = self.attachAsset('deckLabel', {
anchorX: 0.5,
anchorY: 0.5,
y: 350,
width: 90,
height: 30
});
// 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: 490
});
beatLight.alpha = 0.2;
// Methods
self.setActive = function (active) {
self.isActive = active;
if (active) {
highlight.alpha = 0.6;
highlight.visible = true;
// Ensure highlight is above platter in display order
self.removeChild(highlight);
self.addChild(highlight);
// Flash effect for better visual feedback
tween(highlight, {
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut
});
} else {
highlight.alpha = 0;
highlight.visible = false;
}
};
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 using platter dimensions
var dx = x - platter.width / 2;
var dy = y - platter.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 using platter dimensions
var dx = x - platter.width / 2;
var dy = y - platter.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 () {
// Determine if this deck should be spinning based on start button state
var shouldSpin = false;
if (self.track === 'A' && typeof leftStartButtonOn !== 'undefined' && leftStartButtonOn) {
shouldSpin = true;
} else if (self.track === 'B' && typeof rightStartButtonOn !== 'undefined' && rightStartButtonOn) {
shouldSpin = true;
}
// If not scratching, platter rotates at normal speed only if should spin
if (!self.isScratching && self.playing && shouldSpin) {
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 ---
// Render both front and back halves for a full 3D ball illusion
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);
// Draw both front and back tiles, but make back tiles dimmer and behind
for (var side = 0; side < 2; side++) {
// side 0: front (z2d > 0), side 1: back (z2d < 0)
var isFront = side === 0;
// Always create both front and back tiles, but only show one at a time
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;
// Back tiles are dimmer and more transparent
if (isFront) {
tile.alpha = 0.92 - 0.18 * (lat / numLat) + Math.random() * 0.08;
} else {
tile.alpha = 0.32 - 0.10 * (lat / numLat) + Math.random() * 0.04;
}
// Position
tile.x = x2d;
tile.y = y;
// Simulate 3D: scaleX based on z2d
tile.scaleX = 1 + 0.18 * (Math.abs(z2d) / ballRadius);
tile.scaleY = 1;
// For back tiles, send to back (add first), for front tiles, add last
if (isFront) {
self.addChild(tile);
} else {
self.addChildAt(tile, 0);
}
tiles.push({
tile: tile,
lat: lat,
lon: lon,
theta: theta,
phi: phi,
isFront: isFront
});
}
}
}
// --- Specular highlight (white spot) ---
// Removed the white oval particle in front of the discoball
// --- 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 ---
self.update = function () {
// Animate y-axis spin in a full 360-degree circle
spinY += spinSpeed * spinDir;
if (spinY > Math.PI * 2) spinY -= Math.PI * 2;
if (spinY < 0) spinY += Math.PI * 2;
self._spinY = spinY; // direct assignment for full rotation
// 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);
// For front tiles, show if z2d > 0; for back tiles, show if z2d < 0
if (t.isFront && z2d > 0 || !t.isFront && z2d < 0) {
t.tile.visible = true;
t.tile.x = x2d;
t.tile.y = y3d;
t.tile.scaleX = 1 + 0.18 * (Math.abs(z2d) / ballRadius);
t.tile.scaleY = 1;
// Flicker for disco effect
if (t.isFront) {
t.tile.alpha = 0.88 - 0.18 * (t.lat / numLat) + Math.random() * 0.09;
} else {
t.tile.alpha = 0.28 - 0.10 * (t.lat / numLat) + Math.random() * 0.04;
}
} else {
t.tile.visible = false;
}
}
// Animate highlight to move in a small circle for extra 3D effect
// (highlight removed, nothing to animate here)
var t = Date.now() * 0.001;
// 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;
});
// EqualizerBars: Animated frequency visualization bars for screens
var EqualizerBars = Container.expand(function () {
var self = Container.call(this);
// Config
var numBars = 12;
var barWidth = 25 * 1.2;
var barSpacing = 8;
var maxBarHeight = 100;
var minBarHeight = 10;
var bars = [];
// Create equalizer bars
for (var i = 0; i < numBars; i++) {
var bar = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 1.0,
width: barWidth,
height: minBarHeight
});
// Color based on frequency range (bass=red, mid=yellow, treble=cyan)
if (i < 4) {
bar.tint = 0xff0000; // Bass - red
} else if (i < 8) {
bar.tint = 0xffff00; // Mid - yellow
} else {
bar.tint = 0x00ffff; // Treble - cyan
}
bar.x = (i - (numBars - 1) / 2) * (barWidth + barSpacing);
bar.y = 0;
self.addChild(bar);
bars.push({
obj: bar,
phase: Math.random() * Math.PI * 2,
baseHeight: minBarHeight
});
}
// Animation
self.update = function () {
var t = Date.now() * 0.001;
for (var i = 0; i < bars.length; i++) {
var b = bars[i];
// Simulate frequency response with different speeds for different frequency ranges
var speed = 1.0;
if (i < 4) speed = 0.8; // Bass moves slower
else if (i < 8) speed = 1.2; // Mid moves medium
else speed = 1.8; // Treble moves faster
// Create realistic frequency bar movement
var height = minBarHeight + (maxBarHeight - minBarHeight) * (0.3 + 0.7 * Math.abs(Math.sin(t * speed * 2 + b.phase + i * 0.3)));
b.obj.height = height;
// Add beat sync flash effect
if (beatTimer && beatTimer < 100) {
b.obj.alpha = 0.7 + 0.3 * Math.sin(t * 10 + i);
} else {
b.obj.alpha = 0.9;
}
}
};
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;
});
// FerrisWheel: Animated slow spinning, color-changing Ferris wheel
var FerrisWheel = Container.expand(function () {
var self = Container.call(this);
// Config
self.wheelRadius = 200;
self.numCabins = 8;
self.spinSpeed = 0.002; // Radians per update for wheelAssembly
self.colorChangeCycleTime = 6000; // ms for a full color cycle for a cabin
// HSV to RGB helper function (essential for color animations)
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_color = v * (1 - (1 - f) * s); // Renamed 't' to avoid conflict
switch (i % 6) {
case 0:
r = v;
g = t_color;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t_color;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t_color;
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)];
}
// Wheel structure (hub and spokes) - this part will rotate
self.wheelAssembly = self.addChild(new Container());
// --- Full Circle (Rim) ---
// Approximate a circle by placing many small ellipses around the rim
self.rimSegments = 36;
self.rimRadius = self.wheelRadius;
for (var i = 0; i < self.rimSegments; i++) {
var rimAngle = Math.PI * 2 / self.rimSegments * i;
var rimX = Math.cos(rimAngle) * self.rimRadius;
var rimY = Math.sin(rimAngle) * self.rimRadius;
var rim = self.wheelAssembly.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: 11,
height: 11,
x: rimX,
y: rimY
});
rim.tint = 0xffffff;
rim.alpha = 0.7;
}
// Central Hub
var hub = self.wheelAssembly.attachAsset('ferrisHub', {
anchorX: 0.5,
anchorY: 0.5
});
// Spokes
for (var i = 0; i < self.numCabins; i++) {
var angle = Math.PI * 2 / self.numCabins * i;
var spoke = self.wheelAssembly.attachAsset('ferrisSpoke', {
anchorX: 0.5,
anchorY: 0,
// Anchor at the hub-connection point
height: self.wheelRadius,
// Spoke length is the wheel radius
rotation: angle
});
}
// Cabins - these will be positioned along the rim and kept upright
self.cabins = [];
for (var i = 0; i < self.numCabins; i++) {
var cabinAngle = Math.PI * 2 / self.numCabins * i;
// Create cabin using LK.getAsset and add it as a child to the FerrisWheel container (self)
var cabin = self.addChild(LK.getAsset('ferrisCabin', {
anchorX: 0.5,
anchorY: 0.5
}));
cabin.initialAngle = cabinAngle; // Store its angular position on the wheel
// Initial position and color
var xPos = Math.cos(cabinAngle) * self.wheelRadius;
var yPos = Math.sin(cabinAngle) * self.wheelRadius;
cabin.x = xPos;
cabin.y = yPos;
var initialHue = cabin.initialAngle / (Math.PI * 2) % 1.0;
var initialRgb = hsvToRgb(initialHue, 0.85, 0.95);
cabin.tint = initialRgb[0] << 16 | initialRgb[1] << 8 | initialRgb[2];
self.cabins.push(cabin);
}
self.update = function () {
// Spin the wheel assembly
self.wheelAssembly.rotation += self.spinSpeed;
// Update cabin positions and colors
var globalTimeFactor = Date.now() % self.colorChangeCycleTime / self.colorChangeCycleTime;
for (var i = 0; i < self.cabins.length; i++) {
var cabin = self.cabins[i];
// Calculate current angle of the cabin attachment point on the rotating wheel
var currentAttachmentAngle = cabin.initialAngle + self.wheelAssembly.rotation;
// Update cabin position relative to the FerrisWheel container's center
cabin.x = Math.cos(currentAttachmentAngle) * self.wheelRadius;
cabin.y = Math.sin(currentAttachmentAngle) * self.wheelRadius;
// Cabins are direct children of 'self' (FerrisWheel container).
// 'self' itself is not rotating, so cabins remain upright (rotation = 0) by default.
// Animate color: Cycle hue for each cabin
var cabinHue = (cabin.initialAngle / (Math.PI * 2) + globalTimeFactor) % 1.0;
var rgb = hsvToRgb(cabinHue, 0.85, 0.95);
var newTint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
// Tween for smooth color change
if (cabin.tint !== newTint) {
tween.stop(cabin, {
tint: true
}); // Stop existing tint tweens on this cabin
tween(cabin, {
tint: newTint
}, {
duration: 300,
easing: tween.linear
});
}
}
};
return self;
});
// FireworksEffect: Animated fireworks exploding in the upper half of the screen
var FireworksEffect = Container.expand(function () {
var self = Container.call(this);
// Config
var numRockets = 2; // Number of simultaneous rockets/explosions
var rocketInterval = 2500; // ms between new rockets
var rocketTimer = 0;
var lastTickTime = Date.now();
var rockets = [];
var explosionParticles = [];
// Predefined rainbow colors for explosions
var beamColors = [0xff0000,
// red
0xff8000,
// orange
0xffff00,
// yellow
0x00ff00,
// green
0x00ffff,
// cyan
0x0000ff,
// blue
0x8000ff,
// violet
0xff00ff // magenta
];
// Explosion particle configuration
var particleMinSize = 8;
var particleMaxSize = 20;
var particleSpeed = 15; // pixels per update
var particleLifetime = 1000; // ms
// Create an explosion
function createExplosion(x, y, color) {
var numParticles = 20 + Math.random() * 10;
for (var i = 0; i < numParticles; i++) {
var angle = Math.random() * Math.PI * 2;
var speed = particleSpeed * (0.8 + Math.random() * 0.4);
var particle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: (particleMinSize + Math.random() * (particleMaxSize - particleMinSize)) * 0.5,
height: (particleMinSize + Math.random() * (particleMaxSize - particleMinSize)) * 0.5
});
particle.tint = color;
particle.alpha = 1.0;
particle.x = x;
particle.y = y;
self.addChild(particle);
explosionParticles.push({
obj: particle,
speedX: Math.cos(angle) * speed,
speedY: Math.sin(angle) * speed,
startTime: Date.now(),
color: color
});
}
}
// Animation
self.update = function () {
var now = Date.now();
var delta = now - lastTickTime;
lastTickTime = now;
// --- Manage rockets ---
rocketTimer += delta;
if (rocketTimer >= rocketInterval && rockets.length < numRockets) {
rocketTimer -= rocketInterval;
// Launch a new rocket from the bottom
var startX = 200 + Math.random() * (2048 - 400);
var endY = 200 + Math.random() * (600 - 200); // Explode in upper half
var rocket = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: 10,
height: 10
});
rocket.tint = 0xffffff; // White trail
rocket.alpha = 0.8;
rocket.x = startX;
rocket.y = 2732; // Start from bottom
self.addChild(rocket);
rockets.push({
obj: rocket,
startX: startX,
endY: endY,
speedY: -(2732 - endY) / (rocketInterval * 0.6) * 16,
// Adjust speed based on distance and interval
color: beamColors[Math.floor(Math.random() * beamColors.length)],
// Random explosion color from beamColors
launchedTime: now
});
}
// Update rockets
for (var i = rockets.length - 1; i >= 0; i--) {
var rocket = rockets[i];
rocket.obj.y += rocket.speedY * (delta / 16); // Move rocket based on delta
// Check if rocket reached explosion point
if (rocket.obj.y <= rocket.endY || now - rocket.launchedTime > rocketInterval * 0.8) {
// Explode also after a certain time
createExplosion(rocket.obj.x, rocket.obj.y, rocket.color);
rocket.obj.destroy();
rockets.splice(i, 1);
}
}
// Update explosion particles
for (var i = explosionParticles.length - 1; i >= 0; i--) {
var p = explosionParticles[i];
var elapsed = now - p.startTime;
if (elapsed > particleLifetime) {
p.obj.destroy();
explosionParticles.splice(i, 1);
} else {
// Move particle
p.obj.x += p.speedX * (delta / 16);
p.obj.y += p.speedY * (delta / 16);
// Fade out
p.obj.alpha = 1.0 - elapsed / particleLifetime;
}
}
};
return self;
});
// Flamethrower: Animated flames from the ground
var Flamethrower = Container.expand(function () {
var self = Container.call(this);
// Visuals - Flamethrower base
var base = self.attachAsset('flamethrowerBase', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 0.5,
scaleY: 0.5
});
base.y = 0; // Position at the base of the container
// Config
var numParticles = 20;
var particles = [];
var particleMinSize = 40;
var particleMaxSize = 120;
var speedY = -15; // pixels per second (upwards)
var speedX = 4; // horizontal flicker/sway
var particleLifetime = 500; // ms
// 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)];
}
// Create flame particles
self.createFlame = function () {
var baseSize = (particleMinSize + Math.random() * (particleMaxSize - particleMinSize)) * 0.48;
var size = baseSize;
// Modify size based on fire effect mode
if (typeof fireEffectMode !== 'undefined' && fireEffectMode === 2) {
// Big flames mode - make particles larger
size = baseSize * 2.5;
}
var particle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size
});
// Flame color (yellow to red)
var hue = Math.random() * 0.1 + 0.05; // Hue from 0.05 (reddish-orange) to 0.15 (yellowish-orange)
var rgb = hsvToRgb(hue, 1, 1);
particle.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
// Initial position at the base of the flamethrower
// Position the particle relative to the top-center of the base graphic
particle.x = 0; // Relative to the Flamethrower container's origin
particle.y = -base.height; // Position above the base graphic
particle.alpha = 0.8 + Math.random() * 0.2;
self.addChild(particle);
particles.push({
obj: particle,
speedScale: 0.8 + Math.random() * 0.4,
startTime: Date.now(),
baseSize: size,
phase: Math.random() * Math.PI * 2
});
};
// Animation
self.update = function () {
var now = Date.now();
var delta = now - (self._lastTickTime || now);
self._lastTickTime = now;
// Create new particles periodically based on fire effect mode
var targetParticleCount = numParticles;
if (typeof fireEffectMode !== 'undefined') {
if (fireEffectMode === 0) {
// Off mode - no flames
targetParticleCount = 0;
} else if (fireEffectMode === 2) {
// Big flames mode - more particles
targetParticleCount = numParticles * 2;
}
}
if (particles.length < targetParticleCount) {
self.createFlame();
}
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
var p = particles[i];
var elapsed = now - p.startTime;
if (elapsed > particleLifetime) {
p.obj.destroy();
particles.splice(i, 1);
} else {
// Move particle upwards with horizontal flicker
p.obj.y += speedY * p.speedScale * (delta / 16);
p.obj.x += speedX * Math.sin(now * 0.003 + p.phase) * p.speedScale * (delta / 16);
// Fade out
p.obj.alpha = (1.0 - elapsed / particleLifetime) * (0.8 + 0.2 * Math.sin(now * 0.004 + p.phase)); // Add flicker to fade
// Scale down over time
var size = p.baseSize * (1.0 - elapsed / particleLifetime * 0.8);
p.obj.width = size;
p.obj.height = size;
// Animate color slightly towards red as it fades
var fadeHue = Math.random() * 0.05; // Shift slightly towards red (hue 0)
var fadeRgb = hsvToRgb(fadeHue, 1, 1);
var originalTint = p.obj.tint;
var r1 = originalTint >> 16 & 0xFF;
var g1 = originalTint >> 8 & 0xFF;
var b1 = originalTint & 0xFF;
var r2 = fadeRgb[0];
var g2 = fadeRgb[1];
var b2 = fadeRgb[2];
var blend = elapsed / particleLifetime;
var r = Math.round(r1 * (1 - blend) + r2 * blend);
var g = Math.round(g1 * (1 - blend) + g2 * blend);
var b = Math.round(b1 * (1 - blend) + b2 * blend);
p.obj.tint = r << 16 | g << 8 | b;
}
}
};
return self;
});
// FogEffect: Animated fog in upper half of the map
var FogEffect = Container.expand(function () {
var self = Container.call(this);
// Config
var numParticles = 20;
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 from right to left
p.obj.x -= speedX * p.speedScale;
p.obj.y += speedY * p.speedScale;
// Wrap around horizontally (from left to right)
if (p.obj.x < -particleMaxSize / 2) {
p.obj.x = 2048 + particleMaxSize / 2;
p.obj.y = Math.random() * (2732 / 2 - 100) + 100; // 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 = 700; // Reduced from 1100 to 700 to move heads closer to the middle
var centerX = 2048 / 2;
var centerY = 400;
var beamLength = 1200; // Reduced from 1600 to 1200 to keep beams inside the new head radius
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('laserBeam', {
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;
// Only update head colors every few frames to improve performance
if (LK.ticks % 4 === 0) {
// 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);
// Only tween if color actually changed
if (head.tint !== tint) {
head.tint = tint;
}
}
}
// 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;
// Check laser show mode (controlled by second effect button)
if (typeof laserShowMode !== 'undefined' && laserShowMode === 1) {
// Slow laser show mode - beams visible
beam.visible = true;
var sweep = Math.sin(t * 1.2 + h + b * 0.5) * 0.3 + Math.sin(t * 0.8 + b) * 0.15;
var beatPulse = Math.sin(t * 2.8 + h + b) * 0.12;
beam.rotation = baseAngle - Math.PI / 2 + sweep + beatPulse;
// Slow beam length flicker
var flicker = 1 + 0.18 * Math.sin(t * 3.5 + h * 2 + b * 1.2 + Math.sin(t * 2.0 + b));
beam.height = beamLength * flicker;
// Slow color cycling
var colorIdx = (h * beamsPerHead + b + Math.floor(t * 2.5 + h + b)) % beamColors.length;
beam.tint = beamColors[colorIdx];
// Slow alpha strobe effect
beam.alpha = beamAlpha + 0.2 * Math.abs(Math.sin(t * 5 + h + b));
} else if (typeof laserShowMode !== 'undefined' && laserShowMode === 2) {
// Fast laser show mode - beams visible
beam.visible = true;
var sweep = Math.sin(t * 2.4 + h + b * 0.9) * 0.5 + Math.sin(t * 1.8 + b) * 0.25;
var beatPulse = Math.sin(t * 6.0 + h + b) * 0.2;
beam.rotation = baseAngle - Math.PI / 2 + sweep + beatPulse;
// Fast beam length flicker
var flicker = 1 + 0.35 * Math.sin(t * 7 + h * 2 + b * 1.8 + Math.sin(t * 3.5 + b));
beam.height = beamLength * flicker;
// Fast color cycling
var colorIdx = (h * beamsPerHead + b + Math.floor(t * 6 + h + b)) % beamColors.length;
beam.tint = beamColors[colorIdx];
// Fast alpha strobe effect
beam.alpha = beamAlpha + 0.4 * Math.abs(Math.sin(t * 12 + h + b));
} else {
// Off mode - hide beams completely
beam.visible = false;
}
}
};
return self;
});
// SmokeDiffuser: Animated smoke diffuser with rising smoke puffs
var SmokeDiffuser = Container.expand(function () {
var self = Container.call(this);
// Visuals - Diffuser base (small ellipse)
var base = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 1.0,
width: 60,
height: 30,
y: 0
});
base.tint = 0x888888;
base.alpha = 0.85;
// Config
var numParticles = 10;
var particles = [];
var particleMinSize = 32;
var particleMaxSize = 64;
var speedY = -3.5; // pixels per frame (upwards)
var speedX = 0.7; // horizontal drift
var particleLifetime = 1200; // ms
// Create a smoke puff
self.createSmoke = function () {
var size = particleMinSize + Math.random() * (particleMaxSize - particleMinSize);
var puff = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size
});
// Smoke color: light gray, some randomization
var gray = 180 + Math.floor(Math.random() * 40);
puff.tint = gray << 16 | gray << 8 | gray;
puff.alpha = 0.32 + Math.random() * 0.18;
// Start at base, with slight random x offset
puff.x = Math.random() * 16 - 8;
puff.y = -base.height + Math.random() * 8;
self.addChild(puff);
particles.push({
obj: puff,
speedScale: 0.8 + Math.random() * 0.5,
startTime: Date.now(),
baseSize: size,
phase: Math.random() * Math.PI * 2
});
};
// Animation
self.update = function () {
var now = Date.now();
// Create new puffs if needed
if (particles.length < numParticles) {
self.createSmoke();
}
// Update puffs
for (var i = particles.length - 1; i >= 0; i--) {
var p = particles[i];
var elapsed = now - p.startTime;
if (elapsed > particleLifetime) {
p.obj.destroy();
particles.splice(i, 1);
} else {
// Move upwards, drift sideways
p.obj.y += speedY * p.speedScale;
p.obj.x += speedX * Math.sin(now * 0.001 + p.phase) * p.speedScale;
// Fade out and grow
p.obj.alpha = (1.0 - elapsed / particleLifetime) * (0.32 + 0.18 * Math.sin(now * 0.002 + p.phase));
var size = p.baseSize * (1.0 + elapsed / particleLifetime * 0.7);
p.obj.width = size;
p.obj.height = size;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Add a vertical crossfader track
// --- Reflectors (behind discoball) ---
var reflectors = [];
var numReflectors = 7;
var reflectorSpacing = 2048 / (numReflectors + 1);
var reflectorY = 80; // Top, but below menu area
// Create reflectors but do not add to game yet
for (var i = 0; i < numReflectors; i++) {
var rx = reflectorSpacing * (i + 1);
var reflector = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60
});
reflector.tint = 0xffffff;
reflector.alpha = 0.0;
reflector.x = rx;
reflector.y = reflectorY;
reflectors.push(reflector);
}
// --- Discoball (top of screen) ---
// Asset for dancing woman
// Asset for dancing man
var discoball = new Discoball();
// Add reflectors behind discoball in display order
for (var i = 0; i < reflectors.length; i++) {
game.addChild(reflectors[i]);
}
// Insert discoball after reflectors so it appears above them
game.addChild(discoball);
discoball.x = 2048 / 2;
discoball.y = 200 - 69; // Move discoball up by 69 units
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
// --- Confetti Effect (upper half) ---
var confettiEffect = new ConfettiEffect();
game.addChild(confettiEffect);
confettiEffect.y = 0; // Position at the top of the screen
// --- DJDeck Asset (center of map) ---
var djDeck = LK.getAsset('desk', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2020 * (2048 / 2040) // maintain aspect ratio
});
game.addChild(djDeck);
djDeck.x = 2048 / 2;
djDeck.y = 2732 / 2 + 333 + 12 + 12; // Move the DJ deck down by 357 units
// --- Rim Assets (both sides of djdeck) ---
var rimLeft = LK.getAsset('rim', {
anchorX: 0.5,
anchorY: 0.5
});
rimLeft.x = djDeck.x - djDeck.width / 2 + rimLeft.width / 2 + 49;
rimLeft.y = djDeck.y;
var rimRight = LK.getAsset('rim', {
anchorX: 0.5,
anchorY: 0.5
});
rimRight.x = djDeck.x + djDeck.width / 2 - rimRight.width / 2 - 150 + 108;
rimRight.y = djDeck.y;
// Add rim assets after djdeck to ensure they appear above in display order
game.addChild(rimLeft);
game.addChild(rimRight);
// Move rim assets above djdeck in display order
var djdeckIndex = game.children.indexOf(djDeck);
if (djdeckIndex !== -1) {
game.setChildIndex(rimLeft, djdeckIndex + 1);
game.setChildIndex(rimRight, djdeckIndex + 2);
}
// Remove and re-add rim assets to ensure they're above djdeckAsset in display order
if (game.children.indexOf(rimLeft) !== -1) {
game.removeChild(rimLeft);
}
if (game.children.indexOf(rimRight) !== -1) {
game.removeChild(rimRight);
}
game.addChild(rimLeft);
game.addChild(rimRight);
// --- Dancing People ---
var dancingPeople = [];
var numPeople = 8;
var peopleAreaY = djDeck.y - djDeck.height / 2 - 200 + 200 + 69; // Position above the DJ deck, moved down by 200 units, then down by 69 more
var peopleAreaWidth = 1600 - 25 * (numPeople - 1); // Area width for dancing people, reduced to move people closer
var startX = 2048 / 2 - peopleAreaWidth / 2 - 77;
var personSpacing = peopleAreaWidth / (numPeople - 1);
for (var i = 0; i < numPeople; i++) {
// Alternate: even index = woman, odd index = man
var genderAsset = i % 2 === 0 ? 'dancingWoman' : 'dancingMan';
var person = new DancingPerson(genderAsset);
person.x = startX + i * personSpacing;
person.baseY = peopleAreaY; // Set the base Y position for animation
game.addChild(person);
dancingPeople.push(person);
}
// --- Laser Show (upper half) ---
var laserShow = new LaserShow();
game.addChild(laserShow);
laserShow.y = -456; // Move laser effect up by 456 units (333 + 123)
// --- Fireworks Effect (upper half) ---
var fireworksEffect = new FireworksEffect();
game.addChild(fireworksEffect);
fireworksEffect.y = 0; // Position at the top of the screen
// --- Balloons (falling from top) ---
var balloons = [];
var numBalloons = 50; // Increased number of balloons
for (var i = 0; i < numBalloons; i++) {
var balloon = new Balloon();
// Position balloons initially above the screen
balloon.y = -300 - Math.random() * 1000; // Start higher up for more variety
balloon.x = Math.random() * 2048;
game.addChild(balloon);
balloons.push(balloon);
}
// --- Ferris Wheel (upper half) ---
var ferrisWheel = new FerrisWheel();
game.addChild(ferrisWheel);
ferrisWheel.x = 2048 / 2 - 400;
ferrisWheel.y = 450; // Positioned in the upper-middle part of the screen
ferrisWheel.scaleX = 0.8;
ferrisWheel.scaleY = 0.8;
// --- DJ Deck Asset ---
var djDeck = LK.getAsset('desk', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2020 * (2048 / 2040) // maintain aspect ratio
});
game.addChild(djDeck);
djDeck.x = 2048 / 2;
djDeck.y = 2732 / 2 + 333 + 12 + 12; // Move the DJ deck down by 357 units
// No dark overlay is present, so nothing to remove.
// --- Dancing People ---
var dancingPeople = [];
var numPeople = 8;
var peopleAreaY = djDeck.y - djDeck.height / 2 - 200 + 200 + 69; // Position above the DJ deck, moved down by 200 units, then down by 69 more
var peopleAreaWidth = 1600 - 25 * (numPeople - 1); // Area width for dancing people, reduced to move people closer
var startX = 2048 / 2 - peopleAreaWidth / 2;
var personSpacing = peopleAreaWidth / (numPeople - 1);
for (var i = 0; i < numPeople; i++) {
var person = new DancingPerson();
person.x = startX + i * personSpacing;
person.baseY = peopleAreaY; // Set the base Y position for animation
game.addChild(person);
dancingPeople.push(person);
}
// --- Smoke Diffuser (left of people line) ---
var smokeDiffuser = new SmokeDiffuser();
// Place to the left of the first dancing person, with a little gap, and move right by 32 units
smokeDiffuser.x = startX - 80 + 32;
smokeDiffuser.y = peopleAreaY + 18 - 50; // Align base with people feet, moved up by 50 units
game.addChild(smokeDiffuser);
// --- Add 5 more smoke machines to the right of the first one, spaced 300 units apart, all moved right by 32 units ---
var smokeDiffusers = [smokeDiffuser];
for (var i = 1; i <= 5; i++) {
var sd = new SmokeDiffuser();
sd.x = smokeDiffuser.x + i * 300;
sd.y = peopleAreaY + 18 - 50; // Moved up by 50 units
game.addChild(sd);
smokeDiffusers.push(sd);
}
// --- Flamethrower ---
var flamethrower = new Flamethrower();
// Position the flamethrower to the right of the dancing people line
flamethrower.x = startX + peopleAreaWidth + 100 + 77 + 7; // Move flamethrower right by 84 units (77+7)
// Move the flamethrower down so the flame aligns with the top of the base, then up by 100 units
flamethrower.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
game.addChild(flamethrower);
// --- Second Flamethrower (left edge) ---
var flamethrowerLeft = new Flamethrower();
// Place at the left edge, aligned with the people line
flamethrowerLeft.x = startX - 200; // Move left flamethrower left by 100 more units
flamethrowerLeft.y = peopleAreaY + (flamethrowerLeft.height ? flamethrowerLeft.height * 0.5 : 75) - 100; // Move base up by 100 units
game.addChild(flamethrowerLeft);
// Ensure ferriswheel, cabins, and rim dots are always under the dancing people in display order
for (var i = 0; i < dancingPeople.length; i++) {
// Find the minimum index among all dancing people
var minIndex = game.children.length;
for (var j = 0; j < dancingPeople.length; j++) {
var idx = game.children.indexOf(dancingPeople[j]);
if (idx !== -1 && idx < minIndex) minIndex = idx;
}
// Move ferrisWheel itself below all dancing people
if (game.children.indexOf(ferrisWheel) > minIndex) {
game.setChildIndex(ferrisWheel, minIndex);
}
// Move all cabins below all dancing people
if (ferrisWheel.cabins) {
for (var c = 0; c < ferrisWheel.cabins.length; c++) {
var cabin = ferrisWheel.cabins[c];
if (game.children.indexOf(cabin) > minIndex) {
game.setChildIndex(cabin, minIndex);
}
}
}
// Move all rim dots (centerCircle assets attached to wheelAssembly) below all dancing people
if (ferrisWheel.wheelAssembly && ferrisWheel.wheelAssembly.children) {
for (var w = 0; w < ferrisWheel.wheelAssembly.children.length; w++) {
var rimDot = ferrisWheel.wheelAssembly.children[w];
// Only move rim dots (centerCircle assets, not hub or spokes)
if (rimDot && rimDot.assetId === 'centerCircle') {
// The rim dots are not direct children of game, but of wheelAssembly, so nothing to do here for game order
// If in future, rim dots are added to game, ensure they are below dancing people
}
}
}
// Now, ensure this dancing person is above ferrisWheel and all its parts
var maxFerrisIndex = game.children.indexOf(ferrisWheel);
if (ferrisWheel.cabins) {
for (var c = 0; c < ferrisWheel.cabins.length; c++) {
var idx = game.children.indexOf(ferrisWheel.cabins[c]);
if (idx > maxFerrisIndex) maxFerrisIndex = idx;
}
}
// (Rim dots are not direct children of game, so not included)
game.setChildIndex(dancingPeople[i], maxFerrisIndex + 1);
}
// Ensure balloons are behind the dancing people but in front of the DJ deck
var minDancingPeopleIndex = game.children.length;
for (var i = 0; i < dancingPeople.length; i++) {
var idx = game.children.indexOf(dancingPeople[i]);
if (idx !== -1 && idx < minDancingPeopleIndex) minDancingPeopleIndex = idx;
}
var djDeckIndex = game.children.indexOf(djdeckAsset); // Use djdeckAsset which is the visible asset
if (balloons) {
for (var i = 0; i < balloons.length; i++) {
var balloon = balloons[i];
var balloonIndex = game.children.indexOf(balloon);
if (balloonIndex !== -1) {
// Position balloons just behind the dancing people (minIndex - 1)
// But also ensure they are in front of the djdeckAsset (djDeckIndex + 1)
var targetIndex = Math.max(djDeckIndex + 1, minDancingPeopleIndex - 1);
// Make sure the targetIndex is valid
if (targetIndex < game.children.length) {
game.setChildIndex(balloon, targetIndex);
} else {
// If target index is out of bounds, place it just before the dancing people
game.setChildIndex(balloon, minDancingPeopleIndex > 0 ? minDancingPeopleIndex - 1 : 0);
}
}
}
}
// --- 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 = 2300;
var fxButtonY = 2200;
// --- 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 + 333 - 124;
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);
// --- DJDeck Asset (center of map) ---
var djdeckAsset = LK.getAsset('djdeck', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(djdeckAsset);
djdeckAsset.x = 2048 / 2;
djdeckAsset.y = 2732 / 2 + 300 + 23 - 5 - 15 - 5;
// Scale djdeck to fit the screen width properly
djdeckAsset.width = 2048;
djdeckAsset.height = djdeckAsset.height * (2048 / djdeckAsset.width);
// Ensure rim assets are above djdeckAsset in display order
var djdeckAssetIndex = game.children.indexOf(djdeckAsset);
if (djdeckAssetIndex !== -1) {
var rimLeftIndex = game.children.indexOf(rimLeft);
var rimRightIndex = game.children.indexOf(rimRight);
if (rimLeftIndex !== -1 && rimLeftIndex <= djdeckAssetIndex) {
var targetIndexLeft = djdeckAssetIndex + 1;
if (targetIndexLeft < game.children.length) {
game.setChildIndex(rimLeft, targetIndexLeft);
} else {
// If target index is out of bounds, move to last position
game.setChildIndex(rimLeft, game.children.length - 1);
}
// Update djdeckAssetIndex after moving rimLeft
djdeckAssetIndex = game.children.indexOf(djdeckAsset);
}
if (rimRightIndex !== -1 && rimRightIndex <= djdeckAssetIndex) {
// Get fresh index for rimLeft after potential move
var currentRimLeftIndex = game.children.indexOf(rimLeft);
var targetIndex = Math.max(djdeckAssetIndex + 1, currentRimLeftIndex + 1);
if (targetIndex < game.children.length) {
game.setChildIndex(rimRight, targetIndex);
} else {
// If target index is out of bounds, move to last position
game.setChildIndex(rimRight, game.children.length - 1);
}
}
}
// --- Sampletable Asset (center of map) ---
var sampletableAsset = LK.getAsset('sampletable', {
anchorX: 0.5,
anchorY: 1.0
});
game.addChild(sampletableAsset);
sampletableAsset.x = 2048 / 2;
sampletableAsset.y = 2732;
// --- Crossfader ---
// Remove and re-add crossfader to ensure it's above the sampletable
if (game.children.indexOf(crossfader) !== -1) {
game.removeChild(crossfader);
}
game.addChild(crossfader);
// --- FX Button ---
// Remove and re-add fxButton to ensure it's above the sampletable
if (game.children.indexOf(fxButton) !== -1) {
game.removeChild(fxButton);
}
game.addChild(fxButton);
// --- Samplebutton Asset (left side corner of sampletable) ---
var samplebuttonAsset = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAsset);
samplebuttonAsset.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset.width / 2 + 50 - 4;
samplebuttonAsset.y = sampletableAsset.y - samplebuttonAsset.height / 2 - 50;
// Add functionality to first samplebutton
samplebuttonAsset.down = function (x, y, obj) {
// Play sample1 sound
LK.getSound('sample1').play();
// Visual feedback - scale animation
tween(samplebuttonAsset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(samplebuttonAsset, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Flash effect
LK.effects.flashObject(samplebuttonAsset, 0xff0000, 300);
};
// --- Second Samplebutton Asset (reusing existing asset for memory efficiency) ---
var samplebuttonAsset2 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAsset2);
samplebuttonAsset2.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset2.width / 2 + 200 - 4;
samplebuttonAsset2.y = sampletableAsset.y - samplebuttonAsset2.height / 2 - 50;
// --- Third Samplebutton Asset ---
var samplebuttonAsset3 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAsset3);
samplebuttonAsset3.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset3.width / 2 + 350;
samplebuttonAsset3.y = sampletableAsset.y - samplebuttonAsset3.height / 2 - 50;
// Add functionality to third samplebutton
samplebuttonAsset3.down = function (x, y, obj) {
// Play sample3 sound
LK.getSound('sample3').play();
// Visual feedback - color flash animation
tween(samplebuttonAsset3, {
tint: 0x0000ff
}, {
duration: 150,
onFinish: function onFinish() {
tween(samplebuttonAsset3, {
tint: 0xffffff
}, {
duration: 150
});
}
});
// Flash effect with blue color
LK.effects.flashObject(samplebuttonAsset3, 0x0000ff, 300);
score += 50;
combo += 1;
};
// --- Fourth Samplebutton Asset ---
var samplebuttonAsset4 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAsset4);
samplebuttonAsset4.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset4.width / 2 + 500 - 4;
samplebuttonAsset4.y = sampletableAsset.y - samplebuttonAsset4.height / 2 - 50;
// Add functionality to fourth samplebutton
samplebuttonAsset4.down = function (x, y, obj) {
// Play sample4 sound
LK.getSound('sample4').play();
// Visual feedback - pulse animation
tween(samplebuttonAsset4, {
alpha: 0.3
}, {
duration: 80,
onFinish: function onFinish() {
tween(samplebuttonAsset4, {
alpha: 1.0
}, {
duration: 80
});
}
});
// Flash effect with purple color
LK.effects.flashObject(samplebuttonAsset4, 0xff00ff, 300);
score += 50;
combo += 1;
};
// --- Second Line Samplebuttons (Above First Line) ---
// --- First Samplebutton Second Line ---
var samplebuttonAsset5 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAsset5);
samplebuttonAsset5.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset5.width / 2 + 50 - 4;
samplebuttonAsset5.y = sampletableAsset.y - samplebuttonAsset5.height / 2 - 250;
// Add functionality to fifth samplebutton
samplebuttonAsset5.down = function (x, y, obj) {
// Play sample1 sound with different effect
LK.getSound('sample1').play();
// Visual feedback - scale animation
tween(samplebuttonAsset5, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(samplebuttonAsset5, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
// Flash effect with cyan color
LK.effects.flashObject(samplebuttonAsset5, 0x00ffff, 300);
score += 75;
combo += 1;
};
// --- Second Samplebutton Second Line ---
var samplebuttonAsset6 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAsset6);
samplebuttonAsset6.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset6.width / 2 + 200 - 4;
samplebuttonAsset6.y = sampletableAsset.y - samplebuttonAsset6.height / 2 - 250;
// Add functionality to sixth samplebutton
samplebuttonAsset6.down = function (x, y, obj) {
// Play sample2 sound with different effect
LK.getSound('sample2').play();
// Visual feedback - scale animation
tween(samplebuttonAsset6, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
onFinish: function onFinish() {
tween(samplebuttonAsset6, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
}
});
// Flash effect with magenta color
LK.effects.flashObject(samplebuttonAsset6, 0xff00ff, 300);
score += 75;
combo += 1;
};
// --- Third Samplebutton Second Line ---
var samplebuttonAsset7 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAsset7);
samplebuttonAsset7.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset7.width / 2 + 350 - 4;
samplebuttonAsset7.y = sampletableAsset.y - samplebuttonAsset7.height / 2 - 250;
// Add functionality to seventh samplebutton
samplebuttonAsset7.down = function (x, y, obj) {
// Play sample3 sound with different effect
LK.getSound('sample3').play();
// Visual feedback - pulsing tint animation
tween(samplebuttonAsset7, {
tint: 0xffff00,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 120,
onFinish: function onFinish() {
tween(samplebuttonAsset7, {
tint: 0xffffff,
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
// Flash effect with yellow color
LK.effects.flashObject(samplebuttonAsset7, 0xffff00, 300);
score += 75;
combo += 1;
};
// --- Fourth Samplebutton Second Line ---
var samplebuttonAsset8 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAsset8);
samplebuttonAsset8.x = sampletableAsset.x - sampletableAsset.width / 2 + samplebuttonAsset8.width / 2 + 500 - 4;
samplebuttonAsset8.y = sampletableAsset.y - samplebuttonAsset8.height / 2 - 250;
// Add functionality to eighth samplebutton
samplebuttonAsset8.down = function (x, y, obj) {
// Play sample4 sound with different effect
LK.getSound('sample4').play();
// Visual feedback - alpha fade
tween(samplebuttonAsset8, {
alpha: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
tween(samplebuttonAsset8, {
alpha: 1.0
}, {
duration: 100
});
}
});
// Flash effect with orange color
LK.effects.flashObject(samplebuttonAsset8, 0xff8000, 300);
score += 75;
combo += 1;
};
// Add different functionality to second samplebutton
samplebuttonAsset2.down = function (x, y, obj) {
// Play sample2 sound (different from first button)
LK.getSound('sample2').play();
// Visual feedback - scale animation
tween(samplebuttonAsset2, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(samplebuttonAsset2, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Flash effect with different color
LK.effects.flashObject(samplebuttonAsset2, 0x00ff00, 300);
// Add score bonus for using sample buttons
score += 50;
combo += 1;
};
// --- Right Side Sample Buttons (First Line) ---
// --- First Samplebutton Right Side First Line ---
var samplebuttonAssetR1 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAssetR1);
samplebuttonAssetR1.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR1.width / 2 - 50 + 4;
samplebuttonAssetR1.y = sampletableAsset.y - samplebuttonAssetR1.height / 2 - 50;
// Add functionality to first right side samplebutton
samplebuttonAssetR1.down = function (x, y, obj) {
// Play sample1 sound
LK.getSound('sample1').play();
// Visual feedback - scale animation
tween(samplebuttonAssetR1, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(samplebuttonAssetR1, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Flash effect
LK.effects.flashObject(samplebuttonAssetR1, 0xff0000, 300);
};
// --- Second Samplebutton Right Side First Line ---
var samplebuttonAssetR2 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAssetR2);
samplebuttonAssetR2.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR2.width / 2 - 200 + 4;
samplebuttonAssetR2.y = sampletableAsset.y - samplebuttonAssetR2.height / 2 - 50;
// Add functionality to second right side samplebutton
samplebuttonAssetR2.down = function (x, y, obj) {
// Play sample2 sound
LK.getSound('sample2').play();
// Visual feedback - scale animation
tween(samplebuttonAssetR2, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(samplebuttonAssetR2, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Flash effect with different color
LK.effects.flashObject(samplebuttonAssetR2, 0x00ff00, 300);
// Add score bonus for using sample buttons
score += 50;
combo += 1;
};
// --- Third Samplebutton Right Side First Line ---
var samplebuttonAssetR3 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAssetR3);
samplebuttonAssetR3.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR3.width / 2 - 350 + 4;
samplebuttonAssetR3.y = sampletableAsset.y - samplebuttonAssetR3.height / 2 - 50;
// Add functionality to third right side samplebutton
samplebuttonAssetR3.down = function (x, y, obj) {
// Play sample3 sound
LK.getSound('sample3').play();
// Visual feedback - color flash animation
tween(samplebuttonAssetR3, {
tint: 0x0000ff
}, {
duration: 150,
onFinish: function onFinish() {
tween(samplebuttonAssetR3, {
tint: 0xffffff
}, {
duration: 150
});
}
});
// Flash effect with blue color
LK.effects.flashObject(samplebuttonAssetR3, 0x0000ff, 300);
score += 50;
combo += 1;
};
// --- Left Deck Asset ---
var leftDeckAsset = LK.getAsset('Deck', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(leftDeckAsset);
leftDeckAsset.x = rimLeft.x;
leftDeckAsset.y = rimLeft.y;
// --- Right Deck Asset ---
var rightDeckAsset = LK.getAsset('Deck', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightDeckAsset);
rightDeckAsset.x = rimRight.x;
rightDeckAsset.y = rimRight.y;
// --- Right Side Sample Buttons (Second Line) ---
// --- First Samplebutton Right Side Second Line ---
var samplebuttonAssetR5 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAssetR5);
samplebuttonAssetR5.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR5.width / 2 - 50 + 4;
samplebuttonAssetR5.y = sampletableAsset.y - samplebuttonAssetR5.height / 2 - 250;
// Add functionality to fifth right side samplebutton
samplebuttonAssetR5.down = function (x, y, obj) {
// Play sample1 sound with different effect
LK.getSound('sample1').play();
// Visual feedback - scale animation
tween(samplebuttonAssetR5, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(samplebuttonAssetR5, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
// Flash effect with cyan color
LK.effects.flashObject(samplebuttonAssetR5, 0x00ffff, 300);
score += 75;
combo += 1;
};
// --- Second Samplebutton Right Side Second Line ---
var samplebuttonAssetR6 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAssetR6);
samplebuttonAssetR6.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR6.width / 2 - 200 + 4;
samplebuttonAssetR6.y = sampletableAsset.y - samplebuttonAssetR6.height / 2 - 250;
// Add functionality to sixth right side samplebutton
samplebuttonAssetR6.down = function (x, y, obj) {
// Play sample2 sound with different effect
LK.getSound('sample2').play();
// Visual feedback - scale animation
tween(samplebuttonAssetR6, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
onFinish: function onFinish() {
tween(samplebuttonAssetR6, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
}
});
// Flash effect with magenta color
LK.effects.flashObject(samplebuttonAssetR6, 0xff00ff, 300);
score += 75;
combo += 1;
};
// --- Third Samplebutton Right Side Second Line ---
var samplebuttonAssetR7 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAssetR7);
samplebuttonAssetR7.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR7.width / 2 - 350 + 4;
samplebuttonAssetR7.y = sampletableAsset.y - samplebuttonAssetR7.height / 2 - 250;
// Add functionality to seventh right side samplebutton
samplebuttonAssetR7.down = function (x, y, obj) {
// Play sample3 sound with different effect
LK.getSound('sample3').play();
// Visual feedback - pulsing tint animation
tween(samplebuttonAssetR7, {
tint: 0xffff00,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 120,
onFinish: function onFinish() {
tween(samplebuttonAssetR7, {
tint: 0xffffff,
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
// Flash effect with yellow color
LK.effects.flashObject(samplebuttonAssetR7, 0xffff00, 300);
score += 75;
combo += 1;
};
// --- Fourth Samplebutton Right Side Second Line ---
var samplebuttonAssetR8 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAssetR8);
samplebuttonAssetR8.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR8.width / 2 - 500 + 4;
samplebuttonAssetR8.y = sampletableAsset.y - samplebuttonAssetR8.height / 2 - 250;
// --- Fourth Samplebutton Right Side First Line ---
var samplebuttonAssetR4 = LK.getAsset('samplebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(samplebuttonAssetR4);
samplebuttonAssetR4.x = sampletableAsset.x + sampletableAsset.width / 2 - samplebuttonAssetR4.width / 2 - 500 + 4;
samplebuttonAssetR4.y = sampletableAsset.y - samplebuttonAssetR4.height / 2 - 50;
// Add functionality to fourth right side samplebutton
samplebuttonAssetR4.down = function (x, y, obj) {
// Play sample4 sound
LK.getSound('sample4').play();
// Visual feedback - pulse animation
tween(samplebuttonAssetR4, {
alpha: 0.3
}, {
duration: 80,
onFinish: function onFinish() {
tween(samplebuttonAssetR4, {
alpha: 1.0
}, {
duration: 80
});
}
});
// Flash effect with purple color
LK.effects.flashObject(samplebuttonAssetR4, 0xff00ff, 300);
score += 50;
combo += 1;
};
// Add functionality to eighth right side samplebutton
samplebuttonAssetR8.down = function (x, y, obj) {
// Play sample4 sound with different effect
LK.getSound('sample4').play();
// Visual feedback - alpha fade
tween(samplebuttonAssetR8, {
alpha: 0.5
}, {
duration: 300,
onFinish: function onFinish() {
tween(samplebuttonAssetR8, {
alpha: 1.0
}, {
duration: 100
});
}
});
// Flash effect with orange color
LK.effects.flashObject(samplebuttonAssetR8, 0xff8000, 300);
score += 75;
combo += 1;
};
// Helper to format time as HH:MM:SS
function formatTime(date) {
var h = date.getHours();
var m = date.getMinutes();
var s = date.getSeconds();
function pad(n) {
return n < 10 ? '0' + n : n;
}
return pad(h) + ':' + pad(m) + ':' + pad(s);
}
// --- Fog Button under pause button (top left, but not in 0,0 area) ---
var fogButton = LK.getAsset('fogButton', {
anchorX: 1.0,
anchorY: 0.0
});
LK.gui.topRight.addChild(fogButton);
fogButton.x = 0;
fogButton.y = 0;
// 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
});
// HSV to RGB helper for background color
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)];
}
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;
// Check first samplebutton
var sb1 = samplebuttonAsset.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sb1.x - samplebuttonAsset.width / 2, 2) + Math.pow(sb1.y - samplebuttonAsset.height / 2, 2) < 75 * 75) return samplebuttonAsset;
// Check second samplebutton
var sb2 = samplebuttonAsset2.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sb2.x - samplebuttonAsset2.width / 2, 2) + Math.pow(sb2.y - samplebuttonAsset2.height / 2, 2) < 75 * 75) return samplebuttonAsset2;
// Check third samplebutton
var sb3 = samplebuttonAsset3.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sb3.x - samplebuttonAsset3.width / 2, 2) + Math.pow(sb3.y - samplebuttonAsset3.height / 2, 2) < 75 * 75) return samplebuttonAsset3;
// Check fourth samplebutton
var sb4 = samplebuttonAsset4.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sb4.x - samplebuttonAsset4.width / 2, 2) + Math.pow(sb4.y - samplebuttonAsset4.height / 2, 2) < 75 * 75) return samplebuttonAsset4;
// Check second line sample buttons
// Check fifth samplebutton (second line, first button)
var sb5 = samplebuttonAsset5.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sb5.x - samplebuttonAsset5.width / 2, 2) + Math.pow(sb5.y - samplebuttonAsset5.height / 2, 2) < 75 * 75) return samplebuttonAsset5;
// Check sixth samplebutton (second line, second button)
var sb6 = samplebuttonAsset6.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sb6.x - samplebuttonAsset6.width / 2, 2) + Math.pow(sb6.y - samplebuttonAsset6.height / 2, 2) < 75 * 75) return samplebuttonAsset6;
// Check seventh samplebutton (second line, third button)
var sb7 = samplebuttonAsset7.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sb7.x - samplebuttonAsset7.width / 2, 2) + Math.pow(sb7.y - samplebuttonAsset7.height / 2, 2) < 75 * 75) return samplebuttonAsset7;
// Check eighth samplebutton (second line, fourth button)
var sb8 = samplebuttonAsset8.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sb8.x - samplebuttonAsset8.width / 2, 2) + Math.pow(sb8.y - samplebuttonAsset8.height / 2, 2) < 75 * 75) return samplebuttonAsset8;
// Check right side sample buttons
// Check first right side samplebutton (first line)
var sbR1 = samplebuttonAssetR1.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sbR1.x - samplebuttonAssetR1.width / 2, 2) + Math.pow(sbR1.y - samplebuttonAssetR1.height / 2, 2) < 75 * 75) return samplebuttonAssetR1;
// Check second right side samplebutton (first line)
var sbR2 = samplebuttonAssetR2.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sbR2.x - samplebuttonAssetR2.width / 2, 2) + Math.pow(sbR2.y - samplebuttonAssetR2.height / 2, 2) < 75 * 75) return samplebuttonAssetR2;
// Check third right side samplebutton (first line)
var sbR3 = samplebuttonAssetR3.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sbR3.x - samplebuttonAssetR3.width / 2, 2) + Math.pow(sbR3.y - samplebuttonAssetR3.height / 2, 2) < 75 * 75) return samplebuttonAssetR3;
// Check fourth right side samplebutton (first line)
var sbR4 = samplebuttonAssetR4.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sbR4.x - samplebuttonAssetR4.width / 2, 2) + Math.pow(sbR4.y - samplebuttonAssetR4.height / 2, 2) < 75 * 75) return samplebuttonAssetR4;
// Check fifth right side samplebutton (second line)
var sbR5 = samplebuttonAssetR5.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sbR5.x - samplebuttonAssetR5.width / 2, 2) + Math.pow(sbR5.y - samplebuttonAssetR5.height / 2, 2) < 75 * 75) return samplebuttonAssetR5;
// Check sixth right side samplebutton (second line)
var sbR6 = samplebuttonAssetR6.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sbR6.x - samplebuttonAssetR6.width / 2, 2) + Math.pow(sbR6.y - samplebuttonAssetR6.height / 2, 2) < 75 * 75) return samplebuttonAssetR6;
// Check seventh right side samplebutton (second line)
var sbR7 = samplebuttonAssetR7.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sbR7.x - samplebuttonAssetR7.width / 2, 2) + Math.pow(sbR7.y - samplebuttonAssetR7.height / 2, 2) < 75 * 75) return samplebuttonAssetR7;
// Check eighth right side samplebutton (second line)
var sbR8 = samplebuttonAssetR8.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(sbR8.x - samplebuttonAssetR8.width / 2, 2) + Math.pow(sbR8.y - samplebuttonAssetR8.height / 2, 2) < 75 * 75) return samplebuttonAssetR8;
// Check right loop exit button
var rightLoopExitLocal = rightLoopExitButton.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(rightLoopExitLocal.x - rightLoopExitButton.width / 2, 2) + Math.pow(rightLoopExitLocal.y - rightLoopExitButton.height / 2, 2) < 50 * 50) return rightLoopExitButton;
// Check right in button
var rightInLocal = rightInButton.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(rightInLocal.x - rightInButton.width / 2, 2) + Math.pow(rightInLocal.y - rightInButton.height / 2, 2) < 50 * 50) return rightInButton;
// Check right out button
var rightOutLocal = rightOutButton.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(rightOutLocal.x - rightOutButton.width / 2, 2) + Math.pow(rightOutLocal.y - rightOutButton.height / 2, 2) < 50 * 50) return rightOutButton;
// Check left start button
var leftStartLocal = leftStartButton.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(leftStartLocal.x - leftStartButton.width / 2, 2) + Math.pow(leftStartLocal.y - leftStartButton.height / 2, 2) < 100 * 100) return leftStartButton;
// Check right start button
var rightStartLocal = rightStartButton.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(rightStartLocal.x - rightStartButton.width / 2, 2) + Math.pow(rightStartLocal.y - rightStartButton.height / 2, 2) < 100 * 100) return rightStartButton;
// Check left cue button
var leftCueLocal = leftCueButton.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(leftCueLocal.x - leftCueButton.width / 2, 2) + Math.pow(leftCueLocal.y - leftCueButton.height / 2, 2) < 50 * 50) return leftCueButton;
// Check right cue button
var rightCueLocal = rightCueButton.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(rightCueLocal.x - rightCueButton.width / 2, 2) + Math.pow(rightCueLocal.y - rightCueButton.height / 2, 2) < 50 * 50) return rightCueButton;
// Check vertical crossfader track
var verticalCfLocal = verticalCrossfaderTrack.toLocal(game.toGlobal({
x: x,
y: y
}));
if (verticalCfLocal.x > 0 && verticalCfLocal.x < verticalCrossfaderTrack.width && verticalCfLocal.y > 0 && verticalCfLocal.y < verticalCrossfaderTrack.height) return verticalCrossfaderTrack;
// Check second vertical crossfader track
var verticalCfLocal2 = verticalCrossfaderTrack2.toLocal(game.toGlobal({
x: x,
y: y
}));
if (verticalCfLocal2.x > 0 && verticalCfLocal2.x < verticalCrossfaderTrack2.width && verticalCfLocal2.y > 0 && verticalCfLocal2.y < verticalCrossfaderTrack2.height) return verticalCrossfaderTrack2;
}
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) {
var local = dragging.toLocal(game.toGlobal({
x: x,
y: y
}));
if (dragging === verticalCrossfaderTrack) {
// Use the object's own move method for consistent behavior
dragging.move(local.x, local.y, obj);
} else if (dragging === verticalCrossfaderTrack2) {
// Use the object's own move method for consistent behavior
dragging.move(local.x, local.y, obj);
} else if (dragging.move) {
// Handle move for other objects that have a move method
dragging.move(local.x, local.y, obj);
}
}
};
// --- Start Button State Variables ---
var leftStartButtonOn = false;
var rightStartButtonOn = false;
// --- Deck Spinning State Variables ---
var leftDeckSpinning = false;
var rightDeckSpinning = false;
// --- Left Start Button ---
var leftStartButton = LK.getAsset('Startbutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(leftStartButton);
leftStartButton.x = rimLeft.x - 200;
leftStartButton.y = rimLeft.y + rimLeft.height / 2 + leftStartButton.height / 2 + 20;
// --- Left Cue Button ---
var leftCueButton = LK.getAsset('Cuebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(leftCueButton);
leftCueButton.x = leftStartButton.x + leftStartButton.width / 2 + leftCueButton.width / 2 + 20 + 200 - 20;
leftCueButton.y = leftStartButton.y;
// Add functionality to left start button
leftStartButton.down = function (x, y, obj) {
// Visual feedback - scale animation
tween(leftStartButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
onFinish: function onFinish() {
tween(leftStartButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
}
});
// Toggle button state
leftStartButtonOn = !leftStartButtonOn;
// Stop any existing tween first
tween.stop(leftStartButton, {
tint: true
});
if (leftStartButtonOn) {
// Turn on green light effect
tween(leftStartButton, {
tint: 0x00ff00
}, {
duration: 200,
onFinish: function onFinish() {
// Create pulsing green light effect
function createPulse() {
if (leftStartButtonOn) {
// Only continue pulsing if still on
tween(leftStartButton, {
tint: 0x88ff88
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (leftStartButtonOn) {
// Only continue pulsing if still on
tween(leftStartButton, {
tint: 0x00ff00
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: createPulse
});
}
}
});
}
}
createPulse();
}
});
} else {
// Turn off light effect - return to normal tint
tween(leftStartButton, {
tint: 0xffffff
}, {
duration: 200
});
}
// Start/stop left deck
leftDeck.playing = !leftDeck.playing;
// Start/stop left deck spinning
leftDeckSpinning = !leftDeckSpinning;
if (leftDeckSpinning) {
// Start continuous clockwise spinning synchronized with deckplatter
var _spinLeftDeck = function spinLeftDeck() {
if (leftDeckSpinning) {
// Synchronize deck asset rotation with deckplatter rotation speed
// Deckplatter rotates at 0.02 radians per frame (60fps), so full rotation takes ~314 frames (~5.23 seconds)
// To match this, deck asset should complete rotation in same time
tween(leftDeckAsset, {
rotation: leftDeckAsset.rotation + Math.PI * 2
}, {
duration: 5233,
easing: tween.linear,
onFinish: _spinLeftDeck
});
}
};
_spinLeftDeck();
} else {
// Stop spinning by stopping any rotation tweens
tween.stop(leftDeckAsset, {
rotation: true
});
}
// Play beat sound
LK.getSound('beat').play();
// Add score bonus
score += 100;
combo += 1;
};
// --- Right Start Button ---
var rightStartButton = LK.getAsset('Startbutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightStartButton);
rightStartButton.x = rimRight.x - 200;
rightStartButton.y = rimRight.y + rimRight.height / 2 + rightStartButton.height / 2 + 20;
// --- Right Cue Button ---
var rightCueButton = LK.getAsset('Cuebutton', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightCueButton);
rightCueButton.x = rightStartButton.x + rightStartButton.width / 2 + rightCueButton.width / 2 + 20 + 200 - 20 - 5 - 5;
rightCueButton.y = rightStartButton.y;
// Add functionality to right start button
rightStartButton.down = function (x, y, obj) {
// Visual feedback - scale animation
tween(rightStartButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
onFinish: function onFinish() {
tween(rightStartButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150
});
}
});
// Toggle button state
rightStartButtonOn = !rightStartButtonOn;
// Stop any existing tween first
tween.stop(rightStartButton, {
tint: true
});
if (rightStartButtonOn) {
// Turn on green light effect
tween(rightStartButton, {
tint: 0x00ff00
}, {
duration: 200,
onFinish: function onFinish() {
// Create pulsing green light effect
function createPulse() {
if (rightStartButtonOn) {
// Only continue pulsing if still on
tween(rightStartButton, {
tint: 0x88ff88
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (rightStartButtonOn) {
// Only continue pulsing if still on
tween(rightStartButton, {
tint: 0x00ff00
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: createPulse
});
}
}
});
}
}
createPulse();
}
});
} else {
// Turn off light effect - return to normal tint
tween(rightStartButton, {
tint: 0xffffff
}, {
duration: 200
});
}
// Start/stop right deck
rightDeck.playing = !rightDeck.playing;
// Start/stop right deck spinning
rightDeckSpinning = !rightDeckSpinning;
if (rightDeckSpinning) {
// Start continuous clockwise spinning synchronized with deckplatter
var _spinRightDeck = function spinRightDeck() {
if (rightDeckSpinning) {
// Synchronize deck asset rotation with deckplatter rotation speed
// Deckplatter rotates at 0.02 radians per frame (60fps), so full rotation takes ~314 frames (~5.23 seconds)
// To match this, deck asset should complete rotation in same time
tween(rightDeckAsset, {
rotation: rightDeckAsset.rotation + Math.PI * 2
}, {
duration: 5233,
easing: tween.linear,
onFinish: _spinRightDeck
});
}
};
_spinRightDeck();
} else {
// Stop spinning by stopping any rotation tweens
tween.stop(rightDeckAsset, {
rotation: true
});
}
// Play beat sound
LK.getSound('beat').play();
// Add score bonus
score += 100;
combo += 1;
};
// Add functionality to left cue button
leftCueButton.down = function (x, y, obj) {
// Visual feedback - scale animation
tween(leftCueButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(leftCueButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Flash effect with cyan color
LK.effects.flashObject(leftCueButton, 0x00ffff, 300);
// Reset left deck to start position
leftDeck.rotationOffset = 0;
leftDeck.currentRotation = 0;
leftDeck.rotation = 0;
// Play scratch sound
LK.getSound('scratch').play();
// Add score bonus
score += 50;
combo += 1;
};
// Add functionality to right cue button
rightCueButton.down = function (x, y, obj) {
// Visual feedback - scale animation
tween(rightCueButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(rightCueButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Flash effect with magenta color
LK.effects.flashObject(rightCueButton, 0xff00ff, 300);
// Reset right deck to start position
rightDeck.rotationOffset = 0;
rightDeck.currentRotation = 0;
rightDeck.rotation = 0;
// Play scratch sound
LK.getSound('scratch').play();
// Add score bonus
score += 50;
combo += 1;
};
// Center left deck platter to the left deck center
leftDeck.x = leftDeckAsset.x;
leftDeck.y = leftDeckAsset.y - 3;
// Center right deck platter to the right deck center
rightDeck.x = rightDeckAsset.x;
rightDeck.y = rightDeckAsset.y - 3;
// --- Screens above decks ---
// Left deck screen
var leftDeckScreen = LK.getAsset('screen', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(leftDeckScreen);
leftDeckScreen.x = leftDeckAsset.x;
leftDeckScreen.y = leftDeckAsset.y - leftDeckAsset.height / 2 - leftDeckScreen.height / 2 - 50 - 200;
// Right deck screen
var rightDeckScreen = LK.getAsset('screen', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightDeckScreen);
rightDeckScreen.x = rightDeckAsset.x;
rightDeckScreen.y = rightDeckAsset.y - rightDeckAsset.height / 2 - rightDeckScreen.height / 2 - 50 - 200;
// --- Effect Buttons Above Screens ---
var effectButtons = [];
var effectButtonSpacing = 220;
var effectButtonY = leftDeckScreen.y - leftDeckScreen.height / 2 - 80 - 55;
// Create 6 effect buttons (3 above each screen)
for (var i = 0; i < 6; i++) {
var effectButton = LK.getAsset('Effect', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(effectButton);
// Position 3 buttons above left screen, 3 above right screen
if (i < 3) {
// Left side buttons
effectButton.x = leftDeckScreen.x - effectButtonSpacing + i * effectButtonSpacing;
} else {
// Right side buttons
effectButton.x = rightDeckScreen.x - effectButtonSpacing + (i - 3) * effectButtonSpacing;
}
effectButton.y = effectButtonY;
// Add 'FIRE' text above the first effect button (i === 0)
if (i === 0) {
var fireText = new Text2('FIRE', {
size: 36,
fill: 0xFFFFFF
});
fireText.anchor.set(0.5, 0.5);
fireText.x = effectButton.x;
fireText.y = effectButton.y - effectButton.height / 2 - 80;
game.addChild(fireText);
}
// Add 'LASER' text above the second effect button (i === 1)
if (i === 1) {
var laserText = new Text2('LASER', {
size: 36,
fill: 0xFFFFFF
});
laserText.anchor.set(0.5, 0.5);
laserText.x = effectButton.x;
laserText.y = effectButton.y - effectButton.height / 2 - 80;
game.addChild(laserText);
}
// Add 'LIGHT' text above the third effect button (i === 2)
if (i === 2) {
var lightText = new Text2('LIGHT', {
size: 36,
fill: 0xFFFFFF
});
lightText.anchor.set(0.5, 0.5);
lightText.x = effectButton.x;
lightText.y = effectButton.y - effectButton.height / 2 - 80;
game.addChild(lightText);
// Store the third effect button for later access
effectButtons[i] = effectButton;
}
// Add 'SMOKE' text above the fourth effect button (i === 3)
if (i === 3) {
var smokeText = new Text2('SMOKE', {
size: 36,
fill: 0xFFFFFF
});
smokeText.anchor.set(0.5, 0.5);
smokeText.x = effectButton.x;
smokeText.y = effectButton.y - effectButton.height / 2 - 80;
game.addChild(smokeText);
}
// Add 'UV' text above the fifth effect button (i === 4)
if (i === 4) {
var uvText = new Text2('UV', {
size: 36,
fill: 0xFFFFFF
});
uvText.anchor.set(0.5, 0.5);
uvText.x = effectButton.x;
uvText.y = effectButton.y - effectButton.height / 2 - 80;
game.addChild(uvText);
}
// Scale up effect button by 1.5
tween(effectButton, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut
});
// Add functionality to each effect button
effectButton.down = function (x, y, obj) {
// Visual feedback - scale animation that returns to 1.5 instead of 1.0
tween(this, {
scaleX: 1.7,
scaleY: 1.7
}, {
duration: 150,
onFinish: function () {
tween(this, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 150
});
}.bind(this)
});
// Play FX sound
LK.getSound('fx').play();
// Flash effect with random color
var colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
LK.effects.flashObject(this, randomColor, 400);
// Add score bonus
score += 75;
combo += 1;
};
// If this is the first effect button (index 0) - FIRE button
if (i === 0) {
effectButton.down = function (x, y, obj) {
// Visual feedback - scale animation that returns to 1.5 instead of 1.0
tween(this, {
scaleX: 1.7,
scaleY: 1.7
}, {
duration: 150,
onFinish: function () {
tween(this, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 150
});
}.bind(this)
});
// Play FX sound
LK.getSound('fx').play();
// Cycle through fire effect modes: 0 (off) -> 1 (normal) -> 2 (big) -> 0 (off)
fireEffectMode = (fireEffectMode + 1) % 3;
// Flash effect with different colors based on mode
var fireColors;
if (fireEffectMode === 0) {
// Off mode - gray color
fireColors = [0x888888];
} else if (fireEffectMode === 1) {
// Normal mode - orange colors
fireColors = [0xff8000, 0xff4400, 0xffaa00];
} else {
// Big flames mode - red colors
fireColors = [0xff0000, 0xff4444, 0xff8888];
}
var randomColor = fireColors[Math.floor(Math.random() * fireColors.length)];
LK.effects.flashObject(this, randomColor, 400);
// Add score bonus
score += 75;
combo += 1;
};
}
effectButtons.push(effectButton);
// If this is the second effect button (index 1) - LASER button
if (i === 1) {
effectButton.down = function (x, y, obj) {
// Visual feedback - scale animation that returns to 1.5 instead of 1.0
tween(this, {
scaleX: 1.7,
scaleY: 1.7
}, {
duration: 150,
onFinish: function () {
tween(this, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 150
});
}.bind(this)
});
// Play FX sound
LK.getSound('fx').play();
// Cycle through laser show modes: 0 (off) -> 1 (slow) -> 2 (fast) -> 0 (off)
laserShowMode = (laserShowMode + 1) % 3;
// Flash effect with different colors based on mode
var laserColors;
if (laserShowMode === 0) {
// Off mode - gray color
laserColors = [0x888888];
} else if (laserShowMode === 1) {
// Slow mode - blue colors
laserColors = [0x0000ff, 0x4444ff, 0x8888ff];
} else {
// Fast mode - rainbow colors
laserColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
}
var randomColor = laserColors[Math.floor(Math.random() * laserColors.length)];
LK.effects.flashObject(this, randomColor, 400);
// Add score bonus
score += 75;
combo += 1;
};
}
// If this is the third effect button (index 2)
if (i === 2) {
effectButton.down = function (x, y, obj) {
// Visual feedback - scale animation that returns to 1.5 instead of 1.0
tween(this, {
scaleX: 1.7,
scaleY: 1.7
}, {
duration: 150,
onFinish: function () {
tween(this, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 150
});
}.bind(this)
});
// Play FX sound
LK.getSound('fx').play();
// Flash effect with random color
var colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
LK.effects.flashObject(this, randomColor, 400);
// Add score bonus
score += 75;
combo += 1;
// Toggle RGB flashing state
isRgbFlashingActive = !isRgbFlashingActive;
};
}
}
// Tablet between the two screens
var tabletAsset = LK.getAsset('tablet', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(tabletAsset);
// Ensure screens exist before positioning tablet
if (typeof leftDeckScreen !== 'undefined' && typeof rightDeckScreen !== 'undefined') {
tabletAsset.x = (leftDeckScreen.x + rightDeckScreen.x) / 2;
tabletAsset.y = leftDeckScreen.y + 77 + 35 - 20;
} else {
// Fallback positioning if screens are not defined
tabletAsset.x = 2048 / 2;
tabletAsset.y = 1366;
}
// --- Digital Clock (center of map) ---
var digitalClockTxt = new Text2('', {
size: 30,
fill: "#fff"
});
digitalClockTxt.anchor.set(0.5, 0.5);
digitalClockTxt.x = 2048 / 2;
digitalClockTxt.y = tabletAsset.y + tabletAsset.height / 2 + 100;
game.addChild(digitalClockTxt);
// --- IN Button under tablet screen ---
var inButton = LK.getAsset('in', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(inButton);
inButton.x = tabletAsset.x - 700 - 200 - 12;
inButton.y = tabletAsset.y + tabletAsset.height / 2 + inButton.height / 2 + 20 - 300 + 77;
// Add whitegray text: ADJUST above in buttons
var adjustTextLeft = new Text2('ADJUST', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
adjustTextLeft.anchor.set(0.5, 0.5);
adjustTextLeft.x = inButton.x + 107;
adjustTextLeft.y = inButton.y - inButton.height / 2 - 20; // Position above the button
game.addChild(adjustTextLeft);
// Add whitegray text: IN under in buttons
var inTextLeft = new Text2('IN', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
inTextLeft.anchor.set(0.5, 0.5);
inTextLeft.x = inButton.x;
inTextLeft.y = inButton.y + inButton.height / 2 + 20; // Position under the button
game.addChild(inTextLeft);
// Add functionality to IN button
inButton.down = function (x, y, obj) {
// Stop any existing flashing effect first
tween.stop(inButton, {
tint: true
});
// Start flashing orange light effect
function createOrangeFlash() {
tween(inButton, {
tint: 0xff8000 // Orange color
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(inButton, {
tint: 0xffffff // Back to white/normal
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: createOrangeFlash // Continue flashing
});
}
});
}
createOrangeFlash();
// Add score bonus
score += 25;
combo += 1;
};
// --- OUT Button under tablet screen ---
var outButton = LK.getAsset('Out', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(outButton);
outButton.x = tabletAsset.x + 700 + 200;
outButton.y = tabletAsset.y + tabletAsset.height / 2 + outButton.height / 2 + 20 - 300 + 77;
// --- Right IN Button to the left of right OUT button ---
var rightInButton = LK.getAsset('in', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightInButton);
rightInButton.x = outButton.x - 192 - 200 - 12;
rightInButton.y = outButton.y;
// Create right ADJUST text now that rightInButton is defined
var adjustTextRight = new Text2('ADJUST', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
adjustTextRight.anchor.set(0.5, 0.5);
adjustTextRight.x = rightInButton.x + 107;
adjustTextRight.y = rightInButton.y - rightInButton.height / 2 - 20; // Position above the button
game.addChild(adjustTextRight);
// Add whitegray text: IN under right in buttons
var inTextRight = new Text2('IN', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
inTextRight.anchor.set(0.5, 0.5);
inTextRight.x = rightInButton.x;
inTextRight.y = rightInButton.y + rightInButton.height / 2 + 20; // Position under the button
game.addChild(inTextRight);
// Add functionality to right IN button
rightInButton.down = function (x, y, obj) {
// Stop any existing flashing effect first
tween.stop(rightInButton, {
tint: true
});
// Start flashing orange light effect
function createOrangeFlash() {
tween(rightInButton, {
tint: 0xff8000 // Orange color
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(rightInButton, {
tint: 0xffffff // Back to white/normal
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: createOrangeFlash // Continue flashing
});
}
});
}
createOrangeFlash();
// Add score bonus
score += 25;
combo += 1;
};
// --- OUT Button above left deck ---
var outButtonLeft = LK.getAsset('Out', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(outButtonLeft);
outButtonLeft.x = leftDeckAsset.x + 192 - 200;
outButtonLeft.y = inButton.y;
// --- Loop Exit Button on the right side of left out button ---
var loopExitButton = LK.getAsset('LoopExit', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(loopExitButton);
loopExitButton.x = outButtonLeft.x + 150 + 50;
loopExitButton.y = outButtonLeft.y;
// Add whitegray text: OUT under left out button
var outTextLeft = new Text2('OUT', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
outTextLeft.anchor.set(0.5, 0.5);
outTextLeft.x = outButtonLeft.x;
outTextLeft.y = inTextLeft.y - 3; // Position at same height as IN text, moved up by 3 units
game.addChild(outTextLeft);
// Add whitegray text: LOOP between left out button and left loop exit button
var loopTextLeft = new Text2('LOOP', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
loopTextLeft.anchor.set(0.5, 0.5);
loopTextLeft.x = (outButtonLeft.x + loopExitButton.x) / 2;
loopTextLeft.y = adjustTextLeft.y; // Position at same height as ADJUST text
game.addChild(loopTextLeft);
// Add whitegray text: EXIT under left loop exit button
var exitTextLeft = new Text2('EXIT', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
exitTextLeft.anchor.set(0.5, 0.5);
exitTextLeft.x = loopExitButton.x;
exitTextLeft.y = loopExitButton.y + loopExitButton.height / 2 + 20; // Position under the button
game.addChild(exitTextLeft);
// Add functionality to loop exit button
loopExitButton.down = function (x, y, obj) {
// Visual feedback - scale animation
tween(loopExitButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(loopExitButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Flash effect with purple color
LK.effects.flashObject(loopExitButton, 0x8000ff, 300);
// Add score bonus
score += 30;
combo += 1;
};
// Add functionality to left OUT button
outButtonLeft.down = function (x, y, obj) {
// Stop any existing flashing effect first
tween.stop(outButtonLeft, {
tint: true
});
// Stop flashing the corresponding 'in' button
tween.stop(inButton, {
tint: true
});
inButton.tint = 0xffffff; // Reset tint to normal
// Start flashing orange light effect
function createOrangeFlash() {
tween(outButtonLeft, {
tint: 0xff8000 // Orange color
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(outButtonLeft, {
tint: 0xffffff // Back to white/normal
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: createOrangeFlash // Continue flashing
});
}
});
}
createOrangeFlash();
// Add score bonus
score += 25;
combo += 1;
};
// --- Right OUT Button ---
var rightOutButton = LK.getAsset('Out', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightOutButton);
rightOutButton.x = rightDeckAsset.x + 192 - 200;
rightOutButton.y = inButton.y;
// --- Right Loop Exit Button next to right out button ---
var rightLoopExitButton = LK.getAsset('LoopExit', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightLoopExitButton);
rightLoopExitButton.x = rightOutButton.x + 150 + 50 + 5;
rightLoopExitButton.y = rightOutButton.y;
// Add functionality to right loop exit button
rightLoopExitButton.down = function (x, y, obj) {
// Visual feedback - scale animation
tween(rightLoopExitButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(rightLoopExitButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Flash effect with purple color
LK.effects.flashObject(rightLoopExitButton, 0x8000ff, 300);
// Add score bonus
score += 30;
combo += 1;
};
// Add whitegray text: OUT under right out button
var outTextRight = new Text2('OUT', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
outTextRight.anchor.set(0.5, 0.5);
outTextRight.x = rightOutButton.x;
outTextRight.y = inTextRight.y - 3; // Position at same height as IN text, moved up by 3 units
game.addChild(outTextRight);
// Add whitegray text: LOOP between right out button and right loop exit button
var loopTextRight = new Text2('LOOP', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
loopTextRight.anchor.set(0.5, 0.5);
loopTextRight.x = (rightOutButton.x + rightLoopExitButton.x) / 2;
loopTextRight.y = adjustTextRight.y; // Position at same height as ADJUST text
game.addChild(loopTextRight);
// Add whitegray text: EXIT under right loop exit button
var exitTextRight = new Text2('EXIT', {
size: 24,
fill: 0xCCCCCC // Whitegray color
});
exitTextRight.anchor.set(0.5, 0.5);
exitTextRight.x = rightLoopExitButton.x;
exitTextRight.y = rightLoopExitButton.y + rightLoopExitButton.height / 2 + 20; // Position under the button
game.addChild(exitTextRight);
// Add functionality to right OUT button
rightOutButton.down = function (x, y, obj) {
// Stop any existing flashing effect first
tween.stop(rightOutButton, {
tint: true
});
// Stop flashing the corresponding 'in' button
tween.stop(rightInButton, {
tint: true
});
rightInButton.tint = 0xffffff; // Reset tint to normal
// Start flashing orange light effect
function createOrangeFlash() {
tween(rightOutButton, {
tint: 0xff8000 // Orange color
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(rightOutButton, {
tint: 0xffffff // Back to white/normal
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: createOrangeFlash // Continue flashing
});
}
});
}
createOrangeFlash();
// Add score bonus
score += 25;
combo += 1;
};
// --- Connecting Lines between In and Out Buttons ---
// Line between inButton and outButtonLeft
var lineInToOutLeft = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: Math.abs(outButtonLeft.x - inButton.x) - 120,
height: 3
});
game.addChild(lineInToOutLeft);
lineInToOutLeft.x = (inButton.x + outButtonLeft.x) / 2;
lineInToOutLeft.y = inButton.y;
lineInToOutLeft.tint = 0x888888; // Gray color
// Line between rightInButton and rightOutButton
var lineRightInToOut = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: Math.abs(rightOutButton.x - rightInButton.x) - 120,
height: 3
});
game.addChild(lineRightInToOut);
lineRightInToOut.x = (rightInButton.x + rightOutButton.x) / 2;
lineRightInToOut.y = rightInButton.y;
lineRightInToOut.tint = 0x888888; // Gray color
// Add a vertical crossfader track
var verticalCrossfaderTrack = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 12,
height: 500
});
game.addChild(verticalCrossfaderTrack);
verticalCrossfaderTrack.x = djdeckAsset.x - 250;
verticalCrossfaderTrack.y = djdeckAsset.y - 100 + 400;
// Add a knob onto the vertical crossfader track
var verticalCrossfaderKnob = LK.getAsset('crossfaderKnob', {
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.PI / 2
});
game.addChild(verticalCrossfaderKnob);
verticalCrossfaderKnob.x = verticalCrossfaderTrack.x;
verticalCrossfaderKnob.y = verticalCrossfaderTrack.y;
// Add a second vertical crossfader track
var verticalCrossfaderTrack2 = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 12,
height: 500
});
game.addChild(verticalCrossfaderTrack2);
verticalCrossfaderTrack2.x = djdeckAsset.x + 250; // Position on the right side
verticalCrossfaderTrack2.y = djdeckAsset.y - 100 + 400;
// Add a knob onto the second vertical crossfader track
var verticalCrossfaderKnob2 = LK.getAsset('crossfaderKnob', {
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.PI / 2
});
game.addChild(verticalCrossfaderKnob2);
verticalCrossfaderKnob2.x = verticalCrossfaderTrack2.x;
verticalCrossfaderKnob2.y = verticalCrossfaderTrack2.y;
// Vertical crossfader state
var verticalCrossfaderValue = 0.5; // 0 = top, 1 = bottom
var verticalCrossfaderDragging = false;
// Second vertical crossfader state
var verticalCrossfaderValue2 = 0.5; // 0 = top, 1 = bottom
var verticalCrossfaderDragging2 = false;
var isRgbFlashingActive = false; // State variable for RGB flashing effect
var laserShowMode = 0; // Laser show state: 0 = off, 1 = slow, 2 = fast
var fireEffectMode = 0; // Fire effect state: 0 = off, 1 = normal flames, 2 = big flames
// Add vertical crossfader functionality with improved touch detection
verticalCrossfaderTrack.down = function (x, y, obj) {
verticalCrossfaderDragging = true;
// Use relative position within track bounds for precise control
var relativeY = (y + verticalCrossfaderTrack.height / 2) / verticalCrossfaderTrack.height;
verticalCrossfaderValue = Math.max(0, Math.min(1, relativeY));
// Update knob position smoothly
verticalCrossfaderKnob.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 + verticalCrossfaderValue * verticalCrossfaderTrack.height;
};
verticalCrossfaderTrack.up = function (x, y, obj) {
verticalCrossfaderDragging = false;
};
verticalCrossfaderTrack.move = function (x, y, obj) {
if (verticalCrossfaderDragging) {
// Use relative position within track bounds for precise control
var relativeY = (y + verticalCrossfaderTrack.height / 2) / verticalCrossfaderTrack.height;
verticalCrossfaderValue = Math.max(0, Math.min(1, relativeY));
// Update knob position smoothly
verticalCrossfaderKnob.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 + verticalCrossfaderValue * verticalCrossfaderTrack.height;
}
};
// Add vertical crossfader functionality for the second crossfader with improved touch detection
verticalCrossfaderTrack2.down = function (x, y, obj) {
verticalCrossfaderDragging2 = true;
// Use relative position within track bounds for precise control
var relativeY = (y + verticalCrossfaderTrack2.height / 2) / verticalCrossfaderTrack2.height;
verticalCrossfaderValue2 = Math.max(0, Math.min(1, relativeY));
// Update knob position smoothly
verticalCrossfaderKnob2.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 + verticalCrossfaderValue2 * verticalCrossfaderTrack2.height;
};
verticalCrossfaderTrack2.up = function (x, y, obj) {
verticalCrossfaderDragging2 = false;
};
verticalCrossfaderTrack2.move = function (x, y, obj) {
if (verticalCrossfaderDragging2) {
// Use relative position within track bounds for precise control
var relativeY = (y + verticalCrossfaderTrack2.height / 2) / verticalCrossfaderTrack2.height;
verticalCrossfaderValue2 = Math.max(0, Math.min(1, relativeY));
// Update knob position smoothly
verticalCrossfaderKnob2.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 + verticalCrossfaderValue2 * verticalCrossfaderTrack2.height;
}
};
var leftEqualizer = new EqualizerBars();
game.addChild(leftEqualizer);
leftEqualizer.x = leftDeckScreen.x;
leftEqualizer.y = leftDeckScreen.y + 50;
// Add equalizer to right deck screen
var rightEqualizer = new EqualizerBars();
game.addChild(rightEqualizer);
rightEqualizer.x = rightDeckScreen.x;
rightEqualizer.y = rightDeckScreen.y + 50;
// Ensure deck platters are always at the top of the display order
if (game.children.indexOf(leftDeck) !== -1) {
game.setChildIndex(leftDeck, game.children.length - 1);
}
if (game.children.indexOf(rightDeck) !== -1) {
game.setChildIndex(rightDeck, game.children.length - 1);
}
// --- Game update ---
game.update = function () {
// Update discoball animation
discoball.update();
// Update fog effect animation
fogEffect.update();
// Update confetti effect animation
confettiEffect.update();
// Update balloons animation
if (balloons) {
for (var i = 0; i < balloons.length; i++) {
balloons[i].update();
}
}
// Update dancing people animations
for (var i = 0; i < dancingPeople.length; i++) {
dancingPeople[i].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;
}
}
// Animate flashing white reflectors
if (reflectors) {
var t = Date.now() * 0.001;
for (var i = 0; i < reflectors.length; i++) {
// Staggered flash, each reflector flashes in sequence
var phase = t * 2.2 + i * 0.5;
// Use a sharp pulse for flash, then fade out
var flash = Math.max(0, Math.sin(phase));
// Sharpen the flash curve for a strobe effect
flash = Math.pow(flash, 6);
reflectors[i].alpha = 0.18 + 0.82 * flash;
// Animate as perfect circles for extra pop (half size base)
var size = 60 + 20 * flash;
// Prevent reflectors from covering the discoball
// Compute distance from reflector to discoball center
var dx = reflectors[i].x - discoball.x;
var dy = reflectors[i].y - discoball.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// Discoball's visible radius (scaled)
var discoballRadius = 150 * discoball.scaleX; // matches Discoball class
// If reflector would overlap discoball, shrink it so it cannot cover
if (dist < discoballRadius + size / 2) {
// Max allowed size so edge of reflector does not enter discoball
var maxSize = Math.max(0, 2 * (dist - discoballRadius));
if (size > maxSize) size = maxSize;
if (size < 0) size = 0;
}
reflectors[i].width = size;
reflectors[i].height = size;
}
}
// Update laser show animation
laserShow.update();
// Update fireworks effect animation
fireworksEffect.update();
// Update Ferris wheel animation
if (typeof ferrisWheel !== 'undefined' && ferrisWheel.update) {
// Defensive check
ferrisWheel.update();
}
// Update smoke diffuser animation
// --- Synchronize all smoke diffusers so they emit smoke puffs at the same time ---
if (typeof smokeDiffusers !== 'undefined' && smokeDiffusers.length > 0) {
// Use the first smoke diffuser as the "master" for timing
var now = Date.now();
// All diffusers share the same "now" and will create puffs in sync
for (var i = 0; i < smokeDiffusers.length; i++) {
var sd = smokeDiffusers[i];
// Patch: override the update method to use the same "now" for all
if (sd && typeof sd.update === 'function') {
// Save original Date.now
var origDateNow = Date.now;
Date.now = function () {
return now;
};
sd.update();
Date.now = origDateNow;
}
}
}
// Update flamethrower animation
if (typeof flamethrower !== 'undefined' && flamethrower.update) {
flamethrower.update();
}
// Update decks
leftDeck.update();
rightDeck.update();
// Update equalizers
leftEqualizer.update();
rightEqualizer.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
}
// Animate background color
var time = Date.now() * 0.0005; // Time for animation
var hue = time * 360 % 360; // Cycle through hues over time
var rgb = hsvToRgb(hue / 360, 0.6, 0.5); // Convert HSV to RGB (adjust saturation and value for desired effect)
// Only animate the background color if RGB flashing is active on the third effect button
if (isRgbFlashingActive) {
game.setBackgroundColor(rgb[0] << 16 | rgb[1] << 8 | rgb[2]);
} else {
// If RGB flashing is not active, set a default background color
game.setBackgroundColor(0x000000); // Or any other default color
}
// Win condition disabled
// --- Update Digital Clock ---
if (typeof digitalClockTxt !== 'undefined') {
var now = new Date();
digitalClockTxt.setText(formatTime(now));
}
// Display laser flashing effect on the second effect button's frame based on mode
if (effectButtons[1]) {
if (laserShowMode === 0) {
// Off mode - normal white tint
effectButtons[1].tint = 0xFFFFFF;
} else if (laserShowMode === 1) {
// Slow mode - slow blue pulsing
var time = Date.now() * 0.0008; // Slow pulsing
var intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);
var blueValue = Math.floor(intensity * 255);
effectButtons[1].tint = 0x4444ff | blueValue << 8 | blueValue;
} else if (laserShowMode === 2) {
// Fast mode - slower rainbow cycling
var time = Date.now() * 0.0008; // Slower cycling (reduced from 0.002)
var laserColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
var colorIndex = Math.floor(time * 3) % laserColors.length; // Slower color cycling (reduced from 8 to 3)
effectButtons[1].tint = laserColors[colorIndex];
}
}
// Display fire effect flashing on the first effect button's frame based on mode
if (effectButtons[0]) {
if (fireEffectMode === 0) {
// Off mode - normal white tint
effectButtons[0].tint = 0xFFFFFF;
} else if (fireEffectMode === 1) {
// Normal flames mode - orange flashing
var time = Date.now() * 0.002; // Medium speed flashing
var intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);
var redValue = Math.floor(255);
var greenValue = Math.floor(intensity * 128 + 64); // Orange tint
var blueValue = 0;
effectButtons[0].tint = redValue << 16 | greenValue << 8 | blueValue;
} else if (fireEffectMode === 2) {
// Big flames mode - red flashing
var time = Date.now() * 0.003; // Faster flashing
var intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);
var redValue = Math.floor(255);
var greenValue = Math.floor(intensity * 64); // More red tint
var blueValue = Math.floor(intensity * 64);
effectButtons[0].tint = redValue << 16 | greenValue << 8 | blueValue;
}
}
// Display RGB flashing effect on the third effect button's frame if active
if (isRgbFlashingActive && effectButtons[2]) {
var time = Date.now() * 0.0005; // Time for animation, even slower
var hue = time * 360 % 360; // Cycle through hues
var rgb = hsvToRgb(hue / 360, 1.0, 1.0); // Full saturation and value for vibrant flash
effectButtons[2].tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
} else if (effectButtons[2]) {
// If not active, set the tint back to white
effectButtons[2].tint = 0xFFFFFF;
}
}; ===================================================================
--- original.js
+++ change.js
@@ -2372,17 +2372,8 @@
LK.effects.flashObject(samplebuttonAssetR8, 0xff8000, 300);
score += 75;
combo += 1;
};
-// --- Digital Clock (center of map) ---
-var digitalClockTxt = new Text2('', {
- size: 30,
- fill: "#fff"
-});
-digitalClockTxt.anchor.set(0.5, 0.5);
-digitalClockTxt.x = 2048 / 2;
-// Will position after tablet is created
-game.addChild(digitalClockTxt);
// Helper to format time as HH:MM:SS
function formatTime(date) {
var h = date.getHours();
var m = date.getMinutes();
@@ -3248,10 +3239,17 @@
// Fallback positioning if screens are not defined
tabletAsset.x = 2048 / 2;
tabletAsset.y = 1366;
}
-// Position digital clock now that tablet is created
+// --- Digital Clock (center of map) ---
+var digitalClockTxt = new Text2('', {
+ size: 30,
+ fill: "#fff"
+});
+digitalClockTxt.anchor.set(0.5, 0.5);
+digitalClockTxt.x = 2048 / 2;
digitalClockTxt.y = tabletAsset.y + tabletAsset.height / 2 + 100;
+game.addChild(digitalClockTxt);
// --- IN Button under tablet screen ---
var inButton = LK.getAsset('in', {
anchorX: 0.5,
anchorY: 0.5
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