Update README.md with new demo links and video resources. Changed live demo URL to Hugging Face and added YouTube and dev.to links for the demo video and social post, respectively.
Refactor overlay behavior to improve user interaction during descent transition. The start button now has its pointer events disabled when the overlay is hidden, preventing click interference with underlying elements while maintaining a smooth fade-out effect.
Update startDescent function to hide the start button during descent transition. This change prevents the button from capturing pointer events and allows user interactions with underlying elements, ensuring a smoother experience.
Update README.md to enhance project description and add badge goals for the Build Small Hackathon. Changed short description to reflect focus on lofi beats, and included detailed sections on project features, generation pipeline, and personal background. Added tags for better categorization.
Remove 'ready' class from start button to prevent click interference during descent transition. This change ensures the overlay fades correctly while allowing user interactions with underlying elements.
A fixed glass button in the top-right toggles mute for every audio element (tapes + lobby) via querySelectorAll('audio').muted - independent of the volume/fade logic, so unmuting restores it. The choice persists in localStorage ('lofinity:muted') and is restored on load. z-index 50 keeps it above the modals so it works while a tape plays. Verified in preview: renders, mutes all 3 audio elements, persists across reload.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refactor UI code for improved readability and consistency
Updated formatting in ui.js for better code clarity, including consistent line breaks and indentation. Adjusted lobby music volume from 0.28 to 0.2 for a softer background experience. Ensured that the length slider and related functions maintain their intended behavior while enhancing overall code maintainability.
Gate the intro camera descent behind a 'click to start' button
The descent auto-fired HOLD_MS after load; now the camera holds on the sky until the user clicks a 'click to start' button on the title overlay (a glass pill matching the subtitle, revealed once assets + fonts are ready). The same click is the user gesture that also starts the lobby music. Drops the now-unused HOLD_MS and the auto-descent timer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A looping background track (frontend/lobby.mp3, LFS-tracked, served at /static/lobby.mp3) starts on the user's first gesture (browsers gate audio autoplay) and plays whenever the player is idle - no tape loaded, or paused. It fades out under a playing tape and back in when the tape stops, driven from the one play/pause chokepoint syncPlayState() -> updateLobby(). Track: Alex Morgan, 'Peaceful Cafe Jazz' (Pixabay, royalty-free). Also adds *.mp3 to Git LFS.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Clear the prompt on 'make another', keep the chosen length
The again-btn handler did input.select() (kept the previous prompt text selected). Clear the textarea instead so each new tape starts from an empty prompt; the length slider is untouched, so the chosen duration carries over.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Scale model + tape length to the hardware (GPU vs CPU)
On a ZeroGPU Space: musicgen-medium, tapes up to 90s (chunked) - unchanged. Without a GPU: fall back to musicgen-small and a single 30s shot (no chunking), since medium + chunking on CPU would take minutes. Both the model default and ALLOWED_SECONDS now branch on IS_ZEROGPU (env still overrides the model). New /api/config exposes the allowed lengths; the length slider fetches it and collapses to a single 0:30 when that's all the backend offers - defensive, so any fetch failure keeps the 30/60/90 default and the GPU path is untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cap continuation generation at 28s to stay in musicgen's 30s window
musicgen is trained on 30s clips, so a single shot longer than ~30s degrades its tail into noise. Each continuation prepended the OVERLAP_S seed and then generated a full 30s of NEW audio (seed + 30 = 31-32s total), pushing the tail past the training window — the source of the 'weird noise', and why shrinking the seed kept helping. Now a continuation generates only MAX_GEN_S - OVERLAP_S new seconds so the whole shot stays <=28s (env LOFINITY_MAX_GEN_S, default 28). The first chunk is unchanged (text-only, exactly 30s, already clean). Side effect: long tapes are slightly shorter — each continuation adds ~27s of clean audio instead of 30s of partly-degraded — so 60s->~57s, 90s->~84s.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Shorten the continuation seed to 2s (env LOFINITY_OVERLAP_S)
Feed only the last 2s (was 6s) back as the continuation seed, so each chunk re-encodes less audio through EnCodec and leans more on the text prompt - an attempt to cut the continuation noise. Seed length is now the LOFINITY_OVERLAP_S env var (default 2) so it's tunable from Space settings without a code push.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Switch to musicgen-medium for cleaner continuations
musicgen-small's audio continuations degrade into noise after a chunk or two: text-only chunks stay clean (spectral flatness ~0.1) but every audio-seeded continuation is ~3x noisier (~0.3) regardless of guidance_scale or seed normalization. Swap to musicgen-medium, which continues more cleanly. Model id is now the LOFINITY_MUSICGEN env var (default facebook/musicgen-medium). Widen the @spaces.GPU duration budget to 40 + 40*chunks and bump the progress estimate, since medium renders slower and an overrun gets the brew KILLED mid-render.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Report a time-based brew estimate so the progress bar moves on ZeroGPU (Stage 3)
The @spaces.GPU worker is a separate process, so it can't push per-chunk progress back to /api/progress - the brew bar froze at 0% then jumped to 100% on the Space. /api/progress now returns a smooth time-based estimate (fractional done, capped at 92%) computed from the brew's start + a rough per-length budget, snapping to 100% when the tape lands. Local/stub paths keep their real per-chunk progress (the estimate only kicks in while a ZeroGPU brew is active).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add MiniCPM5-1B prompt enrichment for ZeroGPU Spaces (Stage 2)
A Space has no Ollama daemon, so enrichment fell back to the plain non-LLM path (bland titles). Add a MiniCPM5-1B backend (standard LlamaForCausalLM, no trust_remote_code, thinking mode off, robust JSON parse) loaded on cuda at startup and run INSIDE the @spaces.GPU call alongside MusicGen - one GPU acquisition per vend. enrich_prompt now dispatches by environment: MiniCPM on ZeroGPU, Ollama locally, plain fallback on any failure (a bad enricher can't crash the app - startup load is guarded). No new dependencies (transformers already covers it). Local mps/cpu/stub paths and progress are unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fix ZeroGPU detection: read spaces Config.zero_gpu, not exact env match
The previous check compared SPACES_ZERO_GPU to the literal "true", but the ZeroGPU runtime sets a value the spaces library parses loosely ("1"/"t"/"true"), so IS_ZEROGPU was False on the Space and generation fell back to CPU (loaded lazily on cpu mid-brew). Read the library's own Config.zero_gpu - the same flag that gates the @spaces.GPU decorator - so detection is True exactly when a GPU will be allocated. Add a startup log of the resolved flag for diagnosis.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add ZeroGPU support for GPU-accelerated MusicGen on HF Spaces
Detect the ZeroGPU runtime via SPACES_ZERO_GPU and shim the spaces package to a no-op locally, so the same code runs on mps/cpu unchanged. On ZeroGPU the model loads on cuda at module level (the documented pattern) and generation runs inside an @spaces.GPU call with a dynamic duration budget; generate_song routes to the GPU path only on the Space, leaving local mps/cpu/stub paths and progress untouched. Bump the Space to python 3.12.12 (ZeroGPU requirement) and add spaces to requirements.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Enhance music generation functionality by introducing a tape-length slider and progress tracking. Updated app.py to manage chunk lengths and progress callbacks, while frontend files now include a slider for selecting tape length and a progress bar to visualize the brewing process. Improved user experience during audio generation with real-time feedback on progress.
Refactor subtitle presentation in index.html and enhance animations in style.css. Wrapped the subtitle in a new div for improved styling and added slide and fade animations to enhance visual appeal during the title display.
Enhance audio playback controls with loop functionality. Added a loop button in index.html and corresponding styles in style.css. Updated ui.js to manage loop state and toggle behavior, allowing users to switch between looping the current tape and playing through the shelf. Refactored loadCassette function to accommodate new looping logic.
Refactor audio handling to return base64 WAV data URIs instead of writing to disk. Updated generate_song function to streamline audio response and removed list_songs functionality, enhancing session management by keeping tapes in memory. Adjusted frontend to handle new audio data format and removed unused functions for a cleaner codebase.
Throttle render loop to 30fps for improved performance in garden animation. Updated frame handling in createGarden function to reduce CPU/GPU load while maintaining smooth visuals.
Replace loading animation with a new plant-themed grow-loader in index.html and style.css. The updated loader features sprouting plants that bloom while the beat brews, enhancing the visual experience during loading times.
Add "play while waiting" feature to enhance user experience. Introduced a new button in index.html that allows users to engage with a garden mini-game while waiting. Updated main.js to handle the button's functionality, and modified ui.js to manage its visibility based on the current stage. Enhanced style.css with new styles for the button, ensuring it is visually appealing and interactive.
Refactor HTML structure and enhance CSS for Game Boy modal. Improved the organization of meta tags in index.html for better readability and SEO. Updated style.css to optimize the Game Boy modal's appearance and interaction, including new styles for the d-pad and button interactions. Enhanced ui.js to integrate a garden mini-game within the Game Boy modal, ensuring a smoother user experience.
Implement audio crossfade and playlist functionality in UI. Enhanced the audio management system by introducing two audio elements for crossfading, updating the track loading mechanism, and adding playlist support. Refactored related functions for improved clarity and performance, ensuring a seamless user experience during audio transitions.
Update README and index.html for enhanced metadata and visuals. Added a thumbnail link to README and improved SEO with Open Graph and Twitter meta tags in index.html, including updated title and description for better social sharing.
Add Game Boy feature and modal interaction. Introduced a Game Boy model in the scene, updated main.js to handle zoom interactions and modal display, and enhanced UI components in ui.js for opening and closing the Game Boy modal. Added corresponding styles in style.css for the modal's appearance and animations. Updated index.html to include a new label for the Game Boy interaction.
Optimize scene rendering by merging static geometries. Added a function to collapse static meshes in the scene into single meshes per material, significantly reducing draw calls. Excluded interactable and animated objects to maintain functionality. Updated main.js to integrate this optimization.
Implement day/night cycle and lamp interaction features. Updated main.js to manage the transition between day and night modes, including dynamic lighting adjustments and palette changes. Added a new lamp label in index.html for user interaction, and modified style.css for proper positioning of the label. Enhanced world.js to include outlines for the lamp and its components, improving visual feedback during interactions.
Enhance carousel functionality and styling. Updated ui.js to implement a coverflow layout for cassette cards, allowing for improved visual presentation and interaction. Added keyboard navigation for carousel controls and refined button states in style.css for better user experience. Adjusted card animations and positioning for a more dynamic interface.
Add ambience generation features and assets. Introduced ambience.py for procedural and sampled ambience beds, updated app.py to integrate ambience selection into music generation, and modified requirements.txt to include new dependencies. Added scripts for fetching and rendering ambience samples, along with new audio assets and credits for attribution.
Add song metadata handling and collection feature. Updated app.py to generate and store song metadata alongside audio files, introduced a new API endpoint for listing songs, and enhanced frontend components in ui.js and main.js to manage song collection display and interactions. Modified index.html and style.css for improved UI presentation of the cassette collection.
Enhance interactable features and visual labels in the scene. Updated index.html to add a new collection label, modified main.js to manage hover interactions for both vending machine and cassette collection, and adjusted style.css for consistent label styling. Improved world.js to include outlines for the cassette pile and walkman, enabling better user interaction.
Add bird animation and cassette pile to the scene. Updated main.js to include bird movement and tail flicking behavior, and enhanced world.js with new cassette pile, walkman, and headphones models. Integrated cable geometry for visual detail and adjusted bird positioning on the bench.
Refine music prompt generation in app.py. Updated the ENRICH_SYSTEM to clarify JSON response structure and enhance music_prompt template with specific instrument and background noise guidelines. Adjusted temperature setting for improved output consistency and ensured background noise is always included in the music prompt.
Optimize rendering performance and scene management in main.js. Updated WebGLRenderer settings for lower power consumption, adjusted pixel ratio, and improved shadow map handling. Enhanced animation frame control for smoother transitions and reduced unnecessary computations in static scene objects.
Enhance audio generation capabilities and enrich prompt processing. Updated app.py to implement a new prompt enrichment function using Ollama, added environment variable configurations, and improved the music generation engine. Modified requirements.txt to include necessary dependencies for transformers and torch. Updated index.html to inform users about audio generation duration.
Implement vending machine modal and audio generation features. Updated app.py to include audio URL for browser clients, enhanced index.html with a modal for user interaction, and added corresponding styles in style.css. Improved main.js to manage camera transitions and modal behavior during audio generation.
Add vending machine interaction features. Introduced a floating label for the vending machine in index.html, implemented hover effects and click handling in main.js, and styled the label in style.css. Enhanced world.js to include a visual outline for the vending machine during hover.
Enhance visual presentation and camera dynamics. Updated subtitle styling in index.html, refined camera movement and lighting in main.js, and improved cloud generation in world.js. Adjusted CSS for smoother transitions and animations, enhancing overall user experience.
Refactor main.js to enhance scene setup and integrate world building. Updated camera positioning, lighting settings, and removed placeholder objects in favor of a new world.js module. Improved intro choreography and added debug functionality for skipping the intro.