10 KiB
10 KiB
AGENTS.md
Guidance for AI agents (and humans) working on Vision Start. Read before making changes.
0. First rule: keep project-context.md alive
- Always read
project-context.mdfirst. It is the canonical map of the project: structure, features, data model, flow, build/release. Treat it as required reading before any non-trivial change. - Always keep it updated. Whenever you add, remove, rename, or materially change files, modules, features, storage keys, config fields, build/release steps, or workflows, update the relevant section of
project-context.mdin the same change set. If your work touches the structure tree, the data model, the storage layout, or the quick-lookup table, those sections must reflect the new state. - Keep it a general overview, not a coding-style guide — that distinction lives here in
AGENTS.md.
1. Styling guidance
The design language is light liquid glass: translucent bright surfaces, refractive edge highlights, backdrop blur, soft shadows, cyan accents, and iOS-like easing.
Surface recipe (use consistently)
- Tiles / floating controls / light surfaces:
liquid-surfaceplusliquid-control/liquid-tile/liquid-focusas appropriate. - Cards / modals / panels:
liquid-panel liquid-modal-card rounded-3xlfor centered modals;liquid-drawerfor the settings drawer. - Inputs:
liquid-input p-3; ranges useliquid-range. - Buttons:
liquid-buttonplus one ofliquid-button-primary,liquid-button-success,liquid-button-secondary, orliquid-button-danger. - Add/edit surfaces: add tiles use
liquid-ghost-tile; tile edit controls useliquid-edit-toolbarandliquid-edit-action. - Full-screen modal overlay:
liquid-modal-backdrop.
Color tokens
- Accent / focus / selection: cyan via
liquid-focus,cyan-400,cyan-200, andliquid-button-primary - Confirm/Save:
liquid-button-success - Cancel/secondary:
liquid-button-secondary - Destructive:
liquid-button-dangeror red text onliquid-edit-action - Tertiary (export/import etc.):
liquid-button-secondary - Status: online
bg-green-400 text-green-400, offlinebg-red-400 text-red-400, pendingbg-slate-400 text-slate-400 - Text: primary
text-white, secondarytext-slate-300/text-slate-400, mutedtext-white/50(in-app hover states)
Motion
- Use the custom easing tokens defined in
index.css:ease-ios(default),ease-spring(toggle knobs, drawer slides), andease-liquid(tile lift and wallpaper transitions). - Standard durations:
duration-150(buttons),duration-200(tiles, toggles, icons), andduration-300(drawers/modals). - Prefer the shared liquid classes for hover/press motion. Add custom transforms only when the shared classes do not cover the interaction.
- Keep
prefers-reduced-motionbehavior intact when adding animations.
Tailwind specifics
- Tailwind v4 via
@tailwindcss/viteand@tailwindcss/postcss. Custom easing is inindex.cssunder@theme {}— add new theme tokens there, not intailwind.config.js. tailwind.config.jshas a safelist ofw-[Npx]/h-[Npx]classes because tile/icon sizes are constructed dynamically. If you add new pixel-size classes that are generated at runtime (not literally present in source), add them to the safelist or they will be purged.- Prefer static classes; only build dynamic class strings when unavoidable and then safelist them.
Components with established conventions to reuse
Dropdown(components/Dropdown.tsx) for selects — single or multi. Has a glassy look and custom arrow. Always use it instead of<select>/<input type=...>for option picking.ToggleSwitch(components/ToggleSwitch.tsx) for boolean toggles — always use it instead of checkboxes.- Modal pattern:
liquid-modal-backdrop+ centeredliquid-panel liquid-modal-card rounded-3xl, close on overlay click viahandleOverlayClick(if (e.target === e.currentTarget) onClose()). - New editors/settings go in
components/configuration/as a*Tab.tsxand are wired intoConfigurationModal.tsx. - New options' size presets follow the existing scale:
tiny | small | medium | large(seeHeader.tsx,WebsiteTile.tsx).
2. New feature guidance
A "feature" in this project typically means: a new widget, a new settings option, or a new bit of persisted state. When adding one, follow this checklist.
A. Types & defaults (in order)
types.ts— add new fields to the relevant interface (usuallyConfig, sometimes a nested one likeclock/serverWidget). Create a nested object when a feature has 2+ sub-options (mirror theclock/serverWidgetpattern).components/services/ConfigurationService.tsDEFAULT_CONFIG— add the new field with a sane default so existing users (with a previously-savedConfig) get it via the{ ...DEFAULT_CONFIG, ...parsed }merge on load.- Any new standalone collections (not inside
Config) get their own storage key/helper inConfigurationService(seeuserWallpapers,wallpaperStatefor the pattern).
B. Settings UI (if the feature is user-configurable)
- Create
components/configuration/<Feature>Tab.tsxand add its entry to thetabsarray incomponents/ConfigurationModal.tsx. - Receive
configand anonChange(updates: Partial<Config>)callback; emit partial updates —App.tsx'shandleConfigChangemerges shallowly, so update nested objects as whole units (e.g.{ clock: { ...config.clock, ...updates } }). - Use
Dropdown/ToggleSwitch/ range inputs per the styling section above.
C. Rendering & wiring
- Render the feature in
App.tsx(or a dedicated component imported byApp.tsx), gated by itsconfig.<feature>.enabledflag when it can be turned off. - Mark up new modal/edit surfaces to match existing modals (backdrop click closes, glass card styling).
D. Persistence — configs must be properly saved
App.tsxalready persistsconfigviaConfigurationService.saveConfig(config)in auseEffect. Any state added toConfigis persisted automatically — do not introduce parallel ad-hoclocalStoragewrites for config fields.- Standalone collections (not in
Config) need explicit save calls — mirroruserWallpapers: load on mount, save on every mutation, never keep stale copies. - Never write to
chrome.storage.localdirectly outsidecomponents/utils/StorageLocalManager.ts. Always checkcheckChromeStorageLocalAvailable()first and gracefully degrade (the app must still run as a plain web page). Throw informative errors when the storage is required but missing.
E. Export / import must keep working
- If you add a new
localStoragekey (other than config fields, which are exported/imported automatically), add it toREQUIRED_LOCAL_STORAGE_KEYSinConfigurationService.tsso it is included in exports and restored on imports. - After adding fields to
Config, double check the import path:importConfigwrites each restored key tolocalStorageand returns{ config, userWallpapers }. New config sub-objects flow through automatically because they're insideconfig.
F. Defaults & migrations
- Default values must be chosen so a fresh install and an upgrade from an older
Configboth behave sensibly (the load path merges ontoDEFAULT_CONFIG). - If a new field changes behavior in a way that existing users' stored data should be preserved differently, handle the migration inside
loadConfig(and consider bumping the exportversionfield inexportConfigif the shape changes non-additively).
G. Style of new tiles/widgets
- A new widget should follow the existing widget shape: optional/gated by
config.<feature>.enabled, positioned with a liquid glass container, and use the surface/duration/easing tokens above. - New "editable" tiles/content reuse the
isEditingmode and the edit/move/delete affordances pattern fromWebsiteTile.tsxandCategoryGroup.tsx.
3. General engineering rules
- Language: TypeScript strict mode (
tsconfig.jsonenforcesstrict,noUnusedLocals,noUnusedParameters,noFallthroughCasesInSwitch,noUncheckedSideEffectImports). Do not loosen these. - Runtime note: Preact is the actual runtime (
@preact/preset-vite), but types and imports usereact/@types/react. Do not introduce React-only APIs without verifying Preact compatibility. - Path alias:
@/*maps to the project root (seetsconfig.jsonpaths). Source files currently use relative imports (./,../) — match the surrounding file. - No comments in committed code unless explicitly requested.
- Build vs. dev: Prefer verifying with
npm run buildrather thannpm run dev. The only npm scripts aredev,build,preview. - No lint/typecheck script is configured. Verify TS correctness manually (e.g.
npx tsc --noEmit), and confirmnpm run buildsucceeds before considering a task complete. - Don't touch
public/icon-metadata.json— it's gitignored and fetched at release-build time byscripts/prepare_release.sh. Don't commit a local copy. - Don't reintroduce dead code:
components/EditModal.tsximportslucide-reactand./IconPicker, neither of which is a dependency. It is not wired into the app. UseWebsiteEditModal.tsx/CategoryEditModal.tsxinstead, and add the icon picker inline (as inWebsiteEditModal.tsx) rather than revivingIconPicker. - External asset URLs: any new icons/css/JS pulled from CDNs (e.g.
cdn.jsdelivr.net) must work offline-or-not without crashing — always provide a fallback (see howiconService.tsfalls back to Google's S2 favicon service). - Manifest & extension constraints: the extension uses Manifest V3 with
script-src 'self'CSP and only thestoragepermission. Don't introduce inline scripts/eval, and avoid requesting new permissions unless essential — added permissions can disable updates on installed extensions. - Commits: never commit unless explicitly asked. Don't touch secrets, don't edit
.gitignore/.env.local/.claude/, don't rungit config.
4. When in doubt
- Read
project-context.md. - Mirror the nearest existing equivalent (a similar widget, modal, or config tab) before inventing a new pattern.
- Favor the established liquid utilities (
liquid-surface,liquid-panel,liquid-input,liquid-button,liquid-focus) over ad-hoc glass class strings. - Surface failing assumptions (CORS, missing chrome.storage, larger-than-4MB wallpapers) with clear errors, matching the style of
StorageLocalManager.tsandiconService.ts. - Update
project-context.mdafter your change.