| name | loopaper-conventions |
| description | Background knowledge for working on the Loopaper codebase — the domain glossary, locked architecture decisions, and target module map. Loaded automatically when writing or changing Loopaper Swift code, UI strings, or docs so generated code stays on-vocabulary and in the right file. |
| user-invocable | false |
Loopaper conventions
Apply this whenever you write or change code, UI strings, or docs in this repo.
Use the exact domain vocabulary (CONTEXT.md)
CONTEXT.md is the source of truth. Use these terms in names, comments, and user-facing English strings; avoid the listed synonyms:
- Wallpaper (the looping video the user sets) — not video/background/clip/animation
- Desktop Window (borderless NSWindow below the icon layer) — not overlay/player window/background window
- Freeze (capture current frame → real OS desktop image on Quit) — not snapshot/pause-image/static fallback
- Library — not catalog/gallery/collection
- Source — not origin/provider
- Pause (video stops on last frame, real wallpaper untouched, resumable; all power auto-stops are Pauses) — not stop/freeze/suspend
- Disable (Desktop Window closes, Original Wallpaper restored, app keeps running) — not stop/turn off/reset
- Like — not favorite/star/bookmark
- Screen (a display keyed by a stable id, not the transient
CGDirectDisplayID) — not monitor/display/screenID
- Original Wallpaper (the user's desktop image before the app first took over a screen) — not previous/system/default wallpaper
The three states are distinct — never conflate Pause / Disable / Quit.
Respect the locked architecture decisions (docs/adr/)
These are decided. Do not re-litigate without updating the ADR:
- ADR-0001 — non-sandboxed Developer ID distribution. App Sandbox OFF, Hardened Runtime ON. (Sandbox would block the Freeze feature.)
- ADR-0002 — Desktop rendering: per-screen borderless
NSWindow hosting AVPlayerLayer, level between kCGDesktopWindowLevel and kCGDesktopIconWindowLevel, ignoresMouseEvents, canJoinAllSpaces; real desktop image untouched while running; Freeze pre-renders to native pixel size with non-rescaling fill options.
Other settled invariants from CLAUDE.md: lazy first occupation (back up Original Wallpaper once, at first set, non-destructive on failure); per-screen state { screenKey → wallpaperID } with one AVPlayer each; screenKey = UUID → EDID → transient:displayID; all players isMuted = true in v1; user-added videos copied into App Support.
Put code in the right place (docs/work-plan.md)
Follow the target module map in docs/work-plan.md — e.g. Desktop/WallpaperEngine.swift, Freeze/FrameFreezer.swift, Freeze/OriginalWallpaperStore.swift, Screens/ScreenIdentity.swift, Power/PowerManager.swift, Library/…, UI/…. Work proceeds in phases (tracer-bullet first); check which Phase a task belongs to before adding files. Min target macOS 14.0, Universal. UI is English-only in v1.
When in doubt, read CONTEXT.md, the relevant ADR, and docs/work-plan.md rather than inventing terminology or structure.