User prompt
Parameters for AI: Speed: Extremely slow. Think of water barely stirring. Amplitude: Very low, creating subtle undulations rather than waves. Frequency: Infrequent, natural-looking pulses of movement. Direction: Radial outwards from subtle, random points, or a gentle, consistent drift. Visual Effect: Causes subtle, elongated reflections of the sky and distant land to gently shift. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Mechanism: Shader-based animation. A ripple texture or noise pattern will be applied to the water's surface, slowly scrolling and distorting to simulate gentle movement. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Technical Specifications for AI (if generating code/assets): "Utilize shader-based animations where possible for performance and seamless integration." "Ensure all particle systems are optimized for low impact on performance, maintaining the smooth, relaxing experience." "Animations should be scalable and responsive to different screen resolutions." ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Specific Animation Elements (with parameters for AI): Water Ripples: "Implement a shader-based ripple effect on the lake surface. Parameters: ripple_speed: very_slow, ripple_amplitude: minimal, fade_rate: slow." Luminescent Particles: "Generate small, glowing particles (particle_size: tiny, glow_intensity: soft, color: #E0FFFF (light cyan) or random_pastel), with a continuous upward and lateral drift (drift_speed: very_slow, drift_variance: low). Spawning density: sparse." Tree Sway: "Apply a gentle, continuous sway to tree foliage and branches (sway_angle: 1-3 degrees, sway_frequency: 0.1-0.2 Hz)." Distant Cloud Movement: "Clouds in the background should drift horizontally (cloud_speed: extremely_slow)." Light Shimmer: "Implement a subtle, slow pulsing/shimmering effect on the main light source in the sky (pulse_frequency: 0.05 Hz, intensity_variance: 5-10%)." Aura Wisps: "When an aura is spawned, animate a small, colored particle cluster (aura_color: matching aura type) to float towards the player (float_speed: slow). Upon collection, trigger a rapid, soft fade-out animation." Ephemeral Creature Glimmer: "Upon appearance/disappearance, apply a brief, soft, sparkling particle burst (sparkle_duration: 1-2 seconds, particle_count: low, color: white/gold)." Rare Aura Bloom Pulse: "The bloom should exhibit a slow, rhythmic glow pulse (pulse_frequency: 0.5 Hz, intensity_variance: 20-30%). Upon collection, emit a larger, short-lived burst of glowing particles (burst_duration: 1 second, particle_count: medium, color: vibrant_pastel_mix)." Hidden Vignette Animations: "Each vignette will have unique, subtle animations (e.g., fireflies: random_path_movement, soft_glow_pulse; waterfall: gentle_mist_swirl, rainbow_fade_in_out)." ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: LK.stopSound is not a function' in or related to this line: 'LK.stopSound(soundName);' Line Number: 1412
User prompt
Visuals - Animation Principles: "All animations should adhere to a principle of subtle, slow, and organic movement. Avoid fast, jerky, or high-contrast animations. The goal is to enhance tranquility, not stimulate excitement." "Animations should seamlessly integrate with the hand-drawn, watercolor aesthetic, appearing as natural extensions of the environment." "Particle effects should be soft, ethereal, and sparse, using colors that complement the existing palette." ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: Cannot use 'in' operator to search for 'alpha' in null' in or related to this line: 'tween(zenText, {' Line Number: 1667 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Rare Aura Bloom Pulse: When a "Rare Aura Bloom" appears, it will have a more pronounced, slow, and rhythmic pulsating glow, drawing the player's eye without being urgent. Upon collection, it will release a burst of larger, more vibrant glowing particles that quickly dissipate. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ephemeral Creature Glimmers: When an "Ephemeral Creature" appears (as described in the previous turn), it will emerge with a soft, sparkling shimmer effect and then fade away with a similar, gentle dissipation animation. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Aura Wisps: As the player moves, small, glowing "aura wisps" will emerge from various points in the environment (e.g., from under a rock, near a patch of glowing mushrooms, or from within a tree trunk). These wisps will gently float towards the player, dissolving upon collection. Their color will match the aura types mentioned previously (green, blue, yellow, etc.). ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Subtle Light Shimmer: A very faint, almost imperceptible shimmering or pulsing effect will be applied to the light source (e.g., the sun or moon glow) in the sky, creating a soft, breathing ambiance. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Soft Tree Sway: The leaves and branches of the trees, especially those in the foreground and mid-ground, will exhibit a very gentle, rhythmic sway, as if a faint, warm breeze is passing through them. This will be a slow, continuous motion. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Floating Luminescent Particles: Throughout the air, particularly over the water and near the trees, tiny, soft, glowing particles (like fireflies or dust motes) will slowly drift upwards and across the scene, adding a magical, ethereal quality. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Gentle Water Ripples: The surface of the lake will have very slow, subtle ripples that gently expand and fade, reflecting the light from the sky and surrounding elements. This will be almost imperceptible but add a living quality to the water. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Zen Moments: After a certain amount of continuous exploration or Haven building, a "Zen Moment" might trigger. The screen subtly desaturates slightly, the music becomes even more minimalistic, and a short, positive affirmation appears on screen (e.g., "Find your calm," "Embrace tranquility," "You are here."). This is a gentle prompt to simply observe and breathe. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Weather Transformations: While generally clear, there's a small chance for the weather to subtly shift to a gentle rain shower or a soft snowfall, affecting the visuals and adding a new layer of ambient ASMR sounds. This transformation is always calming, never harsh. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Hidden Vignettes: Tucked away in obscure corners of the map are small, beautifully animated vignettes. These could be: A tiny, glowing mushroom ring where fireflies dance. A hidden waterfall that creates a rainbow in the mist. A sleeping creature (e.g., a large, gentle bear) that emits soft, rhythmic breathing sounds. Discovering these triggers a unique, brief, and very peaceful soundscape. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ephemeral Creatures: Very rarely, unique, non-interactive "Ephemeral Creatures" (e.g., a glowing fox, a sparkling hummingbird, a shy forest spirit) will briefly appear in a biome, observe the player, and then gently fade away. Seeing one is a special, calming moment. They don't provide a reward, but seeing them is the reward. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Rare Aura Blooms: Occasionally, a large, pulsating "Rare Aura Bloom" will appear in a random location. Collecting it yields a significant amount of auras and triggers a unique, brief visual spectacle (e.g., a burst of gentle light, a swirl of colored particles) and a particularly serene musical flourish. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ASMR Effects: Subtle & Contextual: ASMR sounds are integrated naturally into the environment and actions. Examples: Footsteps: Gentle rustling of leaves when walking through grass, soft crunch on pebbles, subtle plash in shallow water. Environment: Distant, gentle crackling of a soft fire, subtle dripping in caverns, very light rain on leaves, the soft hum of fireflies. Interaction: A faint, pleasant ding when collecting an aura, the soft click or whoosh when placing an item in the Haven, the gentle rustle of interacting with a plant. Nature Sounds: Delicate bird chirps, the distant murmur of a stream, soft wind chimes.
User prompt
Dynamic Looping: The music shifts subtly based on the biome the player is in, maintaining a consistent calm tone but with variations in instrumentation and melody. Instruments: Focus on instruments like soft pianos, gentle strings, flutes, chimes, and ambient pads. Avoid sharp or jarring sounds. BPM: Very low BPM (beats per minute) to encourage slow, deliberate movement. Themes: Melodies that evoke feelings of peace, wonder, and warmth.
User prompt
Visuals: Art Style: Soft, watercolor-inspired hand-drawn graphics with gentle animations (e.g., swaying trees, rippling water, subtle dust motes in the air). Color Palette: Predominantly pastel and earthy tones, with soft glows from auras and lighting. Particle Effects: Subtle, ethereal particle effects for auras, gentle snowfall/rainfall, or floating pollen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Aura Haven - Peaceful Exploration & Sanctuary Building
Initial prompt
Exploration: Players gently glide through various themed biomes (e.g., Whispering Woods, Crystal Caverns, Serene Shoreline, Starfall Sanctuary). Each biome has unique visual aesthetics and ambient sounds. Aura Collection: Wisps of colored "auras" (glowing particles representing positive energy) are scattered throughout the environment. Players simply move over them to collect them. Different aura colors might have different symbolic meanings (e.g., green for growth, blue for peace, yellow for joy). Haven Cultivation: Collected auras are used to unlock and place decorative elements within the player's personal "Haven." The Haven starts as a blank canvas and can be customized with plants, small structures, water features, ambient lights, and even gentle, animated creatures.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AuraParticle = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'green'; self.collected = false; var assetName = 'aura' + self.type.charAt(0).toUpperCase() + self.type.slice(1); var auraGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); auraGraphics.alpha = 0.8; self.floatOffset = Math.random() * Math.PI * 2; self.floatSpeed = 0.02 + Math.random() * 0.03; self.pulseOffset = Math.random() * Math.PI * 2; self.initialY = 0; self.initialScale = 1.0; // Start gentle pulsing animation tween(auraGraphics, { scaleX: 1.2, scaleY: 1.2, alpha: 1.0 }, { duration: 1500 + Math.random() * 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (!self.collected) { tween(auraGraphics, { scaleX: 0.8, scaleY: 0.8, alpha: 0.6 }, { duration: 1500 + Math.random() * 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (!self.collected) { tween(auraGraphics, { scaleX: 1.0, scaleY: 1.0, alpha: 0.8 }, { duration: 1000, easing: tween.easeInOut }); } } }); } } }); self.update = function () { if (!self.collected) { self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 8; auraGraphics.rotation += 0.015; } }; return self; }); var AuraWisp = Container.expand(function (wispType) { var self = Container.call(this); self.wispType = wispType || 'green'; self.collected = false; self.isMovingToPlayer = false; self.moveSpeed = 3.5; // Set wisp color based on type var wispColors = { green: 0xc8e6c9, blue: 0xb3d9ff, yellow: 0xfff8d1 }; var wispGraphics = self.attachAsset('auraWisp', { anchorX: 0.5, anchorY: 0.5 }); // Apply wisp type color wispGraphics.tint = wispColors[self.wispType]; wispGraphics.alpha = 0.7; self.floatOffset = Math.random() * Math.PI * 2; self.floatSpeed = 0.025 + Math.random() * 0.015; self.pulseOffset = Math.random() * Math.PI * 2; self.initialY = 0; self.emergeDuration = 120; // 2 seconds to emerge self.emergeTimer = 0; // Start gentle emergence animation tween(wispGraphics, { alpha: 0.9, scaleX: 1.2, scaleY: 1.2 }, { duration: 1000 + Math.random() * 500, easing: tween.easeOut, onFinish: function onFinish() { if (!self.collected) { // Start floating towards player self.isMovingToPlayer = true; } } }); self.moveTowardsPlayer = function () { if (!player || self.collected) return; var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 10) { // Gentle movement towards player self.x += dx / distance * self.moveSpeed; self.y += dy / distance * self.moveSpeed; } else { // Close enough to be collected self.collected = true; // Award small aura auraCount[self.wispType]++; updateUI(); // Gentle collection animation tween(wispGraphics, { scaleX: 1.8, scaleY: 1.8, alpha: 1.0 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(wispGraphics, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); } }); } }); LK.getSound('collectAura').play(); } }; self.update = function () { if (self.collected) return; if (!self.isMovingToPlayer) { // Gentle floating motion while emerging self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 6; self.emergeTimer++; // Start moving towards player after emergence period if (self.emergeTimer >= self.emergeDuration) { self.isMovingToPlayer = true; } } else { // Move towards player with gentle floating motion self.moveTowardsPlayer(); // Add gentle floating while moving var floatMotion = Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 4; self.y += floatMotion * 0.1; } // Gentle pulsing glow wispGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.04 + self.pulseOffset) * 0.3; wispGraphics.rotation += 0.01; }; return self; }); var DistantCloud = Container.expand(function () { var self = Container.call(this); var cloudGraphics = self.attachAsset('distantCloud', { anchorX: 0.5, anchorY: 0.5 }); cloudGraphics.alpha = 0.3 + Math.random() * 0.2; self.driftSpeed = 0.1 + Math.random() * 0.15; // Extremely slow drift self.initialX = 0; self.floatOffset = Math.random() * Math.PI * 2; self.floatSpeed = 0.003 + Math.random() * 0.005; // Very slow vertical float self.initialY = 0; // Start gentle size pulsing for natural cloud variation tween(cloudGraphics, { scaleX: 1.1 + Math.random() * 0.2, scaleY: 1.1 + Math.random() * 0.2 }, { duration: 8000 + Math.random() * 4000, easing: tween.easeInOut, onFinish: function onFinish() { tween(cloudGraphics, { scaleX: 0.9, scaleY: 0.9 }, { duration: 8000 + Math.random() * 4000, easing: tween.easeInOut }); } }); self.update = function () { // Imperceptibly slow horizontal drift - consistent with typical cloud movement // Enhanced with tween-based smooth transitions for more natural movement self.x += self.driftSpeed * 0.3; // Reduced to imperceptibly slow speed // Very subtle vertical floating motion self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 8; // Reset cloud when it goes off screen if (self.x > 2100) { self.x = -200; self.initialX = self.x; // Add subtle tween variation when cloud resets for natural repositioning tween(self, { x: self.x + (Math.random() - 0.5) * 100, y: self.initialY + (Math.random() - 0.5) * 80 }, { duration: 5000 + Math.random() * 3000, easing: tween.easeInOut }); } }; return self; }); var EphemeralCreature = Container.expand(function (creatureType) { var self = Container.call(this); self.creatureType = creatureType || 'fox'; self.hasAppeared = false; self.isObserving = false; self.observeTimer = 0; self.observeDuration = 180; // 3 seconds at 60fps var assetName = 'ephemeral' + self.creatureType.charAt(0).toUpperCase() + self.creatureType.slice(1); var creatureGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); // Start invisible creatureGraphics.alpha = 0; self.floatOffset = Math.random() * Math.PI * 2; self.floatSpeed = 0.015; self.initialY = 0; self.appear = function () { if (self.hasAppeared) return; self.hasAppeared = true; // Create sparkling shimmer effect during appearance self.createShimmerBurst(12); // Gentle fade in appearance tween(creatureGraphics, { alpha: 0.8, scaleX: 1.1, scaleY: 1.1 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { self.isObserving = true; // Gentle glow pulsing while observing tween(creatureGraphics, { alpha: 1.0, scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(creatureGraphics, { alpha: 0.7, scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut }); } }); } }); }; self.fadeAway = function () { self.isObserving = false; // Create gentle dissipation shimmer effect self.createShimmerBurst(8); // Gentle fade out tween(creatureGraphics, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 2000, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); } }); }; self.update = function () { if (self.hasAppeared && !self.isObserving) return; // Gentle floating motion self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 12; // Subtle rotation for hummingbird if (self.creatureType === 'hummingbird') { creatureGraphics.rotation = Math.sin(LK.ticks * 0.08) * 0.1; } // Count observe timer if (self.isObserving) { self.observeTimer++; if (self.observeTimer >= self.observeDuration) { self.fadeAway(); } } }; self.createShimmerBurst = function (count) { for (var i = 0; i < count; i++) { var shimmer = new EphemeralShimmer(); // Position around creature with some spread var angle = Math.random() * Math.PI * 2; var distance = 30 + Math.random() * 60; shimmer.x = self.x + Math.cos(angle) * distance; shimmer.y = self.y + Math.sin(angle) * distance; // Add to global shimmer tracking ephemeralShimmers.push(shimmer); game.addChild(shimmer); // Gentle sparkle appearance tween(shimmer, { alpha: 0.7 + Math.random() * 0.3, scaleX: 1.2, scaleY: 1.2 }, { duration: 300 + Math.random() * 200, easing: tween.easeOut }); } }; return self; }); var EphemeralShimmer = Container.expand(function () { var self = Container.call(this); var shimmerGraphics = self.attachAsset('ephemeralShimmer', { anchorX: 0.5, anchorY: 0.5 }); shimmerGraphics.alpha = 0; self.speed = 1.5 + Math.random() * 2.0; self.driftX = (Math.random() - 0.5) * 4; self.driftY = -1 - Math.random() * 2; self.floatOffset = Math.random() * Math.PI * 2; self.floatSpeed = 0.05 + Math.random() * 0.03; self.lifetime = 90 + Math.random() * 60; // 1.5-2.5 seconds self.age = 0; self.update = function () { self.age++; self.x += self.driftX; self.y += self.driftY; // Gentle floating motion self.x += Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 0.5; // Fade out over lifetime var lifeProgress = self.age / self.lifetime; shimmerGraphics.alpha = (1 - lifeProgress) * 0.8; shimmerGraphics.scaleX = 1 - lifeProgress * 0.3; shimmerGraphics.scaleY = 1 - lifeProgress * 0.3; // Remove when lifetime exceeded if (self.age >= self.lifetime) { self.destroy(); } }; return self; }); var FloatingParticle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('floatingParticle', { anchorX: 0.5, anchorY: 0.5 }); particleGraphics.alpha = 0.3 + Math.random() * 0.4; self.driftSpeed = 0.5 + Math.random() * 1.0; self.floatOffset = Math.random() * Math.PI * 2; self.floatSpeed = 0.01 + Math.random() * 0.02; self.initialX = 0; self.update = function () { self.y -= self.driftSpeed; self.x = self.initialX + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 20; particleGraphics.rotation += 0.01; // Reset particle when it goes off screen if (self.y < -50) { self.y = 2800; self.x = Math.random() * 2048; self.initialX = self.x; } }; return self; }); var HavenDecoration = Container.expand(function (decorationType) { var self = Container.call(this); self.decorationType = decorationType || 'plant'; var assetName = self.decorationType + 'Decoration'; var decorationGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 1.0 }); decorationGraphics.alpha = 0.9; self.swayOffset = Math.random() * Math.PI * 2; self.swaySpeed = 0.01 + Math.random() * 0.02; self.update = function () { // Gentle swaying animation for plants and light decorations if (self.decorationType === 'plant' || self.decorationType === 'light') { decorationGraphics.rotation = Math.sin(LK.ticks * self.swaySpeed + self.swayOffset) * 0.05; } // Subtle pulsing for light decorations if (self.decorationType === 'light') { decorationGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.03 + self.swayOffset) * 0.2; } }; return self; }); var HiddenVignette = Container.expand(function (vignetteType) { var self = Container.call(this); self.vignetteType = vignetteType || 'mushroom'; self.discovered = false; self.isActive = false; self.fireflies = []; // Create main vignette element var mainAsset = ''; if (self.vignetteType === 'mushroom') mainAsset = 'mushroomRing';else if (self.vignetteType === 'waterfall') mainAsset = 'hiddenWaterfall';else if (self.vignetteType === 'bear') mainAsset = 'sleepingBear'; var vignetteGraphics = self.attachAsset(mainAsset, { anchorX: 0.5, anchorY: 0.5 }); vignetteGraphics.alpha = 0; // Start invisible self.pulseOffset = Math.random() * Math.PI * 2; self.breathOffset = Math.random() * Math.PI * 2; // Discover animation self.discover = function () { if (self.discovered) return; self.discovered = true; self.isActive = true; // Gentle fade in discovery tween(vignetteGraphics, { alpha: 0.8, scaleX: 1.0, scaleY: 1.0 }, { duration: 2000, easing: tween.easeOut }); // Play vignette-specific sound var soundName = 'vignette' + self.vignetteType.charAt(0).toUpperCase() + self.vignetteType.slice(1); LK.getSound(soundName).play(); // Create special effects based on type if (self.vignetteType === 'mushroom') { self.createFireflies(); } else if (self.vignetteType === 'waterfall') { self.createRainbow(); } }; self.createFireflies = function () { // Create dancing fireflies around mushroom ring for (var i = 0; i < 8; i++) { var firefly = self.addChild(LK.getAsset('firefly', { anchorX: 0.5, anchorY: 0.5 })); firefly.alpha = 0; firefly.danceAngle = Math.PI * 2 / 8 * i; firefly.danceRadius = 80 + Math.random() * 40; firefly.danceSpeed = 0.02 + Math.random() * 0.02; firefly.pulseOffset = Math.random() * Math.PI * 2; self.fireflies.push(firefly); // Fade in firefly tween(firefly, { alpha: 0.7 + Math.random() * 0.3 }, { duration: 1000 + Math.random() * 1000, easing: tween.easeOut }); } }; self.createRainbow = function () { // Create subtle rainbow mist effect LK.effects.flashObject(vignetteGraphics, 0xff9800, 3000); // Add gentle shimmer tween(vignetteGraphics, { alpha: 1.0 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(vignetteGraphics, { alpha: 0.6 }, { duration: 1500, easing: tween.easeInOut }); } }); }; self.update = function () { if (!self.isActive) return; // Gentle pulsing for mushroom ring if (self.vignetteType === 'mushroom') { vignetteGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.02 + self.pulseOffset) * 0.2; // Animate fireflies dancing for (var i = 0; i < self.fireflies.length; i++) { var firefly = self.fireflies[i]; firefly.danceAngle += firefly.danceSpeed; firefly.x = Math.cos(firefly.danceAngle) * firefly.danceRadius; firefly.y = Math.sin(firefly.danceAngle) * firefly.danceRadius; firefly.alpha = 0.4 + Math.sin(LK.ticks * 0.05 + firefly.pulseOffset) * 0.4; } } // Gentle breathing for sleeping bear else if (self.vignetteType === 'bear') { var breathScale = 1.0 + Math.sin(LK.ticks * 0.015 + self.breathOffset) * 0.05; vignetteGraphics.scaleX = breathScale; vignetteGraphics.scaleY = breathScale; } // Subtle shimmer for waterfall else if (self.vignetteType === 'waterfall') { vignetteGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.03 + self.pulseOffset) * 0.1; } }; return self; }); var LightShimmer = Container.expand(function () { var self = Container.call(this); var shimmerGraphics = self.attachAsset('lightShimmer', { anchorX: 0.5, anchorY: 0.5 }); shimmerGraphics.alpha = 0.1; self.pulseOffset = Math.random() * Math.PI * 2; self.pulseSpeed = 0.005 + Math.random() * 0.003; // Very slow, breathing-like pulse self.breathAmplitude = 0.05 + Math.random() * 0.03; // Very subtle intensity variation // Start gentle breathing animation using tween for smooth transitions self.startShimmer = function () { var breatheIn = function breatheIn() { tween(shimmerGraphics, { alpha: 0.15 + self.breathAmplitude, scaleX: 1.05, scaleY: 1.05 }, { duration: 8000 + Math.random() * 4000, // 8-12 seconds per breath easing: tween.easeInOut, onFinish: breatheOut }); }; var breatheOut = function breatheOut() { tween(shimmerGraphics, { alpha: 0.05, scaleX: 0.95, scaleY: 0.95 }, { duration: 8000 + Math.random() * 4000, // 8-12 seconds per breath easing: tween.easeInOut, onFinish: breatheIn }); }; // Start with random direction if (Math.random() < 0.5) { breatheIn(); } else { breatheOut(); } }; self.update = function () { // Additional very subtle pulsing using sine wave for natural variation var subtlePulse = Math.sin(LK.ticks * self.pulseSpeed + self.pulseOffset) * 0.02; shimmerGraphics.alpha += subtlePulse; // Ensure alpha stays within reasonable bounds shimmerGraphics.alpha = Math.max(0.02, Math.min(0.25, shimmerGraphics.alpha)); }; return self; }); var LuminescentParticle = Container.expand(function () { var self = Container.call(this); // Use alternating particle types for variety var assetName = Math.random() < 0.7 ? 'luminescentParticle' : 'luminescentParticleAlt'; var particleGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); // Soft intensity with pastel colors var pastelColors = [0xe0ffff, 0xf0f8ff, 0xfffacd, 0xf0fff0, 0xffe4e1]; particleGraphics.tint = pastelColors[Math.floor(Math.random() * pastelColors.length)]; particleGraphics.alpha = 0.3 + Math.random() * 0.2; // Reduced for subtle effect // Enhanced movement properties for gentle floating self.driftSpeed = 0.08 + Math.random() * 0.12; // Very slow upward drift self.lateralAmplitude = 20 + Math.random() * 30; // Gentle S-curve amplitude self.lateralSpeed = 0.003 + Math.random() * 0.005; // Very slow lateral sway frequency self.initialX = 0; self.lateralOffset = Math.random() * Math.PI * 2; // Random phase for S-curve self.lateralDirection = Math.random() < 0.5 ? 1 : -1; // Random sway direction // Long lifetime properties self.age = 0; self.maxAge = 3600 + Math.random() * 1800; // 60-90 seconds lifetime for long traversal self.spawned = false; // Soft pulsing properties self.pulseOffset = Math.random() * Math.PI * 2; self.pulseSpeed = 0.008 + Math.random() * 0.007; // Very gentle pulse frequency self.baseAlpha = 0.25 + Math.random() * 0.15; // Soft base opacity // Start gentle emergence animation self.emerge = function () { if (self.spawned) return; self.spawned = true; // Gentle fade in and scale up tween(particleGraphics, { alpha: self.baseAlpha, scaleX: 1.0, scaleY: 1.0 }, { duration: 2000 + Math.random() * 1000, easing: tween.easeOut }); }; // Start gentle pulsing animation self.startPulse = function () { var pulseIn = function pulseIn() { if (self.age >= self.maxAge) return; tween(particleGraphics, { alpha: self.baseAlpha + 0.2, scaleX: 1.1, scaleY: 1.1 }, { duration: 3000 + Math.random() * 2000, easing: tween.easeInOut, onFinish: pulseOut }); }; var pulseOut = function pulseOut() { if (self.age >= self.maxAge) return; tween(particleGraphics, { alpha: self.baseAlpha - 0.1, scaleX: 0.9, scaleY: 0.9 }, { duration: 3000 + Math.random() * 2000, easing: tween.easeInOut, onFinish: pulseIn }); }; // Start with random direction if (Math.random() < 0.5) { pulseIn(); } else { pulseOut(); } }; // Enhanced floating movement system self.update = function () { if (!self.spawned) { self.emerge(); self.startPulse(); } self.age++; // Very slow upward drift - effortless floating self.y -= self.driftSpeed; // Gentle lateral sway in S-curve pattern var lateralSway = Math.sin(LK.ticks * self.lateralSpeed + self.lateralOffset) * self.lateralAmplitude * self.lateralDirection; var secondarySway = Math.cos(LK.ticks * self.lateralSpeed * 0.7 + self.lateralOffset + Math.PI) * self.lateralAmplitude * 0.3; self.x = self.initialX + lateralSway + secondarySway; // Additional very subtle sine wave variation for natural movement var microDrift = Math.sin(LK.ticks * 0.002 + self.lateralOffset) * 3; self.x += microDrift; // Subtle additional alpha variation for ethereal effect var additionalGlow = Math.sin(LK.ticks * self.pulseSpeed + self.pulseOffset) * 0.08; particleGraphics.alpha += additionalGlow; // Gentle rotation for natural floating particleGraphics.rotation += 0.003 * self.lateralDirection; // Reset particle when lifetime exceeded or goes off screen if (self.age >= self.maxAge || self.y < -100) { // Reset for reuse with long lifetime self.y = 2800 + Math.random() * 200; self.x = Math.random() * 2048; self.initialX = self.x; self.age = 0; self.spawned = false; // Randomize movement parameters for variety self.driftSpeed = 0.08 + Math.random() * 0.12; self.lateralAmplitude = 20 + Math.random() * 30; self.lateralSpeed = 0.003 + Math.random() * 0.005; self.lateralDirection = Math.random() < 0.5 ? 1 : -1; self.lateralOffset = Math.random() * Math.PI * 2; self.maxAge = 3600 + Math.random() * 1800; self.baseAlpha = 0.25 + Math.random() * 0.15; // Reset graphics properties particleGraphics.alpha = 0; particleGraphics.scaleX = 0.8; particleGraphics.scaleY = 0.8; } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.targetX = 0; self.targetY = 0; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Play footstep sounds based on biome if (LK.ticks - lastFootstepTime > footstepInterval * 60 / 1000) { var footstepSound = ''; if (currentBiome === 0) footstepSound = 'footstepsGrass'; // Woods else if (currentBiome === 1) footstepSound = 'footstepsPebbles'; // Caverns else if (currentBiome === 2) footstepSound = 'footstepsWater'; // Shore else footstepSound = 'footstepsGrass'; // Sanctuary LK.getSound(footstepSound).play(); lastFootstepTime = LK.ticks; } } }; return self; }); var RareAuraBloom = Container.expand(function () { var self = Container.call(this); self.collected = false; var bloomGraphics = self.attachAsset('rareAuraBloom', { anchorX: 0.5, anchorY: 0.5 }); bloomGraphics.alpha = 0.9; self.pulseOffset = Math.random() * Math.PI * 2; self.floatOffset = Math.random() * Math.PI * 2; self.floatSpeed = 0.03; self.initialY = 0; // Start dramatic pulsating animation tween(bloomGraphics, { scaleX: 1.5, scaleY: 1.5, alpha: 1.0 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (!self.collected) { tween(bloomGraphics, { scaleX: 1.0, scaleY: 1.0, alpha: 0.7 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (!self.collected) { tween(bloomGraphics, { scaleX: 1.5, scaleY: 1.5, alpha: 1.0 }, { duration: 1000, easing: tween.easeInOut }); } } }); } } }); self.update = function () { if (!self.collected) { self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 15; bloomGraphics.rotation += 0.02; } }; return self; }); var RareBloomBurst = Container.expand(function () { var self = Container.call(this); var burstGraphics = self.attachAsset('rareBloomBurstParticle', { anchorX: 0.5, anchorY: 0.5 }); // Vibrant pastel mix colors var vibrantColors = [0xffd700, 0xff69b4, 0x98fb98, 0x87ceeb, 0xdda0dd, 0xf0e68c]; burstGraphics.tint = vibrantColors[Math.floor(Math.random() * vibrantColors.length)]; burstGraphics.alpha = 0; self.velocity = { x: (Math.random() - 0.5) * 8, y: -2 - Math.random() * 6 }; self.lifetime = 60; // 1 second burst duration self.age = 0; self.gravity = 0.2; // Start burst animation tween(burstGraphics, { alpha: 0.8, scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(burstGraphics, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 800, easing: tween.easeIn }); } }); self.update = function () { self.age++; self.x += self.velocity.x; self.y += self.velocity.y; self.velocity.y += self.gravity; burstGraphics.rotation += 0.1; // Remove when lifetime exceeded if (self.age >= self.lifetime) { self.destroy(); } }; return self; }); var TreeSwayBranch = Container.expand(function () { var self = Container.call(this); var branchGraphics = self.attachAsset('treeSwayBranch', { anchorX: 0.5, anchorY: 1.0 }); branchGraphics.alpha = 0.7; // Enhanced tree sway parameters for natural movement self.swayOffset = Math.random() * Math.PI * 2; // Random phase for variation between trees self.swaySpeed = 0.006 + Math.random() * 0.004; // Very low frequency (0.1-0.2 Hz equivalent) self.swayAmplitude = 0.02 + Math.random() * 0.015; // Small amplitude (1-3 degrees) self.secondarySwayOffset = Math.random() * Math.PI * 2; // Secondary sway for complexity self.secondarySwaySpeed = 0.004 + Math.random() * 0.003; // Even slower secondary movement self.windVariation = Math.random() * 0.5 + 0.5; // Random wind strength per tree // Enhanced continuous sway animation with multiple layers self.startSway = function () { // Primary sway motion - main side-to-side movement var primarySwayLeft = function primarySwayLeft() { tween(branchGraphics, { rotation: -self.swayAmplitude * self.windVariation }, { duration: 4000 + Math.random() * 3000, // 4-7 seconds per sway for calming rhythm easing: tween.easeInOut, onFinish: primarySwayRight }); }; var primarySwayRight = function primarySwayRight() { tween(branchGraphics, { rotation: self.swayAmplitude * self.windVariation }, { duration: 4000 + Math.random() * 3000, // 4-7 seconds per sway for calming rhythm easing: tween.easeInOut, onFinish: primarySwayLeft }); }; // Start with random direction for phase variation if (Math.random() < 0.5) { primarySwayLeft(); } else { primarySwayRight(); } }; self.update = function () { // Multi-layered natural sway simulation mimicking light breeze // Primary sine wave for main movement var primarySway = Math.sin(LK.ticks * self.swaySpeed + self.swayOffset) * 0.008 * self.windVariation; // Secondary sine wave for complexity and natural variation var secondarySway = Math.sin(LK.ticks * self.secondarySwaySpeed + self.secondarySwayOffset) * 0.004 * self.windVariation; // Tertiary micro-movement for realistic rustling var microSway = Math.sin(LK.ticks * 0.01 + self.swayOffset * 2) * 0.002; // Combine all movement layers for natural breeze effect var totalSway = primarySway + secondarySway + microSway; branchGraphics.rotation += totalSway; // Subtle scale variation to simulate depth movement in breeze var scaleVariation = 1.0 + Math.sin(LK.ticks * self.swaySpeed * 0.7 + self.swayOffset) * 0.01; branchGraphics.scaleX = scaleVariation; }; return self; }); var WaterRipple = Container.expand(function () { var self = Container.call(this); var rippleGraphics = self.attachAsset('waterRipple', { anchorX: 0.5, anchorY: 0.5 }); // Start invisible and small rippleGraphics.alpha = 0; rippleGraphics.scaleX = 0.05; rippleGraphics.scaleY = 0.05; self.isActive = false; self.maxScale = 0.8 + Math.random() * 0.4; // Very low amplitude for barely stirring water self.expandDuration = 15000 + Math.random() * 10000; // Extremely slow 15-25 seconds expansion // Enhanced shader-based animation properties self.noiseOffset = Math.random() * Math.PI * 2; self.noiseOffset2 = Math.random() * Math.PI * 2; self.noiseSpeed = 0.0003 + Math.random() * 0.0002; // Extremely slow noise scrolling self.distortionAmplitude = 0.008 + Math.random() * 0.005; // Minimal distortion for subtle undulations self.scrollDirection = Math.random() * Math.PI * 2; // Random scroll direction self.rippleFrequency = 0.1 + Math.random() * 0.05; // Infrequent pulse frequency self.noiseScrollX = 0; self.noiseScrollY = 0; self.radialOffset = Math.random() * Math.PI * 2; // For radial outward movement self.reflectionShift = 0; // For elongated reflection simulation self.startRipple = function () { if (self.isActive) return; self.isActive = true; // Reset noise pattern position self.noiseScrollX = 0; self.noiseScrollY = 0; self.reflectionShift = 0; // Extremely gentle fade in with very minimal alpha tween(rippleGraphics, { alpha: 0.08, scaleX: 0.1, scaleY: 0.1 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { // Extremely slow main expansion phase with gradual fade tween(rippleGraphics, { alpha: 0, scaleX: self.maxScale, scaleY: self.maxScale }, { duration: self.expandDuration, easing: tween.easeOut, onFinish: function onFinish() { // Reset for reuse self.isActive = false; rippleGraphics.alpha = 0; rippleGraphics.scaleX = 0.05; rippleGraphics.scaleY = 0.05; } }); } }); }; self.update = function () { if (!self.isActive) return; // Enhanced shader-based noise pattern simulation for natural water movement self.noiseScrollX += Math.cos(self.scrollDirection) * self.noiseSpeed; self.noiseScrollY += Math.sin(self.scrollDirection) * self.noiseSpeed; // Multi-layered noise for complex water surface simulation var primaryNoise = Math.sin(LK.ticks * self.noiseSpeed + self.noiseOffset) * self.distortionAmplitude; var secondaryNoise = Math.cos(LK.ticks * self.noiseSpeed * 1.7 + self.noiseOffset2 + Math.PI) * self.distortionAmplitude * 0.6; var tertiaryNoise = Math.sin(LK.ticks * self.noiseSpeed * 0.5 + self.noiseOffset + Math.PI * 0.5) * self.distortionAmplitude * 0.3; // Radial outward movement simulation var radialPulse = Math.sin(LK.ticks * self.rippleFrequency + self.radialOffset) * 0.002; var radialExpansion = Math.cos(LK.ticks * self.rippleFrequency * 0.7 + self.radialOffset) * 0.001; // Apply extremely subtle rotation distortion for natural water movement rippleGraphics.rotation = (primaryNoise + secondaryNoise * 0.5) * 0.3; // Apply minimal position distortion for gentle drift rippleGraphics.x = (secondaryNoise + tertiaryNoise) * 1.5 + radialPulse * 50; rippleGraphics.y = (primaryNoise + tertiaryNoise * 0.8) * 1.2 + radialPulse * 30; // Simulate scrolling texture pattern with very subtle alpha variation var scrollPattern = Math.sin(self.noiseScrollX * 8) * Math.cos(self.noiseScrollY * 6) * 0.015; var reflectionPattern = Math.sin(self.reflectionShift * 0.1) * 0.01; self.reflectionShift += self.noiseSpeed * 100; // Apply elongated reflection shifts for sky/land reflection simulation rippleGraphics.skewX = (primaryNoise + reflectionPattern) * 0.02; rippleGraphics.skewY = (secondaryNoise + reflectionPattern * 0.7) * 0.015; // Combine all patterns for final alpha with natural pulsing var combinedAlpha = scrollPattern + reflectionPattern + radialExpansion; rippleGraphics.alpha = Math.max(0, Math.min(0.12, rippleGraphics.alpha + combinedAlpha)); }; return self; }); var WeatherParticle = Container.expand(function (weatherType) { var self = Container.call(this); self.weatherType = weatherType || 'rain'; self.speed = 0; self.drift = 0; self.initialX = 0; var assetName = weatherType === 'rain' ? 'rainDrop' : 'snowFlake'; var particleGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); if (weatherType === 'rain') { particleGraphics.alpha = 0.6 + Math.random() * 0.4; self.speed = 8 + Math.random() * 4; self.drift = (Math.random() - 0.5) * 2; } else if (weatherType === 'snow') { particleGraphics.alpha = 0.7 + Math.random() * 0.3; self.speed = 2 + Math.random() * 2; self.drift = (Math.random() - 0.5) * 4; self.floatOffset = Math.random() * Math.PI * 2; self.floatSpeed = 0.02 + Math.random() * 0.02; } self.update = function () { if (self.weatherType === 'rain') { self.y += self.speed; self.x += self.drift; } else if (self.weatherType === 'snow') { self.y += self.speed; self.x = self.initialX + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 30; particleGraphics.rotation += 0.01; } // Reset particle when it goes off screen if (self.y > 2780) { self.y = -50; self.x = Math.random() * 2048; self.initialX = self.x; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1B5E20 }); /**** * Game Code ****/ // Game state var gameState = 'exploration'; // 'exploration' or 'haven' var currentBiome = 0; var biomes = ['Whispering Woods', 'Crystal Caverns', 'Serene Shoreline', 'Starfall Sanctuary']; var biomeColors = [0xd7e4bd, 0xe1bee7, 0xb2dfdb, 0xc5cae9]; var biomeMusicTracks = ['whisperingWoods', 'crystalCaverns', 'sereneShore', 'starfallSanctuary']; var currentMusicTrack = null; var musicFadeTime = 2000; // ASMR ambient sound tracking var currentAmbientSounds = []; var lastFootstepTime = 0; var footstepInterval = 800; // milliseconds between footsteps var biomeAmbientSounds = [['birdChirps', 'lightRain'], // Whispering Woods ['caveDrops', 'fireflies'], // Crystal Caverns ['streamMurmur', 'windChimes'], // Serene Shoreline ['fireflies', 'gentleFire'] // Starfall Sanctuary ]; // Player and game objects var player = new Player(); var auraParticles = []; var havenDecorations = []; var floatingParticles = []; var luminescentParticles = []; var rareBloom = null; var rareBloomTimer = 0; var rareBloomSpawnInterval = 1800; // 30 seconds at 60fps var ephemeralCreature = null; var ephemeralTimer = 0; var ephemeralSpawnInterval = 3600; // 60 seconds at 60fps var ephemeralCreatureTypes = ['fox', 'hummingbird', 'spirit']; var hiddenVignettes = []; var vignetteTypes = ['mushroom', 'waterfall', 'bear']; var vignetteDiscoveryRadius = 120; // Weather system var currentWeather = 'clear'; // 'clear', 'rain', 'snow' var weatherParticles = []; var weatherTimer = 0; var weatherCheckInterval = 1800; // 30 seconds at 60fps var weatherDuration = 3600; // 60 seconds at 60fps var weatherEndTimer = 0; var isWeatherActive = false; // Water ripple system var waterRipples = []; var rippleTimer = 0; var rippleSpawnInterval = 900 + Math.random() * 1200; // 15-35 seconds at 60fps for extremely slow, infrequent ripples var maxActiveRipples = 3; // Zen moment system var zenMomentTimer = 0; var zenMomentInterval = 4500; // 75 seconds at 60fps of continuous activity var isZenMomentActive = false; var zenMomentDuration = 480; // 8 seconds at 60fps var zenMomentEndTimer = 0; var originalBackgroundTint = 0x000000; var zenAffirmations = ['Find your calm', 'Embrace tranquility', 'You are here', 'Breathe deeply', 'Peace flows through you', 'This moment is yours', 'Feel the serenity']; var zenText = null; // Tree sway system var treeSwayBranches = []; // Light shimmer system var lightShimmers = []; // Aura wisp system var auraWisps = []; var wispSpawnTimer = 0; var wispSpawnInterval = 120 + Math.random() * 180; // 2-5 seconds at 60fps var maxActiveWisps = 6; // Ephemeral shimmer particles var ephemeralShimmers = []; // Distant cloud system var distantClouds = []; // Rare bloom burst particles var rareBloomBursts = []; var biomeBackground = null; var havenBackground = null; // Aura collection tracking var auraCount = storage.auraCount || { green: 0, blue: 0, yellow: 0 }; var totalAuras = auraCount.green + auraCount.blue + auraCount.yellow; // UI elements var auraCountText = new Text2('Auras: ' + totalAuras, { size: 80, fill: 0xFFFFFF }); auraCountText.anchor.set(0.5, 0); var biomeText = new Text2(biomes[currentBiome], { size: 60, fill: 0xFFFFFF }); biomeText.anchor.set(0.5, 0); var havenButton = new Text2('Haven', { size: 70, fill: 0xFFEB3B }); havenButton.anchor.set(1, 0); var exploreButton = new Text2('Explore', { size: 70, fill: 0x4CAF50 }); exploreButton.anchor.set(0, 0); // Add UI to GUI LK.gui.top.addChild(auraCountText); LK.gui.top.addChild(biomeText); LK.gui.topRight.addChild(havenButton); LK.gui.topLeft.addChild(exploreButton); // Position UI elements auraCountText.y = 20; biomeText.y = 120; havenButton.x = -20; havenButton.y = 20; exploreButton.x = 120; exploreButton.y = 20; // Initialize game function initializeExploration() { gameState = 'exploration'; // Clear existing objects if (biomeBackground) biomeBackground.destroy(); if (havenBackground) havenBackground.destroy(); // Create biome background biomeBackground = game.addChild(LK.getAsset('biomeBackground', { anchorX: 0, anchorY: 0, x: 0, y: 0, tint: biomeColors[currentBiome] })); // Add player player.x = 1024; player.y = 1366; player.targetX = player.x; player.targetY = player.y; game.addChild(player); // Generate aura particles generateAuraParticles(); // Generate floating ambient particles generateFloatingParticles(); // Generate luminescent particles for magical atmosphere generateLuminescentParticles(); // Generate gentle tree sway for natural ambiance generateTreeSway(); // Generate subtle light shimmer for sky ambiance generateLightShimmer(); // Generate distant clouds for background movement generateDistantClouds(); // Spawn hidden vignettes for discovery spawnHiddenVignettes(); // Reset rare bloom timer rareBloomTimer = Math.floor(Math.random() * rareBloomSpawnInterval); // Clear ephemeral creature if (ephemeralCreature) { ephemeralCreature.destroy(); ephemeralCreature = null; } // Reset ephemeral timer ephemeralTimer = Math.floor(Math.random() * ephemeralSpawnInterval); // Reset weather timer weatherTimer = Math.floor(Math.random() * weatherCheckInterval); // Reset zen moment timer zenMomentTimer = Math.floor(Math.random() * zenMomentInterval); // Reset water ripple timer rippleTimer = Math.floor(Math.random() * rippleSpawnInterval); // Reset aura wisp timer wispSpawnTimer = Math.floor(Math.random() * wispSpawnInterval); // Update UI biomeText.setText(biomes[currentBiome]); biomeText.visible = true; exploreButton.visible = false; havenButton.visible = true; // Play biome-specific music and ambient sounds playBiomeMusic(currentBiome); playAmbientSounds(currentBiome); } function initializeHaven() { gameState = 'haven'; // Clear existing objects if (biomeBackground) biomeBackground.destroy(); clearAuraParticles(); clearFloatingParticles(); clearLuminescentParticles(); clearHiddenVignettes(); // Clear rare bloom if (rareBloom) { rareBloom.destroy(); rareBloom = null; } // Clear ephemeral creature if (ephemeralCreature) { ephemeralCreature.destroy(); ephemeralCreature = null; } // Clear weather effects if (isWeatherActive) { endWeatherTransformation(); } // Clear zen moment if (isZenMomentActive) { endZenMoment(); } // Clear water ripples clearWaterRipples(); // Clear tree sway clearTreeSway(); // Clear light shimmer clearLightShimmer(); // Clear aura wisps clearAuraWisps(); // Clear ephemeral shimmers clearEphemeralShimmers(); // Clear distant clouds clearDistantClouds(); // Clear rare bloom bursts clearRareBloomBursts(); // Create haven background havenBackground = game.addChild(LK.getAsset('havenBackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Remove player from haven if (player.parent) player.parent.removeChild(player); // Load existing decorations loadHavenDecorations(); // Update UI biomeText.visible = false; exploreButton.visible = true; havenButton.visible = false; // Stop exploration ambient sounds for (var i = 0; i < currentAmbientSounds.length; i++) { var sound = LK.getSound(currentAmbientSounds[i]); sound.loop = false; sound.stop(); } currentAmbientSounds = []; // Play haven ambient music playHavenMusic(); } function generateAuraParticles() { clearAuraParticles(); var particleCount = 15 + Math.floor(Math.random() * 10); var auraTypes = ['green', 'blue', 'yellow']; for (var i = 0; i < particleCount; i++) { var auraType = auraTypes[Math.floor(Math.random() * auraTypes.length)]; var aura = new AuraParticle(auraType); aura.x = 100 + Math.random() * 1848; aura.y = 200 + Math.random() * 2332; aura.initialY = aura.y; auraParticles.push(aura); game.addChild(aura); } } function clearAuraParticles() { for (var i = auraParticles.length - 1; i >= 0; i--) { auraParticles[i].destroy(); auraParticles.splice(i, 1); } } function generateFloatingParticles() { clearFloatingParticles(); var particleCount = 20 + Math.floor(Math.random() * 15); for (var i = 0; i < particleCount; i++) { var particle = new FloatingParticle(); particle.x = Math.random() * 2048; particle.y = Math.random() * 2732; particle.initialX = particle.x; floatingParticles.push(particle); game.addChild(particle); } } function clearFloatingParticles() { for (var i = floatingParticles.length - 1; i >= 0; i--) { floatingParticles[i].destroy(); floatingParticles.splice(i, 1); } } function generateLuminescentParticles() { clearLuminescentParticles(); // Low spawn rate for sparse, ethereal feel var particleCount = 8 + Math.floor(Math.random() * 6); for (var i = 0; i < particleCount; i++) { var particle = new LuminescentParticle(); // Focus particles over magical areas with sparse distribution var spawnArea = Math.random(); if (spawnArea < 0.3) { // Over water area (magical reflections) particle.x = 300 + Math.random() * 1448; particle.y = 1600 + Math.random() * 1000; } else if (spawnArea < 0.6) { // Near mystical trees/edges particle.x = Math.random() < 0.5 ? Math.random() * 250 : 1798 + Math.random() * 250; particle.y = 200 + Math.random() * 2200; } else { // Scattered throughout for ambient magic particle.x = Math.random() * 2048; particle.y = 200 + Math.random() * 2200; } particle.initialX = particle.x; luminescentParticles.push(particle); game.addChild(particle); } } function clearLuminescentParticles() { for (var i = luminescentParticles.length - 1; i >= 0; i--) { luminescentParticles[i].destroy(); luminescentParticles.splice(i, 1); } } function clearEphemeralShimmers() { for (var i = ephemeralShimmers.length - 1; i >= 0; i--) { ephemeralShimmers[i].destroy(); ephemeralShimmers.splice(i, 1); } } function generateDistantClouds() { clearDistantClouds(); // Sparse cloud coverage for background ambiance var cloudCount = 3 + Math.floor(Math.random() * 4); for (var i = 0; i < cloudCount; i++) { var cloud = new DistantCloud(); // Position clouds in upper portion of sky cloud.x = Math.random() * 2400; // Start some off-screen cloud.y = 100 + Math.random() * 400; // Upper sky area cloud.initialX = cloud.x; cloud.initialY = cloud.y; // Vary cloud sizes for depth var depthScale = 0.4 + Math.random() * 0.8; cloud.scaleX = depthScale; cloud.scaleY = depthScale; distantClouds.push(cloud); game.addChild(cloud); } } function clearDistantClouds() { for (var i = distantClouds.length - 1; i >= 0; i--) { distantClouds[i].destroy(); distantClouds.splice(i, 1); } } function clearRareBloomBursts() { for (var i = rareBloomBursts.length - 1; i >= 0; i--) { rareBloomBursts[i].destroy(); rareBloomBursts.splice(i, 1); } } function spawnRareBloom() { if (rareBloom) return; // Only one rare bloom at a time rareBloom = new RareAuraBloom(); rareBloom.x = 200 + Math.random() * 1648; rareBloom.y = 300 + Math.random() * 2132; rareBloom.initialY = rareBloom.y; game.addChild(rareBloom); // Play appearance sound LK.getSound('rareBloomAppear').play(); // Create burst of light effect LK.effects.flashScreen(0xffd700, 800); // Reset timer for next spawn rareBloomTimer = 0; } function spawnEphemeralCreature() { if (ephemeralCreature) return; // Only one ephemeral creature at a time var creatureType = ephemeralCreatureTypes[Math.floor(Math.random() * ephemeralCreatureTypes.length)]; ephemeralCreature = new EphemeralCreature(creatureType); // Position away from player for mystical discovery var playerDistance = 300 + Math.random() * 400; var angle = Math.random() * Math.PI * 2; ephemeralCreature.x = Math.max(100, Math.min(1948, player.x + Math.cos(angle) * playerDistance)); ephemeralCreature.y = Math.max(200, Math.min(2532, player.y + Math.sin(angle) * playerDistance)); ephemeralCreature.initialY = ephemeralCreature.y; game.addChild(ephemeralCreature); // Play gentle appearance sound LK.getSound('ephemeralAppear').play(); // Trigger appearance animation ephemeralCreature.appear(); // Reset timer for next spawn ephemeralTimer = Math.floor(Math.random() * ephemeralSpawnInterval) + ephemeralSpawnInterval; } function spawnHiddenVignettes() { clearHiddenVignettes(); // Spawn 2-4 vignettes per biome in obscure corners var vignetteCount = 2 + Math.floor(Math.random() * 3); for (var i = 0; i < vignetteCount; i++) { var vignetteType = vignetteTypes[Math.floor(Math.random() * vignetteTypes.length)]; var vignette = new HiddenVignette(vignetteType); // Position in obscure corners and edges of map var cornerPositions = [{ x: 150, y: 250 }, // Top-left corner { x: 1900, y: 250 }, // Top-right corner { x: 150, y: 2500 }, // Bottom-left corner { x: 1900, y: 2500 }, // Bottom-right corner { x: 1024, y: 150 }, // Top center hidden { x: 100, y: 1366 }, // Left edge hidden { x: 1948, y: 1366 }, // Right edge hidden { x: 1024, y: 2600 } // Bottom center hidden ]; var position = cornerPositions[Math.floor(Math.random() * cornerPositions.length)]; // Add some randomness to exact position vignette.x = position.x + (Math.random() - 0.5) * 200; vignette.y = position.y + (Math.random() - 0.5) * 200; // Ensure vignette stays within bounds vignette.x = Math.max(100, Math.min(1948, vignette.x)); vignette.y = Math.max(200, Math.min(2532, vignette.y)); hiddenVignettes.push(vignette); game.addChild(vignette); } } function clearHiddenVignettes() { for (var i = hiddenVignettes.length - 1; i >= 0; i--) { hiddenVignettes[i].destroy(); hiddenVignettes.splice(i, 1); } } function loadHavenDecorations() { var savedDecorations = storage.havenDecorations || []; for (var i = 0; i < savedDecorations.length; i++) { var decorationData = savedDecorations[i]; var decoration = new HavenDecoration(decorationData.type); decoration.x = decorationData.x; decoration.y = decorationData.y; havenDecorations.push(decoration); game.addChild(decoration); } } function saveHavenDecorations() { var decorationData = []; for (var i = 0; i < havenDecorations.length; i++) { var decoration = havenDecorations[i]; decorationData.push({ type: decoration.decorationType, x: decoration.x, y: decoration.y }); } storage.havenDecorations = decorationData; } function updateUI() { totalAuras = auraCount.green + auraCount.blue + auraCount.yellow; auraCountText.setText('Auras: ' + totalAuras); storage.auraCount = auraCount; } function playAmbientSounds(biomeIndex) { // Stop current ambient sounds for (var i = 0; i < currentAmbientSounds.length; i++) { var sound = LK.getSound(currentAmbientSounds[i]); sound.loop = false; sound.stop(); } currentAmbientSounds = []; // Start new ambient sounds for this biome var sounds = biomeAmbientSounds[biomeIndex]; for (var j = 0; j < sounds.length; j++) { var sound = LK.getSound(sounds[j]); sound.loop = true; sound.play(); currentAmbientSounds.push(sounds[j]); } } function playBiomeMusic(biomeIndex) { var targetTrack = biomeMusicTracks[biomeIndex]; if (currentMusicTrack === targetTrack) return; if (currentMusicTrack) { // Fade out current music LK.playMusic(currentMusicTrack, { fade: { start: 0.7, end: 0, duration: musicFadeTime } }); LK.setTimeout(function () { // Fade in new music LK.playMusic(targetTrack, { fade: { start: 0, end: 0.7, duration: musicFadeTime } }); currentMusicTrack = targetTrack; }, musicFadeTime); } else { // First time playing music LK.playMusic(targetTrack, { fade: { start: 0, end: 0.7, duration: musicFadeTime } }); currentMusicTrack = targetTrack; } } function startWeatherTransformation() { if (isWeatherActive || gameState !== 'exploration') return; // Small chance for weather (10% chance each check) if (Math.random() > 0.1) return; // Choose weather type (equal chance for rain or snow) var weatherTypes = ['rain', 'snow']; currentWeather = weatherTypes[Math.floor(Math.random() * weatherTypes.length)]; isWeatherActive = true; weatherEndTimer = 0; // Create weather particles generateWeatherParticles(); // Play weather ambient sound var soundName = currentWeather === 'rain' ? 'gentleRain' : 'softSnow'; var weatherSound = LK.getSound(soundName); weatherSound.loop = true; weatherSound.play(); currentAmbientSounds.push(soundName); // Gentle screen tint for weather atmosphere if (currentWeather === 'rain') { tween(biomeBackground, { tint: 0x8fa5c7 }, { duration: 3000, easing: tween.easeInOut }); } else if (currentWeather === 'snow') { tween(biomeBackground, { tint: 0xc8d6e5 }, { duration: 3000, easing: tween.easeInOut }); } } function endWeatherTransformation() { if (!isWeatherActive) return; isWeatherActive = false; clearWeatherParticles(); // Stop weather ambient sound var soundName = currentWeather === 'rain' ? 'gentleRain' : 'softSnow'; var weatherSound = LK.getSound(soundName); weatherSound.loop = false; weatherSound.stop(); var soundIndex = currentAmbientSounds.indexOf(soundName); if (soundIndex > -1) { currentAmbientSounds.splice(soundIndex, 1); } // Restore original biome tint if (biomeBackground) { tween(biomeBackground, { tint: biomeColors[currentBiome] }, { duration: 3000, easing: tween.easeInOut }); } currentWeather = 'clear'; weatherTimer = Math.floor(Math.random() * weatherCheckInterval); } function generateWeatherParticles() { clearWeatherParticles(); var particleCount = currentWeather === 'rain' ? 25 : 20; for (var i = 0; i < particleCount; i++) { var particle = new WeatherParticle(currentWeather); particle.x = Math.random() * 2200; // Slightly wider than screen particle.y = Math.random() * 2800; particle.initialX = particle.x; weatherParticles.push(particle); game.addChild(particle); } } function clearWeatherParticles() { for (var i = weatherParticles.length - 1; i >= 0; i--) { weatherParticles[i].destroy(); weatherParticles.splice(i, 1); } } function generateWaterRipple() { // Only spawn ripples in Serene Shoreline biome (index 2) if (currentBiome !== 2 || gameState !== 'exploration') return; // Limit number of active ripples var activeRipples = 0; for (var i = 0; i < waterRipples.length; i++) { if (waterRipples[i].isActive) activeRipples++; } if (activeRipples >= maxActiveRipples) return; // Find an inactive ripple to reuse, or create new one var ripple = null; for (var j = 0; j < waterRipples.length; j++) { if (!waterRipples[j].isActive) { ripple = waterRipples[j]; break; } } if (!ripple) { ripple = new WaterRipple(); waterRipples.push(ripple); game.addChild(ripple); } // Position ripple in lower half of screen (lake area) ripple.x = 300 + Math.random() * 1448; // Avoid edges ripple.y = 1500 + Math.random() * 800; // Lower half for lake // Start the ripple animation ripple.startRipple(); // Reset timer with some randomness rippleTimer = 0; rippleSpawnInterval = 900 + Math.random() * 1200; // Extremely slow ripple spawn timing } function clearWaterRipples() { for (var i = waterRipples.length - 1; i >= 0; i--) { waterRipples[i].destroy(); waterRipples.splice(i, 1); } } function generateTreeSway() { clearTreeSway(); var branchCount = 8 + Math.floor(Math.random() * 6); // 8-14 swaying branches for (var i = 0; i < branchCount; i++) { var branch = new TreeSwayBranch(); // Position trees in foreground (edges) and mid-ground areas var positionArea = Math.random(); if (positionArea < 0.3) { // Left foreground trees branch.x = 50 + Math.random() * 300; branch.y = 400 + Math.random() * 1800; } else if (positionArea < 0.6) { // Right foreground trees branch.x = 1700 + Math.random() * 300; branch.y = 400 + Math.random() * 1800; } else { // Mid-ground scattered trees branch.x = 300 + Math.random() * 1400; branch.y = 200 + Math.random() * 1200; } // Vary branch sizes for depth var depthScale = 0.6 + Math.random() * 0.8; branch.scaleX = depthScale; branch.scaleY = depthScale; // Start the gentle swaying animation branch.startSway(); treeSwayBranches.push(branch); game.addChild(branch); } } function clearTreeSway() { for (var i = treeSwayBranches.length - 1; i >= 0; i--) { treeSwayBranches[i].destroy(); treeSwayBranches.splice(i, 1); } } function generateLightShimmer() { clearLightShimmer(); // Create 1-3 light sources depending on biome (sun/moon/stars) var shimmerCount = 1 + Math.floor(Math.random() * 3); for (var i = 0; i < shimmerCount; i++) { var shimmer = new LightShimmer(); // Position light sources in upper portion of sky if (shimmerCount === 1) { // Single main light source (sun/moon) positioned in upper third shimmer.x = 800 + Math.random() * 400; // Center-ish area shimmer.y = 200 + Math.random() * 400; // Upper third } else { // Multiple light sources (stars, etc.) scattered in upper half shimmer.x = 200 + Math.random() * 1648; shimmer.y = 100 + Math.random() * 600; } // Vary shimmer sizes for depth and variety var sizeScale = 0.5 + Math.random() * 1.0; shimmer.scaleX = sizeScale; shimmer.scaleY = sizeScale; // Start the gentle shimmer breathing animation shimmer.startShimmer(); lightShimmers.push(shimmer); game.addChild(shimmer); } } function clearLightShimmer() { for (var i = lightShimmers.length - 1; i >= 0; i--) { lightShimmers[i].destroy(); lightShimmers.splice(i, 1); } } function generateAuraWisp() { if (gameState !== 'exploration') return; // Limit number of active wisps var activeWisps = 0; for (var i = 0; i < auraWisps.length; i++) { if (!auraWisps[i].collected) activeWisps++; } if (activeWisps >= maxActiveWisps) return; // Choose wisp type based on current biome preference var wispTypes = ['green', 'blue', 'yellow']; var wispType = wispTypes[Math.floor(Math.random() * wispTypes.length)]; var wisp = new AuraWisp(wispType); // Position wisp to emerge from environmental elements var emergenceLocations = [ // From under rocks (bottom edges) { x: 100 + Math.random() * 300, y: 2400 + Math.random() * 200 }, { x: 1600 + Math.random() * 300, y: 2400 + Math.random() * 200 }, // Near glowing mushrooms (mid areas) { x: 400 + Math.random() * 1200, y: 1200 + Math.random() * 800 }, // From within tree trunks (forest edges) { x: 50 + Math.random() * 200, y: 600 + Math.random() * 1200 }, { x: 1800 + Math.random() * 200, y: 600 + Math.random() * 1200 }, // From crystal formations (upper areas for crystal caverns) { x: 300 + Math.random() * 1400, y: 300 + Math.random() * 600 }]; var location = emergenceLocations[Math.floor(Math.random() * emergenceLocations.length)]; // Add some randomness to exact position wisp.x = location.x + (Math.random() - 0.5) * 100; wisp.y = location.y + (Math.random() - 0.5) * 100; wisp.initialY = wisp.y; // Ensure wisp stays within bounds wisp.x = Math.max(50, Math.min(1998, wisp.x)); wisp.y = Math.max(200, Math.min(2532, wisp.y)); auraWisps.push(wisp); game.addChild(wisp); // Reset timer with some randomness wispSpawnTimer = 0; wispSpawnInterval = 120 + Math.random() * 180; } function clearAuraWisps() { for (var i = auraWisps.length - 1; i >= 0; i--) { auraWisps[i].destroy(); auraWisps.splice(i, 1); } } function triggerZenMoment() { if (isZenMomentActive || gameState !== 'exploration') return; isZenMomentActive = true; zenMomentEndTimer = 0; // Store original background tint if (biomeBackground) { originalBackgroundTint = biomeBackground.tint; // Subtle desaturation effect tween(biomeBackground, { tint: 0xb0b0b0 }, { duration: 2000, easing: tween.easeInOut }); } // Create zen affirmation text var affirmation = zenAffirmations[Math.floor(Math.random() * zenAffirmations.length)]; zenText = new Text2(affirmation, { size: 120, fill: 0xffffff }); zenText.anchor.set(0.5, 0.5); zenText.alpha = 0; // Position zen text in center LK.gui.center.addChild(zenText); // Gentle fade in for zen text - ensure zenText exists before tweening if (zenText) { tween(zenText, { alpha: 0.9, scaleX: 1.1, scaleY: 1.1 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { // Gentle pulsing while displayed - check zenText still exists if (zenText) { tween(zenText, { alpha: 0.7, scaleX: 1.0, scaleY: 1.0 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (zenText) { tween(zenText, { alpha: 0.9, scaleX: 1.1, scaleY: 1.1 }, { duration: 1000, easing: tween.easeInOut }); } } }); } } }); } // Play gentle zen bell sound LK.getSound('zenMomentBell').play(); // Play zen moment music (very minimalistic) var currentVolume = 0.7; if (currentMusicTrack) { // Fade current music to lower volume LK.playMusic(currentMusicTrack, { fade: { start: currentVolume, end: 0.2, duration: 1500 } }); } // Start zen music softly LK.playMusic('zenMomentMusic', { fade: { start: 0, end: 0.3, duration: 1500 } }); } function endZenMoment() { if (!isZenMomentActive) return; isZenMomentActive = false; // Fade out zen text if (zenText && zenText.parent) { tween(zenText, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 2000, easing: tween.easeIn, onFinish: function onFinish() { if (zenText && zenText.parent) { zenText.parent.removeChild(zenText); } zenText = null; } }); } else if (zenText) { // If zenText exists but has no parent, just set to null zenText = null; } // Restore original background tint if (biomeBackground) { tween(biomeBackground, { tint: originalBackgroundTint }, { duration: 2000, easing: tween.easeInOut }); } // Restore original music LK.playMusic('zenMomentMusic', { fade: { start: 0.3, end: 0, duration: 1500 } }); LK.setTimeout(function () { if (currentMusicTrack && currentMusicTrack !== 'zenMomentMusic') { LK.playMusic(currentMusicTrack, { fade: { start: 0.2, end: 0.7, duration: 1500 } }); } }, 1500); // Reset timer for next zen moment zenMomentTimer = Math.floor(Math.random() * zenMomentInterval) + zenMomentInterval; } function playHavenMusic() { if (currentMusicTrack === 'havenAmbient') return; if (currentMusicTrack) { // Fade out current music var prevTrack = currentMusicTrack; LK.playMusic(prevTrack, { fade: { start: 0.7, end: 0, duration: musicFadeTime } }); LK.setTimeout(function () { // Fade in haven music LK.playMusic('havenAmbient', { fade: { start: 0, end: 0.6, duration: musicFadeTime } }); currentMusicTrack = 'havenAmbient'; }, musicFadeTime); } else { // First time playing music LK.playMusic('havenAmbient', { fade: { start: 0, end: 0.6, duration: musicFadeTime } }); currentMusicTrack = 'havenAmbient'; } } // Touch/Mouse handlers var draggedDecoration = null; var isPlacingDecoration = false; game.move = function (x, y, obj) { if (gameState === 'exploration') { player.targetX = x; player.targetY = y; } else if (gameState === 'haven' && draggedDecoration) { draggedDecoration.x = x; draggedDecoration.y = y; } }; game.down = function (x, y, obj) { if (gameState === 'haven') { // Check if touching a decoration for (var i = 0; i < havenDecorations.length; i++) { var decoration = havenDecorations[i]; var dx = x - decoration.x; var dy = y - decoration.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 60) { draggedDecoration = decoration; // Play rustle sound for plant interactions if (decoration.decorationType === 'plant') { LK.getSound('plantRustle').play(); } break; } } // Try to place new decoration if not dragging if (!draggedDecoration && totalAuras >= 10) { var decorationTypes = ['plant', 'light', 'water']; var randomType = decorationTypes[Math.floor(Math.random() * decorationTypes.length)]; var newDecoration = new HavenDecoration(randomType); newDecoration.x = x; newDecoration.y = y; havenDecorations.push(newDecoration); game.addChild(newDecoration); auraCount.green = Math.max(0, auraCount.green - 4); auraCount.blue = Math.max(0, auraCount.blue - 3); auraCount.yellow = Math.max(0, auraCount.yellow - 3); updateUI(); saveHavenDecorations(); LK.getSound('placeItem').play(); } } }; game.up = function (x, y, obj) { if (draggedDecoration) { saveHavenDecorations(); draggedDecoration = null; } }; // Button handlers havenButton.down = function (x, y, obj) { if (gameState === 'exploration') { initializeHaven(); } }; exploreButton.down = function (x, y, obj) { if (gameState === 'haven') { initializeExploration(); } }; // Main game update loop game.update = function () { if (gameState === 'exploration') { // Check rare bloom spawning rareBloomTimer++; if (rareBloomTimer >= rareBloomSpawnInterval && !rareBloom) { spawnRareBloom(); } // Check ephemeral creature spawning ephemeralTimer++; if (ephemeralTimer >= ephemeralSpawnInterval && !ephemeralCreature) { spawnEphemeralCreature(); } // Check weather transformations weatherTimer++; if (weatherTimer >= weatherCheckInterval && !isWeatherActive) { startWeatherTransformation(); } // Check zen moment triggering zenMomentTimer++; if (zenMomentTimer >= zenMomentInterval && !isZenMomentActive) { triggerZenMoment(); } // Check water ripple spawning (only in Serene Shoreline) if (currentBiome === 2) { rippleTimer++; if (rippleTimer >= rippleSpawnInterval) { generateWaterRipple(); } } // Check aura wisp spawning wispSpawnTimer++; if (wispSpawnTimer >= wispSpawnInterval) { generateAuraWisp(); } // Clean up collected wisps for (var w = auraWisps.length - 1; w >= 0; w--) { if (auraWisps[w].collected) { auraWisps.splice(w, 1); } } // Clean up expired ephemeral shimmers for (var s = ephemeralShimmers.length - 1; s >= 0; s--) { if (!ephemeralShimmers[s].parent) { ephemeralShimmers.splice(s, 1); } } // Clean up expired rare bloom burst particles for (var b = rareBloomBursts.length - 1; b >= 0; b--) { if (!rareBloomBursts[b].parent) { rareBloomBursts.splice(b, 1); } } // Check zen moment duration if (isZenMomentActive) { zenMomentEndTimer++; if (zenMomentEndTimer >= zenMomentDuration) { endZenMoment(); } } // Check weather duration if (isWeatherActive) { weatherEndTimer++; if (weatherEndTimer >= weatherDuration) { endWeatherTransformation(); } } // Check hidden vignette discovery for (var v = 0; v < hiddenVignettes.length; v++) { var vignette = hiddenVignettes[v]; if (!vignette.discovered) { var dx = player.x - vignette.x; var dy = player.y - vignette.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < vignetteDiscoveryRadius) { vignette.discover(); } } } // Check rare bloom collection if (rareBloom && !rareBloom.collected && player.intersects(rareBloom)) { rareBloom.collected = true; // Award significant auras (5 of each type) auraCount.green += 5; auraCount.blue += 5; auraCount.yellow += 5; updateUI(); // Play special collection sound LK.getSound('rareBloomCollect').play(); // Create spectacular visual effect LK.effects.flashScreen(0xffd700, 1500); // Create burst of glowing particles (medium count for spectacular effect) for (var b = 0; b < 12; b++) { var burstParticle = new RareBloomBurst(); burstParticle.x = rareBloom.x; burstParticle.y = rareBloom.y; rareBloomBursts.push(burstParticle); game.addChild(burstParticle); } // Burst animation with swirl of particles tween(rareBloom, { scaleX: 3.0, scaleY: 3.0, alpha: 1.0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(rareBloom, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { rareBloom.destroy(); rareBloom = null; // Reset timer for next rare bloom rareBloomTimer = Math.floor(Math.random() * rareBloomSpawnInterval); } }); } }); } // Check aura collection for (var i = auraParticles.length - 1; i >= 0; i--) { var aura = auraParticles[i]; if (!aura.collected && player.intersects(aura)) { aura.collected = true; auraCount[aura.type]++; updateUI(); // Collect animation with gentle glow effect tween(aura, { scaleX: 2.0, scaleY: 2.0, alpha: 1.0 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(aura, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { aura.destroy(); } }); } }); auraParticles.splice(i, 1); LK.getSound('collectAura').play(); } } // Check if all auras collected if (auraParticles.length === 0) { LK.setTimeout(function () { currentBiome = (currentBiome + 1) % biomes.length; generateAuraParticles(); // Update biome display and music biomeText.setText(biomes[currentBiome]); if (biomeBackground) { biomeBackground.tint = biomeColors[currentBiome]; } playBiomeMusic(currentBiome); playAmbientSounds(currentBiome); }, 1000); } } }; // Start the game initializeExploration();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AuraParticle = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'green';
self.collected = false;
var assetName = 'aura' + self.type.charAt(0).toUpperCase() + self.type.slice(1);
var auraGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
auraGraphics.alpha = 0.8;
self.floatOffset = Math.random() * Math.PI * 2;
self.floatSpeed = 0.02 + Math.random() * 0.03;
self.pulseOffset = Math.random() * Math.PI * 2;
self.initialY = 0;
self.initialScale = 1.0;
// Start gentle pulsing animation
tween(auraGraphics, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1.0
}, {
duration: 1500 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.collected) {
tween(auraGraphics, {
scaleX: 0.8,
scaleY: 0.8,
alpha: 0.6
}, {
duration: 1500 + Math.random() * 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.collected) {
tween(auraGraphics, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.8
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}
});
}
}
});
self.update = function () {
if (!self.collected) {
self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 8;
auraGraphics.rotation += 0.015;
}
};
return self;
});
var AuraWisp = Container.expand(function (wispType) {
var self = Container.call(this);
self.wispType = wispType || 'green';
self.collected = false;
self.isMovingToPlayer = false;
self.moveSpeed = 3.5;
// Set wisp color based on type
var wispColors = {
green: 0xc8e6c9,
blue: 0xb3d9ff,
yellow: 0xfff8d1
};
var wispGraphics = self.attachAsset('auraWisp', {
anchorX: 0.5,
anchorY: 0.5
});
// Apply wisp type color
wispGraphics.tint = wispColors[self.wispType];
wispGraphics.alpha = 0.7;
self.floatOffset = Math.random() * Math.PI * 2;
self.floatSpeed = 0.025 + Math.random() * 0.015;
self.pulseOffset = Math.random() * Math.PI * 2;
self.initialY = 0;
self.emergeDuration = 120; // 2 seconds to emerge
self.emergeTimer = 0;
// Start gentle emergence animation
tween(wispGraphics, {
alpha: 0.9,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000 + Math.random() * 500,
easing: tween.easeOut,
onFinish: function onFinish() {
if (!self.collected) {
// Start floating towards player
self.isMovingToPlayer = true;
}
}
});
self.moveTowardsPlayer = function () {
if (!player || self.collected) return;
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) {
// Gentle movement towards player
self.x += dx / distance * self.moveSpeed;
self.y += dy / distance * self.moveSpeed;
} else {
// Close enough to be collected
self.collected = true;
// Award small aura
auraCount[self.wispType]++;
updateUI();
// Gentle collection animation
tween(wispGraphics, {
scaleX: 1.8,
scaleY: 1.8,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(wispGraphics, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.destroy();
}
});
}
});
LK.getSound('collectAura').play();
}
};
self.update = function () {
if (self.collected) return;
if (!self.isMovingToPlayer) {
// Gentle floating motion while emerging
self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 6;
self.emergeTimer++;
// Start moving towards player after emergence period
if (self.emergeTimer >= self.emergeDuration) {
self.isMovingToPlayer = true;
}
} else {
// Move towards player with gentle floating motion
self.moveTowardsPlayer();
// Add gentle floating while moving
var floatMotion = Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 4;
self.y += floatMotion * 0.1;
}
// Gentle pulsing glow
wispGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.04 + self.pulseOffset) * 0.3;
wispGraphics.rotation += 0.01;
};
return self;
});
var DistantCloud = Container.expand(function () {
var self = Container.call(this);
var cloudGraphics = self.attachAsset('distantCloud', {
anchorX: 0.5,
anchorY: 0.5
});
cloudGraphics.alpha = 0.3 + Math.random() * 0.2;
self.driftSpeed = 0.1 + Math.random() * 0.15; // Extremely slow drift
self.initialX = 0;
self.floatOffset = Math.random() * Math.PI * 2;
self.floatSpeed = 0.003 + Math.random() * 0.005; // Very slow vertical float
self.initialY = 0;
// Start gentle size pulsing for natural cloud variation
tween(cloudGraphics, {
scaleX: 1.1 + Math.random() * 0.2,
scaleY: 1.1 + Math.random() * 0.2
}, {
duration: 8000 + Math.random() * 4000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(cloudGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 8000 + Math.random() * 4000,
easing: tween.easeInOut
});
}
});
self.update = function () {
// Imperceptibly slow horizontal drift - consistent with typical cloud movement
// Enhanced with tween-based smooth transitions for more natural movement
self.x += self.driftSpeed * 0.3; // Reduced to imperceptibly slow speed
// Very subtle vertical floating motion
self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 8;
// Reset cloud when it goes off screen
if (self.x > 2100) {
self.x = -200;
self.initialX = self.x;
// Add subtle tween variation when cloud resets for natural repositioning
tween(self, {
x: self.x + (Math.random() - 0.5) * 100,
y: self.initialY + (Math.random() - 0.5) * 80
}, {
duration: 5000 + Math.random() * 3000,
easing: tween.easeInOut
});
}
};
return self;
});
var EphemeralCreature = Container.expand(function (creatureType) {
var self = Container.call(this);
self.creatureType = creatureType || 'fox';
self.hasAppeared = false;
self.isObserving = false;
self.observeTimer = 0;
self.observeDuration = 180; // 3 seconds at 60fps
var assetName = 'ephemeral' + self.creatureType.charAt(0).toUpperCase() + self.creatureType.slice(1);
var creatureGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Start invisible
creatureGraphics.alpha = 0;
self.floatOffset = Math.random() * Math.PI * 2;
self.floatSpeed = 0.015;
self.initialY = 0;
self.appear = function () {
if (self.hasAppeared) return;
self.hasAppeared = true;
// Create sparkling shimmer effect during appearance
self.createShimmerBurst(12);
// Gentle fade in appearance
tween(creatureGraphics, {
alpha: 0.8,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isObserving = true;
// Gentle glow pulsing while observing
tween(creatureGraphics, {
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(creatureGraphics, {
alpha: 0.7,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
}
});
};
self.fadeAway = function () {
self.isObserving = false;
// Create gentle dissipation shimmer effect
self.createShimmerBurst(8);
// Gentle fade out
tween(creatureGraphics, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 2000,
easing: tween.easeIn,
onFinish: function onFinish() {
self.destroy();
}
});
};
self.update = function () {
if (self.hasAppeared && !self.isObserving) return;
// Gentle floating motion
self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 12;
// Subtle rotation for hummingbird
if (self.creatureType === 'hummingbird') {
creatureGraphics.rotation = Math.sin(LK.ticks * 0.08) * 0.1;
}
// Count observe timer
if (self.isObserving) {
self.observeTimer++;
if (self.observeTimer >= self.observeDuration) {
self.fadeAway();
}
}
};
self.createShimmerBurst = function (count) {
for (var i = 0; i < count; i++) {
var shimmer = new EphemeralShimmer();
// Position around creature with some spread
var angle = Math.random() * Math.PI * 2;
var distance = 30 + Math.random() * 60;
shimmer.x = self.x + Math.cos(angle) * distance;
shimmer.y = self.y + Math.sin(angle) * distance;
// Add to global shimmer tracking
ephemeralShimmers.push(shimmer);
game.addChild(shimmer);
// Gentle sparkle appearance
tween(shimmer, {
alpha: 0.7 + Math.random() * 0.3,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300 + Math.random() * 200,
easing: tween.easeOut
});
}
};
return self;
});
var EphemeralShimmer = Container.expand(function () {
var self = Container.call(this);
var shimmerGraphics = self.attachAsset('ephemeralShimmer', {
anchorX: 0.5,
anchorY: 0.5
});
shimmerGraphics.alpha = 0;
self.speed = 1.5 + Math.random() * 2.0;
self.driftX = (Math.random() - 0.5) * 4;
self.driftY = -1 - Math.random() * 2;
self.floatOffset = Math.random() * Math.PI * 2;
self.floatSpeed = 0.05 + Math.random() * 0.03;
self.lifetime = 90 + Math.random() * 60; // 1.5-2.5 seconds
self.age = 0;
self.update = function () {
self.age++;
self.x += self.driftX;
self.y += self.driftY;
// Gentle floating motion
self.x += Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 0.5;
// Fade out over lifetime
var lifeProgress = self.age / self.lifetime;
shimmerGraphics.alpha = (1 - lifeProgress) * 0.8;
shimmerGraphics.scaleX = 1 - lifeProgress * 0.3;
shimmerGraphics.scaleY = 1 - lifeProgress * 0.3;
// Remove when lifetime exceeded
if (self.age >= self.lifetime) {
self.destroy();
}
};
return self;
});
var FloatingParticle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('floatingParticle', {
anchorX: 0.5,
anchorY: 0.5
});
particleGraphics.alpha = 0.3 + Math.random() * 0.4;
self.driftSpeed = 0.5 + Math.random() * 1.0;
self.floatOffset = Math.random() * Math.PI * 2;
self.floatSpeed = 0.01 + Math.random() * 0.02;
self.initialX = 0;
self.update = function () {
self.y -= self.driftSpeed;
self.x = self.initialX + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 20;
particleGraphics.rotation += 0.01;
// Reset particle when it goes off screen
if (self.y < -50) {
self.y = 2800;
self.x = Math.random() * 2048;
self.initialX = self.x;
}
};
return self;
});
var HavenDecoration = Container.expand(function (decorationType) {
var self = Container.call(this);
self.decorationType = decorationType || 'plant';
var assetName = self.decorationType + 'Decoration';
var decorationGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 1.0
});
decorationGraphics.alpha = 0.9;
self.swayOffset = Math.random() * Math.PI * 2;
self.swaySpeed = 0.01 + Math.random() * 0.02;
self.update = function () {
// Gentle swaying animation for plants and light decorations
if (self.decorationType === 'plant' || self.decorationType === 'light') {
decorationGraphics.rotation = Math.sin(LK.ticks * self.swaySpeed + self.swayOffset) * 0.05;
}
// Subtle pulsing for light decorations
if (self.decorationType === 'light') {
decorationGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.03 + self.swayOffset) * 0.2;
}
};
return self;
});
var HiddenVignette = Container.expand(function (vignetteType) {
var self = Container.call(this);
self.vignetteType = vignetteType || 'mushroom';
self.discovered = false;
self.isActive = false;
self.fireflies = [];
// Create main vignette element
var mainAsset = '';
if (self.vignetteType === 'mushroom') mainAsset = 'mushroomRing';else if (self.vignetteType === 'waterfall') mainAsset = 'hiddenWaterfall';else if (self.vignetteType === 'bear') mainAsset = 'sleepingBear';
var vignetteGraphics = self.attachAsset(mainAsset, {
anchorX: 0.5,
anchorY: 0.5
});
vignetteGraphics.alpha = 0; // Start invisible
self.pulseOffset = Math.random() * Math.PI * 2;
self.breathOffset = Math.random() * Math.PI * 2;
// Discover animation
self.discover = function () {
if (self.discovered) return;
self.discovered = true;
self.isActive = true;
// Gentle fade in discovery
tween(vignetteGraphics, {
alpha: 0.8,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 2000,
easing: tween.easeOut
});
// Play vignette-specific sound
var soundName = 'vignette' + self.vignetteType.charAt(0).toUpperCase() + self.vignetteType.slice(1);
LK.getSound(soundName).play();
// Create special effects based on type
if (self.vignetteType === 'mushroom') {
self.createFireflies();
} else if (self.vignetteType === 'waterfall') {
self.createRainbow();
}
};
self.createFireflies = function () {
// Create dancing fireflies around mushroom ring
for (var i = 0; i < 8; i++) {
var firefly = self.addChild(LK.getAsset('firefly', {
anchorX: 0.5,
anchorY: 0.5
}));
firefly.alpha = 0;
firefly.danceAngle = Math.PI * 2 / 8 * i;
firefly.danceRadius = 80 + Math.random() * 40;
firefly.danceSpeed = 0.02 + Math.random() * 0.02;
firefly.pulseOffset = Math.random() * Math.PI * 2;
self.fireflies.push(firefly);
// Fade in firefly
tween(firefly, {
alpha: 0.7 + Math.random() * 0.3
}, {
duration: 1000 + Math.random() * 1000,
easing: tween.easeOut
});
}
};
self.createRainbow = function () {
// Create subtle rainbow mist effect
LK.effects.flashObject(vignetteGraphics, 0xff9800, 3000);
// Add gentle shimmer
tween(vignetteGraphics, {
alpha: 1.0
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(vignetteGraphics, {
alpha: 0.6
}, {
duration: 1500,
easing: tween.easeInOut
});
}
});
};
self.update = function () {
if (!self.isActive) return;
// Gentle pulsing for mushroom ring
if (self.vignetteType === 'mushroom') {
vignetteGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.02 + self.pulseOffset) * 0.2;
// Animate fireflies dancing
for (var i = 0; i < self.fireflies.length; i++) {
var firefly = self.fireflies[i];
firefly.danceAngle += firefly.danceSpeed;
firefly.x = Math.cos(firefly.danceAngle) * firefly.danceRadius;
firefly.y = Math.sin(firefly.danceAngle) * firefly.danceRadius;
firefly.alpha = 0.4 + Math.sin(LK.ticks * 0.05 + firefly.pulseOffset) * 0.4;
}
}
// Gentle breathing for sleeping bear
else if (self.vignetteType === 'bear') {
var breathScale = 1.0 + Math.sin(LK.ticks * 0.015 + self.breathOffset) * 0.05;
vignetteGraphics.scaleX = breathScale;
vignetteGraphics.scaleY = breathScale;
}
// Subtle shimmer for waterfall
else if (self.vignetteType === 'waterfall') {
vignetteGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.03 + self.pulseOffset) * 0.1;
}
};
return self;
});
var LightShimmer = Container.expand(function () {
var self = Container.call(this);
var shimmerGraphics = self.attachAsset('lightShimmer', {
anchorX: 0.5,
anchorY: 0.5
});
shimmerGraphics.alpha = 0.1;
self.pulseOffset = Math.random() * Math.PI * 2;
self.pulseSpeed = 0.005 + Math.random() * 0.003; // Very slow, breathing-like pulse
self.breathAmplitude = 0.05 + Math.random() * 0.03; // Very subtle intensity variation
// Start gentle breathing animation using tween for smooth transitions
self.startShimmer = function () {
var breatheIn = function breatheIn() {
tween(shimmerGraphics, {
alpha: 0.15 + self.breathAmplitude,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 8000 + Math.random() * 4000,
// 8-12 seconds per breath
easing: tween.easeInOut,
onFinish: breatheOut
});
};
var breatheOut = function breatheOut() {
tween(shimmerGraphics, {
alpha: 0.05,
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 8000 + Math.random() * 4000,
// 8-12 seconds per breath
easing: tween.easeInOut,
onFinish: breatheIn
});
};
// Start with random direction
if (Math.random() < 0.5) {
breatheIn();
} else {
breatheOut();
}
};
self.update = function () {
// Additional very subtle pulsing using sine wave for natural variation
var subtlePulse = Math.sin(LK.ticks * self.pulseSpeed + self.pulseOffset) * 0.02;
shimmerGraphics.alpha += subtlePulse;
// Ensure alpha stays within reasonable bounds
shimmerGraphics.alpha = Math.max(0.02, Math.min(0.25, shimmerGraphics.alpha));
};
return self;
});
var LuminescentParticle = Container.expand(function () {
var self = Container.call(this);
// Use alternating particle types for variety
var assetName = Math.random() < 0.7 ? 'luminescentParticle' : 'luminescentParticleAlt';
var particleGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
// Soft intensity with pastel colors
var pastelColors = [0xe0ffff, 0xf0f8ff, 0xfffacd, 0xf0fff0, 0xffe4e1];
particleGraphics.tint = pastelColors[Math.floor(Math.random() * pastelColors.length)];
particleGraphics.alpha = 0.3 + Math.random() * 0.2; // Reduced for subtle effect
// Enhanced movement properties for gentle floating
self.driftSpeed = 0.08 + Math.random() * 0.12; // Very slow upward drift
self.lateralAmplitude = 20 + Math.random() * 30; // Gentle S-curve amplitude
self.lateralSpeed = 0.003 + Math.random() * 0.005; // Very slow lateral sway frequency
self.initialX = 0;
self.lateralOffset = Math.random() * Math.PI * 2; // Random phase for S-curve
self.lateralDirection = Math.random() < 0.5 ? 1 : -1; // Random sway direction
// Long lifetime properties
self.age = 0;
self.maxAge = 3600 + Math.random() * 1800; // 60-90 seconds lifetime for long traversal
self.spawned = false;
// Soft pulsing properties
self.pulseOffset = Math.random() * Math.PI * 2;
self.pulseSpeed = 0.008 + Math.random() * 0.007; // Very gentle pulse frequency
self.baseAlpha = 0.25 + Math.random() * 0.15; // Soft base opacity
// Start gentle emergence animation
self.emerge = function () {
if (self.spawned) return;
self.spawned = true;
// Gentle fade in and scale up
tween(particleGraphics, {
alpha: self.baseAlpha,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeOut
});
};
// Start gentle pulsing animation
self.startPulse = function () {
var pulseIn = function pulseIn() {
if (self.age >= self.maxAge) return;
tween(particleGraphics, {
alpha: self.baseAlpha + 0.2,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 3000 + Math.random() * 2000,
easing: tween.easeInOut,
onFinish: pulseOut
});
};
var pulseOut = function pulseOut() {
if (self.age >= self.maxAge) return;
tween(particleGraphics, {
alpha: self.baseAlpha - 0.1,
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 3000 + Math.random() * 2000,
easing: tween.easeInOut,
onFinish: pulseIn
});
};
// Start with random direction
if (Math.random() < 0.5) {
pulseIn();
} else {
pulseOut();
}
};
// Enhanced floating movement system
self.update = function () {
if (!self.spawned) {
self.emerge();
self.startPulse();
}
self.age++;
// Very slow upward drift - effortless floating
self.y -= self.driftSpeed;
// Gentle lateral sway in S-curve pattern
var lateralSway = Math.sin(LK.ticks * self.lateralSpeed + self.lateralOffset) * self.lateralAmplitude * self.lateralDirection;
var secondarySway = Math.cos(LK.ticks * self.lateralSpeed * 0.7 + self.lateralOffset + Math.PI) * self.lateralAmplitude * 0.3;
self.x = self.initialX + lateralSway + secondarySway;
// Additional very subtle sine wave variation for natural movement
var microDrift = Math.sin(LK.ticks * 0.002 + self.lateralOffset) * 3;
self.x += microDrift;
// Subtle additional alpha variation for ethereal effect
var additionalGlow = Math.sin(LK.ticks * self.pulseSpeed + self.pulseOffset) * 0.08;
particleGraphics.alpha += additionalGlow;
// Gentle rotation for natural floating
particleGraphics.rotation += 0.003 * self.lateralDirection;
// Reset particle when lifetime exceeded or goes off screen
if (self.age >= self.maxAge || self.y < -100) {
// Reset for reuse with long lifetime
self.y = 2800 + Math.random() * 200;
self.x = Math.random() * 2048;
self.initialX = self.x;
self.age = 0;
self.spawned = false;
// Randomize movement parameters for variety
self.driftSpeed = 0.08 + Math.random() * 0.12;
self.lateralAmplitude = 20 + Math.random() * 30;
self.lateralSpeed = 0.003 + Math.random() * 0.005;
self.lateralDirection = Math.random() < 0.5 ? 1 : -1;
self.lateralOffset = Math.random() * Math.PI * 2;
self.maxAge = 3600 + Math.random() * 1800;
self.baseAlpha = 0.25 + Math.random() * 0.15;
// Reset graphics properties
particleGraphics.alpha = 0;
particleGraphics.scaleX = 0.8;
particleGraphics.scaleY = 0.8;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
// Play footstep sounds based on biome
if (LK.ticks - lastFootstepTime > footstepInterval * 60 / 1000) {
var footstepSound = '';
if (currentBiome === 0) footstepSound = 'footstepsGrass'; // Woods
else if (currentBiome === 1) footstepSound = 'footstepsPebbles'; // Caverns
else if (currentBiome === 2) footstepSound = 'footstepsWater'; // Shore
else footstepSound = 'footstepsGrass'; // Sanctuary
LK.getSound(footstepSound).play();
lastFootstepTime = LK.ticks;
}
}
};
return self;
});
var RareAuraBloom = Container.expand(function () {
var self = Container.call(this);
self.collected = false;
var bloomGraphics = self.attachAsset('rareAuraBloom', {
anchorX: 0.5,
anchorY: 0.5
});
bloomGraphics.alpha = 0.9;
self.pulseOffset = Math.random() * Math.PI * 2;
self.floatOffset = Math.random() * Math.PI * 2;
self.floatSpeed = 0.03;
self.initialY = 0;
// Start dramatic pulsating animation
tween(bloomGraphics, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.collected) {
tween(bloomGraphics, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.7
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!self.collected) {
tween(bloomGraphics, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 1.0
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}
});
}
}
});
self.update = function () {
if (!self.collected) {
self.y = self.initialY + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 15;
bloomGraphics.rotation += 0.02;
}
};
return self;
});
var RareBloomBurst = Container.expand(function () {
var self = Container.call(this);
var burstGraphics = self.attachAsset('rareBloomBurstParticle', {
anchorX: 0.5,
anchorY: 0.5
});
// Vibrant pastel mix colors
var vibrantColors = [0xffd700, 0xff69b4, 0x98fb98, 0x87ceeb, 0xdda0dd, 0xf0e68c];
burstGraphics.tint = vibrantColors[Math.floor(Math.random() * vibrantColors.length)];
burstGraphics.alpha = 0;
self.velocity = {
x: (Math.random() - 0.5) * 8,
y: -2 - Math.random() * 6
};
self.lifetime = 60; // 1 second burst duration
self.age = 0;
self.gravity = 0.2;
// Start burst animation
tween(burstGraphics, {
alpha: 0.8,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(burstGraphics, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 800,
easing: tween.easeIn
});
}
});
self.update = function () {
self.age++;
self.x += self.velocity.x;
self.y += self.velocity.y;
self.velocity.y += self.gravity;
burstGraphics.rotation += 0.1;
// Remove when lifetime exceeded
if (self.age >= self.lifetime) {
self.destroy();
}
};
return self;
});
var TreeSwayBranch = Container.expand(function () {
var self = Container.call(this);
var branchGraphics = self.attachAsset('treeSwayBranch', {
anchorX: 0.5,
anchorY: 1.0
});
branchGraphics.alpha = 0.7;
// Enhanced tree sway parameters for natural movement
self.swayOffset = Math.random() * Math.PI * 2; // Random phase for variation between trees
self.swaySpeed = 0.006 + Math.random() * 0.004; // Very low frequency (0.1-0.2 Hz equivalent)
self.swayAmplitude = 0.02 + Math.random() * 0.015; // Small amplitude (1-3 degrees)
self.secondarySwayOffset = Math.random() * Math.PI * 2; // Secondary sway for complexity
self.secondarySwaySpeed = 0.004 + Math.random() * 0.003; // Even slower secondary movement
self.windVariation = Math.random() * 0.5 + 0.5; // Random wind strength per tree
// Enhanced continuous sway animation with multiple layers
self.startSway = function () {
// Primary sway motion - main side-to-side movement
var primarySwayLeft = function primarySwayLeft() {
tween(branchGraphics, {
rotation: -self.swayAmplitude * self.windVariation
}, {
duration: 4000 + Math.random() * 3000,
// 4-7 seconds per sway for calming rhythm
easing: tween.easeInOut,
onFinish: primarySwayRight
});
};
var primarySwayRight = function primarySwayRight() {
tween(branchGraphics, {
rotation: self.swayAmplitude * self.windVariation
}, {
duration: 4000 + Math.random() * 3000,
// 4-7 seconds per sway for calming rhythm
easing: tween.easeInOut,
onFinish: primarySwayLeft
});
};
// Start with random direction for phase variation
if (Math.random() < 0.5) {
primarySwayLeft();
} else {
primarySwayRight();
}
};
self.update = function () {
// Multi-layered natural sway simulation mimicking light breeze
// Primary sine wave for main movement
var primarySway = Math.sin(LK.ticks * self.swaySpeed + self.swayOffset) * 0.008 * self.windVariation;
// Secondary sine wave for complexity and natural variation
var secondarySway = Math.sin(LK.ticks * self.secondarySwaySpeed + self.secondarySwayOffset) * 0.004 * self.windVariation;
// Tertiary micro-movement for realistic rustling
var microSway = Math.sin(LK.ticks * 0.01 + self.swayOffset * 2) * 0.002;
// Combine all movement layers for natural breeze effect
var totalSway = primarySway + secondarySway + microSway;
branchGraphics.rotation += totalSway;
// Subtle scale variation to simulate depth movement in breeze
var scaleVariation = 1.0 + Math.sin(LK.ticks * self.swaySpeed * 0.7 + self.swayOffset) * 0.01;
branchGraphics.scaleX = scaleVariation;
};
return self;
});
var WaterRipple = Container.expand(function () {
var self = Container.call(this);
var rippleGraphics = self.attachAsset('waterRipple', {
anchorX: 0.5,
anchorY: 0.5
});
// Start invisible and small
rippleGraphics.alpha = 0;
rippleGraphics.scaleX = 0.05;
rippleGraphics.scaleY = 0.05;
self.isActive = false;
self.maxScale = 0.8 + Math.random() * 0.4; // Very low amplitude for barely stirring water
self.expandDuration = 15000 + Math.random() * 10000; // Extremely slow 15-25 seconds expansion
// Enhanced shader-based animation properties
self.noiseOffset = Math.random() * Math.PI * 2;
self.noiseOffset2 = Math.random() * Math.PI * 2;
self.noiseSpeed = 0.0003 + Math.random() * 0.0002; // Extremely slow noise scrolling
self.distortionAmplitude = 0.008 + Math.random() * 0.005; // Minimal distortion for subtle undulations
self.scrollDirection = Math.random() * Math.PI * 2; // Random scroll direction
self.rippleFrequency = 0.1 + Math.random() * 0.05; // Infrequent pulse frequency
self.noiseScrollX = 0;
self.noiseScrollY = 0;
self.radialOffset = Math.random() * Math.PI * 2; // For radial outward movement
self.reflectionShift = 0; // For elongated reflection simulation
self.startRipple = function () {
if (self.isActive) return;
self.isActive = true;
// Reset noise pattern position
self.noiseScrollX = 0;
self.noiseScrollY = 0;
self.reflectionShift = 0;
// Extremely gentle fade in with very minimal alpha
tween(rippleGraphics, {
alpha: 0.08,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Extremely slow main expansion phase with gradual fade
tween(rippleGraphics, {
alpha: 0,
scaleX: self.maxScale,
scaleY: self.maxScale
}, {
duration: self.expandDuration,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset for reuse
self.isActive = false;
rippleGraphics.alpha = 0;
rippleGraphics.scaleX = 0.05;
rippleGraphics.scaleY = 0.05;
}
});
}
});
};
self.update = function () {
if (!self.isActive) return;
// Enhanced shader-based noise pattern simulation for natural water movement
self.noiseScrollX += Math.cos(self.scrollDirection) * self.noiseSpeed;
self.noiseScrollY += Math.sin(self.scrollDirection) * self.noiseSpeed;
// Multi-layered noise for complex water surface simulation
var primaryNoise = Math.sin(LK.ticks * self.noiseSpeed + self.noiseOffset) * self.distortionAmplitude;
var secondaryNoise = Math.cos(LK.ticks * self.noiseSpeed * 1.7 + self.noiseOffset2 + Math.PI) * self.distortionAmplitude * 0.6;
var tertiaryNoise = Math.sin(LK.ticks * self.noiseSpeed * 0.5 + self.noiseOffset + Math.PI * 0.5) * self.distortionAmplitude * 0.3;
// Radial outward movement simulation
var radialPulse = Math.sin(LK.ticks * self.rippleFrequency + self.radialOffset) * 0.002;
var radialExpansion = Math.cos(LK.ticks * self.rippleFrequency * 0.7 + self.radialOffset) * 0.001;
// Apply extremely subtle rotation distortion for natural water movement
rippleGraphics.rotation = (primaryNoise + secondaryNoise * 0.5) * 0.3;
// Apply minimal position distortion for gentle drift
rippleGraphics.x = (secondaryNoise + tertiaryNoise) * 1.5 + radialPulse * 50;
rippleGraphics.y = (primaryNoise + tertiaryNoise * 0.8) * 1.2 + radialPulse * 30;
// Simulate scrolling texture pattern with very subtle alpha variation
var scrollPattern = Math.sin(self.noiseScrollX * 8) * Math.cos(self.noiseScrollY * 6) * 0.015;
var reflectionPattern = Math.sin(self.reflectionShift * 0.1) * 0.01;
self.reflectionShift += self.noiseSpeed * 100;
// Apply elongated reflection shifts for sky/land reflection simulation
rippleGraphics.skewX = (primaryNoise + reflectionPattern) * 0.02;
rippleGraphics.skewY = (secondaryNoise + reflectionPattern * 0.7) * 0.015;
// Combine all patterns for final alpha with natural pulsing
var combinedAlpha = scrollPattern + reflectionPattern + radialExpansion;
rippleGraphics.alpha = Math.max(0, Math.min(0.12, rippleGraphics.alpha + combinedAlpha));
};
return self;
});
var WeatherParticle = Container.expand(function (weatherType) {
var self = Container.call(this);
self.weatherType = weatherType || 'rain';
self.speed = 0;
self.drift = 0;
self.initialX = 0;
var assetName = weatherType === 'rain' ? 'rainDrop' : 'snowFlake';
var particleGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
if (weatherType === 'rain') {
particleGraphics.alpha = 0.6 + Math.random() * 0.4;
self.speed = 8 + Math.random() * 4;
self.drift = (Math.random() - 0.5) * 2;
} else if (weatherType === 'snow') {
particleGraphics.alpha = 0.7 + Math.random() * 0.3;
self.speed = 2 + Math.random() * 2;
self.drift = (Math.random() - 0.5) * 4;
self.floatOffset = Math.random() * Math.PI * 2;
self.floatSpeed = 0.02 + Math.random() * 0.02;
}
self.update = function () {
if (self.weatherType === 'rain') {
self.y += self.speed;
self.x += self.drift;
} else if (self.weatherType === 'snow') {
self.y += self.speed;
self.x = self.initialX + Math.sin(LK.ticks * self.floatSpeed + self.floatOffset) * 30;
particleGraphics.rotation += 0.01;
}
// Reset particle when it goes off screen
if (self.y > 2780) {
self.y = -50;
self.x = Math.random() * 2048;
self.initialX = self.x;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1B5E20
});
/****
* Game Code
****/
// Game state
var gameState = 'exploration'; // 'exploration' or 'haven'
var currentBiome = 0;
var biomes = ['Whispering Woods', 'Crystal Caverns', 'Serene Shoreline', 'Starfall Sanctuary'];
var biomeColors = [0xd7e4bd, 0xe1bee7, 0xb2dfdb, 0xc5cae9];
var biomeMusicTracks = ['whisperingWoods', 'crystalCaverns', 'sereneShore', 'starfallSanctuary'];
var currentMusicTrack = null;
var musicFadeTime = 2000;
// ASMR ambient sound tracking
var currentAmbientSounds = [];
var lastFootstepTime = 0;
var footstepInterval = 800; // milliseconds between footsteps
var biomeAmbientSounds = [['birdChirps', 'lightRain'],
// Whispering Woods
['caveDrops', 'fireflies'],
// Crystal Caverns
['streamMurmur', 'windChimes'],
// Serene Shoreline
['fireflies', 'gentleFire'] // Starfall Sanctuary
];
// Player and game objects
var player = new Player();
var auraParticles = [];
var havenDecorations = [];
var floatingParticles = [];
var luminescentParticles = [];
var rareBloom = null;
var rareBloomTimer = 0;
var rareBloomSpawnInterval = 1800; // 30 seconds at 60fps
var ephemeralCreature = null;
var ephemeralTimer = 0;
var ephemeralSpawnInterval = 3600; // 60 seconds at 60fps
var ephemeralCreatureTypes = ['fox', 'hummingbird', 'spirit'];
var hiddenVignettes = [];
var vignetteTypes = ['mushroom', 'waterfall', 'bear'];
var vignetteDiscoveryRadius = 120;
// Weather system
var currentWeather = 'clear'; // 'clear', 'rain', 'snow'
var weatherParticles = [];
var weatherTimer = 0;
var weatherCheckInterval = 1800; // 30 seconds at 60fps
var weatherDuration = 3600; // 60 seconds at 60fps
var weatherEndTimer = 0;
var isWeatherActive = false;
// Water ripple system
var waterRipples = [];
var rippleTimer = 0;
var rippleSpawnInterval = 900 + Math.random() * 1200; // 15-35 seconds at 60fps for extremely slow, infrequent ripples
var maxActiveRipples = 3;
// Zen moment system
var zenMomentTimer = 0;
var zenMomentInterval = 4500; // 75 seconds at 60fps of continuous activity
var isZenMomentActive = false;
var zenMomentDuration = 480; // 8 seconds at 60fps
var zenMomentEndTimer = 0;
var originalBackgroundTint = 0x000000;
var zenAffirmations = ['Find your calm', 'Embrace tranquility', 'You are here', 'Breathe deeply', 'Peace flows through you', 'This moment is yours', 'Feel the serenity'];
var zenText = null;
// Tree sway system
var treeSwayBranches = [];
// Light shimmer system
var lightShimmers = [];
// Aura wisp system
var auraWisps = [];
var wispSpawnTimer = 0;
var wispSpawnInterval = 120 + Math.random() * 180; // 2-5 seconds at 60fps
var maxActiveWisps = 6;
// Ephemeral shimmer particles
var ephemeralShimmers = [];
// Distant cloud system
var distantClouds = [];
// Rare bloom burst particles
var rareBloomBursts = [];
var biomeBackground = null;
var havenBackground = null;
// Aura collection tracking
var auraCount = storage.auraCount || {
green: 0,
blue: 0,
yellow: 0
};
var totalAuras = auraCount.green + auraCount.blue + auraCount.yellow;
// UI elements
var auraCountText = new Text2('Auras: ' + totalAuras, {
size: 80,
fill: 0xFFFFFF
});
auraCountText.anchor.set(0.5, 0);
var biomeText = new Text2(biomes[currentBiome], {
size: 60,
fill: 0xFFFFFF
});
biomeText.anchor.set(0.5, 0);
var havenButton = new Text2('Haven', {
size: 70,
fill: 0xFFEB3B
});
havenButton.anchor.set(1, 0);
var exploreButton = new Text2('Explore', {
size: 70,
fill: 0x4CAF50
});
exploreButton.anchor.set(0, 0);
// Add UI to GUI
LK.gui.top.addChild(auraCountText);
LK.gui.top.addChild(biomeText);
LK.gui.topRight.addChild(havenButton);
LK.gui.topLeft.addChild(exploreButton);
// Position UI elements
auraCountText.y = 20;
biomeText.y = 120;
havenButton.x = -20;
havenButton.y = 20;
exploreButton.x = 120;
exploreButton.y = 20;
// Initialize game
function initializeExploration() {
gameState = 'exploration';
// Clear existing objects
if (biomeBackground) biomeBackground.destroy();
if (havenBackground) havenBackground.destroy();
// Create biome background
biomeBackground = game.addChild(LK.getAsset('biomeBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
tint: biomeColors[currentBiome]
}));
// Add player
player.x = 1024;
player.y = 1366;
player.targetX = player.x;
player.targetY = player.y;
game.addChild(player);
// Generate aura particles
generateAuraParticles();
// Generate floating ambient particles
generateFloatingParticles();
// Generate luminescent particles for magical atmosphere
generateLuminescentParticles();
// Generate gentle tree sway for natural ambiance
generateTreeSway();
// Generate subtle light shimmer for sky ambiance
generateLightShimmer();
// Generate distant clouds for background movement
generateDistantClouds();
// Spawn hidden vignettes for discovery
spawnHiddenVignettes();
// Reset rare bloom timer
rareBloomTimer = Math.floor(Math.random() * rareBloomSpawnInterval);
// Clear ephemeral creature
if (ephemeralCreature) {
ephemeralCreature.destroy();
ephemeralCreature = null;
}
// Reset ephemeral timer
ephemeralTimer = Math.floor(Math.random() * ephemeralSpawnInterval);
// Reset weather timer
weatherTimer = Math.floor(Math.random() * weatherCheckInterval);
// Reset zen moment timer
zenMomentTimer = Math.floor(Math.random() * zenMomentInterval);
// Reset water ripple timer
rippleTimer = Math.floor(Math.random() * rippleSpawnInterval);
// Reset aura wisp timer
wispSpawnTimer = Math.floor(Math.random() * wispSpawnInterval);
// Update UI
biomeText.setText(biomes[currentBiome]);
biomeText.visible = true;
exploreButton.visible = false;
havenButton.visible = true;
// Play biome-specific music and ambient sounds
playBiomeMusic(currentBiome);
playAmbientSounds(currentBiome);
}
function initializeHaven() {
gameState = 'haven';
// Clear existing objects
if (biomeBackground) biomeBackground.destroy();
clearAuraParticles();
clearFloatingParticles();
clearLuminescentParticles();
clearHiddenVignettes();
// Clear rare bloom
if (rareBloom) {
rareBloom.destroy();
rareBloom = null;
}
// Clear ephemeral creature
if (ephemeralCreature) {
ephemeralCreature.destroy();
ephemeralCreature = null;
}
// Clear weather effects
if (isWeatherActive) {
endWeatherTransformation();
}
// Clear zen moment
if (isZenMomentActive) {
endZenMoment();
}
// Clear water ripples
clearWaterRipples();
// Clear tree sway
clearTreeSway();
// Clear light shimmer
clearLightShimmer();
// Clear aura wisps
clearAuraWisps();
// Clear ephemeral shimmers
clearEphemeralShimmers();
// Clear distant clouds
clearDistantClouds();
// Clear rare bloom bursts
clearRareBloomBursts();
// Create haven background
havenBackground = game.addChild(LK.getAsset('havenBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Remove player from haven
if (player.parent) player.parent.removeChild(player);
// Load existing decorations
loadHavenDecorations();
// Update UI
biomeText.visible = false;
exploreButton.visible = true;
havenButton.visible = false;
// Stop exploration ambient sounds
for (var i = 0; i < currentAmbientSounds.length; i++) {
var sound = LK.getSound(currentAmbientSounds[i]);
sound.loop = false;
sound.stop();
}
currentAmbientSounds = [];
// Play haven ambient music
playHavenMusic();
}
function generateAuraParticles() {
clearAuraParticles();
var particleCount = 15 + Math.floor(Math.random() * 10);
var auraTypes = ['green', 'blue', 'yellow'];
for (var i = 0; i < particleCount; i++) {
var auraType = auraTypes[Math.floor(Math.random() * auraTypes.length)];
var aura = new AuraParticle(auraType);
aura.x = 100 + Math.random() * 1848;
aura.y = 200 + Math.random() * 2332;
aura.initialY = aura.y;
auraParticles.push(aura);
game.addChild(aura);
}
}
function clearAuraParticles() {
for (var i = auraParticles.length - 1; i >= 0; i--) {
auraParticles[i].destroy();
auraParticles.splice(i, 1);
}
}
function generateFloatingParticles() {
clearFloatingParticles();
var particleCount = 20 + Math.floor(Math.random() * 15);
for (var i = 0; i < particleCount; i++) {
var particle = new FloatingParticle();
particle.x = Math.random() * 2048;
particle.y = Math.random() * 2732;
particle.initialX = particle.x;
floatingParticles.push(particle);
game.addChild(particle);
}
}
function clearFloatingParticles() {
for (var i = floatingParticles.length - 1; i >= 0; i--) {
floatingParticles[i].destroy();
floatingParticles.splice(i, 1);
}
}
function generateLuminescentParticles() {
clearLuminescentParticles();
// Low spawn rate for sparse, ethereal feel
var particleCount = 8 + Math.floor(Math.random() * 6);
for (var i = 0; i < particleCount; i++) {
var particle = new LuminescentParticle();
// Focus particles over magical areas with sparse distribution
var spawnArea = Math.random();
if (spawnArea < 0.3) {
// Over water area (magical reflections)
particle.x = 300 + Math.random() * 1448;
particle.y = 1600 + Math.random() * 1000;
} else if (spawnArea < 0.6) {
// Near mystical trees/edges
particle.x = Math.random() < 0.5 ? Math.random() * 250 : 1798 + Math.random() * 250;
particle.y = 200 + Math.random() * 2200;
} else {
// Scattered throughout for ambient magic
particle.x = Math.random() * 2048;
particle.y = 200 + Math.random() * 2200;
}
particle.initialX = particle.x;
luminescentParticles.push(particle);
game.addChild(particle);
}
}
function clearLuminescentParticles() {
for (var i = luminescentParticles.length - 1; i >= 0; i--) {
luminescentParticles[i].destroy();
luminescentParticles.splice(i, 1);
}
}
function clearEphemeralShimmers() {
for (var i = ephemeralShimmers.length - 1; i >= 0; i--) {
ephemeralShimmers[i].destroy();
ephemeralShimmers.splice(i, 1);
}
}
function generateDistantClouds() {
clearDistantClouds();
// Sparse cloud coverage for background ambiance
var cloudCount = 3 + Math.floor(Math.random() * 4);
for (var i = 0; i < cloudCount; i++) {
var cloud = new DistantCloud();
// Position clouds in upper portion of sky
cloud.x = Math.random() * 2400; // Start some off-screen
cloud.y = 100 + Math.random() * 400; // Upper sky area
cloud.initialX = cloud.x;
cloud.initialY = cloud.y;
// Vary cloud sizes for depth
var depthScale = 0.4 + Math.random() * 0.8;
cloud.scaleX = depthScale;
cloud.scaleY = depthScale;
distantClouds.push(cloud);
game.addChild(cloud);
}
}
function clearDistantClouds() {
for (var i = distantClouds.length - 1; i >= 0; i--) {
distantClouds[i].destroy();
distantClouds.splice(i, 1);
}
}
function clearRareBloomBursts() {
for (var i = rareBloomBursts.length - 1; i >= 0; i--) {
rareBloomBursts[i].destroy();
rareBloomBursts.splice(i, 1);
}
}
function spawnRareBloom() {
if (rareBloom) return; // Only one rare bloom at a time
rareBloom = new RareAuraBloom();
rareBloom.x = 200 + Math.random() * 1648;
rareBloom.y = 300 + Math.random() * 2132;
rareBloom.initialY = rareBloom.y;
game.addChild(rareBloom);
// Play appearance sound
LK.getSound('rareBloomAppear').play();
// Create burst of light effect
LK.effects.flashScreen(0xffd700, 800);
// Reset timer for next spawn
rareBloomTimer = 0;
}
function spawnEphemeralCreature() {
if (ephemeralCreature) return; // Only one ephemeral creature at a time
var creatureType = ephemeralCreatureTypes[Math.floor(Math.random() * ephemeralCreatureTypes.length)];
ephemeralCreature = new EphemeralCreature(creatureType);
// Position away from player for mystical discovery
var playerDistance = 300 + Math.random() * 400;
var angle = Math.random() * Math.PI * 2;
ephemeralCreature.x = Math.max(100, Math.min(1948, player.x + Math.cos(angle) * playerDistance));
ephemeralCreature.y = Math.max(200, Math.min(2532, player.y + Math.sin(angle) * playerDistance));
ephemeralCreature.initialY = ephemeralCreature.y;
game.addChild(ephemeralCreature);
// Play gentle appearance sound
LK.getSound('ephemeralAppear').play();
// Trigger appearance animation
ephemeralCreature.appear();
// Reset timer for next spawn
ephemeralTimer = Math.floor(Math.random() * ephemeralSpawnInterval) + ephemeralSpawnInterval;
}
function spawnHiddenVignettes() {
clearHiddenVignettes();
// Spawn 2-4 vignettes per biome in obscure corners
var vignetteCount = 2 + Math.floor(Math.random() * 3);
for (var i = 0; i < vignetteCount; i++) {
var vignetteType = vignetteTypes[Math.floor(Math.random() * vignetteTypes.length)];
var vignette = new HiddenVignette(vignetteType);
// Position in obscure corners and edges of map
var cornerPositions = [{
x: 150,
y: 250
},
// Top-left corner
{
x: 1900,
y: 250
},
// Top-right corner
{
x: 150,
y: 2500
},
// Bottom-left corner
{
x: 1900,
y: 2500
},
// Bottom-right corner
{
x: 1024,
y: 150
},
// Top center hidden
{
x: 100,
y: 1366
},
// Left edge hidden
{
x: 1948,
y: 1366
},
// Right edge hidden
{
x: 1024,
y: 2600
} // Bottom center hidden
];
var position = cornerPositions[Math.floor(Math.random() * cornerPositions.length)];
// Add some randomness to exact position
vignette.x = position.x + (Math.random() - 0.5) * 200;
vignette.y = position.y + (Math.random() - 0.5) * 200;
// Ensure vignette stays within bounds
vignette.x = Math.max(100, Math.min(1948, vignette.x));
vignette.y = Math.max(200, Math.min(2532, vignette.y));
hiddenVignettes.push(vignette);
game.addChild(vignette);
}
}
function clearHiddenVignettes() {
for (var i = hiddenVignettes.length - 1; i >= 0; i--) {
hiddenVignettes[i].destroy();
hiddenVignettes.splice(i, 1);
}
}
function loadHavenDecorations() {
var savedDecorations = storage.havenDecorations || [];
for (var i = 0; i < savedDecorations.length; i++) {
var decorationData = savedDecorations[i];
var decoration = new HavenDecoration(decorationData.type);
decoration.x = decorationData.x;
decoration.y = decorationData.y;
havenDecorations.push(decoration);
game.addChild(decoration);
}
}
function saveHavenDecorations() {
var decorationData = [];
for (var i = 0; i < havenDecorations.length; i++) {
var decoration = havenDecorations[i];
decorationData.push({
type: decoration.decorationType,
x: decoration.x,
y: decoration.y
});
}
storage.havenDecorations = decorationData;
}
function updateUI() {
totalAuras = auraCount.green + auraCount.blue + auraCount.yellow;
auraCountText.setText('Auras: ' + totalAuras);
storage.auraCount = auraCount;
}
function playAmbientSounds(biomeIndex) {
// Stop current ambient sounds
for (var i = 0; i < currentAmbientSounds.length; i++) {
var sound = LK.getSound(currentAmbientSounds[i]);
sound.loop = false;
sound.stop();
}
currentAmbientSounds = [];
// Start new ambient sounds for this biome
var sounds = biomeAmbientSounds[biomeIndex];
for (var j = 0; j < sounds.length; j++) {
var sound = LK.getSound(sounds[j]);
sound.loop = true;
sound.play();
currentAmbientSounds.push(sounds[j]);
}
}
function playBiomeMusic(biomeIndex) {
var targetTrack = biomeMusicTracks[biomeIndex];
if (currentMusicTrack === targetTrack) return;
if (currentMusicTrack) {
// Fade out current music
LK.playMusic(currentMusicTrack, {
fade: {
start: 0.7,
end: 0,
duration: musicFadeTime
}
});
LK.setTimeout(function () {
// Fade in new music
LK.playMusic(targetTrack, {
fade: {
start: 0,
end: 0.7,
duration: musicFadeTime
}
});
currentMusicTrack = targetTrack;
}, musicFadeTime);
} else {
// First time playing music
LK.playMusic(targetTrack, {
fade: {
start: 0,
end: 0.7,
duration: musicFadeTime
}
});
currentMusicTrack = targetTrack;
}
}
function startWeatherTransformation() {
if (isWeatherActive || gameState !== 'exploration') return;
// Small chance for weather (10% chance each check)
if (Math.random() > 0.1) return;
// Choose weather type (equal chance for rain or snow)
var weatherTypes = ['rain', 'snow'];
currentWeather = weatherTypes[Math.floor(Math.random() * weatherTypes.length)];
isWeatherActive = true;
weatherEndTimer = 0;
// Create weather particles
generateWeatherParticles();
// Play weather ambient sound
var soundName = currentWeather === 'rain' ? 'gentleRain' : 'softSnow';
var weatherSound = LK.getSound(soundName);
weatherSound.loop = true;
weatherSound.play();
currentAmbientSounds.push(soundName);
// Gentle screen tint for weather atmosphere
if (currentWeather === 'rain') {
tween(biomeBackground, {
tint: 0x8fa5c7
}, {
duration: 3000,
easing: tween.easeInOut
});
} else if (currentWeather === 'snow') {
tween(biomeBackground, {
tint: 0xc8d6e5
}, {
duration: 3000,
easing: tween.easeInOut
});
}
}
function endWeatherTransformation() {
if (!isWeatherActive) return;
isWeatherActive = false;
clearWeatherParticles();
// Stop weather ambient sound
var soundName = currentWeather === 'rain' ? 'gentleRain' : 'softSnow';
var weatherSound = LK.getSound(soundName);
weatherSound.loop = false;
weatherSound.stop();
var soundIndex = currentAmbientSounds.indexOf(soundName);
if (soundIndex > -1) {
currentAmbientSounds.splice(soundIndex, 1);
}
// Restore original biome tint
if (biomeBackground) {
tween(biomeBackground, {
tint: biomeColors[currentBiome]
}, {
duration: 3000,
easing: tween.easeInOut
});
}
currentWeather = 'clear';
weatherTimer = Math.floor(Math.random() * weatherCheckInterval);
}
function generateWeatherParticles() {
clearWeatherParticles();
var particleCount = currentWeather === 'rain' ? 25 : 20;
for (var i = 0; i < particleCount; i++) {
var particle = new WeatherParticle(currentWeather);
particle.x = Math.random() * 2200; // Slightly wider than screen
particle.y = Math.random() * 2800;
particle.initialX = particle.x;
weatherParticles.push(particle);
game.addChild(particle);
}
}
function clearWeatherParticles() {
for (var i = weatherParticles.length - 1; i >= 0; i--) {
weatherParticles[i].destroy();
weatherParticles.splice(i, 1);
}
}
function generateWaterRipple() {
// Only spawn ripples in Serene Shoreline biome (index 2)
if (currentBiome !== 2 || gameState !== 'exploration') return;
// Limit number of active ripples
var activeRipples = 0;
for (var i = 0; i < waterRipples.length; i++) {
if (waterRipples[i].isActive) activeRipples++;
}
if (activeRipples >= maxActiveRipples) return;
// Find an inactive ripple to reuse, or create new one
var ripple = null;
for (var j = 0; j < waterRipples.length; j++) {
if (!waterRipples[j].isActive) {
ripple = waterRipples[j];
break;
}
}
if (!ripple) {
ripple = new WaterRipple();
waterRipples.push(ripple);
game.addChild(ripple);
}
// Position ripple in lower half of screen (lake area)
ripple.x = 300 + Math.random() * 1448; // Avoid edges
ripple.y = 1500 + Math.random() * 800; // Lower half for lake
// Start the ripple animation
ripple.startRipple();
// Reset timer with some randomness
rippleTimer = 0;
rippleSpawnInterval = 900 + Math.random() * 1200; // Extremely slow ripple spawn timing
}
function clearWaterRipples() {
for (var i = waterRipples.length - 1; i >= 0; i--) {
waterRipples[i].destroy();
waterRipples.splice(i, 1);
}
}
function generateTreeSway() {
clearTreeSway();
var branchCount = 8 + Math.floor(Math.random() * 6); // 8-14 swaying branches
for (var i = 0; i < branchCount; i++) {
var branch = new TreeSwayBranch();
// Position trees in foreground (edges) and mid-ground areas
var positionArea = Math.random();
if (positionArea < 0.3) {
// Left foreground trees
branch.x = 50 + Math.random() * 300;
branch.y = 400 + Math.random() * 1800;
} else if (positionArea < 0.6) {
// Right foreground trees
branch.x = 1700 + Math.random() * 300;
branch.y = 400 + Math.random() * 1800;
} else {
// Mid-ground scattered trees
branch.x = 300 + Math.random() * 1400;
branch.y = 200 + Math.random() * 1200;
}
// Vary branch sizes for depth
var depthScale = 0.6 + Math.random() * 0.8;
branch.scaleX = depthScale;
branch.scaleY = depthScale;
// Start the gentle swaying animation
branch.startSway();
treeSwayBranches.push(branch);
game.addChild(branch);
}
}
function clearTreeSway() {
for (var i = treeSwayBranches.length - 1; i >= 0; i--) {
treeSwayBranches[i].destroy();
treeSwayBranches.splice(i, 1);
}
}
function generateLightShimmer() {
clearLightShimmer();
// Create 1-3 light sources depending on biome (sun/moon/stars)
var shimmerCount = 1 + Math.floor(Math.random() * 3);
for (var i = 0; i < shimmerCount; i++) {
var shimmer = new LightShimmer();
// Position light sources in upper portion of sky
if (shimmerCount === 1) {
// Single main light source (sun/moon) positioned in upper third
shimmer.x = 800 + Math.random() * 400; // Center-ish area
shimmer.y = 200 + Math.random() * 400; // Upper third
} else {
// Multiple light sources (stars, etc.) scattered in upper half
shimmer.x = 200 + Math.random() * 1648;
shimmer.y = 100 + Math.random() * 600;
}
// Vary shimmer sizes for depth and variety
var sizeScale = 0.5 + Math.random() * 1.0;
shimmer.scaleX = sizeScale;
shimmer.scaleY = sizeScale;
// Start the gentle shimmer breathing animation
shimmer.startShimmer();
lightShimmers.push(shimmer);
game.addChild(shimmer);
}
}
function clearLightShimmer() {
for (var i = lightShimmers.length - 1; i >= 0; i--) {
lightShimmers[i].destroy();
lightShimmers.splice(i, 1);
}
}
function generateAuraWisp() {
if (gameState !== 'exploration') return;
// Limit number of active wisps
var activeWisps = 0;
for (var i = 0; i < auraWisps.length; i++) {
if (!auraWisps[i].collected) activeWisps++;
}
if (activeWisps >= maxActiveWisps) return;
// Choose wisp type based on current biome preference
var wispTypes = ['green', 'blue', 'yellow'];
var wispType = wispTypes[Math.floor(Math.random() * wispTypes.length)];
var wisp = new AuraWisp(wispType);
// Position wisp to emerge from environmental elements
var emergenceLocations = [
// From under rocks (bottom edges)
{
x: 100 + Math.random() * 300,
y: 2400 + Math.random() * 200
}, {
x: 1600 + Math.random() * 300,
y: 2400 + Math.random() * 200
},
// Near glowing mushrooms (mid areas)
{
x: 400 + Math.random() * 1200,
y: 1200 + Math.random() * 800
},
// From within tree trunks (forest edges)
{
x: 50 + Math.random() * 200,
y: 600 + Math.random() * 1200
}, {
x: 1800 + Math.random() * 200,
y: 600 + Math.random() * 1200
},
// From crystal formations (upper areas for crystal caverns)
{
x: 300 + Math.random() * 1400,
y: 300 + Math.random() * 600
}];
var location = emergenceLocations[Math.floor(Math.random() * emergenceLocations.length)];
// Add some randomness to exact position
wisp.x = location.x + (Math.random() - 0.5) * 100;
wisp.y = location.y + (Math.random() - 0.5) * 100;
wisp.initialY = wisp.y;
// Ensure wisp stays within bounds
wisp.x = Math.max(50, Math.min(1998, wisp.x));
wisp.y = Math.max(200, Math.min(2532, wisp.y));
auraWisps.push(wisp);
game.addChild(wisp);
// Reset timer with some randomness
wispSpawnTimer = 0;
wispSpawnInterval = 120 + Math.random() * 180;
}
function clearAuraWisps() {
for (var i = auraWisps.length - 1; i >= 0; i--) {
auraWisps[i].destroy();
auraWisps.splice(i, 1);
}
}
function triggerZenMoment() {
if (isZenMomentActive || gameState !== 'exploration') return;
isZenMomentActive = true;
zenMomentEndTimer = 0;
// Store original background tint
if (biomeBackground) {
originalBackgroundTint = biomeBackground.tint;
// Subtle desaturation effect
tween(biomeBackground, {
tint: 0xb0b0b0
}, {
duration: 2000,
easing: tween.easeInOut
});
}
// Create zen affirmation text
var affirmation = zenAffirmations[Math.floor(Math.random() * zenAffirmations.length)];
zenText = new Text2(affirmation, {
size: 120,
fill: 0xffffff
});
zenText.anchor.set(0.5, 0.5);
zenText.alpha = 0;
// Position zen text in center
LK.gui.center.addChild(zenText);
// Gentle fade in for zen text - ensure zenText exists before tweening
if (zenText) {
tween(zenText, {
alpha: 0.9,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Gentle pulsing while displayed - check zenText still exists
if (zenText) {
tween(zenText, {
alpha: 0.7,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (zenText) {
tween(zenText, {
alpha: 0.9,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}
});
}
}
});
}
// Play gentle zen bell sound
LK.getSound('zenMomentBell').play();
// Play zen moment music (very minimalistic)
var currentVolume = 0.7;
if (currentMusicTrack) {
// Fade current music to lower volume
LK.playMusic(currentMusicTrack, {
fade: {
start: currentVolume,
end: 0.2,
duration: 1500
}
});
}
// Start zen music softly
LK.playMusic('zenMomentMusic', {
fade: {
start: 0,
end: 0.3,
duration: 1500
}
});
}
function endZenMoment() {
if (!isZenMomentActive) return;
isZenMomentActive = false;
// Fade out zen text
if (zenText && zenText.parent) {
tween(zenText, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 2000,
easing: tween.easeIn,
onFinish: function onFinish() {
if (zenText && zenText.parent) {
zenText.parent.removeChild(zenText);
}
zenText = null;
}
});
} else if (zenText) {
// If zenText exists but has no parent, just set to null
zenText = null;
}
// Restore original background tint
if (biomeBackground) {
tween(biomeBackground, {
tint: originalBackgroundTint
}, {
duration: 2000,
easing: tween.easeInOut
});
}
// Restore original music
LK.playMusic('zenMomentMusic', {
fade: {
start: 0.3,
end: 0,
duration: 1500
}
});
LK.setTimeout(function () {
if (currentMusicTrack && currentMusicTrack !== 'zenMomentMusic') {
LK.playMusic(currentMusicTrack, {
fade: {
start: 0.2,
end: 0.7,
duration: 1500
}
});
}
}, 1500);
// Reset timer for next zen moment
zenMomentTimer = Math.floor(Math.random() * zenMomentInterval) + zenMomentInterval;
}
function playHavenMusic() {
if (currentMusicTrack === 'havenAmbient') return;
if (currentMusicTrack) {
// Fade out current music
var prevTrack = currentMusicTrack;
LK.playMusic(prevTrack, {
fade: {
start: 0.7,
end: 0,
duration: musicFadeTime
}
});
LK.setTimeout(function () {
// Fade in haven music
LK.playMusic('havenAmbient', {
fade: {
start: 0,
end: 0.6,
duration: musicFadeTime
}
});
currentMusicTrack = 'havenAmbient';
}, musicFadeTime);
} else {
// First time playing music
LK.playMusic('havenAmbient', {
fade: {
start: 0,
end: 0.6,
duration: musicFadeTime
}
});
currentMusicTrack = 'havenAmbient';
}
}
// Touch/Mouse handlers
var draggedDecoration = null;
var isPlacingDecoration = false;
game.move = function (x, y, obj) {
if (gameState === 'exploration') {
player.targetX = x;
player.targetY = y;
} else if (gameState === 'haven' && draggedDecoration) {
draggedDecoration.x = x;
draggedDecoration.y = y;
}
};
game.down = function (x, y, obj) {
if (gameState === 'haven') {
// Check if touching a decoration
for (var i = 0; i < havenDecorations.length; i++) {
var decoration = havenDecorations[i];
var dx = x - decoration.x;
var dy = y - decoration.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 60) {
draggedDecoration = decoration;
// Play rustle sound for plant interactions
if (decoration.decorationType === 'plant') {
LK.getSound('plantRustle').play();
}
break;
}
}
// Try to place new decoration if not dragging
if (!draggedDecoration && totalAuras >= 10) {
var decorationTypes = ['plant', 'light', 'water'];
var randomType = decorationTypes[Math.floor(Math.random() * decorationTypes.length)];
var newDecoration = new HavenDecoration(randomType);
newDecoration.x = x;
newDecoration.y = y;
havenDecorations.push(newDecoration);
game.addChild(newDecoration);
auraCount.green = Math.max(0, auraCount.green - 4);
auraCount.blue = Math.max(0, auraCount.blue - 3);
auraCount.yellow = Math.max(0, auraCount.yellow - 3);
updateUI();
saveHavenDecorations();
LK.getSound('placeItem').play();
}
}
};
game.up = function (x, y, obj) {
if (draggedDecoration) {
saveHavenDecorations();
draggedDecoration = null;
}
};
// Button handlers
havenButton.down = function (x, y, obj) {
if (gameState === 'exploration') {
initializeHaven();
}
};
exploreButton.down = function (x, y, obj) {
if (gameState === 'haven') {
initializeExploration();
}
};
// Main game update loop
game.update = function () {
if (gameState === 'exploration') {
// Check rare bloom spawning
rareBloomTimer++;
if (rareBloomTimer >= rareBloomSpawnInterval && !rareBloom) {
spawnRareBloom();
}
// Check ephemeral creature spawning
ephemeralTimer++;
if (ephemeralTimer >= ephemeralSpawnInterval && !ephemeralCreature) {
spawnEphemeralCreature();
}
// Check weather transformations
weatherTimer++;
if (weatherTimer >= weatherCheckInterval && !isWeatherActive) {
startWeatherTransformation();
}
// Check zen moment triggering
zenMomentTimer++;
if (zenMomentTimer >= zenMomentInterval && !isZenMomentActive) {
triggerZenMoment();
}
// Check water ripple spawning (only in Serene Shoreline)
if (currentBiome === 2) {
rippleTimer++;
if (rippleTimer >= rippleSpawnInterval) {
generateWaterRipple();
}
}
// Check aura wisp spawning
wispSpawnTimer++;
if (wispSpawnTimer >= wispSpawnInterval) {
generateAuraWisp();
}
// Clean up collected wisps
for (var w = auraWisps.length - 1; w >= 0; w--) {
if (auraWisps[w].collected) {
auraWisps.splice(w, 1);
}
}
// Clean up expired ephemeral shimmers
for (var s = ephemeralShimmers.length - 1; s >= 0; s--) {
if (!ephemeralShimmers[s].parent) {
ephemeralShimmers.splice(s, 1);
}
}
// Clean up expired rare bloom burst particles
for (var b = rareBloomBursts.length - 1; b >= 0; b--) {
if (!rareBloomBursts[b].parent) {
rareBloomBursts.splice(b, 1);
}
}
// Check zen moment duration
if (isZenMomentActive) {
zenMomentEndTimer++;
if (zenMomentEndTimer >= zenMomentDuration) {
endZenMoment();
}
}
// Check weather duration
if (isWeatherActive) {
weatherEndTimer++;
if (weatherEndTimer >= weatherDuration) {
endWeatherTransformation();
}
}
// Check hidden vignette discovery
for (var v = 0; v < hiddenVignettes.length; v++) {
var vignette = hiddenVignettes[v];
if (!vignette.discovered) {
var dx = player.x - vignette.x;
var dy = player.y - vignette.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < vignetteDiscoveryRadius) {
vignette.discover();
}
}
}
// Check rare bloom collection
if (rareBloom && !rareBloom.collected && player.intersects(rareBloom)) {
rareBloom.collected = true;
// Award significant auras (5 of each type)
auraCount.green += 5;
auraCount.blue += 5;
auraCount.yellow += 5;
updateUI();
// Play special collection sound
LK.getSound('rareBloomCollect').play();
// Create spectacular visual effect
LK.effects.flashScreen(0xffd700, 1500);
// Create burst of glowing particles (medium count for spectacular effect)
for (var b = 0; b < 12; b++) {
var burstParticle = new RareBloomBurst();
burstParticle.x = rareBloom.x;
burstParticle.y = rareBloom.y;
rareBloomBursts.push(burstParticle);
game.addChild(burstParticle);
}
// Burst animation with swirl of particles
tween(rareBloom, {
scaleX: 3.0,
scaleY: 3.0,
alpha: 1.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(rareBloom, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
rareBloom.destroy();
rareBloom = null;
// Reset timer for next rare bloom
rareBloomTimer = Math.floor(Math.random() * rareBloomSpawnInterval);
}
});
}
});
}
// Check aura collection
for (var i = auraParticles.length - 1; i >= 0; i--) {
var aura = auraParticles[i];
if (!aura.collected && player.intersects(aura)) {
aura.collected = true;
auraCount[aura.type]++;
updateUI();
// Collect animation with gentle glow effect
tween(aura, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(aura, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
aura.destroy();
}
});
}
});
auraParticles.splice(i, 1);
LK.getSound('collectAura').play();
}
}
// Check if all auras collected
if (auraParticles.length === 0) {
LK.setTimeout(function () {
currentBiome = (currentBiome + 1) % biomes.length;
generateAuraParticles();
// Update biome display and music
biomeText.setText(biomes[currentBiome]);
if (biomeBackground) {
biomeBackground.tint = biomeColors[currentBiome];
}
playBiomeMusic(currentBiome);
playAmbientSounds(currentBiome);
}, 1000);
}
}
};
// Start the game
initializeExploration();
auraBlue top view. In-Game asset. 2d. High contrast. No shadows
auraGreen top view. In-Game asset. 2d. High contrast. No shadows
auraWisp top view. In-Game asset. 2d. High contrast. No shadows
auraYellow top view. In-Game asset. 2d. High contrast. No shadows
biomeBackground top view. In-Game asset. 2d. High contrast. No shadows
distantCloud top view. In-Game asset. 2d. High contrast. No shadows
waterRipple top view. In-Game asset. 2d. High contrast. No shadows
waterDecoration top view. In-Game asset. 2d. High contrast. No shadows
tree Sway Branch top view. In-Game asset. 2d. High contrast. No shadows
rare Bloom Pulse top view. In-Game asset. 2d. High contrast. No shadows
snow Flake top view. In-Game asset. 2d. High contrast. No shadows
rare Bloom Burst Particle top view. In-Game asset. 2d. High contrast. No shadows
rare Bloom Burst top view. In-Game asset. 2d. High contrast. No shadows
sleeping Bear top view. In-Game asset. 2d. High contrast. No shadows
rare Aura Bloom top view. In-Game asset. 2d. High contrast. No shadows
raindrops. In-Game asset. 2d. High contrast. No shadows
light Shimmer top view. In-Game asset. 2d. High contrast. No shadows
light Decoration top view. In-Game asset. 2d. High contrast. No shadows
hiddenWaterfall. In-Game asset. 2d. High contrast. No shadows
havenBackground. In-Game asset. 2d. High contrast. No shadows
floatingParticle. In-Game asset. 2d. High contrast. No shadows
ephemeralHummingbird. In-Game asset. 2d. High contrast. No shadows
ephemeralFox. In-Game asset. 2d. High contrast. No shadows
ephemeralSpirit. In-Game asset. 2d. High contrast. No shadows
ephemeralShimmer. In-Game asset. 2d. High contrast. No shadows
plantDecoration. In-Game asset. 2d. High contrast. No shadows
mushroomRing. In-Game asset. 2d. High contrast. No shadows
luminescentParticleAlt. In-Game asset. 2d. High contrast. No shadows
luminescentParticle. In-Game asset. 2d. High contrast. No shadows
player aura image top view in space game.