Skip to content

Commit 6ab2e8d

Browse files
authored
Merge pull request #218 from develop
release: develop to main — seekable timeline, Ultra Fast speed, algorithm tips, Turnstile fix
2 parents 25dc443 + 0b3eaca commit 6ab2e8d

46 files changed

Lines changed: 1722 additions & 295 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ VITE_SUPABASE_ANON_KEY=your-anon-key
77
# Google Identity Services — Web OAuth client ID (public)
88
VITE_GOOGLE_WEB_CLIENT_ID=your-web-client-id.apps.googleusercontent.com
99

10+
# Cloudflare Turnstile (signup bot gate) — public site key only
11+
# Matching secret key is a Supabase Edge Function secret: TURNSTILE_SECRET_KEY
12+
VITE_TURNSTILE_SITE_KEY=0x4AAAAA...your-turnstile-site-key
13+
1014
# PostHog analytics (optional — skip in local dev)
1115
VITE_POSTHOG_API_HOST=https://us.i.posthog.com
1216
VITE_POSTHOG_API_KEY=phc_your_project_token

.github/workflows/deploy-cloudflare.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ jobs:
5252
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
5353
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
5454
VITE_GOOGLE_WEB_CLIENT_ID: ${{ secrets.VITE_GOOGLE_WEB_CLIENT_ID }}
55+
VITE_TURNSTILE_SITE_KEY: ${{ secrets.VITE_TURNSTILE_SITE_KEY }}
5556
VITE_POSTHOG_API_KEY: ${{ secrets.VITE_POSTHOG_API_KEY }}
5657
VITE_POSTHOG_API_HOST: ${{ github.event.workflow_run.head_branch == 'main' && 'https://e.bayanflow.com' || 'https://e.dev.bayanflow.com' }}
5758

.github/workflows/preview-cloudflare.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ jobs:
5858
VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
5959
VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
6060
VITE_GOOGLE_WEB_CLIENT_ID: ${{ secrets.VITE_GOOGLE_WEB_CLIENT_ID }}
61+
VITE_TURNSTILE_SITE_KEY: ${{ secrets.VITE_TURNSTILE_SITE_KEY }}
6162
VITE_POSTHOG_API_KEY: ${{ secrets.VITE_POSTHOG_API_KEY }}
6263
VITE_POSTHOG_API_HOST: https://e.dev.bayanflow.com
6364

AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ When docs drift, trust runtime config:
6767
- Complexity panel: interactive SVG chart with log/linear toggle; best/average/worst time + space complexity
6868
- Graph algorithms: `GraphAlgorithmCategoryVisualizer` routes node-link to `GraphVisualizer` and matrix (Floyd-Warshall) to `GraphAlgorithmMatrixVisualizer`; `GraphScenarioDropdown` for preset scenarios
6969
- Searching category: `SearchingCategoryVisualizer` routes array-based to `ArrayVisualizer` and node-link (DFS/BFS graph) to `GraphVisualizer`
70-
- Animation speeds: SLOW 8000ms, MEDIUM 4800ms, FAST 2400ms, VERY_FAST 1200ms
70+
- Animation speeds: SLOW 5000ms, MEDIUM 3000ms, FAST 1500ms, VERY_FAST 700ms, ULTRA_FAST 350ms
7171

7272
## Ship It test ladder
7373

@@ -113,13 +113,13 @@ See reference doc for full checklists (JS, Python, pseudocode, sound, insight, t
113113
- **Anonymous tier (no account):**
114114
- 18 of 45 algorithms (curated starter set across all 5 categories; see `src/constants/algorithmEntitlements.js`)
115115
- 12 visualizations per session (localStorage counter `anon_viz_count`, resets on sign-in)
116-
- Autoplay only, default speed (MEDIUM: 4800ms)
116+
- Autoplay only, default speed (MEDIUM: 3000ms)
117117
- Complexity panel: 2 views per completion (localStorage `anon_complexity_views`), then blur overlay + sign-in gate
118118
- No manual controls, speed adjustment, or category-specific controls (grid size locked to MEDIUM, sort order locked to ascending, graph scenarios disabled)
119119
- No Code Panel, Insight Panel, Video Export, Sound, or Fullscreen
120120
- **Free tier (Google sign-in):**
121121
- All 45 algorithms, unlimited visualizations
122-
- Manual controls, all 4 speed presets
122+
- Manual controls, all 5 speed presets
123123
- Full complexity panel access, all category-specific controls
124124
- Code Panel, Insight Panel (with My Notes tab), Sound, Fullscreen
125125
- Favorite algorithms: up to 20 slots (`FREE_TIER_FAVORITE_SLOT_LIMIT` in `src/constants/personalLearning.js`); stored in Supabase `favorite_algorithms`

docs/AGENTS_REFERENCE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868

6969
### Shared product features
7070

71-
- Playback: manual vs autoplay (`VISUALIZATION_MODES`), four speed presets (`ANIMATION_SPEEDS`)
71+
- Playback: manual vs autoplay (`VISUALIZATION_MODES`), five speed presets (`ANIMATION_SPEEDS`)
7272
- Mobile: horizontal swipe for manual step forward/back (`useSwipe`), one-time swipe tutorial (`SwipeTutorial`)
7373
- Full-screen visualization mode (`useFullScreen`) reuses the same control panel and visualizer registry
7474
- Light/dark theme with system preference fallback (`ThemeContext`, `ThemeToggle`, `useTheme`)
@@ -419,6 +419,7 @@ Migrations: `20260710140000_pro_waitlist.sql`, `20260710150000_pro_waitlist_attr
419419
- Full-screen mode uses the same `ControlPanel` and visualizer registry as normal mode.
420420
- Lazy panels (`PythonCodePanel`, `AlgorithmInsightPanel`) must remain optional overlays and should not block the main visualization path.
421421
- Swipe stepping applies only in manual playback mode on touch devices.
422+
- The step progress bar is seekable: Free-tier users (non-gated) get an invisible full-width range input driving seeking, a circular grab handle (`seek-thumb`) marking the fill edge, and the `controls.dragToSeek` microcopy under the bar. Anonymous/gated users see the **same grab handle** and a persistent `controls.dragToSeekLocked` microcopy ("Sign in to skip steps"), but no range input; the timeline wrapper is a focusable button (`role="button"`) whose click or Enter/Space fires `onGatedFeatureClick('timeline_scrub')``SignInPromptModal` (`featureGate.timeline_scrub`).
422423

423424
## Sound And Export Notes
424425

docs/ARCHITECTURE.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -688,10 +688,11 @@ Speed is user-configurable via constants:
688688
689689
```javascript
690690
export const ANIMATION_SPEEDS = {
691-
SLOW: 8000,
692-
MEDIUM: 4800,
693-
FAST: 2400,
694-
VERY_FAST: 1200,
691+
SLOW: 5000,
692+
MEDIUM: 3000,
693+
FAST: 1500,
694+
VERY_FAST: 700,
695+
ULTRA_FAST: 350,
695696
};
696697
```
697698

index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@
216216
}
217217
})();
218218
</script>
219+
<!-- Cloudflare Turnstile — invisible CAPTCHA for bot signup prevention -->
220+
<script
221+
src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"
222+
async
223+
defer
224+
></script>
219225
</head>
220226
<body>
221227
<div id="root"></div>

public/_headers

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Referrer-Policy: strict-origin-when-cross-origin
66
Permissions-Policy: camera=(), microphone=(), geolocation=(), identity-credentials-get=(self "https://accounts.google.com")
77
# Pyodide CDN origins: jsDelivr below; custom VITE_PYODIDE_CDN_BASE origins appended at build (vite.config.js)
8-
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' blob: https://*.posthog.com https://static.cloudflareinsights.com https://cdn.jsdelivr.net https://accounts.google.com; connect-src 'self' blob: https://*.posthog.com https://e.bayanflow.com https://e.dev.bayanflow.com https://cloudflareinsights.com https://api.github.com https://cdn.jsdelivr.net https://www.remotion.pro https://qketsapzqpzmccljfjcm.supabase.co https://accounts.google.com https://oauth2.googleapis.com; img-src 'self' data: blob: https://api.producthunt.com https://lh3.googleusercontent.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; font-src 'self' data:; worker-src 'self' blob:; media-src 'self' blob:; frame-src https://www.youtube-nocookie.com https://accounts.google.com; object-src 'none'; base-uri 'self'; form-action 'self'
8+
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' blob: https://*.posthog.com https://static.cloudflareinsights.com https://cdn.jsdelivr.net https://accounts.google.com https://challenges.cloudflare.com; connect-src 'self' blob: https://*.posthog.com https://e.bayanflow.com https://e.dev.bayanflow.com https://cloudflareinsights.com https://api.github.com https://cdn.jsdelivr.net https://www.remotion.pro https://qketsapzqpzmccljfjcm.supabase.co https://accounts.google.com https://oauth2.googleapis.com https://challenges.cloudflare.com; img-src 'self' data: blob: https://api.producthunt.com https://lh3.googleusercontent.com; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; font-src 'self' data:; worker-src 'self' blob:; media-src 'self' blob:; frame-src https://www.youtube-nocookie.com https://accounts.google.com https://challenges.cloudflare.com; object-src 'none'; base-uri 'self'; form-action 'self'
99
Link: <https://bayanflow.com/sitemap.xml>; rel="sitemap"
1010
Link: </.well-known/api-catalog>; rel="api-catalog"
1111
Link: </.well-known/agent-card.json>; rel="service-desc"

public/markdown/app.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
## Features
1313

14-
- Step-by-step animation with configurable speed (Slow/Medium/Fast/Very Fast)
14+
- Step-by-step animation with configurable speed (Slow/Medium/Fast/Very Fast/Ultra Fast)
1515
- Real-time time and space complexity analysis
1616
- Python code execution in the browser via Pyodide (WebAssembly)
1717
- HD video export with optional sound

scripts/cspHeaders.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,23 @@ export function assertAuthCspDirectives(csp, source) {
171171
);
172172
}
173173

174+
if (!scriptSrc?.includes('https://challenges.cloudflare.com')) {
175+
throw new Error(
176+
`${source}: script-src must include https://challenges.cloudflare.com (Turnstile)`
177+
);
178+
}
179+
180+
if (!connectSrc?.includes('https://challenges.cloudflare.com')) {
181+
throw new Error(
182+
`${source}: connect-src must include https://challenges.cloudflare.com (Turnstile)`
183+
);
184+
}
185+
186+
if (!frameSrc?.includes('https://challenges.cloudflare.com')) {
187+
throw new Error(
188+
`${source}: frame-src must include https://challenges.cloudflare.com (Turnstile)`
189+
);
190+
}
191+
174192
return { connectSrc: connectSrc ?? '', imgSrc: imgSrc ?? '' };
175193
}

0 commit comments

Comments
 (0)