You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- License: `Elastic-2.0 OR Commercial` (dual-license)
12
12
- Hosting: **Cloudflare Workers** (static SPA via `wrangler.jsonc`); `netlify.toml` kept for rollback only — CI deploys through `.github/workflows/deploy-cloudflare.yml`
- Version: `0.5.0` in `package.json` — 45 algorithms across 5 categories; optional Google sign-in when Supabase env vars are set
15
+
- Version: `0.5.0` in `package.json` — **45 algorithms** across **5 categories** (14 sorting, 9 pathfinding, 9 searching, 6 tree traversal, 7 graph); optional Google sign-in when Supabase env vars are set
16
16
-**PRs target `develop`**, not `main` (gated by `ensure-pr-source-develop.yml`)
-**Sound:** semantic events in `soundEvents.js` only — not from localized descriptions; visualization-only (no UI click sounds)
38
-
-**Export:** interactive + Remotion parity; `buildExportSoundCues()` from same sound events
48
+
-**Graph algorithms:** node-link vs matrix profiles; Floyd-Warshall matrix max 6 nodes; scenarios from `graphTestScenarios.js` (18 preset scenarios); `GraphScenarioDropdown` when scenario is active
49
+
-**Pathfinding:** grid steps; walls/start/end in `usePathfindingVisualization`; grid size uses named presets (`GRID_SIZES.SMALL/MEDIUM/LARGE`)
-**Sound:** semantic events in `soundEvents.js` only (16 event kinds) — not from localized descriptions; visualization-only (no UI click sounds); uses Tone.js singleton `soundManager` with 5 synths through master chain (gain → filter → compressor → reverb)
52
+
-**Export:** interactive + Remotion parity; `buildExportSoundCues()` from same sound events; WAV assets in `public/video-export/sfx/` (18 pre-rendered files)
53
+
-**Feature gating:** Tiered access model — see Auth contracts for Anonymous vs Free tier access; `SignInPromptModal` blocks gated features; `entitlementService.js` is the single authority for all access checks; `src/constants/algorithmEntitlements.js` defines the anonymous-tier algorithm allowlist
39
54
40
55
## Visualizer UX
41
56
42
57
- Registry-driven architecture — extend config/registries, not `VisualizerApp` one-offs
58
+
- All 5 category hooks called unconditionally in `VisualizerApp` (Rules of Hooks), merged via `useCategoryVisualizations()`
43
59
- Completion: brief final state before `ComplexityPanel`
44
60
- Regenerate control is category-neutral ("Generate New Input")
- Full-screen mode (`useFullScreen`) uses same `ControlPanel` + visualizer registry; F key toggle, Escape exits
64
+
- Touch: horizontal swipe (`useSwipe`) for manual step navigation; one-time `SwipeTutorial` on mobile
65
+
- Video export: horizontal (1920×1080) or vertical (1080×1920) MP4 via `@remotion/web-renderer`; orientation → capability check → render → preview → download
66
+
- Complexity panel: interactive SVG chart with log/linear toggle; best/average/worst time + space complexity
67
+
- Graph algorithms: `GraphAlgorithmCategoryVisualizer` routes node-link to `GraphVisualizer` and matrix (Floyd-Warshall) to `GraphAlgorithmMatrixVisualizer`; `GraphScenarioDropdown` for preset scenarios
68
+
- Searching category: `SearchingCategoryVisualizer` routes array-based to `ArrayVisualizer` and node-link (DFS/BFS graph) to `GraphVisualizer`
69
+
- Animation speeds: SLOW 8000ms, MEDIUM 4800ms, FAST 2400ms, VERY_FAST 1200ms
47
70
48
71
## Ship It test ladder
49
72
@@ -52,32 +75,70 @@ When docs drift, trust runtime config:
Follow `~/.cursor/skills/ship-it/SKILL.md` when user says "ship it".
56
-
57
78
## i18n / user-facing changes
58
79
59
-
Audit all three locales + pseudocode strings + export fallbacks when renaming categories or algorithms. Arabic is RTL — check app UI and Remotion export.
80
+
Audit all three locales (en/fr/ar) + pseudocode strings + export fallbacks when renaming categories or algorithms. Arabic is RTL — check app UI and Remotion export. Translation detection order: `localStorage` → `navigator` → `htmlTag`, cached in localStorage. Pseudocode is English source of truth, FR/AR generated via `localize.js`.
60
81
61
82
## Adding algorithms or categories
62
83
63
-
See reference doc for full checklists (JS, Python, pseudocode, sound, insight, tests, registries). Keep graph algorithm commits scoped to one algorithm when possible.
84
+
See reference doc for full checklists (JS, Python, pseudocode, sound, insight, tests, registries). Keep graph algorithm commits scoped to one algorithm when possible. Algorithms follow dual-export pattern: visualization function → `steps[]` array + `*Pure` function for testing.
64
85
65
86
## Auth contracts (non-negotiable)
66
87
67
88
-**OIDC only** — Google sign-in via Supabase Auth; no email/password flows in v0.5.0
68
-
-**Service layer** — `src/services/authService.js`, `profileService.js`; components use `AuthContext` / `useAuth`, never import Supabase directly
89
+
-**OAuth UX** — Google Identity Services (PKCE popup on `/auth/google/callback`); web uses `signInWithIdToken`, not `signInWithOAuth`; `googleIdentity.js` manages GIS script loading, nonce creation, and popup flow
90
+
-**Service layer** — `src/services/authService.js`, `profileService.js`, `entitlementService.js`, `googleTokenExchange.js`; components use `AuthContext` / `useAuth`, never import Supabase directly
69
91
-**Postgres-portable schema** — `profiles` keyed to `auth.users`; RLS on public tables; client-writable columns: `display_name`, `avatar_preference` only; `avatar_url` is OAuth/trigger-populated (not client-writable); `plan` and future `referral_*` / `pro_*` columns are service role / webhook only
70
-
-**Profile settings** — private route `/settings/profile` (`RequireAuth`); `updateProfile()` in `profileService.js`; security boundary = RLS row scope + `REVOKE UPDATE` + `GRANT UPDATE (display_name, avatar_preference)`; no public profile route or `username` in v0.5.x
71
-
-**Session** — `getSession()`, `onAuthStateChange()`; `AuthProvider` in `src/main.jsx`
72
-
-**OAuth UX** — Google Identity Services (PKCE popup on `/auth/google/callback`); web uses `signInWithIdToken`, not `signInWithOAuth`
73
-
-**i18n** — sign-in/out strings and legal copy in en/fr/ar; audit RTL for Header auth control
74
-
-**Free by default** — core visualization is free; Code Panel, Insight Panel, Video Export, Sound, and Fullscreen require sign-in; auth PRs must not reduce free functionality
-**Session** — `getSession()`, `onAuthStateChange()`; `AuthProvider` in `src/main.jsx`; request-dedup via `requestRef`
94
+
-**Tiered access model** — Anonymous (no account) gets limited access to drive sign-in conversion; Free account (Google sign-in) unlocks the full platform
95
+
-**Anonymous tier (no account):**
96
+
- 18 of 45 algorithms (curated starter set across all 5 categories; see `src/constants/algorithmEntitlements.js`)
97
+
- 12 visualizations per session (localStorage counter `anon_viz_count`, resets on sign-in)
98
+
- Autoplay only, default speed (MEDIUM: 4800ms)
99
+
- Complexity panel: 2 views per completion (localStorage `anon_complexity_views`), then blur overlay + sign-in gate
100
+
- No manual controls, speed adjustment, or category-specific controls (grid size locked to MEDIUM, sort order locked to ascending, graph scenarios disabled)
101
+
- No Code Panel, Insight Panel, Video Export, Sound, or Fullscreen
102
+
-**Free tier (Google sign-in):**
103
+
- All 45 algorithms, unlimited visualizations
104
+
- Manual controls, all 4 speed presets
105
+
- Full complexity panel access, all category-specific controls
106
+
- Code Panel, Insight Panel, Sound, Fullscreen
107
+
- Video Export: unlimited for Free tier with mandatory watermark; Pro tier adds watermark customization/removal; internal daily abuse guard exists (not user-facing)
108
+
-**Auth PRs must not reduce Free tier functionality** — only Anonymous tier can be further restricted
75
109
-**Secrets** — publishable anon key via `VITE_*` only; service role key never in repo or client bundle
76
-
-**CSP** — Supabase origin in `connect-src`; Google profile photos in `img-src`; assert via `scripts/cspHeaders.js`
77
-
-**Tests** — mock Supabase in Vitest (`src/test/supabaseMock.js`, wired in `src/test/setup.js`)
110
+
-**CSP** — Supabase origin in `connect-src`; Google profile photos in `img-src` (lh3.googleusercontent.com); GIS scripts/connect/frame in respective directives; asserted via `scripts/cspHeaders.js` at build time
111
+
-**Tests** — mock Supabase in Vitest (`src/test/supabaseMock.js`, wired in `src/test/setup.js`); mock includes `authStateChangeCallbackRef` for testing auth state changes
112
+
-**Auth pages:**`GoogleAuthCallback.jsx` (handles OAuth redirect), `PrivacyPolicy.jsx`, `TermsOfUse.jsx` (both use shared `LegalDocument` component with content from `src/content/legal/`)
78
113
79
114
## Workflow rules
80
115
81
116
- Minimal diff; no unrelated edits; preserve user-authored changes
82
117
- Sync registries across JS, Python, pseudocode, sound, export, and tests
83
118
- Run focused tests while iterating; full gate before Ship It handoff
119
+
- Generators should accept `rng` param for deterministic test output
120
+
- Sound is silent on initial load, reset, step-back, algorithm changes, and regeneration — only forward playback and manual stepping
121
+
- Do NOT add UI click sounds (panels, buttons, toggles, export) — visualization steps only
122
+
- When adding net-new visual step states, add corresponding `SOUND_EVENT_KINDS` entry and align `buildExportSoundCues.test.js`
123
+
- When adding a graph algorithm, keep commits scoped to one algorithm; update `graphAlgorithmRegistry.js` profile, `graphAlgorithmGenerators.js` if new generator needed, and `graphTestScenarios.js` if new scenarios needed
124
+
125
+
## Build-time env vars
126
+
127
+
| Variable | Required | Purpose |
128
+
|----------|----------|---------|
129
+
|`VITE_GIT_BRANCH`| CI | Deploy context; `isProductionMainBranch()` gates noindex/robots |
|`VITE_GOOGLE_WEB_CLIENT_ID`| Auth | Google OAuth client ID |
133
+
|`VITE_PYODIDE_CDN_BASE`| Optional | Override default jsDelivr CDN for Pyodide |
134
+
|`VITE_DEV_SITE_URL`| CI | Dev site URL for build metadata |
135
+
136
+
## CI workflow summary
137
+
138
+
-`ci.yml` — push/PR to main/develop: quality (lint + format + audit) → test (coverage + Codecov) → build (with `VITE_GIT_BRANCH` + `VITE_DEV_SITE_URL`)
139
+
-`deploy-cloudflare.yml` — triggered by CI completion on main/develop: build + `wrangler deploy` (production/staging envs)
140
+
-`preview-cloudflare.yml` — PR to develop: lint → test → build → `wrangler versions upload` → comment PR with preview URL + QR code; cleanup on PR close
141
+
-`ensure-pr-source-develop.yml` — blocks PRs to `main` unless head is `develop` or user in `ALLOWED_MERGERS`
142
+
-`release.yml` — GitHub release on `v*` tags
143
+
-`keep-supabase-alive.yml` — weekly ping to prevent free-tier project hibernation
0 commit comments