Commit graph

61 commits

Author SHA1 Message Date
SkateSpots
ccc04cc172 feat(sasquatch-pro): server-side Pro gate on the AI proxy + client credentials
- netlify/functions/ai.mjs: optional Pro enforcement (SASQUATCH_REQUIRE_PRO=1).
  Requires a NIP-98 kind-27235 auth header (x-sasquatch-auth) and, unless the
  caller is a platform owner, an active Pro pass (x-sasquatch-pro = a
  provider-authored zap receipt) verified OFFLINE — signature, user binding,
  platform tag, and paid-amount → tier. Off by default.
- src/lib/proAuth.ts: signs the NIP-98 once per session (no Amber popup per
  message) and attaches the Pro receipt.
- sasquatchBrain: threads auth headers through the proxy (streaming + non).
- useSasquatchPro: exposes the winning receipt event.
- Verified: 200 with the gate off, 401 with it on (env reset afterwards).
2026-09-27 14:18:33 +07:00
SkateSpots
670a33123d feat(sasquatch-pro): enforce the paid tier; make AI Pro-only
- useSasquatchPro: derive Pro expiry from what was ACTUALLY paid (largest tier
  the bolt11 covers, run from the receipt time), instead of trusting the
  user-signed `pro-expiry` tag — a 7-day payment could previously self-assert a
  year. Provider-authored receipt + amount checks unchanged.
- SasquatchGuide: AI answers are now Pro-only. Free users get the static FAQ,
  glossary, trip planner and local relay lookups (all no-cost), plus a nudge to
  Pro when a question would otherwise need AI.
- AGENTS.md updated.
2026-09-27 13:56:52 +07:00
SkateSpots
d7bcc35d51 feat(sasquatch): stream the first-pass answer + drop dead Pollinations model
- sasquatchBrain: new streamSasquatchAI — OpenAI-style SSE via OpenRouter (if
  the key is set) then Pollinations; falls back to the non-streaming caller only
  when nothing at all was delivered, so blocked-stream environments still answer.
- SasquatchGuide: stream the first pass into a live bubble (raw JSON tool calls
  are suppressed so partial JSON never shows; prose-then-tool output is dropped),
  finalise the bubble in place, show a blinking cursor, and hide the generic
  'thinking...' bubble while a reply streams.
- Drop Pollinations 'mistral' (now a 404) leaving the live 'openai' slug.
2026-09-27 11:02:56 +07:00
SkateSpots
18cc8218b2 fix(sasquatch): bound AI latency, separate system prompt, verify relay events
- sasquatchBrain: abort each provider request after 15s and give up the whole
  multi-provider attempt after 35s, so a hung OpenRouter/Pollinations call can no
  longer wedge the chat (it now falls through to the static/local fallbacks).
- SasquatchGuide: send the system prompt as a real system message (both the
  first pass and the tool-synthesis pass) instead of smuggling it into a user
  turn, and mark tool output as untrusted — blunts prompt injection via event
  content.
- useCVMClient: signature-verify (verifyEvent) every relay result, matching the
  standalone server and the release-notes claim.
- useCVMServerHealth: stale threshold 1h -> 45m to match the server heartbeat.
2026-09-27 10:32:07 +07:00
SkateSpots
721a5d4b67 chore(lint): clear all react-hooks/exhaustive-deps warnings
Triage per file (not a blanket sweep):
- Memoise shared getters with useCallback and depend on them:
  EventsPage/LabPage/MapPage getTrustScore+getCommentCount (+MapPage getZapTotal)
- Memoise derived values that were recreated each render: CrewChat 'messages',
  RiderCardPage 'cardData'
- Justified eslint-disable for intentional mount-only effects with a comment:
  AppProvider (seed defaults/theme), SpotMap (Leaflet init once),
  SpamFeePayment (auto-pay keyed to invoice/state, not the recreated handler)
- EventCountdown: keep the intentional 'tick' recompute dep (documented disable)

exhaustive-deps: 14 -> 0. Warnings 60 -> 46 (39 unused-vars, 7 react-refresh).
Gate: 101 tests, 0 errors, boot smoke green. AGENTS.md baseline updated.
2026-09-26 22:09:43 +07:00
SkateSpots
ab87b8ab83 chore(lint): remove safely-detectable unused locals
Position-based cleanup (no name collisions) of unused catch bindings and unused
single-line pure consts across 12 files. Automated destructure/prop removals
were proven unsafe (shadowed names + typed shorthand), so those remain.

Warning backlog: 76 -> 60 (39 no-unused-vars, 14 exhaustive-deps, 7 react-refresh).
Gate green: 101 tests, 0 errors, boot smoke passing.
2026-09-26 21:58:03 +07:00
SkateSpots
d1f8870379 chore(lint): remove all explicit any + sweep dead imports
- Fix all 12 no-explicit-any (NPool, NostrEvent[], LabProfile, structural
  Cluster type, explicit SkateSpot cast) -> 0 remaining
- Remove unused imports/vars across 48 files (manual + a verified codemod for
  unused import specifiers only); tsc + tests + boot smoke all green
- Warning backlog: 182 -> 76 (remaining: ~55 no-unused-vars locals,
  14 react-hooks/exhaustive-deps, 7 react-refresh)
- AGENTS.md baseline updated
2026-09-26 21:40:42 +07:00
shakespeare.diy
993bea1b5b Sasquatch Pro: stop selling features that don't exist
Audit found the Pro paywall promised three things with no implementation:
- "Priority AI model, higher limits & longer memory" — Pro and free hit the
  exact same model/limits/history (only difference is the personal-tools prompt)
- "Proactive nudges (weather + spot tips)" — no nudge/scheduler exists anywhere
- "Pro-only Sasquatch skins" — single hardcoded avatar; no skin system
- "Supporter badge" — gating exists but no badge is rendered

Rewrote all Pro copy to promise ONLY what actually ships (personal assistant
over the user's own Stash/crews/spots/listings, confirm-before-publish action
drafts, personal-context answers, and directly funding an ad-free app):
- SasquatchProDialog PERKS list (dropped Sparkles import now unused)
- usePurchasePro receipt DM
- 6 STATIC_FAQ Pro answers in SasquatchGuide

Pricing, payment target (skatespots@minibits.cash) and npub-bound zap-receipt
verification were already accurate and left unchanged. Build clean, no console
errors.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-09-10 00:27:34 +07:00
shakespeare.diy
5506344893 Make Sasquatch tell the truth: direct relay queries, not a CVM server
The chat's data layer (useCVMClient) queries Nostr relays directly from the
browser — the CVM/ContextVM server round-trip was removed earlier for speed.
But the UI and system prompt still claimed data came "from the CVM server",
which is no longer true. Aligned every user-facing claim with reality:

- System prompt: reframed "CVM Tools / MUST route through CVM" as "Live data
  tools that query the Nostr relays directly". Tool-calling behaviour unchanged.
- Streaming status: "Querying CVM for X" → "Searching the relays for X".
- Tool-failure message: no longer blames a non-existent "CVM server"; now
  correctly frames it as relays being slow, with a retry nudge.
- Empty results: stop asserting "not added yet" as fact — an empty result can
  also mean slow relays or a misspelled place. Now offers retry + add-a-spot,
  and names the place searched. Applied to the local formatter, the system
  prompt rules, and the second-pass AI instruction.
- Chat footer: "Powered by ContextVM & Nostr Relays Data" → "Live data from
  Nostr relays" (links the primary community relay).
- About page credit: "AI powered by ContextVM" → "Trust & crew chat via
  ContextVM" (its real role: Relatr trust scores + encrypted crew chat).
- Owner CVM health panel: clarified it probes the standalone MCP server and
  that the in-app chat does not depend on it.
- Updated stale internal comments in SasquatchGuide + CreateSpotPage.

ContextVM references that ARE accurate (Relatr trust scores, crew-chat Cordn
coordinator) were left intact. Build clean, no console errors.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-09-10 00:16:59 +07:00
shakespeare.diy
7e7cf0a8bf Sasquatch fast-path: don't dead-end on empty/typos
The local fast-path was stricter than the AI it replaced: a typo like "bangok"
won't substring-match "Bangkok", so the fast-path returned a false "No spots
listed there yet" even though Bangkok has spots.

Two-layer fix:

1. Safety net (most important): if a finder fast-path comes back EMPTY, fall
   through to the AI path instead of rendering "nothing found". The AI normalizes
   spelling and can still find results. Stats/weather always render immediately.
   Net effect: fast when the local match works, correct-always via AI when it
   doesn't — never a false empty.

2. Typo tolerance: findSpots city matching now uses placeMatches() — substring
   OR edit-distance-1 against candidate word tokens (only for queries ≥4 chars,
   so short words can't over-match). So "bangok" matches "Bangkok" on the fast
   path too. Freeform content stays a strict substring check to avoid false hits.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-09-09 23:52:08 +07:00
shakespeare.diy
6df526bf27 Sasquatch: local fast-path for finder questions (kills ~30s AI wait)
Root cause of the ~35s "spots in bangkok" response: every live-data question
first waited on an AI round-trip just to produce a tool call, and the keyless
backup model (Pollinations) can take tens of seconds. The relay query and local
formatting were already fast — the AI was the bottleneck.

Fix: before touching the AI, try parseLocalIntent(). For clear finder questions
(spots/events/coaches/crews/shops/tours/gear + community stats + weather with a
parseable location) we now go STRAIGHT to the relays (capped at 4.5s) and render
locally — zero AI calls. Expected ~35s → ~2–4s on the most common queries.

Deliberately still routed through the AI:
- trip planning (needs the rich itinerary card)
- personal "my …" Pro queries (get_my_* tools)
- anything without a confidently-parseable intent/location

If the fast-path relay query errors, it falls through to the existing AI loop as
a backup, so nothing regresses.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-09-09 23:24:08 +07:00
shakespeare.diy
8b7d9ca4ea Fix Sasquatch spot results: honest count + collapse duplicates
Two bugs from "spots in bangkok" (said "Found 20" but showed 6, with repeats):

1. Misleading count: formatLocalResults hard-capped the visible list to 6 while
   the headline reported the full count. Now shows up to 10 and appends a
   truthful "…and N more — see them all on the map" line, so the number and the
   list always agree.

2. Duplicate spots: coordinate dedupe (kind:pubkey:d) can't catch the same
   real-world spot re-posted under a different identifier or by another account
   (e.g. "Yellow Park – Sukhumvit 50" appearing twice). Added
   deduplicateByIdentity() — a second-pass dedupe on a normalized
   name + geohash/location signature, keeping the freshest event — applied in
   findSpots so the count and list are clean.

Both fixes flow through the AI tool-call path and the offline fallback path.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-09-09 23:17:15 +07:00
shakespeare.diy
ada4bfee5e Accelerate Sasquatch custom questions (live-data queries)
Three low-risk speedups focused on the slowest path — questions that hit live
relay data:

1. Relay timeout 10s → 4.5s (6s for the fan-out community stats). The useful
   relays answer in ~2s; the old 10s just let one slow/dead relay stall the
   whole reply.

2. Results-first: for finder tools (spots/events/coaches/gear/crews/shops/
   tours/stats/weather) format the CVM result locally and SKIP the second
   "prettify" AI call. Removes a full model round-trip (~2–4s) — users want the
   list, not extra prose. New toolCallToIntent() maps a tool call to the existing
   formatLocalResults() path. Personal/Pro tools (get_my_*) still use AI synthesis.

3. Faster AI fallback: cap OpenRouter attempts to the top 3 free models before
   the keyless backup, and shorten 429 backoff (≤800ms vs ≤2500ms). Avoids the
   worst-case 15–20s grind through 8 models on a busy free tier.

Conversational/knowledge answers (single AI call) keep Sasquatch's personality
and are untouched.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-09-09 23:11:14 +07:00
shakespeare.diy
a0673a3244 Fix ESLint gate: scope ignores to app source (exclude android/.agents/cvm-server/public html/scripts), add index.html title, downgrade unused-vars & no-explicit-any to warnings, fix real lint errors (SkateGlobe unused-expr, EventsPage prefer-const, LicensePage Infinity shadow, useless-escape in SasquatchGuide/RiderCardPage, stale eslint-disable directives)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-09-03 21:30:56 +07:00
shakespeare.diy
a0c8493502 Sasquatch: open the panel on the LEFT again on desktop
- Panel now anchors md:bottom-16 md:left-4 (was bottom-right) so it opens on
  the left as before, and sits ABOVE the desktop footer so it never covers the
  "Made with..." row or footer links.
- Tightened max-height to clear the top nav too (never slides under the menu).
- Bubble stays bottom-right on desktop for discoverability (clear of footer).

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-08-27 16:28:07 +07:00
shakespeare.diy
407ba40a33 Sasquatch: full public-data coverage (all Lab crafts + shops + tours)
- findCoaches now covers EVERY Lab craft (coach, filmer, editor, photographer,
  builder, artist, graffiti, tattoo, trainer, musician, judge) via role param;
  reads skills from `t` tags and strips self-tags.
- New findShops (kind 30017, t=skateshop) and findTours (kind 30823) tools.
- getCommunityStats counts all crafts individually + lab_total + shops + tours,
  and filters spots to t=skatespot (drops foreign kind-30818 events).
- Wired new tools + expanded role vocabulary into the Sasquatch brain: system
  prompt, intent parser, keyword detector, and both dispatch/format paths.
- Privacy preserved: the public CVM data layer never queries the encrypted
  Stash (kind 30001) — verified no 30001/decrypt references. Personal 'my
  stash' stays login+Pro gated and decrypts locally with the user's own key.
- Normalized useCVMClient.ts to clean UTF-8 (comment glyphs only; no code change)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-08-27 16:14:20 +07:00
shakespeare.diy
e996d96fa0 Sasquatch: fix desktop discoverability + repetitive greeting
- Move bubble & panel to bottom-RIGHT on desktop (was bottom-left, colliding
  with / hiding behind the desktop footer). Mobile stays bottom-left.
- Raise bubble/panel z-index to z-60 so it always sits above the footer.
- Re-clamp a stale saved drag position on mount: a bubble dragged off-screen
  on one device no longer disappears on another.
- Stop showing the long welcome greeting + action button on every open once a
  conversation has started (chatMessages > 0), so it no longer "says the same
  thing all over again".

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-08-27 15:51:42 +07:00
shakespeare.diy
33cfe692ed Add privacy transparency: dedicated /privacy page, onboarding privacy note, Sasquatch VPN/Tor Q&A, footer link
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-08-27 10:46:47 +07:00
shakespeare.diy
c683b7e8bf Add clinkme.dev specs and apps page links across the app
- NofferField: link → https://clinkme.dev/specs.html (instead of just /)
- EditProfileForm: link → https://clinkme.dev/specs.html (instead of just /)
- SasquatchGuide: added [specs] and [apps] inline links next to the clink description, pointing to the new pages

The app already referenced clinkme.dev homepage; these add the two new deeper pages for discoverability.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-08-19 15:13:32 +07:00
shakespeare.diy
eed8552e37 Fix Sasquatch panel overflow on mobile: cap height to dvh + safe-area, pin header, scroll body internally
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-08-10 22:23:48 +07:00
shakespeare.diy
d465eabd87 ux(crews): rename "Start a Crew" -> "Create Crew" + clarify Crew vs Lab
"Start a Crew" was ambiguous (team? chat? listing?). Renamed to the clearer
"Create Crew" across the Crews page button/empty state, Create Crew page
title/header/login gate, and Sasquatch FAQ. Added a subtitle distinguishing a
Crew (skate WITH) from The Lab (hire).

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-30 20:02:17 +07:00
shakespeare.diy
ef9bbea465 feat: replace Geyser with Angor across the entire app
Remove all Geyser.fund references and replace with the SkateSpots Angor
project (angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z).

- SupportersPage: remove Geyser leaderboard + API calls entirely; replace
  Supporters section with an Angor CTA card including the on-chain wallet
  address (bc1q2hdfyqa7utrxrd95rlr27shsdr6gtk7dzdqres)
- useGrowthStats: delete useGeyserStats hook + GEYSER_API_URL constant
- CommunityStatsPage: remove Geyser stats widget, replace with Angor CTA
- SasquatchGuide: update system prompt + FAQ (is it free, supporters)
- NewsletterPage: update both Geyser links (body + footer) to Angor
- AboutPage: remove Geyser row, update Angor entry with real project URL
- README.md: update crowdfunding section + credits

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-30 13:23:55 +07:00
shakespeare.diy
d6b50de349 feat(sasquatch): Pro receipt DM + local Pro FAQ + tougher free-tier answers
1. Pro purchase confirmation: on a paid pass, send the buyer an encrypted
   NIP-17 receipt to their own inbox (tier, expiry, unlocked perks). Best-effort
   so it never blocks the purchase. Success toast now points to the DM.

2. Frictionless Pro answers: add local static-FAQ entries for "sasquatch pro",
   "pro perks/version", pricing, "go pro", "upgrade" — so those questions are
   answered instantly and never dead-end when the free AI model is rate-limited
   (the exact failure seen when asking "what perks has the pro version?").

3. FAQ matching now prefers the longest matching key so specific phrases win
   over broad ones ("sasquatch pro" > "pro").

4. Refresh the free-model fallback list (add deepseek-v3, gemini-2.0-flash-exp,
   qwen-2.5-72b) for better free-tier AI availability.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-30 00:21:34 +07:00
shakespeare.diy
1c18163a90 chore(sasquatch): remove joke book, clean up default suggested questions
- Delete sasquatchJokes.ts and all joke usages (idle chat line, fallback
  taglines, Lab/Crew guide messages).
- Tidy the default/generic suggested questions to a clean Nostr-focused set
  (Plan a trip, spots, events, crews, zaps, Nostr, Stash, free).

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-30 00:08:52 +07:00
shakespeare.diy
1efeae0960 feat(sasquatch): add Trip Planner + tougher free-tier fallback + new joke book
- Trip Planner: `plan_trip` tool orchestrates spots+events+coaches+crews+weather
  into a weather-aware, day-by-day itinerary card (TripItineraryCard). Actions:
  save all spots to a NIP-51 Collection, book/zap a coach via their profile,
  and deep-link out to flights/stays (assist, never fake-book, no KYC).
- Free-tier resilience: local intent parser answers "spots/events/coaches/
  crews/gear/weather in <city>" and full trip plans directly via CVM even when
  both AI providers are rate-limited — no more dead-end fallback.
- New shared joke book (sasquatchJokes.ts): skate humor + gentle roasts of the
  KYC-your-audience Bitcoin-influencer crowd. Idle joke on the empty chat state,
  ethos jokes in fallbacks. Dedupes the old inline joke arrays.
- UX polish: taller chat scroll area, trip-planner suggested questions, FAQ
  entries for the planner.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-30 00:04:28 +07:00
shakespeare.diy
5655fbc976 Sasquatch Pro Phase 2: action drafting (draft → you confirm)
Sasquatch can now DRAFT actions from natural language and publish them
only after the user reviews & confirms — it never publishes on its own.

- useSasquatchActions: publishes confirmed drafts via the app's normal
  publish path. Supports post_status (NIP-38 kind 30315, auto-expiring)
  and list_gear (NIP-99 kind 30402, skateboarding-tagged), reusing the
  existing event schemas.
- SasquatchActionCard: inline "review & confirm" card with editable key
  fields (status text / listing title, price, condition), Publish +
  Cancel, and done/cancelled states. Nothing is signed until Publish.
- SasquatchGuide: new draft_action tool (Pro-gated). The AI emits a
  draft; a card renders in-chat; confirmDraft signs & publishes. Non-Pro
  users get an upgrade nudge. Draft lifecycle tracked per message.
- Prompt teaches the model to use draft_action for "post/sell/list/set
  my status" requests and to fill gear fields from the stash first.

Examples now working (Pro): "post that I'm skating Southbank for 3 hours"
· "list my Spitfire wheels for 8000 sats".

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-29 23:41:11 +07:00
shakespeare.diy
79d1d47823 Sasquatch Pro Phase 3: npub-bound Lightning paywall + gating
Adds the Sasquatch Pro supporter pass with strong, forge-resistant
verification bound to the paying user's npub — no backend required.

Verification (useSasquatchPro):
- STRONG: NIP-57 zap receipt (kind 9735). Purchase signs a zap request
  tagged pro-tier/pro-expiry; the receipt embeds it, cryptographically
  binding payment → identity (unforgeable by the user).
- FALLBACK: self-signed kind-32671 receipt so paying users are never
  locked out if the provider emits no zap receipt.
- Platform owners always Pro. Access = max unexpired expiry.

Purchase (usePurchasePro):
- Zap to skatespots@minibits.cash (falls back to plain invoice), pay via
  NWC → WebLN → manual QR. Publishes the fallback receipt on success.

Pricing (sasquatchPro.ts): 4 tiers — 7d/2k, 1mo/5k, 3mo/12k (popular),
1yr/36k sats.

UI (SasquatchProDialog): upgrade sheet with tiers, perk list, QR
fallback, "already Pro" state, extend flow.

Gating (SasquatchGuide):
- Personal tools (get_my_*) now require login + Pro; prompt only exposes
  them to Pro users; tool switch guards with a pro_required nudge.
- ⚡ Pro badge when active, ⚡ Go Pro button otherwise; local upgrade
  nudge for "my/mine" questions from non-Pro users.

Docs: kind 32671 + verification model documented in NIP.md.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-29 23:33:39 +07:00
shakespeare.diy
a37224d8a2 Sasquatch Pro Phase 1: read-only personal assistant tools
Sasquatch can now answer questions about the logged-in user's OWN data
("what's in my stash?", "my crews", "events near my crew", "my spots",
"what am I selling?").

- New usePersonalContext hook: client-side getters for the user's Stash
  (decrypted locally), crews (founder/member), marketplace listings, and
  created spots. Reads own data only — nothing personal leaves the device.
- Registered 4 personal tools (get_my_stash / get_my_crews /
  get_my_listings / get_my_spots) in the Sasquatch tool switch.
- Personal-tools prompt block is appended to the system prompt ONLY when
  a user is logged in, so logged-out UX is unchanged.
- needsLiveData now routes "my/mine" questions to the AI tool path.

Phase 1 is intentionally ungated so we can validate the experience
before wrapping the Pro paywall (Phase 3).

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-29 23:21:37 +07:00
shakespeare.diy
cc84713fe4 Make Sasquatch resilient: local glossary answers + backup AI provider
Fixes the "brain's catching traffic" dead-end for trick/terminology
questions and reduces reliance on a single flaky free API.

- Local glossary answerer (answerFromGlossary): trick/how-to/terminology
  questions ("what is a feeble grind", "how do I do a kickflip", "grosso
  grind") are now answered instantly from the 150+ entry glossary with
  ZERO API calls — so they never hit a rate limit.
- Wired into SasquatchGuide as (a) a fast path before the AI and (b) a
  last-resort fallback when the AI is unreachable.
- sasquatchBrain now has multi-provider fallback: OpenRouter free models
  (with 429 backoff) → keyless Pollinations backup. Only throws if both
  fail, letting the caller fall back to local knowledge.
- Replaced the unhelpful fallback message with useful local links +
  a nudge to ask about a specific trick.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-29 23:04:41 +07:00
shakespeare.diy
a371ff3645 Add Trick Glossary + harden Sasquatch AI rate-limit handling
Glossary:
- New /glossary page: 80+ tricks across 11 categories (fundamentals,
  flips, shoves/spins, grinds, slides, grabs, airs, lip, stalls,
  handplants, boneless, freestyle) with alternate names, difficulty
  badges, live search, and category filters.
- Added to desktop "More" dropdown and mobile burger menu.

Sasquatch AI:
- Fixed/expanded free-model fallback list with valid OpenRouter slugs
  (dropped the non-existent gemma-4 slug).
- Added exponential backoff + one retry on 429 rate limits, respecting
  Retry-After headers.
- SasquatchGuide now reuses the shared sasquatchBrain caller instead of
  a duplicated implementation.
- Friendlier fallback message when the AI is saturated.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-29 22:39:51 +07:00
shakespeare.diy
834f33d53e Make Sasquatch bubble open reliably on first tap (mobile)
The "1st tap does nothing, 2nd/3rd works" bug came from relying solely on
pointer-capture tap detection, which is flaky on the first interaction after
mount in mobile WebViews — and the earlier e.preventDefault() on pointerup was
suppressing the click we could otherwise use.

Fix: add a plain onClick as a reliable open path (the most dependable "tapped"
signal in a WebView), extract an idempotent openPanel() used by both pointerup
and click, and drop the preventDefault so the click isn't swallowed. The
justOpenedRef lock still blocks the ghost-click that would re-close it. Double
firing is harmless since openPanel just sets visible=true.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-25 15:36:11 +07:00
shakespeare.diy
ebbd0fd125 Fix Sasquatch panel opening then instantly closing on mobile
On touch devices, the bubble's pointerup opened the panel and unmounted the
bubble; the synthesized "ghost click" from the same tap then landed on the
panel's minimize/close button (which renders in roughly the same bottom-left
spot), instantly re-closing it.

Fix: preventDefault/stopPropagation on pointerup to suppress the ghost click,
guard releasePointerCapture against unmount throws, and add a 400ms
"just opened" lock so stray close/minimize events from the same tap are
ignored.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-25 15:24:05 +07:00
shakespeare.diy
dec2e730d2 CVM find_crews: Sasquatch can now live-search crews
- useCVMClient: add findCrews (queries kind 35006 across data relays, filters by
  city/country/vibe/search, returns CrewResult with member_count, vibes, url);
  add crews to getCommunityStats + CrewResult type
- SasquatchGuide: register find_crews tool in system prompt + switch handler,
  add crew keywords to needsLiveData, update app-facts (crews are searchable +
  mention cross-linking and Zap-the-Crew)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-24 14:35:16 +07:00
shakespeare.diy
ed27f719fa Sasquatch: teach him all the new features + fix zap comment
- Expand AI system prompt with full feature map: Lab (coaches/filmers/
  photographers/editors/builders + individual vs collective), Crews (map-anchored,
  how they differ from the Lab), Stash, Tours, Shops, Gear Swap, Rider Card
- Document money layer interconnections: wallet rails (Cashu/NWC/WebLN), zap
  fallback order, nutzaps (NIP-61, receiving), CLINK/noffer, Geyser supporters
- Instruct Sasquatch that Crews/Stash/Wallet/Tours/Shops have no live search tool
  and must be answered from knowledge (prevents bogus tool calls)
- Add ~15 new STATIC_FAQ offline answers (crews, stash, builder, nutzap, clink,
  noffer, tours, shops, sell gear, supporters)
- Add Crews page guide context + crew jokes; refresh Lab suggestions
- Fix leftover "Zapped with Engorile!" default comment → SkateSpots branding

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-24 14:12:30 +07:00
shakespeare.diy
1d1e6d18b1 Redesign mobile map controls: Layers popover + Add speed-dial FAB
Replaces the crowded 12-item vertical right rail with a clean, minimal set:
- Right edge now has just two 44px controls: Near Me and a Layers button.
- Layers opens a labelled popover (Spots/Shops/Gear/Tours) with color dots
  and checkmarks, plus a count badge on the button so state is obvious.
- All "add" actions consolidated into a single red speed-dial FAB
  (bottom-right) that fans out to Add Spot / Add Shop / Offer Tour /
  Quick Snap, with a tap-catcher backdrop to dismiss.
- Sasquatch bubble moved to bottom-left on mobile so it no longer competes
  with the Add FAB for the bottom-right corner.
- Larger touch targets (44px) for better native/ZapStore ergonomics.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-24 10:18:35 +07:00
shakespeare.diy
d107c0a860 Fix Sasquatch auto-popup on / and /lab; move map attribution above mobile nav
- Sasquatch panel no longer auto-opens on the map (/) or The Lab (/lab).
  Added an `autoShow` flag to GuideMessage; only opt-in messages (onboarding)
  auto-open. The bubble stays minimized until tapped, and context messages
  still populate the panel when opened manually.
- Map CARTO/OSM attribution now sits above the mobile bottom nav (safe-area
  aware) instead of overlapping the Shops & Spots buttons; made it smaller
  and more subtle. Desktop keeps it in the bottom-left corner.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-24 10:09:15 +07:00
shakespeare.diy
f48844b495 Fix Sasquatch / Add Spot FAB overlap on mobile map
- SasquatchGuide now dispatches 'sasquatch:panelchange' event when panel opens/closes
- MapPage listens to the event and hides the Add Spot FAB (with scale-down animation)
  whenever the Sasquatch panel is open — no more overlap
- FAB reappears with smooth opacity + scale transition when panel closes
- Added a visible close (X) button to the Sasquatch panel header alongside the existing
  minimize button — gives users a clear way to fully dismiss the panel
- Sasquatch panel bottom edge stays 10px above the nav bar on all screen sizes

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-23 22:00:50 +07:00
shakespeare.diy
c9bb5abfff sasquatch: left-anchor panel on mobile, leave right side free for Quick Snap + filter pills
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-23 20:08:03 +07:00
shakespeare.diy
be4e0bc986 map: remove duplicate sasquatch, reposition original bubble to bottom-right below Quick Snap
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-23 20:05:46 +07:00
shakespeare.diy
0dc0d272e1 fix: filter panel overlap, Wallet & Stash rename, Sasquatch on all pages
Filter panel (MapPage):
- Sheet now h-[82vh] max-h-[680px] with flex-col layout
- Scrollable content area uses flex-1 min-h-0 (proper flex children)
- "Show Results" button is now flex-shrink-0 at bottom of column
- No more overlap between Show Results and Stash/Tour quick action buttons

Wallet & Stash rename:
- Settings tab renamed from "Wallet" to "Wallet & Stash"
- "Me" dropdown in mobile header shows "Wallet & Stash" for the wallet link

Sasquatch persistent button (all pages):
- Minimized bubble is now ALWAYS visible on every page (not just pages with a guide message)
- Tapping the bubble on any page opens Sasquatch with a generic helpful greeting
- Pages with specific context (/, /map, /lab, /onboarding) still show their custom message
- Pages without context (/wallet, /settings, /stash, /events, etc.) now show a generic "Ask me anything" greeting with common questions
- Removed the separate X close button (minimize was already the same) — bubble stays visible as entry point at all times
- onPointerUp now also sets isVisible=true so panel opens on pages without a message

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-23 16:45:11 +07:00
shakespeare.diy
6331a937f2 feat: map as homepage, 3D globe, camera fix, Sasquatch upgrades, UI/UX polish
## 1. Map as Homepage
- `/` now renders MapPage (the globe/map) — removed old Index homepage
- `/home` redirects to Index (legacy), `/map` alias still works
- Navbar: removed HOME link, SPOTS (MapPin) is now first nav item
- isActive() treats both `/` and `/map` as active for SPOTS tab

## 2. 3D Globe View
- New SkateGlobe component using pure Three.js (no h3-js/CDN issues)
- Earth night texture with atmospheric neon red glow
- Spot pins (red) + shop pins (lime) on globe surface
- Click pin → zoom camera in + show info card
- Drag to rotate, scroll/pinch to zoom, auto-rotation when idle
- Globe toggle button added to map/list view switcher
- Selected marker ring + info card with View Spot/Shop links
- Lazy-loaded with Suspense skeleton

## 3. Settings → Stash Link
- Added My Stash card in Settings > Wallet tab
- Links to /stash with Package icon and description
- Smooth hover animation with ChevronRight

## 4. Camera Fix (Capacitor Native)
- CameraCapture now detects native Capacitor platform at runtime
- On native Android/iOS: uses @capacitor/camera (OS-level camera, no WebView permission popup)
- On browser: falls back to getUserMedia stream (existing behaviour)
- Added Upload from Gallery fallback when camera permission denied
- Better error handling for user cancellation

## 5. Sasquatch Upgrades
- FAQ page: replaced static accordion wall with Sasquatch-powered UI
  - Quick question chips that pre-load questions into Sasquatch
  - "Open The Sasquatch" CTA button
  - Quick facts grid, clean modern design
- About page: added Sasquatch CTA card at bottom
- SasquatchGuide: listens for sasquatch:open and sasquatch:ask custom events
  - External pages can now trigger and pre-fill the Sasquatch
  - Sasquatch now shows even without a page-level message prop (for external triggers)

## 6. UI/UX Audit & Polish
- Focus rings: on-brand red (WCAG accessible)
- Card hover micro-interactions: subtle translateY + shadow
- Button/link transition consistency (150ms ease)
- Reduced motion support (@media prefers-reduced-motion)
- Modal backdrop blur improvement
- Skeleton shimmer animation utility
- Globe CSS utilities (touch-action: none for canvas)
- Typography helpers (text-balance, text-pretty)
- Improved map-full-height responsive calculation

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-07-22 22:47:39 +07:00
shakespeare.diy
5dffa5cac3 feat: UX improvements - credits, draggable sasquatch, mobile fixes
1. AboutPage: add Credits section (Zapstore, ContextVM, Angor, Geyser, MKStack,
   Shakespeare, Nostr), add Zapstore download button, fix powered-by text overflow
   on mobile (wrap-friendly flex layout)

2. SasquatchGuide: make minimized bubble draggable on all devices
   - pointer events for mouse, touch, and stylus
   - saves position to localStorage, persists across sessions
   - tap still opens, drag moves (5px threshold to distinguish)

3. Layout (burger menu): add overflow-y-auto + pb-8 to SheetContent so
   mobile menu is scrollable when content exceeds screen height

4. CashuWalletCard (wallet): fix input+button rows overflowing on mobile
   - flex-col on small screens, flex-row on xs+ (stacked on phones)
   - whitespace-nowrap on buttons to prevent text wrapping

5. LabPage: compact action buttons on mobile (h-8, text-[10px], px-2)
   so all 4 buttons fit in 2x2 grid without overflow/truncation

6. LoginDialog (Amber): improve visibility-change handler - use fresh
   SimplePool subscription on each foreground return instead of querySync
   (which doesn't exist in nostr-tools v2.13)

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-06-23 09:33:46 +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
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
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
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