User prompt
biraz daha az rastgele melodi üret müzik karmaşası olmasın biraz daha düzgün ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
kafasını sağ sola oynatıncada farklı şeyler yap gözlerini kapatıp açınca ağzını burnunu oynatınca ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
kick snare hihat filter-sweep delay-effect reverb-wash gibi ses efektleri ekledim bunlarıda uygunluğa göre kullan ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Build a music-based interactive game titled "FaceToNote". When the player starts the game, activate the webcam and scan the player’s face using FaceKit. Analyze key facial features such as eyebrow angle, eye distance, mouth width, chin length, and head tilt. Convert these features into abstract shapes (circle, arc, triangle, square) on screen. Then, map each shape to a musical role: Arcs → melody (e.g. piano notes: G3, B3, C4) Ellipses → bass (e.g. synth bass E2) Squares → rhythm (kick/snare/hi-hat) Lines or dots → sound effects (filter sweep, delay, reverb) Head tilt → stereo pan (left or right) After scanning, generate a looping sequence where each shape plays its assigned sound. The result is a personalized music composition based on the player's face. During gameplay, detect real-time expressions: Smiling adds new melody notes Eyebrow frown increases BPM Blinking triggers random effects Visually, show the scanned face with stylized scanning effects (e.g., wireframe mesh, glowing shapes) and sync visual pulses to the beat. Keep the UI minimal, ambient, and responsive to audio. ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
assets içerisinde bir sürü nota ses efekti ekledim kişinin yüz şekline göre rastgele notaları çal ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
okey add background or black color
Code edit (1 edits merged)
Please save this source code
User prompt
Face Scan Shape Creator
Initial prompt
scan the face and create face shape
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ var ExpressionDetector = Container.expand(function () { var self = Container.call(this); // Expression state tracking self.lastSmiling = false; self.lastEyebrowsFrowning = false; self.lastBlinking = false; self.blinkCounter = 0; self.lastBlinkTime = 0; // Expression thresholds self.smileThreshold = 0.3; self.frownThreshold = 0.2; self.blinkThreshold = 50; // milliseconds self.detectSmile = function () { if (!facekit.upperLip || !facekit.lowerLip) return false; // Simple smile detection based on mouth corner positions var mouthCurve = (facekit.upperLip.y - facekit.lowerLip.y) / 20; return mouthCurve > self.smileThreshold; }; self.detectFrown = function () { if (!facekit.leftEye || !facekit.rightEye) return false; // Detect frown based on eyebrow position relative to eyes var eyebrowPosition = (facekit.leftEye.y + facekit.rightEye.y) / 2 - 30; return eyebrowPosition < self.frownThreshold; }; self.detectBlink = function () { // Simplified blink detection (in real implementation would track eye closure) var currentTime = Date.now(); if (currentTime - self.lastBlinkTime > 2000) { // Auto-trigger every 2 seconds for demo self.lastBlinkTime = currentTime; return true; } return false; }; self.onSmile = function (sequencer) { // Add new melody notes when smiling var newMelodyNote = melodyNotes[Math.floor(Math.random() * melodyNotes.length)]; LK.getSound(newMelodyNote).play(); LK.getSound('smile-trigger').play(); // Visual feedback LK.effects.flashScreen(0x00ff88, 300); // Add to score LK.setScore(LK.getScore() + 25); }; self.onFrown = function (sequencer) { // Increase BPM when frowning sequencer.bpm = Math.min(180, sequencer.bpm + 5); sequencer.beatInterval = 60000 / sequencer.bpm; LK.getSound('frown-trigger').play(); // Visual feedback - red flash LK.effects.flashScreen(0xff4444, 200); }; self.onBlink = function (sequencer) { // Trigger random effects on blink var randomEffect = effectSounds[Math.floor(Math.random() * effectSounds.length)]; LK.getSound(randomEffect).play(); LK.getSound('blink-effect').play(); // Create sparkle effect for (var i = 0; i < 5; i++) { var sparkle = game.addChild(LK.getAsset('effectDot', { anchorX: 0.5, anchorY: 0.5, alpha: 1.0, tint: Math.random() * 0xffffff })); sparkle.x = facekit.mouthCenter.x + (Math.random() - 0.5) * 200; sparkle.y = facekit.mouthCenter.y + (Math.random() - 0.5) * 200; tween(sparkle, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 800, onFinish: function onFinish() { sparkle.destroy(); } }); } }; self.update = function (sequencer) { // Check for expression changes var currentSmiling = self.detectSmile(); var currentFrowning = self.detectFrown(); var currentBlinking = self.detectBlink(); // Trigger events on state transitions if (!self.lastSmiling && currentSmiling) { self.onSmile(sequencer); } if (!self.lastEyebrowsFrowning && currentFrowning) { self.onFrown(sequencer); } if (currentBlinking) { self.onBlink(sequencer); } // Update last states self.lastSmiling = currentSmiling; self.lastEyebrowsFrowning = currentFrowning; }; return self; }); var FaceShape = Container.expand(function () { var self = Container.call(this); self.faceOutline = self.attachAsset('faceOutline', { anchorX: 0.5, anchorY: 0.5 }); self.leftEye = self.attachAsset('leftEye', { anchorX: 0.5, anchorY: 0.5 }); self.rightEye = self.attachAsset('rightEye', { anchorX: 0.5, anchorY: 0.5 }); self.nose = self.attachAsset('nose', { anchorX: 0.5, anchorY: 0.5 }); self.mouth = self.attachAsset('mouth', { anchorX: 0.5, anchorY: 0.5 }); self.currentColorIndex = 0; self.colorPalettes = [[0x3498db, 0xe74c3c, 0xf39c12, 0x9b59b6], [0x2ecc71, 0xe67e22, 0x34495e, 0x1abc9c], [0xf1c40f, 0x8e44ad, 0x16a085, 0xc0392b], [0x95a5a6, 0x2980b9, 0x27ae60, 0xd35400]]; self.lastMouthOpen = false; self.updateFacePosition = function (faceX, faceY, faceWidth, faceHeight) { self.x = faceX; self.y = faceY; // Scale based on face size var scale = Math.max(faceWidth / 300, faceHeight / 400) * 0.8; self.faceOutline.scaleX = scale; self.faceOutline.scaleY = scale; // Position facial features relative to face center self.leftEye.x = -faceWidth * 0.15; self.leftEye.y = -faceHeight * 0.1; self.rightEye.x = faceWidth * 0.15; self.rightEye.y = -faceHeight * 0.1; self.nose.x = 0; self.nose.y = 0; self.mouth.x = 0; self.mouth.y = faceHeight * 0.15; }; self.changeColors = function () { self.currentColorIndex = (self.currentColorIndex + 1) % self.colorPalettes.length; var palette = self.colorPalettes[self.currentColorIndex]; tween(self.faceOutline, { tint: palette[0] }, { duration: 500 }); tween(self.leftEye, { tint: palette[1] }, { duration: 500 }); tween(self.rightEye, { tint: palette[1] }, { duration: 500 }); tween(self.nose, { tint: palette[2] }, { duration: 500 }); tween(self.mouth, { tint: palette[3] }, { duration: 500 }); LK.getSound('shapeChange').play(); }; self.update = function () { // Check for mouth open expression change var currentMouthOpen = facekit.mouthOpen; if (!self.lastMouthOpen && currentMouthOpen) { // Mouth just opened self.triggerExpression(); } self.lastMouthOpen = currentMouthOpen; // Update mouth shape based on expression if (currentMouthOpen) { self.mouth.scaleY = 1.5; } else { self.mouth.scaleY = 1.0; } }; self.triggerExpression = function () { // Create particle effect createParticleEffect(self.x, self.y); // Pulse effect on face outline tween(self.faceOutline, { scaleX: self.faceOutline.scaleX * 1.2, scaleY: self.faceOutline.scaleY * 1.2 }, { duration: 200, onFinish: function onFinish() { tween(self.faceOutline, { scaleX: self.faceOutline.scaleX / 1.2, scaleY: self.faceOutline.scaleY / 1.2 }, { duration: 200 }); } }); // Play random note based on current face position and expression var randomNoteIndex = Math.floor(Math.random() * noteIds.length); LK.getSound(noteIds[randomNoteIndex]).play(); LK.getSound('expressionTrigger').play(); LK.setScore(LK.getScore() + 10); scoreText.setText('Score: ' + LK.getScore()); }; return self; }); var FacialAnalyzer = Container.expand(function () { var self = Container.call(this); // Musical shape arrays self.melodyArcs = []; self.bassEllipses = []; self.rhythmSquares = []; self.effectDots = []; self.scanLines = []; self.wireframes = []; // Face analysis data self.eyebrowAngle = 0; self.eyeDistance = 0; self.mouthWidth = 0; self.chinLength = 0; self.headTilt = 0; // Musical timing self.bpm = 120; self.beatCount = 0; self.lastBeatTime = 0; self.analyzeFace = function () { if (!facekit.leftEye || !facekit.rightEye || !facekit.mouthCenter) return; // Calculate facial measurements self.eyeDistance = Math.abs(facekit.rightEye.x - facekit.leftEye.x); self.mouthWidth = Math.abs(facekit.upperLip.x - facekit.lowerLip.x) || 50; self.chinLength = Math.abs(facekit.chin.y - facekit.mouthCenter.y); self.headTilt = (facekit.rightEye.y - facekit.leftEye.y) / self.eyeDistance; // Generate shapes based on facial features self.generateMelodyArcs(); self.generateBassEllipses(); self.generateRhythmSquares(); self.generateEffectDots(); }; self.generateMelodyArcs = function () { // Clear existing arcs for (var i = 0; i < self.melodyArcs.length; i++) { self.melodyArcs[i].destroy(); } self.melodyArcs = []; // Create arcs based on eyebrow angle and eye distance var arcCount = Math.floor(self.eyeDistance / 50) + 2; for (var i = 0; i < arcCount; i++) { var arc = self.addChild(LK.getAsset('melodyArc', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 })); arc.x = facekit.leftEye.x + i * (self.eyeDistance / arcCount); arc.y = facekit.leftEye.y - 50; arc.rotation = self.headTilt * 0.5; arc.noteIndex = i % melodyNotes.length; self.melodyArcs.push(arc); } }; self.generateBassEllipses = function () { // Clear existing ellipses for (var i = 0; i < self.bassEllipses.length; i++) { self.bassEllipses[i].destroy(); } self.bassEllipses = []; // Create bass ellipses based on mouth width var ellipseCount = Math.floor(self.mouthWidth / 30) + 1; for (var i = 0; i < ellipseCount; i++) { var ellipse = self.addChild(LK.getAsset('bassEllipse', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 })); ellipse.x = facekit.mouthCenter.x + (i - ellipseCount / 2) * 60; ellipse.y = facekit.mouthCenter.y + 80; ellipse.noteIndex = i % bassNotes.length; self.bassEllipses.push(ellipse); } }; self.generateRhythmSquares = function () { // Clear existing squares for (var i = 0; i < self.rhythmSquares.length; i++) { self.rhythmSquares[i].destroy(); } self.rhythmSquares = []; // Create rhythm squares based on chin length var squareCount = Math.floor(self.chinLength / 40) + 2; for (var i = 0; i < squareCount; i++) { var square = self.addChild(LK.getAsset('rhythmSquare', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 })); square.x = facekit.chin.x + (i - squareCount / 2) * 70; square.y = facekit.chin.y + 50; square.rhythmIndex = i % rhythmSounds.length; self.rhythmSquares.push(square); } }; self.generateEffectDots = function () { // Clear existing dots for (var i = 0; i < self.effectDots.length; i++) { self.effectDots[i].destroy(); } self.effectDots = []; // Create effect dots around nose area var dotCount = 4; for (var i = 0; i < dotCount; i++) { var dot = self.addChild(LK.getAsset('effectDot', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 })); var angle = i / dotCount * Math.PI * 2; dot.x = facekit.noseTip.x + Math.cos(angle) * 60; dot.y = facekit.noseTip.y + Math.sin(angle) * 40; dot.effectIndex = i % effectSounds.length; self.effectDots.push(dot); } }; self.createScanEffect = function () { // Create scanning wireframe effect var wireframe = self.addChild(LK.getAsset('faceWireframe', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 })); wireframe.x = facekit.mouthCenter.x; wireframe.y = facekit.mouthCenter.y; // Animate scanning effect tween(wireframe, { alpha: 0.8, scaleX: 1.2, scaleY: 1.2 }, { duration: 500, onFinish: function onFinish() { tween(wireframe, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 500, onFinish: function onFinish() { wireframe.destroy(); } }); } }); }; return self; }); var MusicSequencer = Container.expand(function () { var self = Container.call(this); self.bpm = 120; self.beatInterval = 60000 / self.bpm; // milliseconds per beat self.lastBeatTime = 0; self.currentBeat = 0; self.isPlaying = false; // Musical sequences based on face analysis self.melodySequence = []; self.bassSequence = []; self.rhythmSequence = []; self.effectSequence = []; // Stereo panning based on head tilt self.panValue = 0; self.generateSequence = function (analyzer) { // Generate melody sequence from arcs self.melodySequence = []; for (var i = 0; i < analyzer.melodyArcs.length; i++) { var arc = analyzer.melodyArcs[i]; self.melodySequence.push({ note: melodyNotes[arc.noteIndex], beat: i % 4, volume: 0.6 + arc.alpha * 0.4 }); } // Generate bass sequence from ellipses self.bassSequence = []; for (var i = 0; i < analyzer.bassEllipses.length; i++) { var ellipse = analyzer.bassEllipses[i]; self.bassSequence.push({ note: bassNotes[ellipse.noteIndex], beat: i % 2, volume: 0.8 }); } // Generate rhythm sequence from squares self.rhythmSequence = []; for (var i = 0; i < analyzer.rhythmSquares.length; i++) { var square = analyzer.rhythmSquares[i]; self.rhythmSequence.push({ sound: rhythmSounds[square.rhythmIndex], beat: i % 4, volume: 0.7 }); } // Set up effect triggers from dots self.effectSequence = []; for (var i = 0; i < analyzer.effectDots.length; i++) { var dot = analyzer.effectDots[i]; self.effectSequence.push({ effect: effectSounds[dot.effectIndex], trigger: Math.random() < 0.3 }); } self.isPlaying = true; }; self.updatePanning = function (headTilt) { self.panValue = Math.max(-1, Math.min(1, headTilt * 2)); // Apply panning to current sounds (simplified representation) }; self.playBeat = function () { if (!self.isPlaying) return; var beatInSequence = self.currentBeat % 4; // Play melody for (var i = 0; i < self.melodySequence.length; i++) { var melodyNote = self.melodySequence[i]; if (melodyNote.beat === beatInSequence) { LK.getSound(melodyNote.note).play(); } } // Play bass for (var i = 0; i < self.bassSequence.length; i++) { var bassNote = self.bassSequence[i]; if (bassNote.beat === beatInSequence) { LK.getSound(bassNote.note).play(); } } // Play rhythm for (var i = 0; i < self.rhythmSequence.length; i++) { var rhythmHit = self.rhythmSequence[i]; if (rhythmHit.beat === beatInSequence) { LK.getSound(rhythmHit.sound).play(); } } // Random effect triggers if (Math.random() < 0.1) { var randomEffect = self.effectSequence[Math.floor(Math.random() * self.effectSequence.length)]; if (randomEffect) { LK.getSound(randomEffect.effect).play(); } } self.currentBeat++; }; self.update = function () { var currentTime = Date.now(); if (currentTime - self.lastBeatTime >= self.beatInterval) { self.playBeat(); self.lastBeatTime = currentTime; // Create beat visualization var beatPulse = game.addChild(LK.getAsset('beatPulse', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 })); beatPulse.x = 1024; beatPulse.y = 1366; tween(beatPulse, { scaleX: 3, scaleY: 3, alpha: 0 }, { duration: 300, onFinish: function onFinish() { beatPulse.destroy(); } }); } }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); self.graphic = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = (Math.random() - 0.5) * 10; self.velocityY = (Math.random() - 0.5) * 10; self.life = 60; // 1 second at 60fps self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.life--; // Fade out over time self.graphic.alpha = self.life / 60; if (self.life <= 0) { self.destroy(); // Remove from particles array for (var i = particles.length - 1; i >= 0; i--) { if (particles[i] === self) { particles.splice(i, 1); break; } } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Expression triggers // Sound effects - mapped to dots/lines // Rhythm sounds - mapped to squares // Bass notes (synth bass) - mapped to ellipses // Melody notes (piano) - mapped to arcs // Beat visualization // Face wireframe // Scanning wireframe // Dots for effects // Squares for rhythm // Ellipses for bass // Arcs for melody // Face analysis shapes mapped to musical roles // Face-to-Music System Variables var facialAnalyzer; var musicSequencer; var expressionDetector; var scanEffectTimer = 0; var gameInitialized = false; // Musical arrays mapped to shape types var melodyNotes = ['melody-g3', 'melody-b3', 'melody-c4', 'melody-d4', 'melody-e4', 'melody-f4', 'melody-a4']; var bassNotes = ['bass-e2', 'bass-a2', 'bass-d2']; var rhythmSounds = ['kick', 'snare', 'hihat']; var effectSounds = ['filter-sweep', 'delay-effect', 'reverb-wash']; // UI Elements var scoreText; var instructionText; var bpmText; var statusText; var gameTime = 0; // Create score display scoreText = new Text2('Score: 0', { size: 60, fill: 0x00ff88 }); scoreText.anchor.set(0.5, 0); scoreText.y = 50; LK.gui.top.addChild(scoreText); // Create BPM display bpmText = new Text2('BPM: 120', { size: 40, fill: 0x88aaff }); bpmText.anchor.set(0, 0); bpmText.x = 50; bpmText.y = 120; LK.gui.top.addChild(bpmText); // Create status text statusText = new Text2('Scanning face...', { size: 50, fill: 0xffaa44 }); statusText.anchor.set(0.5, 0.5); LK.gui.center.addChild(statusText); // Create instruction text instructionText = new Text2('Express yourself to create music!', { size: 35, fill: 0xffffff }); instructionText.anchor.set(0.5, 1); instructionText.y = -50; LK.gui.bottom.addChild(instructionText); // Initialize face-to-music system components facialAnalyzer = game.addChild(new FacialAnalyzer()); musicSequencer = new MusicSequencer(); expressionDetector = new ExpressionDetector(); function createScanningEffect() { // Create multiple scanning lines for (var i = 0; i < 3; i++) { var scanLine = game.addChild(LK.getAsset('scanLine', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 })); scanLine.x = 1024; scanLine.y = 200 + i * 150; scanLine.scaleX = 0; tween(scanLine, { scaleX: 1.5, alpha: 0 }, { duration: 1000 + i * 200, onFinish: function onFinish() { scanLine.destroy(); } }); } } function createBeatVisualization(x, y, intensity) { var beatPulse = game.addChild(LK.getAsset('beatPulse', { anchorX: 0.5, anchorY: 0.5, alpha: intensity, tint: 0x00ff88 })); beatPulse.x = x; beatPulse.y = y; tween(beatPulse, { scaleX: 2 + intensity, scaleY: 2 + intensity, alpha: 0 }, { duration: 400, onFinish: function onFinish() { beatPulse.destroy(); } }); } function updateMusicVisualization() { // Create visual pulses synced to music if (musicSequencer.isPlaying && gameTime % 15 === 0) { var centerX = 1024; var centerY = 1366; createBeatVisualization(centerX, centerY, 0.8); // Create smaller pulses around face shapes if (facialAnalyzer.melodyArcs.length > 0) { for (var i = 0; i < facialAnalyzer.melodyArcs.length; i++) { var arc = facialAnalyzer.melodyArcs[i]; if (Math.random() < 0.3) { createBeatVisualization(arc.x, arc.y, 0.4); } } } } } // Handle tap to regenerate music composition game.down = function (x, y, obj) { if (gameInitialized && facialAnalyzer) { // Regenerate the musical composition facialAnalyzer.analyzeFace(); musicSequencer.generateSequence(facialAnalyzer); // Visual feedback facialAnalyzer.createScanEffect(); // Audio feedback LK.getSound('smile-trigger').play(); // Add score bonus LK.setScore(LK.getScore() + 15); scoreText.setText('Score: ' + LK.getScore()); // Temporary instruction var originalText = instructionText.text; instructionText.setText('Music composition refreshed!'); LK.setTimeout(function () { instructionText.setText(originalText); }, 2000); } }; // Main face-to-music game loop game.update = function () { gameTime++; // Check if face is detected and initialize system if (facekit.mouthCenter && facekit.leftEye && facekit.rightEye && !gameInitialized) { // Face detected - initialize the music system statusText.setText('Face detected! Analyzing...'); createScanningEffect(); // Allow some time for scanning effect if (scanEffectTimer++ > 120) { // 2 seconds at 60fps facialAnalyzer.analyzeFace(); musicSequencer.generateSequence(facialAnalyzer); gameInitialized = true; statusText.setText('Music composition created!'); // Fade out status text tween(statusText, { alpha: 0 }, { duration: 2000, onFinish: function onFinish() { statusText.setText(''); statusText.alpha = 1; } }); } } // Main music and visual system updates if (gameInitialized && facekit.mouthCenter) { // Update facial analysis continuously facialAnalyzer.analyzeFace(); // Update music sequencer with head tilt for panning if (facekit.leftEye && facekit.rightEye) { var headTilt = (facekit.rightEye.y - facekit.leftEye.y) / Math.abs(facekit.rightEye.x - facekit.leftEye.x); musicSequencer.updatePanning(headTilt); } // Update music sequencer musicSequencer.update(); // Update expression detection expressionDetector.update(musicSequencer); // Update music visualization updateMusicVisualization(); // Update UI bpmText.setText('BPM: ' + musicSequencer.bpm); // Re-analyze face every 5 seconds to keep music fresh if (gameTime % 300 === 0) { facialAnalyzer.analyzeFace(); musicSequencer.generateSequence(facialAnalyzer); } } // Update score based on active music creation if (gameInitialized && musicSequencer.isPlaying) { if (gameTime % 60 === 0) { LK.setScore(LK.getScore() + 2); scoreText.setText('Score: ' + LK.getScore()); } } // Update instruction text based on game state and score if (!gameInitialized) { if (facekit.mouthCenter) { instructionText.setText('Analyzing your face...'); } else { instructionText.setText('Position your face in view of camera'); } } else { if (LK.getScore() > 150) { instructionText.setText('Musical master! Your face creates beautiful compositions!'); } else if (LK.getScore() > 75) { instructionText.setText('Excellent! Try different expressions for variety!'); } else { instructionText.setText('Smile, frown, blink - each expression adds to your music!'); } } };
===================================================================
--- original.js
+++ change.js
@@ -6,8 +6,108 @@
/****
* Classes
****/
+var ExpressionDetector = Container.expand(function () {
+ var self = Container.call(this);
+ // Expression state tracking
+ self.lastSmiling = false;
+ self.lastEyebrowsFrowning = false;
+ self.lastBlinking = false;
+ self.blinkCounter = 0;
+ self.lastBlinkTime = 0;
+ // Expression thresholds
+ self.smileThreshold = 0.3;
+ self.frownThreshold = 0.2;
+ self.blinkThreshold = 50; // milliseconds
+ self.detectSmile = function () {
+ if (!facekit.upperLip || !facekit.lowerLip) return false;
+ // Simple smile detection based on mouth corner positions
+ var mouthCurve = (facekit.upperLip.y - facekit.lowerLip.y) / 20;
+ return mouthCurve > self.smileThreshold;
+ };
+ self.detectFrown = function () {
+ if (!facekit.leftEye || !facekit.rightEye) return false;
+ // Detect frown based on eyebrow position relative to eyes
+ var eyebrowPosition = (facekit.leftEye.y + facekit.rightEye.y) / 2 - 30;
+ return eyebrowPosition < self.frownThreshold;
+ };
+ self.detectBlink = function () {
+ // Simplified blink detection (in real implementation would track eye closure)
+ var currentTime = Date.now();
+ if (currentTime - self.lastBlinkTime > 2000) {
+ // Auto-trigger every 2 seconds for demo
+ self.lastBlinkTime = currentTime;
+ return true;
+ }
+ return false;
+ };
+ self.onSmile = function (sequencer) {
+ // Add new melody notes when smiling
+ var newMelodyNote = melodyNotes[Math.floor(Math.random() * melodyNotes.length)];
+ LK.getSound(newMelodyNote).play();
+ LK.getSound('smile-trigger').play();
+ // Visual feedback
+ LK.effects.flashScreen(0x00ff88, 300);
+ // Add to score
+ LK.setScore(LK.getScore() + 25);
+ };
+ self.onFrown = function (sequencer) {
+ // Increase BPM when frowning
+ sequencer.bpm = Math.min(180, sequencer.bpm + 5);
+ sequencer.beatInterval = 60000 / sequencer.bpm;
+ LK.getSound('frown-trigger').play();
+ // Visual feedback - red flash
+ LK.effects.flashScreen(0xff4444, 200);
+ };
+ self.onBlink = function (sequencer) {
+ // Trigger random effects on blink
+ var randomEffect = effectSounds[Math.floor(Math.random() * effectSounds.length)];
+ LK.getSound(randomEffect).play();
+ LK.getSound('blink-effect').play();
+ // Create sparkle effect
+ for (var i = 0; i < 5; i++) {
+ var sparkle = game.addChild(LK.getAsset('effectDot', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 1.0,
+ tint: Math.random() * 0xffffff
+ }));
+ sparkle.x = facekit.mouthCenter.x + (Math.random() - 0.5) * 200;
+ sparkle.y = facekit.mouthCenter.y + (Math.random() - 0.5) * 200;
+ tween(sparkle, {
+ scaleX: 2,
+ scaleY: 2,
+ alpha: 0
+ }, {
+ duration: 800,
+ onFinish: function onFinish() {
+ sparkle.destroy();
+ }
+ });
+ }
+ };
+ self.update = function (sequencer) {
+ // Check for expression changes
+ var currentSmiling = self.detectSmile();
+ var currentFrowning = self.detectFrown();
+ var currentBlinking = self.detectBlink();
+ // Trigger events on state transitions
+ if (!self.lastSmiling && currentSmiling) {
+ self.onSmile(sequencer);
+ }
+ if (!self.lastEyebrowsFrowning && currentFrowning) {
+ self.onFrown(sequencer);
+ }
+ if (currentBlinking) {
+ self.onBlink(sequencer);
+ }
+ // Update last states
+ self.lastSmiling = currentSmiling;
+ self.lastEyebrowsFrowning = currentFrowning;
+ };
+ return self;
+});
var FaceShape = Container.expand(function () {
var self = Container.call(this);
self.faceOutline = self.attachAsset('faceOutline', {
anchorX: 0.5,
@@ -120,8 +220,274 @@
scoreText.setText('Score: ' + LK.getScore());
};
return self;
});
+var FacialAnalyzer = Container.expand(function () {
+ var self = Container.call(this);
+ // Musical shape arrays
+ self.melodyArcs = [];
+ self.bassEllipses = [];
+ self.rhythmSquares = [];
+ self.effectDots = [];
+ self.scanLines = [];
+ self.wireframes = [];
+ // Face analysis data
+ self.eyebrowAngle = 0;
+ self.eyeDistance = 0;
+ self.mouthWidth = 0;
+ self.chinLength = 0;
+ self.headTilt = 0;
+ // Musical timing
+ self.bpm = 120;
+ self.beatCount = 0;
+ self.lastBeatTime = 0;
+ self.analyzeFace = function () {
+ if (!facekit.leftEye || !facekit.rightEye || !facekit.mouthCenter) return;
+ // Calculate facial measurements
+ self.eyeDistance = Math.abs(facekit.rightEye.x - facekit.leftEye.x);
+ self.mouthWidth = Math.abs(facekit.upperLip.x - facekit.lowerLip.x) || 50;
+ self.chinLength = Math.abs(facekit.chin.y - facekit.mouthCenter.y);
+ self.headTilt = (facekit.rightEye.y - facekit.leftEye.y) / self.eyeDistance;
+ // Generate shapes based on facial features
+ self.generateMelodyArcs();
+ self.generateBassEllipses();
+ self.generateRhythmSquares();
+ self.generateEffectDots();
+ };
+ self.generateMelodyArcs = function () {
+ // Clear existing arcs
+ for (var i = 0; i < self.melodyArcs.length; i++) {
+ self.melodyArcs[i].destroy();
+ }
+ self.melodyArcs = [];
+ // Create arcs based on eyebrow angle and eye distance
+ var arcCount = Math.floor(self.eyeDistance / 50) + 2;
+ for (var i = 0; i < arcCount; i++) {
+ var arc = self.addChild(LK.getAsset('melodyArc', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.7
+ }));
+ arc.x = facekit.leftEye.x + i * (self.eyeDistance / arcCount);
+ arc.y = facekit.leftEye.y - 50;
+ arc.rotation = self.headTilt * 0.5;
+ arc.noteIndex = i % melodyNotes.length;
+ self.melodyArcs.push(arc);
+ }
+ };
+ self.generateBassEllipses = function () {
+ // Clear existing ellipses
+ for (var i = 0; i < self.bassEllipses.length; i++) {
+ self.bassEllipses[i].destroy();
+ }
+ self.bassEllipses = [];
+ // Create bass ellipses based on mouth width
+ var ellipseCount = Math.floor(self.mouthWidth / 30) + 1;
+ for (var i = 0; i < ellipseCount; i++) {
+ var ellipse = self.addChild(LK.getAsset('bassEllipse', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+ }));
+ ellipse.x = facekit.mouthCenter.x + (i - ellipseCount / 2) * 60;
+ ellipse.y = facekit.mouthCenter.y + 80;
+ ellipse.noteIndex = i % bassNotes.length;
+ self.bassEllipses.push(ellipse);
+ }
+ };
+ self.generateRhythmSquares = function () {
+ // Clear existing squares
+ for (var i = 0; i < self.rhythmSquares.length; i++) {
+ self.rhythmSquares[i].destroy();
+ }
+ self.rhythmSquares = [];
+ // Create rhythm squares based on chin length
+ var squareCount = Math.floor(self.chinLength / 40) + 2;
+ for (var i = 0; i < squareCount; i++) {
+ var square = self.addChild(LK.getAsset('rhythmSquare', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8
+ }));
+ square.x = facekit.chin.x + (i - squareCount / 2) * 70;
+ square.y = facekit.chin.y + 50;
+ square.rhythmIndex = i % rhythmSounds.length;
+ self.rhythmSquares.push(square);
+ }
+ };
+ self.generateEffectDots = function () {
+ // Clear existing dots
+ for (var i = 0; i < self.effectDots.length; i++) {
+ self.effectDots[i].destroy();
+ }
+ self.effectDots = [];
+ // Create effect dots around nose area
+ var dotCount = 4;
+ for (var i = 0; i < dotCount; i++) {
+ var dot = self.addChild(LK.getAsset('effectDot', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.5
+ }));
+ var angle = i / dotCount * Math.PI * 2;
+ dot.x = facekit.noseTip.x + Math.cos(angle) * 60;
+ dot.y = facekit.noseTip.y + Math.sin(angle) * 40;
+ dot.effectIndex = i % effectSounds.length;
+ self.effectDots.push(dot);
+ }
+ };
+ self.createScanEffect = function () {
+ // Create scanning wireframe effect
+ var wireframe = self.addChild(LK.getAsset('faceWireframe', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.3
+ }));
+ wireframe.x = facekit.mouthCenter.x;
+ wireframe.y = facekit.mouthCenter.y;
+ // Animate scanning effect
+ tween(wireframe, {
+ alpha: 0.8,
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 500,
+ onFinish: function onFinish() {
+ tween(wireframe, {
+ alpha: 0,
+ scaleX: 1.5,
+ scaleY: 1.5
+ }, {
+ duration: 500,
+ onFinish: function onFinish() {
+ wireframe.destroy();
+ }
+ });
+ }
+ });
+ };
+ return self;
+});
+var MusicSequencer = Container.expand(function () {
+ var self = Container.call(this);
+ self.bpm = 120;
+ self.beatInterval = 60000 / self.bpm; // milliseconds per beat
+ self.lastBeatTime = 0;
+ self.currentBeat = 0;
+ self.isPlaying = false;
+ // Musical sequences based on face analysis
+ self.melodySequence = [];
+ self.bassSequence = [];
+ self.rhythmSequence = [];
+ self.effectSequence = [];
+ // Stereo panning based on head tilt
+ self.panValue = 0;
+ self.generateSequence = function (analyzer) {
+ // Generate melody sequence from arcs
+ self.melodySequence = [];
+ for (var i = 0; i < analyzer.melodyArcs.length; i++) {
+ var arc = analyzer.melodyArcs[i];
+ self.melodySequence.push({
+ note: melodyNotes[arc.noteIndex],
+ beat: i % 4,
+ volume: 0.6 + arc.alpha * 0.4
+ });
+ }
+ // Generate bass sequence from ellipses
+ self.bassSequence = [];
+ for (var i = 0; i < analyzer.bassEllipses.length; i++) {
+ var ellipse = analyzer.bassEllipses[i];
+ self.bassSequence.push({
+ note: bassNotes[ellipse.noteIndex],
+ beat: i % 2,
+ volume: 0.8
+ });
+ }
+ // Generate rhythm sequence from squares
+ self.rhythmSequence = [];
+ for (var i = 0; i < analyzer.rhythmSquares.length; i++) {
+ var square = analyzer.rhythmSquares[i];
+ self.rhythmSequence.push({
+ sound: rhythmSounds[square.rhythmIndex],
+ beat: i % 4,
+ volume: 0.7
+ });
+ }
+ // Set up effect triggers from dots
+ self.effectSequence = [];
+ for (var i = 0; i < analyzer.effectDots.length; i++) {
+ var dot = analyzer.effectDots[i];
+ self.effectSequence.push({
+ effect: effectSounds[dot.effectIndex],
+ trigger: Math.random() < 0.3
+ });
+ }
+ self.isPlaying = true;
+ };
+ self.updatePanning = function (headTilt) {
+ self.panValue = Math.max(-1, Math.min(1, headTilt * 2));
+ // Apply panning to current sounds (simplified representation)
+ };
+ self.playBeat = function () {
+ if (!self.isPlaying) return;
+ var beatInSequence = self.currentBeat % 4;
+ // Play melody
+ for (var i = 0; i < self.melodySequence.length; i++) {
+ var melodyNote = self.melodySequence[i];
+ if (melodyNote.beat === beatInSequence) {
+ LK.getSound(melodyNote.note).play();
+ }
+ }
+ // Play bass
+ for (var i = 0; i < self.bassSequence.length; i++) {
+ var bassNote = self.bassSequence[i];
+ if (bassNote.beat === beatInSequence) {
+ LK.getSound(bassNote.note).play();
+ }
+ }
+ // Play rhythm
+ for (var i = 0; i < self.rhythmSequence.length; i++) {
+ var rhythmHit = self.rhythmSequence[i];
+ if (rhythmHit.beat === beatInSequence) {
+ LK.getSound(rhythmHit.sound).play();
+ }
+ }
+ // Random effect triggers
+ if (Math.random() < 0.1) {
+ var randomEffect = self.effectSequence[Math.floor(Math.random() * self.effectSequence.length)];
+ if (randomEffect) {
+ LK.getSound(randomEffect.effect).play();
+ }
+ }
+ self.currentBeat++;
+ };
+ self.update = function () {
+ var currentTime = Date.now();
+ if (currentTime - self.lastBeatTime >= self.beatInterval) {
+ self.playBeat();
+ self.lastBeatTime = currentTime;
+ // Create beat visualization
+ var beatPulse = game.addChild(LK.getAsset('beatPulse', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8
+ }));
+ beatPulse.x = 1024;
+ beatPulse.y = 1366;
+ tween(beatPulse, {
+ scaleX: 3,
+ scaleY: 3,
+ alpha: 0
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ beatPulse.destroy();
+ }
+ });
+ }
+ };
+ return self;
+});
var Particle = Container.expand(function () {
var self = Container.call(this);
self.graphic = self.attachAsset('particle', {
anchorX: 0.5,
@@ -159,83 +525,224 @@
/****
* Game Code
****/
-var faceShape;
-var particles = [];
+// Expression triggers
+// Sound effects - mapped to dots/lines
+// Rhythm sounds - mapped to squares
+// Bass notes (synth bass) - mapped to ellipses
+// Melody notes (piano) - mapped to arcs
+// Beat visualization
+// Face wireframe
+// Scanning wireframe
+// Dots for effects
+// Squares for rhythm
+// Ellipses for bass
+// Arcs for melody
+// Face analysis shapes mapped to musical roles
+// Face-to-Music System Variables
+var facialAnalyzer;
+var musicSequencer;
+var expressionDetector;
+var scanEffectTimer = 0;
+var gameInitialized = false;
+// Musical arrays mapped to shape types
+var melodyNotes = ['melody-g3', 'melody-b3', 'melody-c4', 'melody-d4', 'melody-e4', 'melody-f4', 'melody-a4'];
+var bassNotes = ['bass-e2', 'bass-a2', 'bass-d2'];
+var rhythmSounds = ['kick', 'snare', 'hihat'];
+var effectSounds = ['filter-sweep', 'delay-effect', 'reverb-wash'];
+// UI Elements
var scoreText;
var instructionText;
-var expressionCount = 0;
+var bpmText;
+var statusText;
var gameTime = 0;
-var noteIds = ['do-c', 're-d', 'mi-e', 'fa-f', 'sol-g', 'la-a', 'si-b'];
-var lastNotePlayTime = 0;
-var notePlayCooldown = 30; // Play note every 30 frames (0.5 seconds at 60fps)
// Create score display
scoreText = new Text2('Score: 0', {
size: 60,
- fill: 0xFFFFFF
+ fill: 0x00ff88
});
scoreText.anchor.set(0.5, 0);
+scoreText.y = 50;
LK.gui.top.addChild(scoreText);
-// Create instruction text
-instructionText = new Text2('Move your face and open your mouth!', {
+// Create BPM display
+bpmText = new Text2('BPM: 120', {
size: 40,
- fill: 0xFFFFFF
+ fill: 0x88aaff
});
+bpmText.anchor.set(0, 0);
+bpmText.x = 50;
+bpmText.y = 120;
+LK.gui.top.addChild(bpmText);
+// Create status text
+statusText = new Text2('Scanning face...', {
+ size: 50,
+ fill: 0xffaa44
+});
+statusText.anchor.set(0.5, 0.5);
+LK.gui.center.addChild(statusText);
+// Create instruction text
+instructionText = new Text2('Express yourself to create music!', {
+ size: 35,
+ fill: 0xffffff
+});
instructionText.anchor.set(0.5, 1);
+instructionText.y = -50;
LK.gui.bottom.addChild(instructionText);
-// Create main face shape
-faceShape = game.addChild(new FaceShape());
-function createParticleEffect(x, y) {
- for (var i = 0; i < 8; i++) {
- var particle = new Particle();
- particle.x = x;
- particle.y = y;
- particle.graphic.tint = Math.random() * 0xffffff;
- particles.push(particle);
- game.addChild(particle);
+// Initialize face-to-music system components
+facialAnalyzer = game.addChild(new FacialAnalyzer());
+musicSequencer = new MusicSequencer();
+expressionDetector = new ExpressionDetector();
+function createScanningEffect() {
+ // Create multiple scanning lines
+ for (var i = 0; i < 3; i++) {
+ var scanLine = game.addChild(LK.getAsset('scanLine', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+ }));
+ scanLine.x = 1024;
+ scanLine.y = 200 + i * 150;
+ scanLine.scaleX = 0;
+ tween(scanLine, {
+ scaleX: 1.5,
+ alpha: 0
+ }, {
+ duration: 1000 + i * 200,
+ onFinish: function onFinish() {
+ scanLine.destroy();
+ }
+ });
}
}
-// Handle tap to change colors
+function createBeatVisualization(x, y, intensity) {
+ var beatPulse = game.addChild(LK.getAsset('beatPulse', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: intensity,
+ tint: 0x00ff88
+ }));
+ beatPulse.x = x;
+ beatPulse.y = y;
+ tween(beatPulse, {
+ scaleX: 2 + intensity,
+ scaleY: 2 + intensity,
+ alpha: 0
+ }, {
+ duration: 400,
+ onFinish: function onFinish() {
+ beatPulse.destroy();
+ }
+ });
+}
+function updateMusicVisualization() {
+ // Create visual pulses synced to music
+ if (musicSequencer.isPlaying && gameTime % 15 === 0) {
+ var centerX = 1024;
+ var centerY = 1366;
+ createBeatVisualization(centerX, centerY, 0.8);
+ // Create smaller pulses around face shapes
+ if (facialAnalyzer.melodyArcs.length > 0) {
+ for (var i = 0; i < facialAnalyzer.melodyArcs.length; i++) {
+ var arc = facialAnalyzer.melodyArcs[i];
+ if (Math.random() < 0.3) {
+ createBeatVisualization(arc.x, arc.y, 0.4);
+ }
+ }
+ }
+ }
+}
+// Handle tap to regenerate music composition
game.down = function (x, y, obj) {
- faceShape.changeColors();
+ if (gameInitialized && facialAnalyzer) {
+ // Regenerate the musical composition
+ facialAnalyzer.analyzeFace();
+ musicSequencer.generateSequence(facialAnalyzer);
+ // Visual feedback
+ facialAnalyzer.createScanEffect();
+ // Audio feedback
+ LK.getSound('smile-trigger').play();
+ // Add score bonus
+ LK.setScore(LK.getScore() + 15);
+ scoreText.setText('Score: ' + LK.getScore());
+ // Temporary instruction
+ var originalText = instructionText.text;
+ instructionText.setText('Music composition refreshed!');
+ LK.setTimeout(function () {
+ instructionText.setText(originalText);
+ }, 2000);
+ }
};
-// Main game update loop
+// Main face-to-music game loop
game.update = function () {
gameTime++;
- // Update face position based on face tracking
- if (facekit.mouthCenter) {
- // Calculate face dimensions and position
- var faceX = (facekit.leftEye.x + facekit.rightEye.x) / 2;
- var faceY = (facekit.leftEye.y + facekit.chin.y) / 2;
- var faceWidth = Math.abs(facekit.rightEye.x - facekit.leftEye.x) * 3;
- var faceHeight = Math.abs(facekit.chin.y - facekit.leftEye.y) * 1.5;
- faceShape.updateFacePosition(faceX, faceY, faceWidth, faceHeight);
+ // Check if face is detected and initialize system
+ if (facekit.mouthCenter && facekit.leftEye && facekit.rightEye && !gameInitialized) {
+ // Face detected - initialize the music system
+ statusText.setText('Face detected! Analyzing...');
+ createScanningEffect();
+ // Allow some time for scanning effect
+ if (scanEffectTimer++ > 120) {
+ // 2 seconds at 60fps
+ facialAnalyzer.analyzeFace();
+ musicSequencer.generateSequence(facialAnalyzer);
+ gameInitialized = true;
+ statusText.setText('Music composition created!');
+ // Fade out status text
+ tween(statusText, {
+ alpha: 0
+ }, {
+ duration: 2000,
+ onFinish: function onFinish() {
+ statusText.setText('');
+ statusText.alpha = 1;
+ }
+ });
+ }
}
- // Auto color change every 5 seconds
- if (gameTime % 300 === 0) {
- faceShape.changeColors();
+ // Main music and visual system updates
+ if (gameInitialized && facekit.mouthCenter) {
+ // Update facial analysis continuously
+ facialAnalyzer.analyzeFace();
+ // Update music sequencer with head tilt for panning
+ if (facekit.leftEye && facekit.rightEye) {
+ var headTilt = (facekit.rightEye.y - facekit.leftEye.y) / Math.abs(facekit.rightEye.x - facekit.leftEye.x);
+ musicSequencer.updatePanning(headTilt);
+ }
+ // Update music sequencer
+ musicSequencer.update();
+ // Update expression detection
+ expressionDetector.update(musicSequencer);
+ // Update music visualization
+ updateMusicVisualization();
+ // Update UI
+ bpmText.setText('BPM: ' + musicSequencer.bpm);
+ // Re-analyze face every 5 seconds to keep music fresh
+ if (gameTime % 300 === 0) {
+ facialAnalyzer.analyzeFace();
+ musicSequencer.generateSequence(facialAnalyzer);
+ }
}
- // Play notes based on face shape and position
- if (facekit.mouthCenter && gameTime - lastNotePlayTime > notePlayCooldown) {
- // Calculate face dimensions for note selection
- var faceWidth = Math.abs(facekit.rightEye.x - facekit.leftEye.x) * 3;
- var faceHeight = Math.abs(facekit.chin.y - facekit.leftEye.y) * 1.5;
- // Use face dimensions and position to select note
- var noteIndex = Math.floor((faceWidth + faceHeight + facekit.mouthCenter.x + facekit.mouthCenter.y) / 100) % noteIds.length;
- if (noteIndex < 0) noteIndex = 0;
- // Play the selected note
- LK.getSound(noteIds[noteIndex]).play();
- lastNotePlayTime = gameTime;
+ // Update score based on active music creation
+ if (gameInitialized && musicSequencer.isPlaying) {
+ if (gameTime % 60 === 0) {
+ LK.setScore(LK.getScore() + 2);
+ scoreText.setText('Score: ' + LK.getScore());
+ }
}
- // Update score based on time
- if (gameTime % 60 === 0) {
- LK.setScore(LK.getScore() + 1);
- scoreText.setText('Score: ' + LK.getScore());
+ // Update instruction text based on game state and score
+ if (!gameInitialized) {
+ if (facekit.mouthCenter) {
+ instructionText.setText('Analyzing your face...');
+ } else {
+ instructionText.setText('Position your face in view of camera');
+ }
+ } else {
+ if (LK.getScore() > 150) {
+ instructionText.setText('Musical master! Your face creates beautiful compositions!');
+ } else if (LK.getScore() > 75) {
+ instructionText.setText('Excellent! Try different expressions for variety!');
+ } else {
+ instructionText.setText('Smile, frown, blink - each expression adds to your music!');
+ }
}
- // Update instruction text based on score
- if (LK.getScore() > 100) {
- instructionText.setText('Amazing! Keep expressing yourself!');
- } else if (LK.getScore() > 50) {
- instructionText.setText('Great job! Try different expressions!');
- }
};
\ No newline at end of file
do-c
Sound effect
re-d
Sound effect
fa-f
Sound effect
sol-g
Sound effect
la-a
Sound effect
si-b
Sound effect
melody-g3
Sound effect
melody-b3
Sound effect
melody-c4
Sound effect
melody-d4
Sound effect
melody-e4
Sound effect
melody-f4
Sound effect
melody-a4
Sound effect
smile-trigger
Sound effect
frown-trigger
Sound effect
blink-effect
Sound effect
shapeChange
Sound effect
kick
Sound effect
snare
Sound effect
hihat
Sound effect
filter-sweep
Sound effect
delay-effect
Sound effect
reverb-wash
Sound effect