Commit graph

1378 commits

Author SHA1 Message Date
shakespeare.diy
05a74ed4f8 Fix logo: original pin+circle design preserved, white skateboard deck clearly visible below
- Keep original gradient circle (red→orange→lime) and white map pin exactly as-is
- White skateboard deck drawn behind the circle, protruding below it
- Deck has popsicle shape (rounded nose + tail), two truck axles, four wheels
  that extend out beyond the deck sides so they're clearly visible
- Wheels have inner hub detail for realism

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-18 00:48:44 +07:00
shakespeare.diy
3cba958437 New logo: map pin on top of skateboard deck, same gradient colors
- Redesigned icon.svg: skateboard deck shape (rounded nose/tail, truck axles,
  wheels) beneath the existing map pin, all using the same red→orange→lime
  gradient as the original
- Replace MapPin component icons in desktop header, mobile header, and footer
  with the actual icon.svg image so the new logo shows everywhere

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-18 00:46:05 +07:00
shakespeare.diy
fad3a3323d Replace Impact with Bebas Neue + Barlow Condensed for authentic skate typography
- Install @fontsource/bebas-neue and @fontsource/barlow-condensed
- Add .font-display (Bebas Neue) and .font-condensed (Barlow Condensed) CSS utilities
- Hero headline: split into two lines SKATE / SPOTS with clamp() fluid sizing,
  Bebas Neue replaces Impact throughout
- Subtitle: Barlow Condensed 700 with wide letter-spacing
- Description: Barlow Condensed italic
- All section headings (Featured Spots, Events, The Lab, CTA, New Here?): Bebas Neue
- Section subheadings: Barlow Condensed with tracked uppercase
- Desktop + mobile header logo: Bebas Neue
- Footer logo: Bebas Neue
- Tagline badge: Barlow Condensed 600

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-18 00:37:32 +07:00
shakespeare.diy
0f98994c86 Fix NostrSync error toast for accounts with no profile published yet
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 23:38:24 +07:00
shakespeare.diy
6e46214747 Fix profile not loading after Amber login - rewrite NostrSync
Root causes found:
1. syncedUsers blocked re-sync permanently even on failure — first attempt
   fires before WebSocket connections are ready on mobile, fails silently,
   gets marked done, profile stays anonymous forever that session
2. useAuthor had 5min staleTime — empty {} result from pre-login query
   was cached and not refetched after login
3. NostrSync did not force-remove the stale useAuthor cache entry

Fixes:
- Rewrite NostrSync with proper retry logic (up to 5 attempts, backoff)
  - Tracks success/failure per pubkey, only stops on confirmed success
  - Re-triggers on user.pubkey change (catches Amber polling completing)
  - Forces queryClient.removeQueries on author cache before each attempt
  - Tries Citrine → bootstrap relays → main pool in order
- useAuthor: reduce staleTime 5min→1min, expand fallback relay list
- Both files now use same BOOTSTRAP_RELAYS set for consistency

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 23:35:18 +07:00
shakespeare.diy
4caad49dfb Fix profile/relay loading after Amber login + add Citrine support
Bug 1 - AppProvider was wiping NIP-65 relay list:
- Relay migration check was comparing stored relays vs defaults and
  resetting them if they differed — overwriting the user's own NIP-65 list
- Fix: only reset relays to defaults if updatedAt === 0 (never synced)
  and relays array is empty

Bug 2 - NostrSync not finding profile on mobile:
- Add Citrine local relay detection (ws://localhost:4869)
  - If Citrine is running, query it first — instant local data
- Add BOOTSTRAP_RELAYS (purplepag.es, relay.nostr.band, nos.lol)
  - Always try these for profile+relays before main pool
- syncRelays() now accepts optional relay group param
- Increase initial delay to 1500ms in PWA mode (800ms in browser)
  to give WebSocket connections time to establish after Amber redirect

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 23:15:54 +07:00
shakespeare.diy
65914303f1 Fix Amber login for PWA installed to home screen
PWA standalone mode is single-tab. Opening nostrsigner: with a callbackUrl
sends the callback to the browser (a different app), not back to the PWA.
The PWA tab is suspended and never sees the result.

Fix:
- Detect PWA standalone mode via matchMedia('(display-mode: standalone)')
- In PWA mode: open Amber WITHOUT a callbackUrl — Amber copies pubkey to
  clipboard automatically when no callback is given
- Use visibilitychange to detect when user returns to PWA after approving
- Auto-read clipboard on return and complete login silently
- Manual "I approved" button now tries localStorage first (browser), then
  falls back to clipboard read (PWA) — covers both contexts with one button
- Browser mode unchanged: localStorage cross-tab polling still works

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 23:04:48 +07:00
shakespeare.diy
0c87fa5827 Fix Amber login not completing on GrapheneOS new-tab callback
Root cause: on GrapheneOS, Amber opens /amber-callback in a BRAND NEW TAB.
login.amber() was being called in that new tab's React instance, which has
no effect on the original tab where the user is waiting.

Fix:
- AmberCallbackPage now writes pubkey to localStorage('amber_pending_pubkey')
  instead of calling login.amber() — a cross-tab signal
- LoginDialog polls for 'amber_pending_pubkey' every 400ms and calls
  login.amber() itself in the correct React context
- Manual "I approved" button also reads the same key
- Removed reliance on getAmberLogin() which checked the wrong localStorage key

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 22:46:39 +07:00
shakespeare.diy
67850348e6 Fix scroll broken on mobile - remove overscroll-behavior:none and webkit-overflow-scrolling:touch from globals
Both were added in the last mobile optimization and caused touch scroll
to stop working on Android/GrapheneOS browsers:
- overscroll-behavior: none on html/body blocks native touch scroll
- * { -webkit-overflow-scrolling: touch } on every element interferes
  with the browser's native scroll handling

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 22:39:28 +07:00
shakespeare.diy
4398c2e73b Fix Amber login stuck on GrapheneOS/Android browsers
Root cause: window.location.href navigates the tab away entirely on Android,
destroying sessionStorage. When Amber calls back to /amber-callback the login
completes there, but returning to the dialog the state is lost.

Fixes:
- Switch from sessionStorage to localStorage for amber_return_path and
  amber_login_attempt_ts — survives tab navigation on Android
- Add 500ms polling loop in handleAmberLogin that checks getAmberLogin()
  every 500ms — detects when AmberCallbackPage stored the pubkey and
  auto-completes login without needing visibilitychange to fire
- Add "I approved — complete login" manual button in waiting state as
  explicit fallback for stuck users (reads localStorage right away)
- AmberCallbackPage now uses localStorage for all persistence
- Clean up poll interval on dialog close and unmount

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 22:37:26 +07:00
shakespeare.diy
03d0fe93b0 Improve Amber login flow - zero friction, auto-complete on return
- Add dedicated /amber-callback route so Amber always has a stable return URL
  - Handles get_public_key (login), sign_event, nip44/nip04 encrypt/decrypt
  - Shows animated processing screen while completing, then redirects back
- Add subscribeToAmberReturn() helper in amber.ts using visibilitychange
  - Auto-detects when user returns to the tab after cancelling in Amber
  - Resets login UI to initial state gracefully
- Update buildCallbackUrl() to use /amber-callback instead of current page URL
- Rewrite Amber tab in LoginDialog:
  - Remove 2-step clipboard paste flow entirely
  - Single tap opens Amber, login completes automatically on return
  - Waiting state shows animated dots + cancel button
  - No manual pubkey entry needed
- Save return path in sessionStorage so AmberCallbackPage redirects user back

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 22:29:06 +07:00
shakespeare.diy
aac2b7b9a2 Improve mobile/Android UI responsiveness
- Add xs (375px) breakpoint to Tailwind config for small phone targeting
- Fix main content bottom padding to account for safe-area-inset-bottom
- Redesign mobile bottom nav: active dot indicator, proper safe-area padding,
  flex-1 tabs that scale to any width, tighter text on xs screens
- Fix hero section: smaller padding/text on tiny phones (320-375px),
  horizontal badge wrapping, full-width buttons stack below xs
- Add CSS improvements: overscroll-behavior, -webkit-text-size-adjust,
  input font-size fix for iOS zoom prevention, scroll-x helper class,
  touch-friendly min tap target sizes

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 22:04:29 +07:00
shakespeare.diy
1441855eb1 feat: add Capacitor + Zapstore config for Android APK distribution
- capacitor.config.ts: Capacitor config with dark theme, WebSocket support,
  splash screen, status bar, keyboard plugins
- zapstore.yaml: Zapstore publish config with npub identity verification
- ZAPSTORE.md: full step-by-step guide (clone → build APK → publish to Zapstore)
- package.json: android:init, android:sync, android:open, android:build scripts
- App ID: org.skatespots.app

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 16:11:28 +07:00
shakespeare.diy
a3cd6cf9f4 feat: Sasquatch clickable links, weather tool, ContextVM footer
- ChatText component renders markdown [label](url) and bare URLs as neon clickable links
- 👉 URL patterns also rendered as clickable links
- get_weather tool: real-time weather + skateability score via Open-Meteo
  Ask "weather in Bangkok?" or "is it good to skate in Barcelona today?"
- Footer updated: "Powered by ContextVM & Nostr Relays Data" with ContextVM
  linking to https://contextvm.org/s/e3564bb877...
- Weather geocodes city name via Nominatim, returns temp/conditions/wind/skateability

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 15:55:53 +07:00
shakespeare.diy
f9c0f3c5ac feat: redesign Sasquatch UI - dark jungle aesthetic, mobile-first
- Dark forest green + neon lime (#ccff00) theme matching app's THUG2 aesthetic
- Mobile: compact strip above bottom nav, no more full-width overlay
- Minimized: small round button with neon pulse, lives at bottom-left
- Jungle texture strips top/bottom, dark gradient background
- Chat bubbles: neon red for user, neon lime for Sasquatch
- Input styled to match dark app theme
- Neon glow effects, live dot indicator
- Works cleanly on all screen sizes

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 12:50:41 +07:00
shakespeare.diy
c31f79e8b0 fix: improve Sasquatch prompts for accuracy and cleaner responses
- Rewrite system prompt: coaches in Thailand → search Bangkok, use limit:20
- Second-pass prompt explicitly bans JSON tool calls in responses
- Country → city mapping guidance (Thailand → Bangkok)
- Cleaner formatting instructions for results presentation

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 12:46:39 +07:00
shakespeare.diy
3a4e4ead05 fix: rewrite useCVMClient to query relays directly instead of NIP-44 round-trip
The encrypted CVM request/response cycle (kind 21000/21001) was too unreliable
in the browser — timeouts on every call. Replace with direct Nostr relay queries
using nostr.group() which is already proven to work in the app. Same filtering
logic as the server. No dependency on CVM server being up for data queries.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 12:32:59 +07:00
shakespeare.diy
c672066c2c fix: update free AI models to confirmed-working OpenRouter models
Previous models (llama-3.1-8b, gemma-3-4b, mistral-7b) returned 404 unavailable.
Tested and confirmed working: openai/gpt-oss-20b:free and google/gemma-4-31b-it:free.
Keep llama-3.3-70b as quality option when not rate-limited.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 12:20:28 +07:00
shakespeare.diy
cb7714d875 fix: Sasquatch AI fallback chain + greeting responses + better error message
- Try 4 free OpenRouter models in order (rate limit resilience)
- Add greeting responses to static FAQ so hi/hello/hey never need AI
- Fix static FAQ to exact-match short words like "hi" before partial match
- Better error message explaining free tier rate limits

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 12:16:13 +07:00
shakespeare.diy
a9c677b58d fix: rewrite useCVMClient to use Relay.connect() instead of SimplePool
nostr-tools v2 SimplePool.subscribeMany() callbacks (onevent/oneose) no
longer fire reliably in browser context, causing the CVM client to always
time out. Switch to raw Relay.connect() which uses the v2 API correctly.
Race across all CVM relays and resolve on first valid response.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 12:10:31 +07:00
shakespeare.diy
c772330e74 fix: remove debug logging from queryNostr, keep clean production server
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 12:02:09 +07:00
shakespeare.diy
4c263e729a fix: replace subscribeMany with querySync for nostr-tools v2 compatibility
The server was using the nostr-tools v1 API (subscribeMany with onevent/oneose
callbacks) but the installed version is v2.23.5 which changed the internal
subscription handling. querySync() is the correct v2 API for one-shot queries
and handles EOSE cleanly without needing manual timeout management.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 11:43:51 +07:00
shakespeare.diy
84aa009b33 fix: CVM server tag mapping + add city/country geocoding to spots
CVM server fixes (cvm-server/server.ts):
- Use 'title' tag instead of 'name' to read spot names (app publishes 'title')
- Search now checks 'title' tag (not just 'name') for keyword matches
- City filter now also checks 'title' tag and event content
- Country filter also checks event content
- Features filter now checks 't' tags (app uses 't' not 'feature')
- Validate spots with 't: skatespot' tag (same rule as the app)
- Return 'location' field and proper features list in results
- Image parsing now supports both 'image' (legacy) and 'imeta' (NIP-92)

CreateSpotPage fix (src/pages/CreateSpotPage.tsx):
- Add reverse geocoding via Nominatim on spot submit
- Emit structured 'city' and 'country' tags so CVM can filter by them
- Auto-fill location field from geocoding if user left it blank

SasquatchGuide improvement (src/components/SasquatchGuide.tsx):
- Add data model notes to system prompt explaining tag structure
- Instruct AI to handle 0-result responses gracefully (encourage adding spots)
- Use limit:20+ for city/country searches

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-17 11:14:50 +07:00
shakespeare.diy
252163625e feat: rebuild Sasquatch as proper CVM agent bridge
- Rich system prompt that explains the CVM architecture: it aggregates
  across multiple relays, deduplicates, and filters by features inside
  events (complex queries that plain Nostr filters can't do)
- Switched tool call format from fragile regex (TOOL:name {...}) to
  clean JSON {"tool":"name","args":{...}} that's easier for the LLM
- More robust JSON parsing — scans the full AI response for the tool call
- Better second-pass prompt: AI formats results with bullet points + links
- Updated suggested questions to showcase real CVM queries
- CVM failure gives a clear message explaining what the server does

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 22:39:51 +07:00
shakespeare.diy
c2b7a29d07 feat: update default relay set to all 5 relays
Added auth.nostr1.com and wotr.relatr.xyz back as default relays.
All 5 relays are now the default for all new users:
- wss://auth.nostr1.com (auth)
- wss://wotr.relatr.xyz (web of trust)
- wss://relay.ditto.pub (general)
- wss://goskatespots.nostr1.com (community - toggleable)
- wss://purplepag.es (profiles - read only)

Updated across: App.tsx, NostrProvider.tsx, NostrSync.tsx, TestApp.tsx
Updated Settings page Default Relays info cards to show all 5 with descriptions.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 22:35:09 +07:00
shakespeare.diy
5526265aea fix: update free model to meta-llama/llama-3.3-70b-instruct:free
The 3.1-8b:free model is no longer free on OpenRouter.
Switching to llama-3.3-70b:free which is available and actually
a much better model (70B vs 8B).

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 22:25:33 +07:00
shakespeare.diy
966907a848 chore: clean up console noise - remove debug logs from NostrProvider, NostrSync, useShakespeare
Removed:
- [NostrProvider] Routing query to read relays (fired on EVERY query)
- [NostrProvider] Publishing kind X to relays
- [NostrSync] Starting sync / querying profile / profile query returned / sync completed
- [NostrSync] Profile not found on main relays
- [NostrSync] Profile synced and cached
- [Shakespeare] Fetching / Model / Response status debug logs

Kept all warn/error logs for actual failure cases.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 22:23:00 +07:00
shakespeare.diy
89b43a44e6 fix: remove leftover shakespeare reference from useCallback deps array
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 22:06:41 +07:00
shakespeare.diy
9be89bf287 feat: switch Sasquatch to free OpenRouter model - works for everyone
Replaced Shakespeare AI (paid, NIP-98) with OpenRouter free model
(meta-llama/llama-3.1-8b-instruct:free). No login required, no credits
needed - anyone can use Sasquatch AI for free.

- Removed useShakespeare hook dependency from SasquatchGuide
- Added direct callAI() function using OpenRouter API
- AI + CVM live data still works the same way
- Removed login nudge, updated placeholder and AI badge

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 22:05:27 +07:00
shakespeare.diy
d18b62431e fix: remove broken CORS proxy, call ai.shakespeare.diy directly
proxy.shakespeare.diy was returning NetworkError on all requests.
Direct calls to ai.shakespeare.diy work fine from a real browser.
Kept debug logging to confirm correct URL and pubkey.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 22:01:15 +07:00
shakespeare.diy
b815cbfda6 fix: remove dead relay.nostr.band from all relay lists across the app
Removed from: useCVMClient, NostrSync, useLoggedInAccounts, useAuthor, SettingsPage
Replaced with relay.damus.io where a fallback was still needed.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 21:49:02 +07:00
shakespeare.diy
c643ddb105 fix: add relay.ditto.pub back to CVM client relay list
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 21:47:14 +07:00
shakespeare.diy
9b50cda191 fix: update CVM client relays - remove dead relay.contextvm.net and relay.ditto.pub
Use goskatespots.nostr1.com as primary (matches CVM server config),
plus relay.nostr.band and relay.damus.io as fallbacks.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 21:42:22 +07:00
shakespeare.diy
51751f9ea7 fix: route Shakespeare AI calls through CORS proxy for iframe compatibility
All fetch calls to ai.shakespeare.diy now go through proxy.shakespeare.diy
so they work from inside the iframe.diy preview sandbox.

The NIP-98 token is still signed against the original URL (not the proxy
URL) so the server-side signature validation passes correctly.

Affects: sendChatMessage, sendStreamingMessage, getAvailableModels

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 20:33:35 +07:00
shakespeare.diy
223b7602bf fix: correct model ID to 'shakespeare/claude-sonnet-4.6' for Shakespeare AI
Previous attempts used 'shakespeare' and 'claude-sonnet-4-5' — both invalid.
The correct format matches the recentlyUsedModels in ai.json config:
provider/model-name with dots not dashes.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 20:26:01 +07:00
shakespeare.diy
2aeb41afdc fix: use correct model ID 'claude-sonnet-4-5' for Shakespeare AI calls
The model name 'shakespeare' does not exist on the API — it was returning:
  "Model 'shakespeare' is not supported" (400 invalid_request_error)

Updated both sendChatMessage calls in SasquatchGuide and the default
model in useShakespeare hook (sendChatMessage + sendStreamingMessage).

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 20:05:26 +07:00
shakespeare.diy
4214845d78 chore: add netlify.toml with build config, cache headers, and SPA redirect
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 19:56:22 +07:00
shakespeare.diy
9d1e875c36 fix: remove wss://wotr.relatr.xyz relay that was consistently failing
The wotr.relatr.xyz relay was generating a flood of AbortError warnings
on every query because it was consistently unreachable/timing out.

Removed from:
- src/App.tsx (default config)
- src/components/NostrProvider.tsx (DEFAULT_RELAYS)
- src/components/NostrSync.tsx (NEW_USER_RELAYS for new users)
- src/test/TestApp.tsx (test config)

Replaced the Settings page entry with purplepag.es (profile aggregator)
which is already in the relay list and actually working.

Updated Sasquatch FAQ answer to reflect the correct relay list.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 19:52:02 +07:00
shakespeare.diy
13eac70cec fix: improve 400 error logging to surface raw API body
Previously, the catch block around response.json() would swallow the
actual error body and replace it with a generic "Invalid request" message.

Now:
- Read response as text() first (never fails)
- Log the raw body to console as [Shakespeare API 400] raw body: <text>
- Parse JSON from the text string separately
- Fallback error message includes the raw body so it's visible in console

This will make it easy to diagnose exactly what the Shakespeare API
is rejecting (model name, message format, missing field, etc.)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 19:49:09 +07:00
shakespeare.diy
632de3e5bd fix: wrap AI block in try/catch for graceful fallback when Shakespeare API fails
If the AI call throws (400, 401, network error, etc.), Sasquatch now:
- Catches the error silently (logs to console as warning)
- Falls back to the static FAQ answer if one matches
- Falls back to a friendly "try again" message if no FAQ match
- Never shows a crash or blank response to the user

The toolMatch reference inside the try block is properly scoped so the
isLive flag works correctly when the full AI + CVM flow succeeds.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 19:47:49 +07:00
shakespeare.diy
054c06d573 fix: shorten system prompt, improve 400 error logging in Shakespeare hook
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 19:42:22 +07:00
shakespeare.diy
ba8b65b6d9 fix: remove system role from Shakespeare AI calls, embed prompt in user message instead
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 19:39:50 +07:00
shakespeare.diy
4aebbc8798 fix: use correct 'shakespeare' model name in SasquatchGuide AI calls
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 19:36:24 +07:00
shakespeare.diy
fadf36d86e feat: upgrade Sasquatch from static FAQ to live AI agent with CVM data
- Add useShakespeare.ts hook (Shakespeare AI via NIP-98 auth)
- Add useCVMClient.ts hook — calls SkateSpots CVM server tools over
  Nostr directly from the browser (NIP-44 encrypted request/response,
  no @contextvm/sdk bundle needed, pure nostr-tools)
- Rewrite SasquatchGuide to use Shakespeare AI + live CVM data:
  * Static FAQ answers for protocol/app questions (fast, no API)
  * Shakespeare AI for natural language understanding
  * AI detects TOOL: calls in its response and executes them live
  * CVM server queried for find_spots, find_events, find_coaches,
    find_gear, get_community_stats
  * Streaming "thinking..." and "Searching Nostr..." indicators
  * Live/offline status badge shows CVM server connectivity
  * Graceful fallback when CVM server unreachable
  * Login nudge for unauthenticated users

CVM server pubkey: e3564bb877adb0c99a7e4973ccb22e516d7d9eca0027d0bd62a04174ed670530
CVM server host: 185.18.221.2 (LNVPS, Dublin)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 19:30:00 +07:00
shakespeare.diy
2db0c6f7e2 feat: add SkateSpots CVM server — MCP tools over Nostr
Adds cvm-server/ directory with complete ContextVM server implementation:

- server.ts: Full MCP server with 5 tools (find_spots, find_events,
  find_coaches, find_gear, get_community_stats) using @contextvm/sdk
- bootstrap.sh: One-command VPS setup script (Bun, PM2, firewall, keygen)
- skatespots-cvm.service: systemd unit for production deployment
- .env.example: Environment variable template
- DEPLOY.md: Step-by-step deploy guide for LNVPS VPS
- package.cvm.json: Dependencies manifest

The server aggregates data from goskatespots.nostr1.com and other relays,
deduplicates addressable events, and exposes structured JSON tools that
AI agents can discover and call via the ContextVM/Nostr protocol (CEP-6).

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 17:45:04 +07:00
shakespeare.diy
320032ea37 fix: add missing User and Building2 lucide icon imports to RiderCardPage
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 17:07:42 +07:00
shakespeare.diy
ebbf2d6326 fix: remove orphaned canvas code from RiderCardPage causing ctx/Printer is not defined crash
The drawCardToCanvas function had an old version of the card rendering logic
that leaked outside the function body (lines 505-731 were orphaned code).
This code referenced local variables (ctx, p, data, qrX, qrSize, PAD, etc.)
that only existed inside the function, causing ReferenceError at module load time
and crashing the entire app with a blank screen.

Also added missing lucide-react imports (Printer, Loader2, Share2, Download,
Check, Copy, Award, Zap, Info, Palette, Shield, ChevronUp, ChevronDown) that
were used in the JSX but not imported, causing the secondary Printer is not
defined ReferenceError.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 17:02:59 +07:00
shakespeare.diy
125bce3637 Replace QRCodeCanvas DOM preview with static placeholder
The qrcode library internally uses var ctx and canvas.getContext('2d') at
initialization time. In the Shakespeare preview iframe environment, canvas
API is restricted causing "ctx is not defined" console errors on every render.

Fix: replace QRCodeCanvas in the DOM screen preview with a static decorative
QR placeholder (5x5 pixel grid). The real, scannable QR code is still
generated correctly in the exported PNG via QRCode.toDataURL() in the
drawCardToCanvas() async function - this is unaffected by the env restriction
since it only runs when the user clicks Print/Save/Share.

Also remove unused QRCodeCanvas import from RiderCardPage.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 16:21:58 +07:00
shakespeare.diy
6ba5dc1187 Fix QRCodeCanvas: guard against empty value and null context
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 16:17:56 +07:00
shakespeare.diy
8d273428f3 Card redesign: 3-zone layout, shop/sponsor styling, Share button, remove Badges tab
Canvas renderer overhaul:
- New 3-zone layout: left sidebar (avatar + stats + since) | right zone
  (name/identity/shop/sponsors/skills) | top-right QR block
- Left sidebar has a subtle tinted background with accent-colored separator
- Stats shown as balanced column grid under the avatar
- Shop: "RIDES FOR" label + bold italic Georgia serif in theme shopColor (distinct from accent)
- Sponsors: "SPONSORS" label + regular weight in theme sponsorColor (warm gold/orange)
- Each theme now has shopColor + sponsorColor + sidebarBg + chipBorder fields
- Skills row appears only when skills/badges exist, with accent border on chips
- Full npub (44+remainder chars) shown at bottom of right zone in monospace
- Bottom bar: subtle fill + "SKATE-SPOTS.ORG" left, year right
- Park Access card: same sidebar layout, access level chip in solid accent fill

Share button:
- Uses Web Share API (navigator.share) if device supports it — opens native
  share sheet (WhatsApp, iMessage, Telegram, AirDrop, etc.) with PNG file
- Falls back to copying profile URL to clipboard
- Lime green color to visually stand out from Print button

UI cleanup:
- Remove Badges tab entirely — was cluttering the nav
- Award Badge moved inline to secondary button row (yellow, subtle)
- Primary actions: Print | Share | Save PNG (all same size, flex-wrap)
- Secondary actions: Copy npub | Award Badge | Publish to Nostr
- Fixed stray closing divs from tab removal

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-16 16:07:47 +07:00