User prompt
REMOVE THE SEACHBAR MOVING, BECAUSE IT IS NEEDLESS
User prompt
YOU HIDED THE REAL ORIGINAL MUSICS FROM THE LIST. GIVE THEM BACK TO THE SELECTABLE MENU AND ENSURE THEM PLAYABLE!
User prompt
ENSURE YOU SHOULD PLAY THE SONG, MUSIC FROM THE REKORBOX, TRACKLIST IF THE PLAYER SELECTED ONE OF THEM BY CLICK OR OK BUTTON OR ENTER
User prompt
ENSURE PLAYER ALSO SELECTING BY CLICK FROM FULLSCREEN TRACKLIST CATEGORIES AND TRACKNAMES
User prompt
Add down functionality to the left arrow button in the keyboard app. Add down functionality to the right arrow button in the keyboard app. Add down functionality to the up arrow button in the keyboard app. Add down functionality to the down arrow button in the keyboard app. Add down functionality to the OK button in the keyboard app. Add down functionality to the enter button in the keyboard app. Add event handlers to the Rekordbox app instance for the keyboard arrow and OK buttons.
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'down')' in or related to this line: 'leftArrowButtonKeyboard.down = function (x, y, obj) {' Line Number: 5527
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'down')' in or related to this line: 'leftArrowButtonKeyboard.down = function (x, y, obj) {' Line Number: 5527
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'down')' in or related to this line: 'leftArrowButtonKeyboard.down = function (x, y, obj) {' Line Number: 5527
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'down')' in or related to this line: 'leftArrowButtonKeyboard.down = function (x, y, obj) {' Line Number: 5527
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'down')' in or related to this line: 'leftArrowButtonKeyboard.down = function (x, y, obj) {' Line Number: 5527
User prompt
OK BUTTON AND ARROW BUTTONS IN FULLSCREEN TRACKLIST APP SHOULD WORKING AS UNDER TABLET. FIX THEM!
User prompt
YOU ARE DOING THE MENU CONTROL EXACTLY INVERTED, AS I ASKED. YOU CHANGE CATEGORIES WITH THE LEFT AND RIGHT ARROW KEYS, BUT YOU SHOULD USE THE UP AND DOWN ARROW KEYS TO MOVE THROUGH THE MENU.
User prompt
menubar asset is not visible in menu. ensure menubar is top in display
User prompt
menubar asset is not visible in menu. ensure menubar is top in display
User prompt
Add a menubar asset behind the selected menu item in the Rekordbox and fullscreen tracklist app.
User prompt
add menubar behind the selected menu element what player selected
User prompt
Add functionality to the keyboard app arrow and OK buttons to navigate and select tracks in the fullscreen Rekordbox app.
User prompt
STILL NOT WORKING THE NAVIGATION BY OK BUTTON AND ARROW BUTTONS!!!
User prompt
DO NOT CLOSE FULLSCREEN TRACKLIST APP WHILE IT IS NOT CLOSED BY PRESSING BUTTON X !!!
User prompt
NAVIGATION BY OK BUTTON AND ARROW BUTTONS ARE NOT WORKING ON FULLSCREEN TRACKLIST APP MENU. FIX THIS SHITBOX!
User prompt
DO NOT CLOSE FULLSCREEN TRACKLIST APP WHILE IT IS NOT CLOSED BY X BUTTON!!!
User prompt
DO NOT LOAD AND DO NOT DISPLAY last added ok and arrow buttons until the fullscreen keyboard is not showing up!!!
User prompt
Hide last added ok and arrow buttons until the fullscreen keyboard is not showing up
User prompt
Move the OK button right by 500 units to the right. Move the all the arrow buttons right by 500 units to the right.
User prompt
Move OK button right by 500 units Move left arrow button right by 500 units Move up arrow button right by 500 units Move down arrow button right by 500 units Move right arrow button right by 500 units
/****
* 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;
self.isUV = false; // Add a property to track if this is a UV person
if (typeof forcedAssetId === 'string') {
assetId = forcedAssetId;
self.isUV = forcedAssetId === 'UVW' || forcedAssetId === 'UWM';
} 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 = 8; // Number of simultaneous rockets/explosions - increased from 4 to 8
var rocketInterval = 800; // ms between new rockets - reduced from 1500 to 800
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 () {
// Only animate if fog animation is active
if (typeof fogAnimationActive !== 'undefined' && !fogAnimationActive) {
// Hide all particles when fog animation is not active
for (var i = 0; i < particles.length; i++) {
var p = particles[i];
p.obj.alpha = 0;
}
return;
}
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;
});
// KeyboardApp: Simple keyboard app for the tablet
var KeyboardApp = Container.expand(function () {
var self = Container.call(this);
// Config
var keyboardWidth = 742;
var keyboardHeight = 250;
var keyWidth = 50;
var keyHeight = 50;
var keySpacing = 8;
var keys = [];
var keyLabels = [['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'], ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'], ['Z', 'X', 'C', 'V', 'B', 'N', 'M']];
var shiftLabels = [['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'], ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'], ['z', 'x', 'c', 'v', 'b', 'n', 'm']];
var symbolLabels = [['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'], [',', '-', '.', '/', '+', ':', ';', '<', '>'], ['_', '=', '|', '\\', '{', '}', '[', ']'], ['é', 'ú', 'ü', 'ű', 'í', 'ó', 'ö', 'ő', 'á']];
self.isSymbolsMode = false; // Track if symbols mode is active
self.isShiftMode = false; // Track if shift mode is active
// Create keyboard background
var keyboardBg = self.attachAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: keyboardWidth,
height: keyboardHeight
});
keyboardBg.tint = 0x333333;
// Create keys
var startX = (keyboardWidth - (keyLabels[0].length * (keyWidth + keySpacing) - keySpacing)) / 2;
var startY = 20;
for (var row = 0; row < keyLabels.length; row++) {
var rowLabels = keyLabels[row];
var rowStartX = (keyboardWidth - (rowLabels.length * (keyWidth + keySpacing) - keySpacing)) / 2;
for (var col = 0; col < rowLabels.length; col++) {
var keyBg = self.attachAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: keyWidth,
height: keyHeight
});
keyBg.tint = 0x555555;
keyBg.x = rowStartX + col * (keyWidth + keySpacing) + keyWidth / 2;
keyBg.y = startY + row * (keyHeight + keySpacing) + keyHeight / 2;
var keyText = new Text2(rowLabels[col], {
size: 40,
fill: 0xFFFFFF
});
keyText.anchor.set(0.5, 0.5);
keyBg.addChild(keyText);
// Add basic press feedback
keyBg.down = function (x, y, obj) {
self.handleKeyPress(keyText.text); // Pass the key label to a new handler
if (keyText.text === '←' && typeof rekordboxApp !== 'undefined') {
// Navigate left in the fullscreen tracklist (assuming fullscreenTracklist is accessible here)
if (game.children.indexOf(rekordboxApp) !== -1 && rekordboxApp.visible) {
rekordboxApp.navigateLeft();
}
}
tween(this, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80
});
// Add orange flashing effect using tint and alpha
// Create a temporary flashing graphic above the key
var flashGraphic = LK.getAsset('flashRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: this.width,
height: this.height
});
flashGraphic.alpha = 1.0;
// Position the flash graphic centered on the key
flashGraphic.x = this.x;
flashGraphic.y = this.y;
self.addChild(flashGraphic);
// Fade out and remove the flash graphic
tween(flashGraphic, {
alpha: 0.0
}, {
duration: 200,
onFinish: function onFinish() {
flashGraphic.destroy();
}
});
tween(this, {
tint: 0xff8000,
alpha: 1.0
}, {
duration: 50,
onFinish: function () {
tween(this, {
tint: 0x555555,
alpha: 0.8 // Slightly faded normal state
}, {
duration: 150
});
}.bind(this)
});
LK.getSound('fx').play(); // Play a generic sound
};
keyBg.up = function (x, y, obj) {
// Return to original tint and alpha on release
tween(this, {
tint: 0x555555,
alpha: 0.8 // Slightly faded normal state
}, {
duration: 100
});
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 80
});
};
keys.push(keyBg);
}
}
// Add space bar
var spaceBarWidth = keyWidth * 6 + keySpacing * 5;
var spaceBarBg = self.attachAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: spaceBarWidth * 1.1,
height: keyHeight
});
var spaceGraphic = self.attachAsset('Space', {
anchorX: 0.5,
anchorY: 0.5
});
spaceGraphic.width = spaceBarWidth * 1.1;
spaceGraphic.height = keyHeight;
spaceBarBg.addChild(spaceGraphic);
spaceBarBg.tint = 0x555555;
spaceBarBg.x = keyboardWidth / 2;
spaceBarBg.y = startY + keyLabels.length * (keyHeight + keySpacing) + keyHeight / 2;
var spaceText = new Text2('SPACE', {
size: 40,
fill: 0xFFFFFF
});
spaceText.anchor.set(0.5, 0.5);
spaceBarBg.addChild(spaceText);
// Add basic press feedback for space bar
spaceBarBg.down = function (x, y, obj) {
if (keyText.text === '→' && typeof rekordboxApp !== 'undefined') {
// Navigate right in the fullscreen tracklist (assuming fullscreenTracklist is accessible here)
if (game.children.indexOf(rekordboxApp) !== -1 && rekordboxApp.visible) {
rekordboxApp.navigateRight();
}
}
tween(this, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 80
});
// Add orange flashing effect using tint and alpha
// Create a temporary flashing graphic above the spacebar
var flashGraphic = LK.getAsset('flashRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: this.width,
height: this.height
});
flashGraphic.alpha = 1.0;
// Position the flash graphic centered on the spacebar
flashGraphic.x = this.x;
flashGraphic.y = this.y;
self.addChild(flashGraphic);
// Fade out and remove the flash graphic
tween(flashGraphic, {
alpha: 0.0
}, {
duration: 200,
onFinish: function onFinish() {
flashGraphic.destroy();
}
});
tween(this, {
tint: 0xff8000,
alpha: 1.0
}, {
duration: 50
});
LK.getSound('fx').play(); // Play a generic sound
};
spaceBarBg.up = function (x, y, obj) {
// Return to original tint and alpha on release
tween(this, {
tint: 0x555555,
alpha: 0.8 // Slightly faded normal state
}, {
duration: 100
});
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 80
});
};
keys.push(spaceBarBg);
// Add symbols button to the left of the space bar
var symbolsBarWidth = keyWidth * 2 + keySpacing;
var symbolsBarBg = self.attachAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: symbolsBarWidth,
height: keyHeight
});
symbolsBarBg.tint = 0x555555;
symbolsBarBg.x = spaceBarBg.x - spaceBarBg.width / 2 - symbolsBarBg.width / 2 - keySpacing - 22;
symbolsBarBg.y = spaceBarBg.y;
var symbolsText = new Text2('SYMBOLS', {
size: 30,
fill: 0xFFFFFF
});
symbolsText.anchor.set(0.5, 0.5);
symbolsBarBg.addChild(symbolsText);
// Add basic press feedback for symbols button
symbolsBarBg.down = function (x, y, obj) {
// Toggle symbols mode
self.isSymbolsMode = !self.isSymbolsMode;
// If switching to symbols mode, turn off shift mode
if (self.isSymbolsMode) {
self.isShiftMode = false;
// Find and update the shift button text
for (var i = 0; i < keys.length; i++) {
if (keys[i].children.length > 0 && keys[i].children[0] instanceof Text2 && keys[i].children[0].text === 'SHIFT') {
keys[i].children[0].setText('shift');
break;
}
}
}
self.updateKeyLabels(); // Update the labels
// Update symbols button text based on mode
symbolsText.setText(self.isSymbolsMode ? 'ABC' : 'SYMBOLS'); // Update symbols button text based on mode
if (keyText.text === '↑' && typeof rekordboxApp !== 'undefined') {
// Navigate up in the fullscreen tracklist (assuming fullscreenTracklist is accessible here)
if (game.children.indexOf(rekordboxApp) !== -1 && rekordboxApp.visible) {
rekordboxApp.navigateUp();
}
}
tween(this, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 80
});
// Add orange flashing effect using tint and alpha
// Create a temporary flashing graphic above the symbols button
var flashGraphic = LK.getAsset('flashRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: this.width,
height: this.height
});
flashGraphic.alpha = 1.0;
// Position the flash graphic centered on the symbols button
flashGraphic.x = this.x;
flashGraphic.y = this.y;
self.addChild(flashGraphic);
// Fade out and remove the flash graphic
tween(flashGraphic, {
alpha: 0.0
}, {
duration: 200,
onFinish: function onFinish() {
flashGraphic.destroy();
}
});
if (keyText.text === '↓' && typeof rekordboxApp !== 'undefined') {
// Navigate down in the fullscreen tracklist (assuming fullscreenTracklist is accessible here)
if (game.children.indexOf(rekordboxApp) !== -1 && rekordboxApp.visible) {
rekordboxApp.navigateDown();
}
}
tween(this, {
tint: 0xff8000,
alpha: 1.0
}, {
duration: 50
});
LK.getSound('fx').play(); // Play a generic sound
};
symbolsBarBg.up = function (x, y, obj) {
// Return to original tint and alpha on release
tween(this, {
tint: 0x555555,
alpha: 0.8 // Slightly faded normal state
}, {
duration: 100
});
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 80
});
};
keys.push(symbolsBarBg);
// Add Shift button above the symbols button
var shiftBarWidth = keyWidth * 2 + keySpacing;
var shiftBarBg = self.attachAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: shiftBarWidth,
height: keyHeight
});
shiftBarBg.tint = 0x555555;
shiftBarBg.x = symbolsBarBg.x;
shiftBarBg.y = symbolsBarBg.y - keyHeight - keySpacing;
var shiftText = new Text2('SHIFT', {
size: 30,
fill: 0xFFFFFF
});
shiftText.anchor.set(0.5, 0.5);
shiftBarBg.addChild(shiftText);
// Add basic press feedback for shift button
shiftBarBg.down = function (x, y, obj) {
// Toggle shift mode
self.isShiftMode = !self.isShiftMode;
self.updateKeyLabels(); // Update the labels
// Update shift button text based on mode
shiftText.setText(self.isShiftMode ? 'SHIFT' : 'shift'); // Maybe change visual later
tween(this, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 80
});
// Add orange flashing effect using tint and alpha
// Create a temporary flashing graphic above the shift button
var flashGraphic = LK.getAsset('flashRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: this.width,
height: this.height
});
flashGraphic.alpha = 1.0;
// Position the flash graphic centered on the shift button
flashGraphic.x = this.x;
flashGraphic.y = this.y;
self.addChild(flashGraphic);
// Fade out and remove the flash graphic
tween(flashGraphic, {
alpha: 0.0
}, {
duration: 200,
onFinish: function onFinish() {
flashGraphic.destroy();
}
});
tween(this, {
tint: 0xff8000,
alpha: 1.0
}, {
duration: 50
});
LK.getSound('fx').play(); // Play a generic sound
};
shiftBarBg.up = function (x, y, obj) {
// Return to original tint and alpha on release
tween(this, {
tint: 0x555555,
alpha: 0.8 // Slightly faded normal state
}, {
duration: 100
});
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 80
});
};
keys.push(shiftBarBg);
// Add X button above the enter button
var xBarWidth = keyWidth * 1.5;
var xBarBg = self.attachAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: xBarWidth,
height: keyHeight
});
xBarBg.tint = 0x555555;
xBarBg.x = spaceBarBg.x + spaceBarBg.width / 2 + xBarBg.width / 2 + keySpacing + 15 + 20;
xBarBg.y = spaceBarBg.y - keyHeight - keySpacing;
var xText = new Text2('DELETE', {
size: 28,
fill: 0xFFFFFF
});
xText.anchor.set(0.5, 0.5);
xBarBg.addChild(xText);
// Add basic press feedback for DELETE button
xBarBg.down = function (x, y, obj) {
self.handleKeyPress('DELETE'); // Handle DELETE/BACKSPACE key press
if (keyText.text === 'OK' && typeof rekordboxApp !== 'undefined' && rekordboxApp.selectTrack) {
// Select track in the fullscreen tracklist (assuming fullscreenTracklist is accessible here)
if (game.children.indexOf(rekordboxApp) !== -1 && rekordboxApp.visible) {
rekordboxApp.selectTrack();
}
}
tween(this, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 80
});
// Add orange flashing effect using tint and alpha
// Create a temporary flashing graphic above the X button
var flashGraphic = LK.getAsset('flashRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: this.width,
height: this.height
});
flashGraphic.alpha = 1.0;
// Position the flash graphic centered on the X button
flashGraphic.x = this.x;
flashGraphic.y = this.y;
self.addChild(flashGraphic);
// Fade out and remove the flash graphic
tween(flashGraphic, {
alpha: 0.0
}, {
duration: 200,
onFinish: function onFinish() {
flashGraphic.destroy();
}
});
tween(this, {
tint: 0xff8000,
alpha: 1.0
}, {
duration: 50
});
LK.getSound('fx').play(); // Play a generic sound
};
xBarBg.up = function (x, y, obj) {
// Return to original tint and alpha on release
tween(this, {
tint: 0x555555,
alpha: 0.8 // Slightly faded normal state
}, {
duration: 100
});
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 80
});
};
keys.push(xBarBg);
// Add enter button to the right of the space bar
var enterBarWidth = keyWidth * 2 + keySpacing;
var enterBarBg = self.attachAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: enterBarWidth,
height: keyHeight
});
enterBarBg.tint = 0x555555;
enterBarBg.x = spaceBarBg.x + spaceBarBg.width / 2 + enterBarBg.width / 2 + keySpacing + 15;
enterBarBg.y = spaceBarBg.y;
var enterText = new Text2('ENTER', {
size: 40,
fill: 0xFFFFFF
});
enterText.anchor.set(0.5, 0.5);
enterBarBg.addChild(enterText);
// Add basic press feedback for enter button
enterBarBg.down = function (x, y, obj) {
tween(this, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 80
});
// Add orange flashing effect using tint and alpha
// Create a temporary flashing graphic above the enter button
var flashGraphic = LK.getAsset('flashRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: this.width,
height: this.height
});
flashGraphic.alpha = 1.0;
// Position the flash graphic centered on the enter button
flashGraphic.x = this.x;
flashGraphic.y = this.y;
self.addChild(flashGraphic);
// Fade out and remove the flash graphic
tween(flashGraphic, {
alpha: 0.0
}, {
duration: 200,
onFinish: function onFinish() {
flashGraphic.destroy();
}
});
tween(this, {
tint: 0xff8000,
alpha: 1.0
}, {
duration: 50
});
LK.getSound('fx').play(); // Play a generic sound
};
enterBarBg.up = function (x, y, obj) {
// Return to original tint and alpha on release
tween(this, {
tint: 0x555555,
alpha: 0.8 // Slightly faded normal state
}, {
duration: 100
});
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 80
});
};
keys.push(enterBarBg);
// Method to update key labels based on mode
self.updateKeyLabels = function () {
var currentLabels;
if (self.isSymbolsMode) {
currentLabels = symbolLabels;
} else if (self.isShiftMode) {
currentLabels = shiftLabels;
} else {
currentLabels = keyLabels;
}
var labelIndex = 0;
for (var row = 0; row < currentLabels.length; row++) {
var rowLabels = currentLabels[row];
for (var col = 0; col < rowLabels.length; col++) {
if (labelIndex < keys.length) {
var keyBg = keys[labelIndex];
// Find the Text2 child object
var keyText = null;
for (var i = 0; i < keyBg.children.length; i++) {
if (keyBg.children[i] instanceof Text2) {
keyText = keyBg.children[i];
break;
}
}
if (keyText && keyText.setText) {
keyText.setText(rowLabels[col]);
}
}
labelIndex++;
}
}
};
// Method to handle key press
self.handleKeyPress = function (key) {
// Initialize searchText if it hasn't been already
if (typeof searchText === 'undefined') {
searchText = new Text2('', {
size: 28,
fill: 0x888888
});
searchText.anchor.set(0.5, 0.5);
// Position placeholder, actual position will be set by RekordboxApp
searchText.x = 0;
searchText.y = 0;
}
console.log("Key pressed:", key);
// Add logic here to handle different key presses, e.g., appending to a text input
};
symbolsBarBg.down = function (x, y, obj) {
// Toggle symbols mode
self.isSymbolsMode = !self.isSymbolsMode;
self.updateKeyLabels(); // Update the labels
tween(this, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 80
});
// Add orange flashing effect using tint and alpha
// Create a temporary flashing graphic above the symbols button
var flashGraphic = LK.getAsset('flashRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: this.width,
height: this.height
});
flashGraphic.alpha = 1.0;
// Position the flash graphic centered on the symbols button
flashGraphic.x = this.x;
flashGraphic.y = this.y;
self.addChild(flashGraphic);
// Fade out and remove the flash graphic
tween(flashGraphic, {
alpha: 0.0
}, {
duration: 200,
onFinish: function onFinish() {
flashGraphic.destroy();
}
});
tween(this, {
tint: 0xff8000,
alpha: 1.0
}, {
duration: 50
});
LK.getSound('fx').play(); // Play a generic sound
};
symbolsBarBg.up = function (x, y, obj) {
// Return to original tint and alpha on release
tween(this, {
tint: 0x555555,
alpha: 0.8 // Slightly faded normal state
}, {
duration: 100
});
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 80
});
};
keys.push(symbolsBarBg);
// Add enter button to the right of the space bar
var enterBarWidth = keyWidth * 2 + keySpacing;
var enterBarBg = self.attachAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: enterBarWidth,
height: keyHeight
});
enterBarBg.tint = 0x555555;
enterBarBg.x = spaceBarBg.x + spaceBarBg.width / 2 + enterBarBg.width / 2 + keySpacing + 15;
enterBarBg.y = spaceBarBg.y;
var enterText = new Text2('ENTER', {
size: 40,
fill: 0xFFFFFF
});
enterText.anchor.set(0.5, 0.5);
enterBarBg.addChild(enterText);
// Add basic press feedback for enter button
enterBarBg.down = function (x, y, obj) {
self.handleKeyPress('ENTER'); // Handle enter key press
if (keyText.text === 'ENTER' && typeof rekordboxApp !== 'undefined' && rekordboxApp.selectTrack) {
// Select track in the fullscreen tracklist (assuming fullscreenTracklist is accessible here)
if (game.children.indexOf(rekordboxApp) !== -1 && rekordboxApp.visible) {
rekordboxApp.selectTrack();
}
}
// Reset shift and symbols mode after enter
self.isShiftMode = false;
self.isSymbolsMode = false;
self.updateKeyLabels();
// Find and update the symbols button text
for (var i = 0; i < keys.length; i++) {
if (keys[i].children.length > 0 && keys[i].children[0] instanceof Text2) {
if (keys[i].children[0].text === 'ABC' || keys[i].children[0].text === 'SYMBOLS') {
// Find the symbols button and update its text
keys[i].children[0].setText('SYMBOLS');
break;
}
}
}
// Find and update the shift button text
for (var i = 0; i < keys.length; i++) {
if (keys[i].children.length > 0 && keys[i].children[0] instanceof Text2 && keys[i].children[0].text === 'SHIFT') {
keys[i].children[0].setText('shift');
break;
}
}
tween(this, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 80
});
// Add orange flashing effect using tint and alpha
// Create a temporary flashing graphic above the enter button
var flashGraphic = LK.getAsset('flashRectangle', {
anchorX: 0.5,
anchorY: 0.5,
width: this.width,
height: this.height
});
flashGraphic.alpha = 1.0;
// Position the flash graphic centered on the enter button
flashGraphic.x = this.x;
flashGraphic.y = this.y;
self.addChild(flashGraphic);
// Fade out and remove the flash graphic
tween(flashGraphic, {
alpha: 0.0
}, {
duration: 200,
onFinish: function onFinish() {
flashGraphic.destroy();
}
});
tween(this, {
tint: 0xff8000,
alpha: 1.0
}, {
duration: 50
});
LK.getSound('fx').play(); // Play a generic sound
};
enterBarBg.up = function (x, y, obj) {
// Return to original tint and alpha on release
tween(this, {
tint: 0x555555,
alpha: 0.8 // Slightly faded normal state
}, {
duration: 100
});
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 80
});
};
keys.push(enterBarBg);
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;
// Color logic: if UV mode is on, show different colors; if only laser mode, all beams same color
if (typeof uvEffectActive !== 'undefined' && uvEffectActive) {
// UV mode active - different colors per beam
var colorIdx = (h * beamsPerHead + b + Math.floor(t * 2.5 + h + b)) % beamColors.length;
beam.tint = beamColors[colorIdx];
} else {
// Only laser mode - all beams same color but cycle through gradient
var sameColorIdx = Math.floor(t * 2.5) % beamColors.length;
beam.tint = beamColors[sameColorIdx];
}
// 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;
// Color logic: if UV mode is on, show different colors; if only laser mode, all beams same color
if (typeof uvEffectActive !== 'undefined' && uvEffectActive) {
// UV mode active - different colors per beam
var colorIdx = (h * beamsPerHead + b + Math.floor(t * 6 + h + b)) % beamColors.length;
beam.tint = beamColors[colorIdx];
} else {
// Only laser mode - all beams same color but cycle through gradient
var sameColorIdx = Math.floor(t * 6) % beamColors.length;
beam.tint = beamColors[sameColorIdx];
}
// 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;
});
// MoneyParticle: Animated money bills falling from the top
var MoneyParticle = Container.expand(function () {
var self = Container.call(this);
// Config
var size = (40 + Math.random() * 30) / 1.2; // Random size between 40-70
var speedY = 1.2 + Math.random() * 0.8; // Vertical speed
var speedX = (Math.random() - 0.5) * 1.5; // Horizontal drift
var rotationSpeed = (Math.random() - 0.5) * 0.03; // Rotation speed
// Create money bill graphic using money asset
var moneyGraphic = self.attachAsset('money', {
anchorX: 0.5,
anchorY: 0.5,
width: size * 1.8,
// Money bills are wider than tall
height: size
});
// Keep natural money asset color (remove tint)
// 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) {
// Reset to top with new random properties
self.y = -size;
self.x = Math.random() * 2048;
// Reset size and properties for variety
size = 40 + Math.random() * 30;
moneyGraphic.width = size * 1.8;
moneyGraphic.height = size;
speedY = 1.2 + Math.random() * 0.8;
speedX = (Math.random() - 0.5) * 1.5;
rotationSpeed = (Math.random() - 0.5) * 0.03;
// Animate scale for sparkle effect instead of tint
tween(moneyGraphic, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(moneyGraphic, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
}
});
}
};
return self;
});
// PianoRoll: Interactive piano roll for composing music
var PianoRoll = Container.expand(function (config) {
var self = Container.call(this);
// Config
self.config = config;
self.notes = []; // Array to store notes {beatIndex, keyIndex, visual, pitch}
self.instruments = ['Drums', 'Guitar', 'Piano', 'Synthesizer', 'Bass', 'Strings']; // Added more instruments
var numKeys = Math.floor(config.height / config.noteHeight);
var keyLabels = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
// Piano Roll Background
var pianoRollBg = self.attachAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: config.width,
height: config.height
});
pianoRollBg.tint = 0x2a2a2a;
pianoRollBg.x = 0; // Relative to container
pianoRollBg.y = 0; // Relative to container
// Piano Keyboard (left side)
var keyboardBg = self.attachAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: config.keyboardWidth,
height: config.height
});
keyboardBg.tint = 0x000000;
keyboardBg.x = 0; // Relative to container
keyboardBg.y = 0; // Relative to container
// Create piano keys
var keys = [];
for (var i = 0; i < numKeys; i++) {
var keyY = i * config.noteHeight;
var keyNote = keyLabels[i % 12];
var isBlackKey = keyNote.indexOf('#') !== -1;
var key = self.attachAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: config.keyboardWidth - 2,
height: config.noteHeight - 1
});
key.tint = isBlackKey ? 0x333333 : 0xFFFFFF;
key.x = 1;
key.y = keyY;
self.addChild(key);
// Key label
var keyText = new Text2(keyNote + Math.floor(i / 12 + 3), {
size: 16,
fill: isBlackKey ? 0xFFFFFF : 0x000000
});
keyText.anchor.set(0, 0.5);
keyText.x = key.x + 5;
keyText.y = key.y + config.noteHeight / 2;
self.addChild(keyText);
// Key interaction
key.keyIndex = i;
key.note = keyNote + Math.floor(i / 12 + 3);
key.down = function (x, y, obj) {
// Play note sound - placeholder for now
console.log("Key pressed:", this.note);
// Visual feedback
var originalTint = this.tint;
this.tint = 0xFF6600;
var keyRef = this;
LK.setTimeout(function () {
keyRef.tint = originalTint;
}, 200);
};
keys.push(key);
}
// Grid lines
var gridContainer = new Container();
self.addChild(gridContainer);
var totalBars = 16; // Example: 16 bars
var beatsPerBar = 4; // Example: 4 beats per bar
var timelineWidth = config.width - config.keyboardWidth;
var beatWidth = timelineWidth / (totalBars * beatsPerBar);
// Horizontal grid lines (for each note)
for (var i = 0; i <= numKeys; i++) {
var gridY = i * config.noteHeight;
var hLine = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: timelineWidth,
height: 1
});
hLine.tint = config.gridColor;
hLine.x = config.keyboardWidth;
hLine.y = gridY;
gridContainer.addChild(hLine);
}
// Vertical grid lines (for each beat)
for (var i = 0; i <= totalBars * beatsPerBar; i++) {
var gridX = config.keyboardWidth + i * beatWidth;
var vLine = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: 1,
height: config.height
});
vLine.tint = i % beatsPerBar === 0 ? 0x555555 : config.gridColor;
vLine.x = gridX;
vLine.y = 0; // Relative to container
gridContainer.addChild(vLine);
}
// Note placement area for interaction
var noteArea = self.attachAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: timelineWidth,
height: config.height
});
noteArea.tint = 0x1a1a1a;
noteArea.alpha = 0.001; // Make it almost transparent but interactive
noteArea.x = config.keyboardWidth;
noteArea.y = 0; // Relative to container
self.addChild(noteArea);
// Variables for dragging instrument voices
var draggedInstrument = null;
var dragOffset = {
x: 0,
y: 0
};
// Instrument voice selection (using instruments from SongMakerApp)
var instrumentVoices = self.config.instruments || ['Drums', 'Guitar', 'Piano', 'Synthesizer', 'Bass', 'Strings'];
var instrumentButtons = [];
var instrumentButtonY = 50; // Position buttons relative to instrumentsToolsContainer
var instrumentsPerRow = 4; // Number of instrument buttons per row
var buttonSpacing = 20;
for (var i = 0; i < instrumentVoices.length; i++) {
var button = self.attachAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 60
});
var row = Math.floor(i / instrumentsPerRow);
var col = i % instrumentsPerRow;
button.tint = config.noteColors[i % config.noteColors.length];
// Position buttons relative to the instrumentsToolsContainer
button.x = config.keyboardWidth + 100 + col * (button.width + buttonSpacing + 80); // Add extra 80px spacing
button.y = instrumentButtonY + row * (button.height + buttonSpacing); // Arrange in rows
self.addChild(button);
var buttonText = new Text2(instrumentVoices[i], {
size: 80,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
button.addChild(buttonText);
button.instrumentVoice = instrumentVoices[i];
button.down = function (x, y, obj) {
draggedInstrument = {
voice: this.instrumentVoice,
color: this.tint
};
dragOffset.x = x;
dragOffset.y = y;
};
instrumentButtons.push(button);
}
self.move = function (x, y, obj) {
if (draggedInstrument) {
// Convert global touch coordinates to local coordinates relative to PianoRoll container
var globalPoint = obj && obj.position ? obj.position : {
x: x,
y: y
}; // Get global position from event object with fallback
var localPoint = self.toLocal(globalPoint);
// Create a temporary visual representation of the dragged note/instrument voice
if (!self.draggedNoteVisual) {
self.draggedNoteVisual = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: beatWidth - 2,
height: config.noteHeight - 2
});
self.draggedNoteVisual.alpha = 0.7;
self.addChild(self.draggedNoteVisual);
}
self.draggedNoteVisual.tint = draggedInstrument.color;
self.draggedNoteVisual.x = localPoint.x - dragOffset.x + config.keyboardWidth; // Adjust for drag offset and keyboard width
self.draggedNoteVisual.y = localPoint.y - dragOffset.y; // Adjust for drag offset
}
};
self.up = function (x, y, obj) {
if (draggedInstrument) {
// Convert global touch coordinates to local coordinates relative to PianoRoll container
var globalPoint = obj && obj.position ? obj.position : {
x: x,
y: y
}; // Get global position from event object with fallback
var localPoint = self.toLocal(globalPoint);
// Calculate grid position based on the release position, relative to the noteArea's origin
var releaseX = localPoint.x - config.keyboardWidth;
var releaseY = localPoint.y;
var beatIndex = Math.floor(releaseX / beatWidth);
var keyIndex = Math.floor(releaseY / config.noteHeight);
// Check if release position is within the note area
if (releaseX >= 0 && releaseX < timelineWidth && releaseY >= 0 && releaseY < config.height) {
if (beatIndex >= 0 && beatIndex < totalBars * beatsPerBar && keyIndex >= 0 && keyIndex < numKeys) {
// Check if a note of this instrument already exists at this position
var existingNoteIndex = -1;
for (var i = 0; i < self.notes.length; i++) {
if (self.notes[i].beatIndex === beatIndex && self.notes[i].keyIndex === keyIndex && self.notes[i].instrument === draggedInstrument.voice) {
existingNoteIndex = i;
break;
}
}
if (existingNoteIndex !== -1) {
// Remove existing note of the same instrument
self.removeChild(self.notes[existingNoteIndex].visual);
self.notes.splice(existingNoteIndex, 1);
} else {
// Create new note
var noteX = config.keyboardWidth + beatIndex * beatWidth;
var noteY = keyIndex * config.noteHeight;
var noteVisual = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: beatWidth - 2,
height: config.noteHeight - 2
});
noteVisual.tint = draggedInstrument.color;
noteVisual.x = noteX + 1;
noteVisual.y = noteY + 1;
self.addChild(noteVisual);
var note = {
beatIndex: beatIndex,
keyIndex: keyIndex,
visual: noteVisual,
pitch: keyLabels[keyIndex % 12] + Math.floor(keyIndex / 12 + 3),
instrument: draggedInstrument.voice // Store the instrument voice
};
self.notes.push(note);
// Play sound for the placed note (placeholder - map instrument voice to sound)
console.log("Placed note:", note);
LK.getSound('fx').play(); // Generic sound for now
}
}
}
// Remove the dragged note visual
if (self.draggedNoteVisual) {
self.removeChild(self.draggedNoteVisual);
self.draggedNoteVisual = null;
}
draggedInstrument = null;
dragOffset = {
x: 0,
y: 0
};
}
};
return self;
});
// RekordboxApp: Full-featured rekordbox application interface for the tablet
var RekordboxApp = Container.expand(function () {
var self = Container.call(this);
// Config
self.currentScreen = 'browser'; // 'browser', 'playlist', 'settings', 'performance'
self.selectedTrackIndex = 0;
self.selectedCategoryIndex = 0;
self.currentCategory = 'all';
// Track database
self.tracks = [{
name: 'Summer Vibes',
artist: 'DJ Alex',
bpm: 128,
key: 'Am',
genre: 'House'
}, {
name: 'Night Drive',
artist: 'Luna Beat',
bpm: 132,
key: 'Fm',
genre: 'Techno'
}, {
name: 'Electric Dreams',
artist: 'Synth Master',
bpm: 140,
key: 'Gm',
genre: 'Electronic'
}, {
name: 'Deep Ocean',
artist: 'Wave Runner',
bpm: 124,
key: 'Dm',
genre: 'Deep House'
}, {
name: 'City Lights',
artist: 'Urban Sound',
bpm: 126,
key: 'Em',
genre: 'Progressive'
}, {
name: 'Midnight Express',
artist: 'Beat Factory',
bpm: 130,
key: 'Cm',
genre: 'Techno'
}, {
name: 'Tropical Storm',
artist: 'Island Beats',
bpm: 118,
key: 'Bm',
genre: 'Tropical'
}, {
name: 'Neon Pulse',
artist: 'Cyber DJ',
bpm: 135,
key: 'F#m',
genre: 'Electro'
}, {
name: 'Sunset Boulevard',
artist: 'Coast Drive',
bpm: 122,
key: 'Am',
genre: 'Chill'
}, {
name: 'Bass Revolution',
artist: 'Low End Theory',
bpm: 128,
key: 'Dm',
genre: 'Bass'
}, {
name: 'Street Anthem',
artist: 'MC Flow',
bpm: 90,
key: 'Em',
genre: 'Hip-Hop'
}, {
name: 'Island Rhythm',
artist: 'Rasta King',
bpm: 75,
key: 'Am',
genre: 'Reggae'
}, {
name: 'Smooth Jazz Night',
artist: 'Jazz Collective',
bpm: 110,
key: 'Bbm',
genre: 'Jazz'
}, {
name: 'Symphony No. 9',
artist: 'Classical Ensemble',
bpm: 120,
key: 'Dm',
genre: 'Classical'
}, {
name: 'Rock The House',
artist: 'Thunder Strike',
bpm: 140,
key: 'Em',
genre: 'EDM'
}, {
name: 'Pop Star',
artist: 'Chart Topper',
bpm: 125,
key: 'Am',
genre: 'Pop'
}, {
name: 'Floating Dreams',
artist: 'Ambient Explorer',
bpm: 80,
key: 'Fm',
genre: 'Ambient'
}, {
name: 'Drop The Beat',
artist: 'Dubstep Master',
bpm: 140,
key: 'Gm',
genre: 'Dubstep'
}, {
name: 'Trap Nation',
artist: 'Trap Lord',
bpm: 75,
key: 'Cm',
genre: 'Trap'
}, {
name: 'Liquid Motion',
artist: 'DNB Producer',
bpm: 175,
key: 'Am',
genre: 'Drum & Bass'
}];
self.categories = ['CATEGORY', 'All Tracks', 'House', 'Techno', 'EDM', 'Electronic', 'Disco', 'Latin', 'POP', 'Hip-Hop'];
self.visibleTrackStart = 0;
self.maxVisibleTracks = 8;
// Create main container for app content
var appContainer = self.addChild(new Container());
// Header bar
var headerBar = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: 742,
height: 50
});
headerBar.tint = 0x1a1a1a;
appContainer.addChild(headerBar);
// TRACKLIST logo/title
var titleText = new Text2('TRACKLIST', {
size: 56,
fill: 0xFF6600
});
titleText.anchor.set(0, 0.5);
titleText.x = 10;
titleText.y = 25;
appContainer.addChild(titleText);
// Screen indicator
var screenIndicator = new Text2('BROWSER', {
size: 40,
fill: 0xFFFFFF
});
screenIndicator.anchor.set(1, 0.5);
screenIndicator.x = 722;
screenIndicator.y = 25;
appContainer.addChild(screenIndicator);
// Sidebar for categories
var sidebar = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: 180,
height: 400
});
sidebar.tint = 0x2a2a2a;
sidebar.y = 60;
appContainer.addChild(sidebar);
// Main content area
var contentArea = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: 542,
height: 400
});
contentArea.tint = 0x1a1a1a;
contentArea.x = 190;
contentArea.y = 60;
appContainer.addChild(contentArea);
// Category items in sidebar
self.categoryItems = [];
for (var i = 0; i < self.categories.length; i++) {
var categoryBg = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: 170,
height: 35
});
categoryBg.tint = i === self.selectedCategoryIndex ? 0x444444 : 0x333333;
categoryBg.x = 5;
categoryBg.y = 70 + i * 40;
appContainer.addChild(categoryBg);
var categoryText = new Text2(self.categories[i], {
size: 28,
fill: i === self.selectedCategoryIndex ? "#ff6600" : "#cccccc"
});
categoryText.anchor.set(0, 0.5);
categoryText.x = 15;
categoryText.y = 87 + i * 40 - 2 - 5;
appContainer.addChild(categoryText);
self.categoryItems.push({
bg: categoryBg,
text: categoryText
});
}
// Menubar graphic (added behind selected category)
self.menubar = LK.getAsset('menubar', {
anchorX: 0,
//{nd.1}
anchorY: 0,
//{nd.2}
width: 180,
//{nd.3}
height: 40 //{nd.4}
}); //{nd.5}
self.menubar.alpha = 0.5; // Slightly transparent
appContainer.addChild(self.menubar);
// Ensure menubar is below category texts but above background
appContainer.setChildIndex(self.menubar, appContainer.children.length - 1);
// Track list headers
// Category texts will be initialized with proper fill colors in updateDisplay method
var headerTrack = new Text2('TRACK', {
size: 28,
fill: 0x888888
});
headerTrack.anchor.set(0, 0);
headerTrack.x = 200;
headerTrack.y = 70;
appContainer.addChild(headerTrack);
var headerArtist = new Text2('ARTIST', {
size: 28,
fill: 0x888888
});
headerArtist.anchor.set(0, 0);
headerArtist.x = 413; // Increased x-position
headerArtist.y = 70;
appContainer.addChild(headerArtist);
var headerBPM = new Text2('BPM', {
size: 28,
fill: 0x888888
});
headerBPM.anchor.set(0, 0);
headerBPM.x = 610; // Increased x-position and moved left by 10 units
headerBPM.y = 70;
appContainer.addChild(headerBPM);
var headerKey = new Text2('KEY', {
size: 28,
fill: 0x888888
});
headerKey.anchor.set(0, 0);
headerKey.x = 620 + 40 + 17; // Increased x-position by adding 17 units to the previous elements x + width
headerKey.y = 70;
appContainer.addChild(headerKey);
// Track list items
self.trackItems = [];
for (var i = 0; i < self.maxVisibleTracks; i++) {
var trackBg = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: 532,
height: 35
});
trackBg.tint = 0x252525;
trackBg.x = 195;
trackBg.y = 95 + i * 40;
var trackText = new Text2('', {
size: 28,
fill: 0xFFFFFF
});
trackText.anchor.set(0, 0.5);
trackText.x = 200;
trackText.y = 112 + i * 40 + 17 + 30;
var artistText = new Text2('', {
size: 28,
//{ O}
fill: 0xCCCCCC //{ P}
}); //{ Q}
artistText.anchor.set(0, 0.5);
artistText.x = 380 + 25 + 10; // Increased x-position//{ O}
artistText.y = 112 + i * 40 + 17 + 30;
var bpmText = new Text2('', {
size: 28,
//{ R}
fill: 0xAAAAAA //{ S}
}); //{ T}
bpmText.anchor.set(0, 0.5);
bpmText.x = 620; // Increased x-position
bpmText.y = 112 + i * 40 + 17 + 30;
var keyText = new Text2('', {
size: 28,
//{ U}
fill: 0xAAAAAA //{ V}
}); //{ W}
keyText.anchor.set(0, 0.5);
keyText.x = 620 + 40 + 17; // Increased x-position by adding 17 units to the previous elements x + width
keyText.y = 112 + i * 40 + 17 + 30;
self.trackItems.push({
bg: trackBg,
track: trackText,
artist: artistText,
bpm: bpmText,
key: keyText
});
// Store original tint
self.trackItems[i].bg.originalTint = trackBg.tint;
}
// Add all backgrounds first to ensure they are at the back
for (var i = 0; i < self.maxVisibleTracks; i++) {
appContainer.addChild(self.trackItems[i].bg);
}
// Then add all text elements so they are rendered on top
for (var i = 0; i < self.maxVisibleTracks; i++) {
var item = self.trackItems[i];
appContainer.addChild(item.track);
appContainer.addChild(item.artist);
appContainer.addChild(item.bpm);
appContainer.addChild(item.key);
}
// Bottom status bar
var statusBar = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: 742,
height: 30
});
statusBar.tint = 0x333333;
statusBar.y = 470;
appContainer.addChild(statusBar);
var statusText = new Text2('Use arrow keys to navigate', {
size: 24,
fill: 0xCCCCCC
});
statusText.anchor.set(0, 0.5);
statusText.x = 235;
statusText.y = 485;
appContainer.addChild(statusText);
// Search bar background
var searchBarBg = LK.getAsset('Searchbarbg', {
anchorX: 0.5,
anchorY: 0.5,
width: 512,
height: 40
});
searchBarBg.tint = 0xffffff;
searchBarBg.x = 457 + 10; // Adjusted for center anchor and moved right by 12 units
searchBarBg.y = 125; // Adjusted for center anchor
self.addChild(searchBarBg); // Add directly to self instead of appContainer for independent positioning
// Search bar text
var searchText = new Text2('Search tracks...', {
size: 28,
fill: 0x888888
});
searchText.anchor.set(0.5, 0.5);
searchText.x = 457; // Centered with search bar background and moved right by 12 units
searchText.y = 125; // Centered with search bar background
self.addChild(searchText); // Add directly to self instead of appContainer for independent positioning
// Track count info
self.trackCountText = new Text2('', {
size: 24,
fill: 0x888888
});
self.trackCountText.anchor.set(1, 0.5);
self.trackCountText.x = 732;
self.trackCountText.y = 485;
appContainer.addChild(self.trackCountText);
// Methods
self.updateDisplay = function () {
// Update categories
for (var i = 0; i < self.categoryItems.length; i++) {
var isSelected = i === self.selectedCategoryIndex;
self.categoryItems[i].bg.tint = isSelected ? 0x444444 : 0x333333;
if (self.categoryItems[i].text) {
self.categoryItems[i].text.fill = isSelected ? "#ff8000" : "#cccccc";
}
}
// Position the menubar behind the selected category
if (self.selectedCategoryIndex < self.categoryItems.length) {
self.menubar.x = self.categoryItems[self.selectedCategoryIndex].bg.x;
self.menubar.y = self.categoryItems[self.selectedCategoryIndex].bg.y;
self.menubar.visible = true; // Make menubar visible
} else {
self.menubar.visible = false; // Hide menubar if no category is selected
}
// Filter tracks based on category
var filteredTracks = self.tracks;
if (self.selectedCategoryIndex > 1) {
// Filter by specific genre, skipping 'CATEGORY' and 'All Tracks'
var genre = self.categories[self.selectedCategoryIndex];
filteredTracks = self.tracks.filter(function (track) {
return track.genre === genre;
});
} else if (self.selectedCategoryIndex === 1) {
// 'All Tracks' category - show all tracks
filteredTracks = self.tracks;
} else {
// 'CATEGORY' category - show no tracks
filteredTracks = [];
}
// Update track list
for (var i = 0; i < self.maxVisibleTracks; i++) {
var trackIndex = self.visibleTrackStart + i;
var item = self.trackItems[i];
if (trackIndex < filteredTracks.length) {
var track = filteredTracks[trackIndex];
var isSelected = trackIndex === self.selectedTrackIndex;
item.bg.tint = isSelected ? 0xff8000 : i % 2 === 0 ? 0x252525 : 0x2a2a2a;
item.track.setText(track.name.length > 20 ? track.name.substring(0, 17) + '...' : track.name);
item.artist.setText(track.artist.length > 15 ? track.artist.substring(0, 12) + '...' : track.artist);
item.bpm.setText(track.bpm.toString());
item.key.setText(track.key);
if (item.track) {
item.track.fill = isSelected ? "#ff8000" : "#cccccc";
}
item.artist.fill = isSelected ? "#ffffff" : "#aaaaaa";
item.bpm.fill = isSelected ? "#ffffff" : "#999999";
item.key.fill = isSelected ? "#ffffff" : "#999999";
item.bg.visible = true;
item.track.visible = true;
item.artist.visible = true;
item.bpm.visible = true;
item.key.visible = true;
item.artist.fill = isSelected ? "#ffffff" : "#aaaaaa";
item.bpm.fill = isSelected ? "#ffffff" : "#999999";
item.key.fill = isSelected ? "#ffffff" : "#999999";
item.bg.visible = true;
item.track.visible = true;
item.artist.visible = true;
item.bpm.visible = true;
item.key.visible = true;
} else {
item.bg.visible = false;
item.track.visible = false;
item.artist.visible = false;
item.bpm.visible = false;
item.key.visible = false;
}
}
// Update track count
self.trackCountText.setText(filteredTracks.length + ' tracks');
// Update screen indicator
screenIndicator.setText(self.currentScreen.toUpperCase());
};
self.navigateUp = function () {
if (self.selectedTrackIndex > 0) {
self.selectedTrackIndex--;
if (self.selectedTrackIndex < self.visibleTrackStart) {
self.visibleTrackStart = self.selectedTrackIndex;
}
self.updateDisplay();
}
};
self.navigateDown = function () {
var maxTracks = self.tracks.length - 1;
if (self.selectedTrackIndex < maxTracks) {
self.selectedTrackIndex++;
if (self.selectedTrackIndex >= self.visibleTrackStart + self.maxVisibleTracks) {
self.visibleTrackStart = self.selectedTrackIndex - self.maxVisibleTracks + 1;
}
self.updateDisplay();
}
};
self.navigateLeft = function () {
if (self.selectedCategoryIndex > 0) {
self.selectedCategoryIndex--;
self.selectedTrackIndex = 0;
self.visibleTrackStart = 0;
self.updateDisplay();
}
};
self.navigateRight = function () {
if (self.selectedCategoryIndex < self.categories.length - 1) {
self.selectedCategoryIndex++;
self.selectedTrackIndex = 0;
self.visibleTrackStart = 0;
self.updateDisplay();
}
};
self.selectTrack = function () {
var filteredTracks = self.tracks;
if (self.selectedCategoryIndex > 1) {
// Filter by specific genre, skipping 'CATEGORY' and 'All Tracks'
var genre = self.categories[self.selectedCategoryIndex];
filteredTracks = self.tracks.filter(function (track) {
return track.genre === genre;
});
} else if (self.selectedCategoryIndex === 1) {
// 'All Tracks' category - show all tracks
filteredTracks = self.tracks;
} else {
// 'CATEGORY' category - show no tracks
filteredTracks = [];
}
if (self.selectedTrackIndex < filteredTracks.length) {
var selectedTrack = filteredTracks[self.selectedTrackIndex];
// Flash effect to show selection
tween(self.trackItems[self.selectedTrackIndex - self.visibleTrackStart].bg, {
tint: 0x00ff00
}, {
duration: 150,
onFinish: function onFinish() {
tween(self.trackItems[self.selectedTrackIndex - self.visibleTrackStart].bg, {
tint: self.trackItems[self.selectedTrackIndex - self.visibleTrackStart].bg.originalTint || (self.selectedTrackIndex - self.visibleTrackStart) % 2 === 0 ? 0x252525 : 0x2a2a2a
}, {
duration: 150
});
}
});
// Play a selection sound
LK.getSound('fx').play();
// Add score for track selection
if (typeof score !== 'undefined') {
score += 25;
combo += 1;
}
}
};
// Make search bar draggable
searchBarBg.down = function (x, y, obj) {
self.searchBarDragging = true;
self.searchBarOffset = {
x: x - searchBarBg.x,
y: y - searchBarBg.y
};
};
searchBarBg.up = function (x, y, obj) {
self.searchBarDragging = false;
self.searchBarOffset = null;
};
searchBarBg.move = function (x, y, obj) {
if (self.searchBarDragging && self.searchBarOffset) {
searchBarBg.x = x - self.searchBarOffset.x;
searchBarBg.y = y - self.searchBarOffset.y;
// Keep search text aligned with background
searchText.x = searchBarBg.x;
searchText.y = searchBarBg.y;
}
};
// Initialize display
self.updateDisplay();
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 = 60; // Increased number of particles for denser smoke
var particles = [];
var particleMinSize = 48;
var particleMaxSize = 96;
var speedY = -3.5; // pixels per frame (upwards)
var speedX = 0.7; // horizontal drift
var particleLifetime = 2500; // ms // Increased particle lifetime
// 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_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)];
}
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 depends on UV effect state
if (typeof uvEffectActive !== 'undefined' && uvEffectActive) {
// Colorful UV smoke
var hue = Math.random();
var rgb = hsvToRgb(hue, 0.9 + Math.random() * 0.1, 0.9 + Math.random() * 0.1);
puff.tint = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
} else {
// Normal 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();
// Only emit smoke if smokeEffectActive is true
if (typeof smokeEffectActive !== 'undefined' && smokeEffectActive) {
// 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;
});
var SongMakerApp = Container.expand(function () {
var self = Container.call(this);
// Config
var appWidth = 2048;
var appHeight = 2732;
// Background
var background = self.attachAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: appWidth,
height: appHeight
});
background.tint = 0x1a1a1a; // Dark background
// App Title
var titleText = new Text2('SONG MAKER', {
size: 100,
fill: 0xFF6600
});
titleText.anchor.set(0.5, 0);
titleText.x = appWidth / 2;
titleText.y = 100;
self.addChild(titleText);
// Piano Roll Configuration
var pianoRollConfig = {
x: 50,
y: 250,
width: appWidth - 100,
height: 1600,
noteHeight: 25,
noteColors: [0xFF6600, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF],
gridColor: 0x333333,
keyboardWidth: 120,
timelineHeight: 80,
instruments: ['Drums', 'Guitar', 'Piano', 'Synthesizer', 'Bass', 'Strings']
};
// Create piano roll instance
var pianoRoll = new PianoRoll(pianoRollConfig);
pianoRoll.x = pianoRollConfig.x; // Position the container
pianoRoll.y = pianoRollConfig.y; // Position the container
self.addChild(pianoRoll);
// Access notes array from the pianoRoll instance
var notes = pianoRoll.notes; // This variable is now accessible
var beatWidth = (pianoRollConfig.width - pianoRollConfig.keyboardWidth) / (16 * 4); // Recalculate beatWidth based on pianoRollConfig
// Instruments tools container
// Instruments tools container
var instrumentsToolsY = pianoRollConfig.y + pianoRollConfig.height + 50;
var instrumentsToolsHeight = 200; // Define height for instruments tools
var instrumentsToolsContainer = self.addChild(new Container());
instrumentsToolsContainer.x = pianoRollConfig.x;
instrumentsToolsContainer.y = instrumentsToolsY;
var instrumentsToolsBg = instrumentsToolsContainer.attachAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: pianoRollConfig.width,
height: instrumentsToolsHeight
});
instrumentsToolsBg.tint = 0x333333;
instrumentsToolsBg.x = 0; // Relative to container
instrumentsToolsBg.y = 0; // Relative to container
// Transport controls
var transportY = instrumentsToolsY + instrumentsToolsHeight + 50; // Position transport controls below instruments tools
var transportBg = self.attachAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: pianoRollConfig.width,
height: 100
});
transportBg.tint = 0x333333;
transportBg.x = pianoRollConfig.x;
transportBg.y = transportY;
self.addChild(transportBg);
// Play button
var playButton = self.attachAsset('Startbutton', {
anchorX: 0.5,
anchorY: 0.5
});
playButton.x = pianoRollConfig.x + 100;
playButton.y = transportY + 50;
playButton.scaleX = 0.5;
playButton.scaleY = 0.5;
self.addChild(playButton);
var isPlaying = false;
var playbackPosition = 0;
var playbackTimer = null;
playButton.down = function (x, y, obj) {
isPlaying = !isPlaying;
if (isPlaying) {
// Start playback
playButton.tint = 0x00FF00;
playbackTimer = LK.setInterval(function () {
// Update playback position
playbackPosition = (playbackPosition + 1) % (16 * 4); // Use totalBars * beatsPerBar
// Play notes at current position
for (var i = 0; i < notes.length; i++) {
if (notes[i].beatIndex === playbackPosition) {
// Play sound associated with the instrument voice
// This needs a mapping from instrument voice to a sound asset ID
// For now, playing a generic sound
LK.getSound('fx').play();
// Flash the note
var originalTint = notes[i].visual.tint;
notes[i].visual.tint = 0xFFFFFF;
var noteRef = notes[i];
LK.setTimeout(function () {
noteRef.visual.tint = originalTint;
}, 100);
}
}
}, 250); // 240 BPM (250ms per beat)
} else {
// Stop playback
playButton.tint = 0xFFFFFF;
if (playbackTimer) {
LK.clearInterval(playbackTimer);
playbackTimer = null;
}
}
};
// Stop button
var stopButton = self.attachAsset('Cuebutton', {
anchorX: 0.5,
anchorY: 0.5
});
stopButton.x = pianoRollConfig.x + 200;
stopButton.y = transportY + 50;
stopButton.scaleX = 0.5;
stopButton.scaleY = 0.5;
self.addChild(stopButton);
stopButton.down = function (x, y, obj) {
isPlaying = false;
playbackPosition = 0;
playButton.tint = 0xFFFFFF;
if (playbackTimer) {
LK.clearInterval(playbackTimer);
playbackTimer = null;
}
};
// Clear button
var clearButton = self.attachAsset('Effect', {
anchorX: 0.5,
anchorY: 0.5
});
clearButton.x = pianoRollConfig.x + 300;
clearButton.y = transportY + 50;
clearButton.scaleX = 0.8;
clearButton.scaleY = 0.8;
self.addChild(clearButton);
var clearText = new Text2('CLEAR', {
size: 24,
fill: 0xFFFFFF
});
clearText.anchor.set(0.5, 0.5);
clearText.x = clearButton.x;
clearText.y = clearButton.y;
self.addChild(clearText);
clearButton.down = function (x, y, obj) {
// Clear all notes
for (var i = 0; i < notes.length; i++) {
self.removeChild(notes[i].visual);
}
notes = []; // Clear the notes array
// Visual feedback
tween(clearButton, {
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 100,
onFinish: function onFinish() {
tween(clearButton, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
}
});
};
// Tempo display
var tempoText = new Text2('BPM: 240', {
size: 32,
fill: 0xFFFFFF
});
tempoText.anchor.set(0, 0.5);
tempoText.x = pianoRollConfig.x + 450;
tempoText.y = transportY + 50;
self.addChild(tempoText);
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
// --- Additional Fireworks Effects for more density in upper half ---
var fireworksEffect2 = new FireworksEffect();
game.addChild(fireworksEffect2);
fireworksEffect2.y = 0; // Position at the top of the screen
fireworksEffect2.x = 500; // Offset position for varied launch points
var fireworksEffect3 = new FireworksEffect();
game.addChild(fireworksEffect3);
fireworksEffect3.y = 0; // Position at the top of the screen
fireworksEffect3.x = -300; // Different offset position
var fireworksEffect4 = new FireworksEffect();
game.addChild(fireworksEffect4);
fireworksEffect4.y = 0; // Position at the top of the screen
fireworksEffect4.x = 800; // Another offset position
// --- 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);
}
// --- Money Particles (falling from top) ---
var moneyParticles = [];
var numMoneyParticles = 25; // Number of money bills falling
for (var i = 0; i < numMoneyParticles; i++) {
var money = new MoneyParticle();
// Position money initially above the screen with staggered timing
money.y = -100 - Math.random() * 800;
money.x = Math.random() * 2048;
game.addChild(money);
moneyParticles.push(money);
// Add initial sparkle effect with tween
tween(money, {
alpha: 0.7
}, {
duration: 1000 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function () {
tween(this, {
alpha: 1.0
}, {
duration: 1000 + Math.random() * 1000,
easing: tween.easeInOut
});
}.bind(money)
});
}
// --- 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.
// --- Second Line Dancing People (append to existing array) ---
// Don't recreate the array, just append to existing dancingPeople array
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(); // Use default random asset initially
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) ---
// Add global smokeEffectActive variable to control smoke emission
var smokeEffectActive = false;
var fogAnimationActive = false;
var fogTimeout = null;
// --- Add 6 smoke diffusers spread out to the left of the people line, spaced 300 units apart, all moved right by 32 units ---
var smokeDiffusers = [];
for (var i = 0; i <= 5; i++) {
var sd = new SmokeDiffuser();
sd.x = startX - 80 + 32 + i * 300;
sd.y = peopleAreaY + 18 - 50; // Align base with people feet, 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();
crossfader.x = 2048 / 2;
crossfader.y = crossfaderY + 333 - 124 + 100;
game.addChild(crossfader);
game.setChildIndex(crossfader, game.children.length - 1); // Ensure knob is on top
crossfader.setValue(0.5);
// --- FX Button ---
var fxButton = new FXButton();
game.addChild(fxButton);
fxButton.x = 2048 / 2 - 150;
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;
// --- MASTER Asset ---
var masterAsset = LK.getAsset('MASTER', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(masterAsset);
masterAsset.x = samplebuttonAssetR8.x - samplebuttonAssetR8.width / 2 - masterAsset.width / 2 - 50 - 100; // Position to the left of samplebuttonAssetR8, moved left by 50 units
masterAsset.y = samplebuttonAssetR8.y; // Align vertically with samplebuttonAssetR8
// Add logo asset between the fx and master button
var logoAsset = LK.getAsset('Logo', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(logoAsset);
logoAsset.x = crossfader.x;
logoAsset.y = crossfader.y + crossfader.height / 2 + 30; // Position under the crossfader
// Add white B letter under master button
var masterButtonBText = new Text2('B', {
size: 48,
fill: 0xFFFFFF // White color
});
masterButtonBText.anchor.set(0.5, 0.5);
masterButtonBText.x = masterAsset.x + 150;
masterButtonBText.y = masterAsset.y + masterAsset.height / 2 + 20; // Position under the button
game.addChild(masterButtonBText);
// Add functionality to master asset
masterAsset.down = function (x, y, obj) {
// Visual feedback - scale animation
tween(masterAsset, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(masterAsset, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Flash effect with white color
LK.effects.flashObject(masterAsset, 0xffffff, 300);
// Add score bonus
score += 100;
combo += 1;
};
// --- 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;
};
// --- 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 = 2732 / 2 - 500;
game.addChild(digitalClockTxt);
// 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);
}
// 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;
// Check filter knobs
var lfh = leftFilterKnobHigh.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(lfh.x - leftFilterKnobHigh.width / 2, 2) + Math.pow(lfh.y - leftFilterKnobHigh.height / 2, 2) < 60 * 60) return leftFilterKnobHigh;
var lfm = leftFilterKnobMid.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(lfm.x - leftFilterKnobMid.width / 2, 2) + Math.pow(lfm.y - leftFilterKnobMid.height / 2, 2) < 60 * 60) return leftFilterKnobMid;
var lfl = leftFilterKnobLow.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(lfl.x - leftFilterKnobLow.width / 2, 2) + Math.pow(lfl.y - leftFilterKnobLow.height / 2, 2) < 60 * 60) return leftFilterKnobLow;
var rfh = rightFilterKnobHigh.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(rfh.x - rightFilterKnobHigh.width / 2, 2) + Math.pow(rfh.y - rightFilterKnobHigh.height / 2, 2) < 60 * 60) return rightFilterKnobHigh;
var rfm = rightFilterKnobMid.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(rfm.x - rightFilterKnobMid.width / 2, 2) + Math.pow(rfm.y - rightFilterKnobMid.height / 2, 2) < 60 * 60) return rightFilterKnobMid;
var rfl = rightFilterKnobLow.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.pow(rfl.x - rightFilterKnobLow.width / 2, 2) + Math.pow(rfl.y - rightFilterKnobLow.height / 2, 2) < 60 * 60) return rightFilterKnobLow;
}
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);
}
lastTouchObj = obj; // Keep track of the object that was touched down
};
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);
}
// Reset filter knob drag state for vertical drag mode
if (dragging === leftFilterKnobHigh || dragging === leftFilterKnobMid || dragging === leftFilterKnobLow || dragging === rightFilterKnobHigh || dragging === rightFilterKnobMid || dragging === rightFilterKnobLow) {
if (typeof dragging._lastY !== "undefined") delete dragging._lastY;
if (typeof dragging._rotationValue !== "undefined") delete dragging._rotationValue;
}
// Only set dragging to null if the released object was the one being dragged
if (dragging === getTouchedControl(x, y) || !getTouchedControl(x, y)) {
// Check if released on the same object or empty space
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 === leftFilterKnobHigh || dragging === leftFilterKnobMid || dragging === leftFilterKnobLow || dragging === rightFilterKnobHigh || dragging === rightFilterKnobMid || dragging === rightFilterKnobLow) {
// --- Filter knob rotation logic: vertical drag (up = right, down = left) ---
// Store lastY on the knob for delta calculation
if (typeof dragging._lastY === "undefined") {
dragging._lastY = local.y;
dragging._rotationValue = dragging.rotation || 0; // Store current rotation in radians
}
// Calculate vertical movement delta
var deltaY = local.y - dragging._lastY;
// Sensitivity: how much vertical movement for full rotation (in px)
var sensitivity = 120; // 120px drag = full range (-150deg to +150deg)
// Calculate rotation change: up = right (increase), down = left (decrease)
var deltaRotation = -deltaY * (Math.PI * 5 / 6) / sensitivity; // 5/6 PI = 150deg
// Clamp rotation to -150deg to +150deg
var minRotation = -Math.PI * 5 / 6;
var maxRotation = Math.PI * 5 / 6;
dragging._rotationValue = Math.max(minRotation, Math.min(maxRotation, (dragging._rotationValue || 0) + deltaRotation));
dragging.rotation = dragging._rotationValue;
// Update lastY for next move
dragging._lastY = local.y;
} 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);
}
// Add 'GIFTS' text above the sixth effect button (i === 5)
if (i === 5) {
var giftsText = new Text2('GIFTS', {
size: 36,
fill: 0xFFFFFF
});
giftsText.anchor.set(0.5, 0.5);
giftsText.x = effectButton.x;
giftsText.y = effectButton.y - effectButton.height / 2 - 80;
game.addChild(giftsText);
}
// Scale up effect button by 1.5
tween(effectButton, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut
});
// Add up handler for SMOKE button (index 3)
if (i === 3) {
effectButton.down = function (x, y, obj) {
smokeEffectActive = true;
fogAnimationActive = true;
// Clear any existing fog timeout
if (fogTimeout) {
LK.clearTimeout(fogTimeout);
fogTimeout = null;
}
tween(this, {
scaleX: 1.7,
scaleY: 1.7
}, {
duration: 150,
onFinish: function () {
tween(this, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 150
});
}.bind(this)
});
LK.getSound('fx').play();
LK.effects.flashObject(this, 0x888888, 200);
};
effectButton.up = function (x, y, obj) {
smokeEffectActive = false;
// Start 4 second countdown to turn off fog animation
fogTimeout = LK.setTimeout(function () {
fogAnimationActive = false;
fogTimeout = null;
}, 4000);
// Optionally, provide a quick scale feedback on release
tween(this, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100
});
};
} else {
// Add functionality to other effect buttons
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;
};
}
// Define variable to track the gifts button mode
var giftsMode = 0; // 0: off, 1: balloons, 2: money, 3: fireworks
// Reference the gifts effect button
var giftsEffectButton;
// If this is the fifth effect button (index 4) - UV button
if (i === 4) {
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();
// Toggle UV effect state
uvEffectActive = !uvEffectActive;
// Flash effect with different colors based on mode
var flashColor = uvEffectActive ? 0x8000ff : 0x888888; // Purple for ON, gray for OFF
LK.effects.flashObject(this, flashColor, 400);
// Add score bonus
score += 75;
combo += 1;
};
// Add a reference to the UV button for flashing in update
effectButtons[4] = effectButton;
}
// If this is the sixth effect button (index 5) - GIFTS button
if (i === 5) {
giftsEffectButton = effectButton; // Store reference to gifts button
effectButton.down = function (x, y, obj) {
// Cycle through gift modes
giftsMode = (giftsMode + 1) % 4;
// Visual feedback - scale animation
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();
// Add score bonus
score += 100;
combo += 1;
};
}
}
// 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;
}
// Create rekordbox app instance
var rekordboxApp = new RekordboxApp();
game.addChild(rekordboxApp);
// Position and scale rekordbox app to fit tablet screen
rekordboxApp.x = tabletAsset.x - tabletAsset.width / 2 + 20 + 30;
rekordboxApp.y = tabletAsset.y - tabletAsset.height / 2 + 20 - 200 - 25;
// Add event handlers for keyboard interaction on the fullscreen tracklist
leftArrowButtonKeyboard.down = function (x, y, obj) {
if (typeof fullscreenTracklist !== 'undefined' && fullscreenTracklist.navigateLeft) {
fullscreenTracklist.navigateLeft();
}
};
rightArrowButtonKeyboard.down = function (x, y, obj) {
if (typeof fullscreenTracklist !== 'undefined' && fullscreenTracklist.navigateRight) {
fullscreenTracklist.navigateRight();
}
};
upArrowButtonKeyboard.down = function (x, y, obj) {
if (typeof fullscreenTracklist !== 'undefined' && fullscreenTracklist.navigateUp) {
fullscreenTracklist.navigateUp();
}
};
downArrowButtonKeyboard.down = function (x, y, obj) {
if (typeof fullscreenTracklist !== 'undefined' && fullscreenTracklist.navigateDown) {
fullscreenTracklist.navigateDown();
}
};
okButtonKeyboard.down = function (x, y, obj) {
if (typeof fullscreenTracklist !== 'undefined' && fullscreenTracklist.selectTrack) {
fullscreenTracklist.selectTrack();
}
};
var enterButtonKeyboard = LK.getAsset('Effect', {
// Using Effect asset as a placeholder
anchorX: 0.5,
anchorY: 0.5
});
enterButtonKeyboard.visible = false; // Initially hidden
// Create keyboard app instance
var keyboardApp = new KeyboardApp();
// Create keyboard app instance
var keyboardApp = new KeyboardApp();
var leftArrowButtonKeyboard;
var rightArrowButtonKeyboard;
var upArrowButtonKeyboard;
var downArrowButtonKeyboard;
var okButtonKeyboard;
var enterButtonKeyboard; // Define enter button
var leftArrowButtonKeyboard = LK.getAsset('Leftarrow', {
anchorX: 0.5,
anchorY: 0.5
});
var rightArrowButtonKeyboard = LK.getAsset('Rightarrow', {
anchorX: 0.5,
anchorY: 0.5
});
var upArrowButtonKeyboard = LK.getAsset('UParrow', {
anchorX: 0.5,
anchorY: 0.5
});
var downArrowButtonKeyboard = LK.getAsset('Downarrow', {
anchorX: 0.5,
anchorY: 0.5
});
var okButtonKeyboard = LK.getAsset('OKbutton', {
anchorX: 0.5,
anchorY: 0.5
});
// Position and scale keyboard app under the tracklist
keyboardApp.x = rekordboxApp.x - 777; // Align with rekordbox app and move left by 777 units
keyboardApp.y = rekordboxApp.y + rekordboxApp.height + 10 + 777 - 300 + 200 - 100 - 100; // Position below tracklist with spacing and move down by 777 units, then up by 300, then down by 200, then up by 100, then up by 100
keyboardApp.scaleX = rekordboxApp.scaleX * 1.1; // Match scale and adjust slightly
keyboardApp.scaleY = keyboardApp.scaleX; // Maintain aspect ratio
keyboardApp.visible = false; // Hide the keyboard initially
var keyboardButtonSpacing = 120; // Reduced spacing
leftArrowButtonKeyboard.x = keyboardApp.x + keyboardApp.width * keyboardApp.scaleX / 2 - keyboardButtonSpacing * 2 - 60;
leftArrowButtonKeyboard.y = keyboardApp.y - leftArrowButtonKeyboard.height / 2 - 20;
rightArrowButtonKeyboard.x = keyboardApp.x + keyboardApp.width * keyboardApp.scaleX / 2 - keyboardButtonSpacing - 30;
rightArrowButtonKeyboard.y = keyboardApp.y - rightArrowButtonKeyboard.height / 2 - 20;
upArrowButtonKeyboard.x = keyboardApp.x + keyboardApp.width * keyboardApp.scaleX / 2;
upArrowButtonKeyboard.y = keyboardApp.y - upArrowButtonKeyboard.height / 2 - 20;
downArrowButtonKeyboard.x = keyboardApp.x + keyboardApp.width * keyboardApp.scaleX / 2 + keyboardButtonSpacing;
downArrowButtonKeyboard.y = keyboardApp.y - downArrowButtonKeyboard.height / 2 - 20;
okButtonKeyboard.x = keyboardApp.x + keyboardApp.width * keyboardApp.scaleX / 2 + keyboardButtonSpacing * 2 + 30;
okButtonKeyboard.y = keyboardApp.y - okButtonKeyboard.height / 2 - 20;
// Scale up keyboard app to 3x size using tween animation
tween(keyboardApp, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 500,
easing: tween.easeOut
});
// Scale down to better fit the tablet asset by 1.1
tween(rekordboxApp, {
scaleX: 0.95 / 1.1,
scaleY: 0.95 / 1.1
}, {
duration: 500,
easing: tween.easeOut
});
// Add tablet press functionality to pop up fullscreen tracklist
tabletAsset.down = function (x, y, obj) {
// Create fullscreen tracklist popup
var fullscreenTracklist = new RekordboxApp();
// Add to game at top layer
game.addChild(fullscreenTracklist);
// Add menubar to the fullscreen tracklist
if (fullscreenTracklist.menubar) {
fullscreenTracklist.addChild(fullscreenTracklist.menubar);
fullscreenTracklist.updateDisplay(); // Update display to position menubar
}
keyboardApp.visible = true; // Show the keyboard app
leftArrowButtonKeyboard.visible = true;
rightArrowButtonKeyboard.visible = true;
upArrowButtonKeyboard.visible = true;
downArrowButtonKeyboard.visible = true;
okButtonKeyboard.visible = true;
// Ensure keyboard is above the overlay and tracklist
game.addChild(keyboardApp);
game.addChild(leftArrowButtonKeyboard);
game.addChild(rightArrowButtonKeyboard);
game.addChild(upArrowButtonKeyboard);
game.addChild(downArrowButtonKeyboard);
game.addChild(okButtonKeyboard);
// Position fullscreen - center on screen and move to top
fullscreenTracklist.x = 2048 / 2 - 371 - 600; // Half of app width (742/2)
fullscreenTracklist.y = 0 + 269; // Move to top of tablet height
// Scale to fullscreen size
fullscreenTracklist.scaleX = 2.5 * 1.05;
fullscreenTracklist.scaleY = 2.5 * 1.05;
// Create semi-transparent background overlay
var overlay = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: 2048,
height: 2732
});
overlay.tint = 0x000000;
overlay.alpha = 0.7;
overlay.x = 0;
overlay.y = 0;
// Add overlay behind the app
game.addChild(overlay);
game.setChildIndex(overlay, game.children.indexOf(fullscreenTracklist) - 1);
// Add X (close window) button to the full screen song maker app top right corner
var closeButton = LK.getAsset('X', {
anchorX: 1.0,
anchorY: 0.0
});
closeButton.scaleX = 2.0;
closeButton.scaleY = 2.0;
closeButton.x = 2048 - 20; // 20px from right edge
closeButton.y = 20; // 20px from top edge
game.addChild(closeButton);
// Add close functionality to the X button
closeButton.down = function (x, y, obj) {
// Remove fullscreen song maker app, overlay, and close button
if (game.children.indexOf(fullscreenTracklist) !== -1) {
game.removeChild(fullscreenTracklist);
}
if (game.children.indexOf(overlay) !== -1) {
game.removeChild(overlay);
}
if (game.children.indexOf(closeButton) !== -1) {
game.removeChild(closeButton);
}
keyboardApp.visible = false; // Hide the keyboard app
leftArrowButtonKeyboard.visible = false;
rightArrowButtonKeyboard.visible = false;
upArrowButtonKeyboard.visible = false;
downArrowButtonKeyboard.visible = false;
okButtonKeyboard.visible = false;
};
// Add close functionality when clicking overlay
// overlay.down = function (x, y, obj) {
// // Remove fullscreen tracklist and overlay
// if (game.children.indexOf(fullscreenTracklist) !== -1) {
// game.removeChild(fullscreenTracklist);
// }
// if (game.children.indexOf(overlay) !== -1) {
// game.removeChild(overlay);
// }
// if (game.children.indexOf(closeButton) !== -1) {
// game.removeChild(closeButton);
// }
// keyboardApp.visible = false; // Hide the keyboard app
// leftArrowButtonKeyboard.visible = false;
// rightArrowButtonKeyboard.visible = false;
// upArrowButtonKeyboard.visible = false;
// downArrowButtonKeyboard.visible = false;
// okButtonKeyboard.visible = false;
// };
// Visual feedback for tablet press
tween(tabletAsset, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(tabletAsset, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
}
});
// Play sound effect
LK.getSound('fx').play();
};
// --- 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 white notches for horizontal crossfader (top side)
var horizontalCrossfaderTrack = crossfader; // Use the existing crossfader
var notchSpacingHorizontal = horizontalCrossfaderTrack.width / 10; // 10 notches
for (var i = 0; i <= 10; i++) {
var notch = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 3,
// Notch width
height: 20 // Notch height
});
notch.tint = 0xFFFFFF; // White color
notch.x = horizontalCrossfaderTrack.x - horizontalCrossfaderTrack.width / 2 + i * notchSpacingHorizontal; // Position along the top edge
notch.y = horizontalCrossfaderTrack.y - 20; // Position above the track
game.addChild(notch);
}
// Add white notches for horizontal crossfader (bottom side)
var horizontalCrossfaderTrack = crossfader; // Use the existing crossfader
var notchSpacingHorizontal = horizontalCrossfaderTrack.width / 10; // 10 notches
for (var i = 0; i <= 10; i++) {
var notch = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 3,
// Notch width
height: 20 // Notch height
});
notch.tint = 0xFFFFFF; // White color
notch.x = horizontalCrossfaderTrack.x - horizontalCrossfaderTrack.width / 2 + i * notchSpacingHorizontal; // Position along the top edge
notch.y = horizontalCrossfaderTrack.y + 20; // Position below the track
game.addChild(notch);
}
// Horizontal crossfader knob is already managed by the crossfader object
// Add a vertical crossfader track
var verticalCrossfaderTrack = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 12,
height: 500
});
// Ensure horizontal crossfader knob is above the notches
game.addChild(crossfader);
crossfader.x = 2048 / 2;
crossfader.y = crossfaderY + 333 - 124 + 100;
crossfader.setValue(0.5);
// 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;
verticalCrossfaderTrack.tint = 0xFFFFFF;
// Add white notches for scaling
var notchSpacing = verticalCrossfaderTrack.height / 10; // 10 notches
for (var i = 0; i <= 10; i++) {
var notch = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
// Notch width
height: 3 // Notch height
});
notch.tint = 0xFFFFFF; // White color
notch.x = verticalCrossfaderTrack.x + 20; // Position to the right of the track
notch.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 + i * notchSpacing;
game.addChild(notch);
}
// Add white notches for scaling on the other side of the track
for (var i = 0; i <= 10; i++) {
var notch = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 3
});
notch.tint = 0xFFFFFF;
notch.x = verticalCrossfaderTrack.x - 20; // Position to the left of the track
notch.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 + i * notchSpacing;
game.addChild(notch);
}
// Add a knob onto the vertical crossfader track
var verticalCrossfaderKnob = LK.getAsset('crossfaderKnob', {
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.PI / 2
});
verticalCrossfaderKnob.x = verticalCrossfaderTrack.x;
verticalCrossfaderKnob.y = verticalCrossfaderTrack.y;
// Add a knob onto the vertical crossfader track
var verticalCrossfaderKnob = LK.getAsset('crossfaderKnob', {
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.PI / 2
});
verticalCrossfaderKnob.x = verticalCrossfaderTrack.x;
verticalCrossfaderKnob.y = verticalCrossfaderTrack.y;
game.addChild(verticalCrossfaderKnob);
// Ensure knob is above the notches by bringing it to the top of the children list of game
game.setChildIndex(verticalCrossfaderKnob, game.children.length - 1);
// Add white "-" text under the left vertical crossfader
var leftCrossfaderMinusText = new Text2('-', {
size: 40,
fill: 0xFFFFFF // White color
});
leftCrossfaderMinusText.scaleX = 4.0; // Increased width by 2x
leftCrossfaderMinusText.scaleY = 2.0; // Increased height by 2x
leftCrossfaderMinusText.anchor.set(0.5, 0.5);
leftCrossfaderMinusText.x = verticalCrossfaderTrack.x;
leftCrossfaderMinusText.y = verticalCrossfaderTrack.y + verticalCrossfaderTrack.height / 2 + 30; // Position under the crossfader
game.addChild(leftCrossfaderMinusText);
// Add white "+" text above the left vertical crossfader
var leftCrossfaderPlusText = new Text2('+', {
size: 40,
fill: 0xFFFFFF // White color
});
leftCrossfaderPlusText.anchor.set(0.5, 0.5);
leftCrossfaderPlusText.x = verticalCrossfaderTrack.x;
leftCrossfaderPlusText.y = verticalCrossfaderTrack.y - verticalCrossfaderTrack.height / 2 - 30; // Position above the crossfader
game.addChild(leftCrossfaderPlusText);
// Add white TEMPO text above the left vertical crossfader plus sign
var leftCrossfaderTempoText = new Text2('TEMPO', {
size: 30,
fill: 0xFFFFFF // White color
});
leftCrossfaderTempoText.anchor.set(0.5, 0.5);
leftCrossfaderTempoText.x = verticalCrossfaderTrack.x;
leftCrossfaderTempoText.y = leftCrossfaderPlusText.y - 40; // Position above the plus sign
game.addChild(leftCrossfaderTempoText);
// 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;
verticalCrossfaderTrack2.tint = 0xFFFFFF;
// Add white notches for scaling
var notchSpacing = verticalCrossfaderTrack2.height / 10; // 10 notches
for (var i = 0; i <= 10; i++) {
var notch = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
// Notch width
height: 3 // Notch height
});
notch.tint = 0xFFFFFF; // White color
notch.x = verticalCrossfaderTrack2.x - 20; // Position to the left of the track
notch.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 + i * notchSpacing;
game.addChild(notch);
}
// Add white notches for scaling on the other side of the track
for (var i = 0; i <= 10; i++) {
var notch = LK.getAsset('crossfaderTrack', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 3
});
notch.tint = 0xFFFFFF;
notch.x = verticalCrossfaderTrack2.x + 20; // Position to the right of the track
notch.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 + i * notchSpacing;
game.addChild(notch);
}
// Add a knob onto the second vertical crossfader track
var verticalCrossfaderKnob2 = LK.getAsset('crossfaderKnob', {
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.PI / 2
});
verticalCrossfaderKnob2.x = verticalCrossfaderTrack2.x;
verticalCrossfaderKnob2.y = verticalCrossfaderTrack2.y;
// Add a knob onto the second vertical crossfader track
var verticalCrossfaderKnob2 = LK.getAsset('crossfaderKnob', {
anchorX: 0.5,
anchorY: 0.5,
rotation: Math.PI / 2
});
verticalCrossfaderKnob2.x = verticalCrossfaderTrack2.x;
verticalCrossfaderKnob2.y = verticalCrossfaderTrack2.y;
game.addChild(verticalCrossfaderKnob2);
// Ensure knob is above the notches by bringing it to the top of the children list of game
game.setChildIndex(verticalCrossfaderKnob2, game.children.length - 1);
// Add white Balance text under the horizontal crossfader
// Add white "-" text under the right vertical crossfader
var rightCrossfaderMinusText = new Text2('-', {
size: 40,
fill: 0xFFFFFF // White color
});
rightCrossfaderMinusText.scaleX = 4.0; // Increased width by 2x
rightCrossfaderMinusText.scaleY = 2.0; // Increased height by 2x
rightCrossfaderMinusText.anchor.set(0.5, 0.5);
rightCrossfaderMinusText.x = verticalCrossfaderTrack2.x;
rightCrossfaderMinusText.y = verticalCrossfaderTrack2.y + verticalCrossfaderTrack2.height / 2 + 30; // Position under the crossfader
game.addChild(rightCrossfaderMinusText);
// Add white "+" text above the right vertical crossfader
var rightCrossfaderPlusText = new Text2('+', {
size: 40,
fill: 0xFFFFFF // White color
});
rightCrossfaderPlusText.anchor.set(0.5, 0.5);
rightCrossfaderPlusText.x = verticalCrossfaderTrack2.x;
rightCrossfaderPlusText.y = verticalCrossfaderTrack2.y - verticalCrossfaderTrack2.height / 2 - 30; // Position above the crossfader
game.addChild(rightCrossfaderPlusText);
// Add white TEMPO text above the right vertical crossfader plus sign
var rightCrossfaderTempoText = new Text2('TEMPO', {
size: 30,
fill: 0xFFFFFF // White color
});
rightCrossfaderTempoText.anchor.set(0.5, 0.5);
rightCrossfaderTempoText.x = verticalCrossfaderTrack2.x;
rightCrossfaderTempoText.y = rightCrossfaderPlusText.y - 40; // Position above the plus sign
game.addChild(rightCrossfaderTempoText);
// Add filter knobs
var leftFilterKnobHigh = LK.getAsset('filterKnob', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(leftFilterKnobHigh);
leftFilterKnobHigh.anchor.set(0.5, 0.5);
leftFilterKnobHigh.x = leftDeckAsset.x + 190 + 400 + 12;
leftFilterKnobHigh.y = leftDeckAsset.y - 100 + 25 + 130;
// Add white HIGH text under the HIGH filter knob
var highTextLeft = new Text2('HIGH', {
size: 24,
fill: 0xFFFFFF // White color
});
highTextLeft.anchor.set(0.5, 0.5);
highTextLeft.x = leftFilterKnobHigh.x;
highTextLeft.y = leftFilterKnobHigh.y + leftFilterKnobHigh.height / 2 + 20; // Position under the knob
game.addChild(highTextLeft);
// Add white FILTER text above the HIGH filter knobs, horizontally between them
var filterTextLeft = new Text2('FILTER', {
size: 30,
fill: 0xFFFFFF // White color
});
filterTextLeft.anchor.set(0.5, 0.5);
filterTextLeft.x = leftFilterKnobHigh.x + 100; // Position text to the right of the knob for horizontal alignment
filterTextLeft.y = leftFilterKnobHigh.y - leftFilterKnobHigh.height / 2 - 40 + 130 - 120; // Position above the knob
game.addChild(filterTextLeft);
tween(leftFilterKnobHigh, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
var leftFilterKnobMid = LK.getAsset('filterKnob', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(leftFilterKnobMid);
leftFilterKnobMid.anchor.set(0.5, 0.5);
leftFilterKnobMid.x = leftDeckAsset.x + 190 + 400 + 12;
leftFilterKnobMid.y = leftDeckAsset.y + 30 + 30 + 30 + 30 + 50 + 30 + 30 + 12;
tween(leftFilterKnobMid, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
var leftFilterKnobLow = LK.getAsset('filterKnob', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(leftFilterKnobLow);
leftFilterKnobLow.anchor.set(0.5, 0.5);
leftFilterKnobLow.x = leftDeckAsset.x + 190 + 400 + 12;
leftFilterKnobLow.y = leftDeckAsset.y + 100 + 120 + 120 + 77;
// Add white LOW text under the LOW filter knob
var lowTextLeft = new Text2('LOW', {
size: 24,
fill: 0xFFFFFF // White color
});
lowTextLeft.anchor.set(0.5, 0.5);
lowTextLeft.x = leftFilterKnobLow.x;
lowTextLeft.y = leftFilterKnobLow.y + leftFilterKnobLow.height / 2 + 20; // Position under the knob
game.addChild(lowTextLeft);
tween(leftFilterKnobLow, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
var rightFilterKnobHigh = LK.getAsset('filterKnob', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightFilterKnobHigh);
rightFilterKnobHigh.anchor.set(0.5, 0.5);
rightFilterKnobHigh.x = rightDeckAsset.x - 190 - 400 - 12;
rightFilterKnobHigh.y = rightDeckAsset.y - 100 + 25 + 130;
// Add white HIGH text under the HIGH filter knobs (Right side)
var highTextRight = new Text2('HIGH', {
size: 24,
fill: 0xFFFFFF // White color
});
highTextRight.anchor.set(0.5, 0.5);
highTextRight.x = rightFilterKnobHigh.x;
highTextRight.y = rightFilterKnobHigh.y + rightFilterKnobHigh.height / 2 + 20; // Position under the knob
game.addChild(highTextRight);
// Add white FILTER text above the HIGH filter knobs, horizontally between them (Right side)
var filterTextRight = new Text2('FILTER', {
size: 30,
fill: 0xFFFFFF // White color
});
filterTextRight.anchor.set(0.5, 0.5);
filterTextRight.x = rightFilterKnobHigh.x - 100; // Position text to the left of the knob for horizontal alignment
filterTextRight.y = rightFilterKnobHigh.y - rightFilterKnobHigh.height / 2 - 40 + 130 - 120; // Position above the knob
game.addChild(filterTextRight);
tween(rightFilterKnobHigh, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
var rightFilterKnobMid = LK.getAsset('filterKnob', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightFilterKnobMid);
rightFilterKnobMid.anchor.set(0.5, 0.5);
rightFilterKnobMid.x = rightDeckAsset.x - 190 - 400 - 12;
rightFilterKnobMid.y = rightDeckAsset.y + 30 + 30 + 30 + 30 + 50 + 30 + 30 + 12;
tween(rightFilterKnobMid, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
var rightFilterKnobLow = LK.getAsset('filterKnob', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(rightFilterKnobLow);
rightFilterKnobLow.anchor.set(0.5, 0.5);
rightFilterKnobLow.x = rightDeckAsset.x - 190 - 400 - 12;
rightFilterKnobLow.y = rightDeckAsset.y + 100 + 120 + 120 + 77;
// Add white LOW text under the LOW filter knob (Right side)
var lowTextRight = new Text2('LOW', {
size: 24,
fill: 0xFFFFFF // White color
});
lowTextRight.anchor.set(0.5, 0.5);
lowTextRight.x = rightFilterKnobLow.x;
lowTextRight.y = rightFilterKnobLow.y + rightFilterKnobLow.height / 2 + 20; // Position under the knob
game.addChild(lowTextRight);
tween(rightFilterKnobLow, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
function setupFilterKnobInteraction(knob) {
knob.down = function (x, y, obj) {
tween.stop(this);
// Scale down the previously selected filter knob if it exists and is not the current one
if (lastSelectedFilterKnob && lastSelectedFilterKnob !== this) {
tween.stop(lastSelectedFilterKnob);
tween(lastSelectedFilterKnob, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut
});
}
lastSelectedFilterKnob = this;
tween(this, {
scaleX: 2.4,
scaleY: 2.4
}, {
duration: 100,
easing: tween.easeOut
});
};
knob.up = function (x, y, obj) {
tween.stop(this);
// Do not scale down on up, keep enlarged
};
}
setupFilterKnobInteraction(leftFilterKnobHigh);
setupFilterKnobInteraction(leftFilterKnobMid);
setupFilterKnobInteraction(leftFilterKnobLow);
setupFilterKnobInteraction(rightFilterKnobHigh);
setupFilterKnobInteraction(rightFilterKnobMid);
setupFilterKnobInteraction(rightFilterKnobLow);
// --- 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
var lastSelectedFilterKnob = null; // Variable to track the last selected filter knob.
var uvEffectActive = false; // UV effect state: false = off, true = on
var uvBackgroundColorTween = null; // Variable to hold the background color tween
// 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 money particles animation
if (moneyParticles) {
for (var i = 0; i < moneyParticles.length; i++) {
moneyParticles[i].update();
}
}
// Update first dancing people line animations (first set created)
for (var i = 0; i < Math.min(dancingPeople.length, 8); i++) {
var person = dancingPeople[i];
// Check if UV effect is active
if (uvEffectActive) {
// If not already a UV person, swap to UV asset
if (!person.isUV) {
var uvAssetId = i % 2 === 0 ? 'UVW' : 'UWM';
var currentScaleX = person.scale.x;
var currentScaleY = person.scale.y;
var currentRotation = person.rotation;
var currentAlpha = person.alpha;
var currentX = person.x;
var currentY = person.y;
var currentBaseY = person.baseY;
var currentPhaseOffset = person.phaseOffset;
// Remove the old graphic child
if (person.children.length > 0) {
person.removeChildAt(0);
}
// Add the new UV graphic child
var uvGraphic = person.attachAsset(uvAssetId, {
anchorX: 0.5,
anchorY: 1.0
});
// Restore previous transform and animation properties
person.scale.set(currentScaleX, currentScaleY);
person.rotation = currentRotation;
person.alpha = currentAlpha;
person.x = currentX;
person.y = currentY;
person.baseY = currentBaseY;
person.phaseOffset = currentPhaseOffset;
person.isUV = true;
}
} else {
// If UV effect is off and it's a UV person, swap back to normal asset
if (person.isUV) {
var normalAssetId = i % 2 === 0 ? 'dancingWoman' : 'dancingMan';
var currentScaleX = person.scale.x;
var currentScaleY = person.scale.y;
var currentRotation = person.rotation;
var currentAlpha = person.alpha;
var currentX = person.x;
var currentY = person.y;
var currentBaseY = person.baseY;
var currentPhaseOffset = person.phaseOffset;
// Remove the old graphic child
if (person.children.length > 0) {
person.removeChildAt(0);
}
// Add the new normal graphic child
var normalGraphic = person.attachAsset(normalAssetId, {
anchorX: 0.5,
anchorY: 1.0
});
// Restore previous transform and animation properties
person.scale.set(currentScaleX, currentScaleY);
person.rotation = currentRotation;
person.alpha = currentAlpha;
person.x = currentX;
person.y = currentY;
person.baseY = currentBaseY;
person.phaseOffset = currentPhaseOffset;
person.isUV = false;
}
}
person.update();
}
// Update second dancing people line animations (second set created) - swap with UV assets when UV is active
for (var i = 8; i < dancingPeople.length; i++) {
var person = dancingPeople[i];
// Check if UV effect is active
if (uvEffectActive) {
// If not already a UV person, swap to UV asset
if (!person.isUV) {
var uvAssetId = (i - 8) % 2 === 0 ? 'UVW' : 'UWM';
var currentScaleX = person.scale.x;
var currentScaleY = person.scale.y;
var currentRotation = person.rotation;
var currentAlpha = person.alpha;
var currentX = person.x;
var currentY = person.y;
var currentBaseY = person.baseY;
var currentPhaseOffset = person.phaseOffset;
// Remove the old graphic child
if (person.children.length > 0) {
person.removeChildAt(0);
}
// Add the new UV graphic child
var uvGraphic = person.attachAsset(uvAssetId, {
anchorX: 0.5,
anchorY: 1.0
});
// Restore previous transform and animation properties
person.scale.set(currentScaleX, currentScaleY);
person.rotation = currentRotation;
person.alpha = currentAlpha;
person.x = currentX;
person.y = currentY;
person.baseY = currentBaseY;
person.phaseOffset = currentPhaseOffset;
person.isUV = true;
}
} else {
// If UV effect is off and it's a UV person, swap back to normal asset
if (person.isUV) {
var normalAssetId = (i - 8) % 2 === 0 ? 'dancingWoman' : 'dancingMan';
var currentScaleX = person.scale.x;
var currentScaleY = person.scale.y;
var currentRotation = person.rotation;
var currentAlpha = person.alpha;
var currentX = person.x;
var currentY = person.y;
var currentBaseY = person.baseY;
var currentPhaseOffset = person.phaseOffset;
// Remove the old graphic child
if (person.children.length > 0) {
person.removeChildAt(0);
}
// Add the new normal graphic child
var normalGraphic = person.attachAsset(normalAssetId, {
anchorX: 0.5,
anchorY: 1.0
});
// Restore previous transform and animation properties
person.scale.set(currentScaleX, currentScaleY);
person.rotation = currentRotation;
person.alpha = currentAlpha;
person.x = currentX;
person.y = currentY;
person.baseY = currentBaseY;
person.phaseOffset = currentPhaseOffset;
person.isUV = false;
}
}
person.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();
fireworksEffect2.update();
fireworksEffect3.update();
fireworksEffect4.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 (uvEffectActive) {
// If UV effect is active, flash between indigo blue and purple
var uvTime = Date.now() * 0.002; // Faster flashing for UV
var uvHue = uvTime * 360 % 360;
// Cycle between indigo (around 240 hue) and purple (around 270 hue)
var targetHue = 240 + Math.sin(uvTime * Math.PI * 2) * 30;
targetHue = (targetHue + 360) % 360;
var uvRgb = hsvToRgb(targetHue / 360, 0.8, 0.7); // Adjust saturation and value for UV colors
game.setBackgroundColor(uvRgb[0] << 16 | uvRgb[1] << 8 | uvRgb[2]);
} else {
// If neither is 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;
}
// --- UV button continuous purple flashing effect ---
if (effectButtons[4]) {
if (uvEffectActive) {
// Animate between indigo and purple
var uvBtnTime = Date.now() * 0.0015; // Slightly faster for button, but slower flashing for button
// Indigo: #4B0082 (0x4B0082), Purple: #8000FF (0x8000FF)
var t = 0.5 + 0.5 * Math.sin(uvBtnTime * Math.PI * 2);
// Interpolate RGB
var r = Math.round(0x4B * (1 - t) + 0x80 * t);
var g = Math.round(0x00 * (1 - t) + 0x00 * t);
var b = Math.round(0x82 * (1 - t) + 0xFF * t);
effectButtons[4].tint = r << 16 | g << 8 | b;
} else {
effectButtons[4].tint = 0xFFFFFF;
}
}
// Manage gifts effects based on giftsMode
if (balloons) {
for (var i = 0; i < balloons.length; i++) {
balloons[i].update();
// Only show balloons if giftsMode is 1 (balloons mode)
balloons[i].visible = giftsMode === 1;
}
}
if (moneyParticles) {
for (var i = 0; i < moneyParticles.length; i++) {
moneyParticles[i].update();
// Only show money particles if giftsMode is 2 (money mode)
moneyParticles[i].visible = giftsMode === 2;
}
}
// Manage fireworks visibility (fireworks are spread across multiple instances)
if (fireworksEffect) fireworksEffect.visible = giftsMode === 3;
if (fireworksEffect2) fireworksEffect2.visible = giftsMode === 3;
if (fireworksEffect3) fireworksEffect3.visible = giftsMode === 3;
if (fireworksEffect4) fireworksEffect4.visible = giftsMode === 3;
// Update fireworks effect animation only if visible
if (fireworksEffect && fireworksEffect.visible) fireworksEffect.update();
if (fireworksEffect2 && fireworksEffect2.visible) fireworksEffect2.update();
if (fireworksEffect3 && fireworksEffect3.visible) fireworksEffect3.update();
if (fireworksEffect4 && fireworksEffect4.visible) fireworksEffect4.update();
// Update gifts button visual feedback based on mode
if (giftsEffectButton) {
tween.stop(giftsEffectButton, {
tint: true
}); // Stop any previous tint tweens
if (giftsMode === 0) {
// Off mode - no light (white tint)
giftsEffectButton.tint = 0xFFFFFF;
} else if (giftsMode === 1) {
// Balloons mode - flashing pink
var time = Date.now() * 0.002; // Medium speed flashing
var intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);
var pinkValue = Math.floor(intensity * 255);
giftsEffectButton.tint = 0xFF00FF | pinkValue << 8 | pinkValue; // Magenta/Pink
} else if (giftsMode === 2) {
// Money mode - green color
giftsEffectButton.tint = 0x00FF00; // Green
} else if (giftsMode === 3) {
// Fireworks mode - flashing gold
var time = Date.now() * 0.002; // Medium speed flashing
var intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);
var goldR = Math.floor(intensity * 255);
var goldG = Math.floor(intensity * 215);
var goldB = Math.floor(intensity * 0);
giftsEffectButton.tint = goldR << 16 | goldG << 8 | goldB; // Gold/Yellowish
}
}
};
tabletAsset.x = (leftDeckScreen.x + rightDeckScreen.x) / 2;
tabletAsset.y = leftDeckScreen.y + 77 + 35 - 20 - 200 - 35;
// --- Arrow Buttons under Tablet ---
var arrowButtonSpacing = 150;
var arrowButtonY = tabletAsset.y + tabletAsset.height / 2 + 80;
var leftArrowButton = LK.getAsset('Leftarrow', {
anchorX: 0.5,
anchorY: 0.5
});
leftArrowButton.x = tabletAsset.x - arrowButtonSpacing * 1.5 - 50 - 5 - 5 - 1;
leftArrowButton.y = arrowButtonY;
game.addChild(leftArrowButton);
// Scale up left arrow button by 1.3
tween(leftArrowButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut
});
var upArrowButton = LK.getAsset('UParrow', {
anchorX: 0.5,
anchorY: 0.5
});
upArrowButton.x = tabletAsset.x + arrowButtonSpacing * 1.5 - 50 - 5 - 12 - 5 - 1;
upArrowButton.y = arrowButtonY;
game.addChild(upArrowButton);
// Scale up up arrow button by 1.3
tween(upArrowButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut
});
var downArrowButton = LK.getAsset('Downarrow', {
anchorX: 0.5,
anchorY: 0.5
});
downArrowButton.x = tabletAsset.x + arrowButtonSpacing * 0.5 - 50 - 5 - 12 - 5 - 1;
downArrowButton.y = arrowButtonY;
game.addChild(downArrowButton);
// Scale up down arrow button by 1.3
tween(downArrowButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut
});
var rightArrowButton = LK.getAsset('Rightarrow', {
anchorX: 0.5,
anchorY: 0.5
});
rightArrowButton.x = tabletAsset.x - arrowButtonSpacing * 0.5 - 50 - 5 - 12 - 5 - 1;
rightArrowButton.y = arrowButtonY;
game.addChild(rightArrowButton);
// Scale up right arrow button by 1.3
tween(rightArrowButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut
});
var okButton = LK.getAsset('OKbutton', {
anchorX: 0.5,
anchorY: 0.5
});
// Place OK button to the right of the right arrow button with the same spacing as between arrow buttons
okButton.x = upArrowButton.x + arrowButtonSpacing - 12 - 5 - 1 + 2 + 2;
okButton.y = arrowButtonY;
game.addChild(okButton);
// Scale up OK button by 1.3 to match arrow buttons
tween(okButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut
});
// Add edit button under the OK button
var editButton = LK.getAsset('editbutton', {
anchorX: 0.5,
anchorY: 0.5
});
editButton.x = okButton.x;
editButton.y = okButton.y + okButton.height + 20; // Position 20 units under the OK button
game.addChild(editButton);
// Scale up edit button by 1.3 to match arrow buttons
tween(editButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut
});
// --- Pulse Button Effect State ---
var pulseButtonEffect = 1.0; // 1.0 = normal, <1.0 = decreased
// Helper to decrease pulse effect
function decreasePulseButtonEffect() {
pulseButtonEffect = 0.5;
// Optionally, restore after a short time for visual feedback
LK.setTimeout(function () {
pulseButtonEffect = 1.0;
}, 200);
}
// --- Add decrease pulse effect to arrow and OK buttons ---
leftArrowButton.down = function (x, y, obj) {
decreasePulseButtonEffect();
// Navigate left in rekordbox app
if (typeof rekordboxApp !== 'undefined') {
// Check if the fullscreen tracklist is currently visible
if (game.children.indexOf(rekordboxApp) !== -1 && rekordboxApp.visible) {
rekordboxApp.navigateLeft();
}
}
// Visual feedback
tween(leftArrowButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
onFinish: function onFinish() {
tween(leftArrowButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 120
});
}
});
};
rightArrowButton.down = function (x, y, obj) {
decreasePulseButtonEffect();
// Navigate right in rekordbox app
if (typeof rekordboxApp !== 'undefined') {
rekordboxApp.navigateRight();
}
tween(rightArrowButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
onFinish: function onFinish() {
tween(rightArrowButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 120
});
}
});
};
upArrowButton.down = function (x, y, obj) {
decreasePulseButtonEffect();
// Navigate up in rekordbox app
if (typeof rekordboxApp !== 'undefined') {
rekordboxApp.navigateUp();
}
tween(upArrowButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
onFinish: function onFinish() {
tween(upArrowButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 120
});
}
});
};
downArrowButton.down = function (x, y, obj) {
decreasePulseButtonEffect();
// Navigate down in rekordbox app
if (typeof rekordboxApp !== 'undefined') {
rekordboxApp.navigateDown();
}
tween(downArrowButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
onFinish: function onFinish() {
tween(downArrowButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 120
});
}
});
};
okButton.down = function (x, y, obj) {
decreasePulseButtonEffect();
// Select track in rekordbox app
if (typeof rekordboxApp !== 'undefined' && rekordboxApp.selectTrack) {
rekordboxApp.selectTrack();
}
tween(okButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
onFinish: function onFinish() {
tween(okButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 120
});
}
});
};
// Add functionality to edit button
editButton.down = function (x, y, obj) {
decreasePulseButtonEffect();
// Create fullscreen song maker app
var songMakerApp = new SongMakerApp();
game.addChild(songMakerApp);
// Create semi-transparent background overlay
var overlay = LK.getAsset('crossfaderTrack', {
anchorX: 0,
anchorY: 0,
width: 2048,
height: 2732
});
overlay.tint = 0x000000;
overlay.alpha = 0.7;
overlay.x = 0;
overlay.y = 0;
// Add overlay behind the app
game.addChild(overlay);
game.setChildIndex(overlay, game.children.indexOf(songMakerApp) - 1);
// Add X (close window) button to the full screen song maker app top right corner
var closeButton = LK.getAsset('X', {
anchorX: 1.0,
anchorY: 0.0
});
closeButton.scaleX = 2.0;
closeButton.scaleY = 2.0;
closeButton.x = 2048 - 20; // 20px from right edge
closeButton.y = 20; // 20px from top edge
game.addChild(closeButton);
// Add close functionality to the X button
closeButton.down = function (x, y, obj) {
// Remove fullscreen song maker app, overlay, and close button
if (game.children.indexOf(songMakerApp) !== -1) {
game.removeChild(songMakerApp);
}
if (game.children.indexOf(overlay) !== -1) {
game.removeChild(overlay);
}
if (game.children.indexOf(closeButton) !== -1) {
game.removeChild(closeButton);
}
};
// Add close functionality when clicking overlay
overlay.down = function (x, y, obj) {
// Remove fullscreen song maker app and overlay
if (game.children.indexOf(songMakerApp) !== -1) {
game.removeChild(songMakerApp);
}
if (game.children.indexOf(overlay) !== -1) {
game.removeChild(overlay);
}
if (game.children.indexOf(closeButton) !== -1) {
game.removeChild(closeButton);
}
};
tween(editButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
onFinish: function onFinish() {
tween(editButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 120
});
}
});
};
// Update second dancing people line animations (second set created) - swap with UV assets when UV is active
for (var i = 8; i < dancingPeople.length; i++) {
var person = dancingPeople[i];
// Check if UV effect is active
if (uvEffectActive) {
// If not already a UV person, swap to UV asset
if (!person.isUV) {
var uvAssetId = (i - 8) % 2 === 0 ? 'UVW' : 'UWM';
var currentScaleX = person.scale.x;
var currentScaleY = person.scale.y;
var currentRotation = person.rotation;
var currentAlpha = person.alpha;
var currentX = person.x;
var currentY = person.y;
var currentBaseY = person.baseY;
var currentPhaseOffset = person.phaseOffset;
// Remove the old graphic child
if (person.children.length > 0) {
person.removeChildAt(0);
}
// Add the new UV graphic child
var uvGraphic = person.attachAsset(uvAssetId, {
anchorX: 0.5,
anchorY: 1.0
});
// Restore previous transform and animation properties
person.scale.set(currentScaleX, currentScaleY);
person.rotation = currentRotation;
person.alpha = currentAlpha;
person.x = currentX;
person.y = currentY;
person.baseY = currentBaseY;
person.phaseOffset = currentPhaseOffset;
person.isUV = true;
}
} else {
// If UV effect is off and it's a UV person, swap back to normal asset
if (person.isUV) {
var normalAssetId = (i - 8) % 2 === 0 ? 'dancingWoman' : 'dancingMan';
var currentScaleX = person.scale.x;
var currentScaleY = person.scale.y;
var currentRotation = person.rotation;
var currentAlpha = person.alpha;
var currentX = person.x;
var currentY = person.y;
var currentBaseY = person.baseY;
var currentPhaseOffset = person.phaseOffset;
// Remove the old graphic child
if (person.children.length > 0) {
person.removeChildAt(0);
}
// Add the new normal graphic child
var normalGraphic = person.attachAsset(normalAssetId, {
anchorX: 0.5,
anchorY: 1.0
});
// Restore previous transform and animation properties
person.scale.set(currentScaleX, currentScaleY);
person.rotation = currentRotation;
person.alpha = currentAlpha;
person.x = currentX;
person.y = currentY;
person.baseY = currentBaseY;
person.phaseOffset = currentPhaseOffset;
person.isUV = false;
}
}
person.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();
fireworksEffect2.update();
fireworksEffect3.update();
fireworksEffect4.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 (uvEffectActive) {
// If UV effect is active, flash between indigo blue and purple
var uvTime = Date.now() * 0.002; // Faster flashing for UV
var uvHue = uvTime * 360 % 360;
// Cycle between indigo (around 240 hue) and purple (around 270 hue)
var targetHue = 240 + Math.sin(uvTime * Math.PI * 2) * 30;
targetHue = (targetHue + 360) % 360;
var uvRgb = hsvToRgb(targetHue / 360, 0.8, 0.7); // Adjust saturation and value for UV colors
game.setBackgroundColor(uvRgb[0] << 16 | uvRgb[1] << 8 | uvRgb[2]);
} else {
// If neither is 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;
}
// --- UV button continuous purple flashing effect ---
if (effectButtons[4]) {
if (uvEffectActive) {
// Animate between indigo and purple
var uvBtnTime = Date.now() * 0.0015; // Slightly faster for button, but slower flashing for button
// Indigo: #4B0082 (0x4B0082), Purple: #8000FF (0x8000FF)
var t = 0.5 + 0.5 * Math.sin(uvBtnTime * Math.PI * 2);
// Interpolate RGB
var r = Math.round(0x4B * (1 - t) + 0x80 * t);
var g = Math.round(0x00 * (1 - t) + 0x00 * t);
var b = Math.round(0x82 * (1 - t) + 0xFF * t);
effectButtons[4].tint = r << 16 | g << 8 | b;
} else {
effectButtons[4].tint = 0xFFFFFF;
}
}
// Manage gifts effects based on giftsMode
if (balloons) {
for (var i = 0; i < balloons.length; i++) {
balloons[i].update();
// Only show balloons if giftsMode is 1 (balloons mode)
balloons[i].visible = giftsMode === 1;
}
}
if (moneyParticles) {
for (var i = 0; i < moneyParticles.length; i++) {
moneyParticles[i].update();
// Only show money particles if giftsMode is 2 (money mode)
moneyParticles[i].visible = giftsMode === 2;
}
}
// Manage fireworks visibility (fireworks are spread across multiple instances)
if (fireworksEffect) fireworksEffect.visible = giftsMode === 3;
if (fireworksEffect2) fireworksEffect2.visible = giftsMode === 3;
if (fireworksEffect3) fireworksEffect3.visible = giftsMode === 3;
if (fireworksEffect4) fireworksEffect4.visible = giftsMode === 3;
// Update fireworks effect animation only if visible
if (fireworksEffect && fireworksEffect.visible) fireworksEffect.update();
if (fireworksEffect2 && fireworksEffect2.visible) fireworksEffect2.update();
if (fireworksEffect3 && fireworksEffect3.visible) fireworksEffect3.update();
if (fireworksEffect4 && fireworksEffect4.visible) fireworksEffect4.update();
// Update gifts button visual feedback based on mode
if (giftsEffectButton) {
tween.stop(giftsEffectButton, {
tint: true
}); // Stop any previous tint tweens
if (giftsMode === 0) {
// Off mode - no light (white tint)
giftsEffectButton.tint = 0xFFFFFF;
} else if (giftsMode === 1) {
// Balloons mode - flashing pink
var time = Date.now() * 0.002; // Medium speed flashing
var intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);
var pinkValue = Math.floor(intensity * 255);
giftsEffectButton.tint = 0xFF00FF | pinkValue << 8 | pinkValue; // Magenta/Pink
} else if (giftsMode === 2) {
// Money mode - green color
giftsEffectButton.tint = 0x00FF00; // Green
} else if (giftsMode === 3) {
// Fireworks mode - flashing gold
var time = Date.now() * 0.002; // Medium speed flashing
var intensity = 0.5 + 0.5 * Math.sin(time * Math.PI * 2);
var goldR = Math.floor(intensity * 255);
var goldG = Math.floor(intensity * 215);
var goldB = Math.floor(intensity * 0);
giftsEffectButton.tint = goldR << 16 | goldG << 8 | goldB; // Gold/Yellowish
}
}
okButton.y = arrowButtonY + 12 + 30 - 25; // Move OK button down by 30 units
game.addChild(okButton);
leftArrowButton.x = tabletAsset.x - arrowButtonSpacing * 1.5 - 50 - 5 - 5 - 1;
leftArrowButton.y = arrowButtonY + 12 + 30 - 25; // Move left arrow down by 30 units
game.addChild(leftArrowButton);
upArrowButton.x = tabletAsset.x + arrowButtonSpacing * 1.5 - 50 - 5 - 12 - 5 - 1;
upArrowButton.y = arrowButtonY + 12 + 30 - 25; // Move up arrow down by 30 units
game.addChild(upArrowButton);
downArrowButton.x = tabletAsset.x + arrowButtonSpacing * 0.5 - 50 - 5 - 12 - 5 - 1;
downArrowButton.y = arrowButtonY + 12 + 30 - 25; // Move down arrow down by 30 units
game.addChild(downArrowButton);
rightArrowButton.x = tabletAsset.x - arrowButtonSpacing * 0.5 - 50 - 5 - 12 - 5 - 1;
rightArrowButton.y = arrowButtonY + 12 + 30 - 25; // Move right arrow down by 30 units
game.addChild(rightArrowButton);
// Update edit button position in update loop
if (typeof editButton !== 'undefined' && typeof okButton !== 'undefined') {
editButton.x = okButton.x;
editButton.y = okButton.y + okButton.height + 20 + 12 - 25 + 20 + 20; // Move down by 12 units + 20 units
}
var editButton = LK.getAsset('editbutton', {
anchorX: 0.5,
anchorY: 0.5
});
fxButton.y = fxButtonY + 200 + 10;
// Add white A letter under fx button
var fxButtonAText = new Text2('A', {
size: 48,
fill: 0xFFFFFF // White color
});
fxButtonAText.anchor.set(0.5, 0.5);
fxButtonAText.x = fxButton.x - 150;
fxButtonAText.y = fxButton.y + fxButton.height / 2 + 20 + 90 + 12; // Position under the button, moved down by 90 units, then down by 12 units
game.addChild(fxButtonAText);
leftFilterKnobMid.y = leftDeckAsset.y + 30 + 30 + 30 + 30 + 50 + 30 + 30 + 12;
// Add white MID text under the MID filter knob
var midTextLeft = new Text2('MID', {
size: 24,
fill: 0xFFFFFF // White color
});
midTextLeft.anchor.set(0.5, 0.5);
midTextLeft.x = leftFilterKnobMid.x;
midTextLeft.y = leftFilterKnobMid.y + leftFilterKnobMid.height / 2 + 20; // Position under the knob
game.addChild(midTextLeft);
tween(leftFilterKnobMid, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
var leftFilterKnobLow = LK.getAsset('filterKnob', {
anchorX: 0.5,
anchorY: 0.5
});
rightFilterKnobMid.y = rightDeckAsset.y + 30 + 30 + 30 + 30 + 50 + 30 + 30 + 12;
// Add white MID text under the MID filter knob (Right side)
var midTextRight = new Text2('MID', {
size: 24,
fill: 0xFFFFFF // White color
});
midTextRight.anchor.set(0.5, 0.5);
midTextRight.x = rightFilterKnobMid.x;
midTextRight.y = rightFilterKnobMid.y + rightFilterKnobMid.height / 2 + 20; // Position under the knob
game.addChild(midTextRight);
tween(rightFilterKnobMid, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut
});
var rightFilterKnobLow = LK.getAsset('filterKnob', {
anchorX: 0.5,
anchorY: 0.5
});
logoAsset.x = crossfader.x;
logoAsset.y = crossfader.y + crossfader.height / 2 + 30 - 350 - 40; // Position under the crossfader, moved up by 350 units;
logoAsset.x = crossfader.x;
logoAsset.y = crossfader.y + crossfader.height / 2 + 30 - 350 - 40 - 50; // Position under the crossfader, moved up by 350 units;;
masterButtonBText.x = masterAsset.x + 150;
masterButtonBText.y = masterAsset.y + masterAsset.height / 2 + 20 + 100; // Position under the button, moved down by 100 units
masterButtonBText.y = masterAsset.y + masterAsset.height / 2 + 20 + 100 + 10; // Position under the button, moved down by 100 units, moved down by 10 units;
game.addChild(masterButtonBText);
fxButtonAText.y = fxButton.y + fxButton.height / 2 + 20 + 90 + 12 + 10; // Position under the button, moved down by 90 units, then down by 12 units, then down by 10 units ===================================================================
--- original.js
+++ change.js
@@ -5387,12 +5387,24 @@
if (typeof fullscreenTracklist !== 'undefined' && fullscreenTracklist.selectTrack) {
fullscreenTracklist.selectTrack();
}
};
+var enterButtonKeyboard = LK.getAsset('Effect', {
+ // Using Effect asset as a placeholder
+ anchorX: 0.5,
+ anchorY: 0.5
+});
+enterButtonKeyboard.visible = false; // Initially hidden
// Create keyboard app instance
var keyboardApp = new KeyboardApp();
// Create keyboard app instance
var keyboardApp = new KeyboardApp();
+var leftArrowButtonKeyboard;
+var rightArrowButtonKeyboard;
+var upArrowButtonKeyboard;
+var downArrowButtonKeyboard;
+var okButtonKeyboard;
+var enterButtonKeyboard; // Define enter button
var leftArrowButtonKeyboard = LK.getAsset('Leftarrow', {
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