This file defines required rules for any human or AI agent modifying Snowify. Follow these rules before writing code.
Snowify is an Electron music player. The renderer is modular ES modules. Do not re-grow a monolithic renderer file. Keep logic in module files.
- Main renderer entry:
src/renderer/app.js - Feature modules:
src/renderer/modules/*.js - State singleton:
src/renderer/modules/state.js - Shared utils:
src/renderer/modules/utils.js - Theme system:
src/renderer/modules/theme.js
app.js should only contain:
- Boot/init orchestration
- Global cloud-sync lifecycle and persistence orchestration
- Welcome overlay state glue
- Global app-level event wiring that is intentionally cross-feature
- Callback injection into module callback objects
All feature logic belongs in modules.
Keep responsibilities in these files:
player.js: playback transport, queue stepping integration, volume/progress, now-playing bar controls, prefetch/normalizer accessorsqueue.js: queue panel, history panel, play-next/add-to-queue/radio helperslibrary.js: playlists, playlist detail view, drag/drop reorder and track movementcontext-menus.js: all context menu rendering and actionshome.js: home view rendering and release cacheexplore.js: explore charts/trending rendering and explore cachealbum.js: album and external playlist detail pagesartist.js: artist page rendering, artist navigation, artist link bindingsearch.js: search view behavior, suggestions, search history UI interactionssettings.js: settings page behavior, auth/profile controls, updater/changelog/dev section/source listsplugins.js: plugin loading/state and marketplace renderinglyrics.js: lyrics panel and sync behaviornow-playing.js: full-screen now-playing and lyrics styling/sync therevideo-player.js: video overlay/miniplayer behavioraudio-ref.js: shared audio engine/audio element references and volume constantscallbacks.js: cross-module callback injection for save/view/meta bridges
If you touch functionality, edit the owning module.
callbacks.js is dependency-inversion glue for modules that need app-owned functions.
callbacks.saveStatecallbacks.maybeEnrichTrackMetacallbacks.switchView
Rules:
- Modules call these callbacks.
app.jsmust assign real implementations infinishInit().- Do not import
app.jsfrom modules.
settings.js exports settingsCallbacks to avoid settings importing app internals.
Required app assignments in finishInit():
forceCloudSavecloudLoadAndMergeupdateSyncStatusgetCloudUsergetCloudSyncPausedsetCloudSyncPausedclearCloudSaveTimeoutshowWelcomeOverlayhideWelcomeOverlaysetWelcomeErrorupdateAccountUI
- Avoid cycles by using callback injection or argument injection.
- If needed, dynamic import inside event handlers is acceptable for low-frequency UI actions.
- Never solve cycles by copying logic across files.
- Global mutable app data must live on
state. - Any user-visible persistent change must call
callbacks.saveState(). - Queue/play log/genre cache persistence shape must remain backward compatible.
- Cloud payload must not include local-only tracks.
- User-facing strings must use
I18n.t(...)keys. - Do not hardcode display text unless it is a strict temporary debug message.
- The single locale directory is
src/renderer/locales/*.json. This is used by both the renderer (viafetch) and the Electron main process (viafs.readFileSync). Always editsrc/renderer/locales/en.json(and other languages) when adding new keys. There is nosrc/locales/directory. - Preserve mobile behavior and gestures.
- Respect reduced-motion and existing animation toggles.
- Reuse existing CSS classes and component patterns.
- Do not introduce major style-system changes without updating all related views.
- Keep DOM queries local to module scope unless shared by design.
window.SnowifySourcesregistration API is app-owned and initialized infinishInit()before plugin use.- Plugins may register song/meta sources only through registry methods.
- Source list UI (
settings.js) is the single source-order control surface.
Before editing:
- Identify owner module.
- Check for existing callback contract.
- Check for i18n keys and mobile behavior impact.
When editing:
- Make the smallest targeted change.
- Do not move unrelated logic.
- Do not rename public exports unless all imports are updated.
- Make sure any Mobile specific changes don't impact Desktop unless required
After editing:
- Run syntax checks for touched files.
- Verify no renderer compile errors.
- Verify no unresolved references.
For renderer changes, run all:
node --check src/renderer/app.jsnode --checkfor every touched module file- Editor diagnostics clean for touched files
For changes to src/mobile/bridge.js, also run:
npm run build:mobile— regeneratessrc/renderer/mobile-bridge.js(the bundled IIFE loaded by the Capacitor WebView)- Commit
src/renderer/mobile-bridge.jsalongside the source change - Never edit
src/renderer/mobile-bridge.jsdirectly — it is a generated artifact and will be overwritten by the next build
For behavior-sensitive changes, ask for manually verification:
- App boot succeeds
- Navigation between home/explore/search/library/settings works
- Playback controls and keyboard shortcuts work
- Settings open and save flows work
- Plugin list still loads
- Do not add new large feature blocks back into
app.js. - Do not directly import app internals into modules.
- Do not duplicate helper logic between modules when a shared helper exists.
- Do not bypass
callbacks.saveState()for persisted state updates. - Do not use destructive git commands to "fix" unrelated changes.
When adding a feature:
- Pick or create a feature module under
src/renderer/modules/. - Export only the public functions needed by callers.
- Add callback injection points if app-owned dependencies are needed.
- Wire imports and callback assignments in
app.js. - Add i18n keys to
src/renderer/locales/en.json(and other language files if applicable). - Run validation checklist.
If extracting code from app.js:
- Move code to module with minimal behavior change.
- Export moved functions.
- Replace old logic with imports/callback wiring.
- Remove dead code from
app.jsimmediately. - Verify all references compile.
The target is stable modular architecture, not temporary dual paths.