- Wire real companionsFetching prop into BlobbiDashboard and pass it to
useFirstHatchTourActivation instead of hardcoded isLoading: false
- Rename skipPostRequirement to skipToEggGlow in both BlobbiPage and
BlobbiDevEditor (no post requirement exists in the simplified flow)
- Update dev button labels: 'Skip to Glow', 'Restart Tour',
'Reset to Egg + Tour' with accurate titles/descriptions
- Handle async resetTour consistently with void in all onClick handlers
- Fix reveal overlay centering: move rays/glow/particles inside the
Blobbi visual container (relative positioning) instead of a separate
viewport-centered absolute layer, so the composition is anchored to
the Blobbi regardless of header/naming section height
- Rewrite useFirstHatchTour to use pure in-memory useState instead of
useLocalStorage. The Kind 11125 profile tag blobbi_first_hatch_tour_done
is now the only persisted completion signal. Refreshing mid-tour simply
re-enters the tour if activation conditions are still met.
- Remove TourPersistedState, FirstHatchTourPersistedState, and
FIRST_HATCH_TOUR_DEFAULT_STATE from tour-types (no longer needed).
- Remove pubkey parameter from useFirstHatchTour (no localStorage to scope).
- Remove profileOnboardingDone from activation input (unused after
localStorage removal; blobbi_first_hatch_tour_done is the only check).
- Make dev reset (Restart Tour button) also republish the Kind 11125
profile with blobbi_first_hatch_tour_done=false so the tour can
immediately re-activate for testing.
- User-scope tour localStorage key by pubkey so different users on the
same device get independent tour state (fixes tour not starting)
- Set current_companion when auto-creating first egg so the Blobbi is
immediately active as the floating companion
- Centralize generateBlobbiContent in blobbi.ts and use it in the reveal
rename flow instead of publishing content: '' (fixes invalid event)
- Gate reveal overlay on companion.stage !== 'egg' so stale cache data
never shows the egg visual instead of the newly hatched baby
- Remove duplicate generateBlobbiContent from useBlobbiStageTransition
and useBlobbiDevUpdate in favor of the shared export
Restructure the first Blobbi onboarding to feel instant, magical, and effortless:
- Add useFirstEggExperience hook: auto-creates Blobbonaut profile (kind 11125) and first egg (kind 31124) without any user confirmation, cost, or reroll
- Remove post-mission requirement from hatch tour (no 'show_hatch_card' step)
- Simplified tour flow: idle -> glowing -> crack stages -> opening -> hatching -> reveal
- Add BlobbiRevealOverlay: celebratory full-screen overlay after hatch with light rays, particles, and naming input
- Add 'blobbi_first_hatch_tour_done' profile tag for future-proof tour completion tracking (separate from blobbi_onboarding_done)
- Update useFirstHatchTourActivation to use the new dedicated tag
- Keep existing adoption flow intact for subsequent Blobbis
- Backward compatible: old users with blobbi_onboarding_done=true can still enter the hatch tour if they have a single unhatched egg
When fewer than 9 media-native events (kind 20, 21, 22, etc.) are found for a
profile, perform a secondary query for kind 1 events with search:media:true and
append them to fill the remaining slots. Kind 20 events are always displayed first.
- New ZapstoreReleaseContent component: shows app icon/name fetched from the
linked kind 32267, version badge, channel badge, release notes, and a
downloads section that fetches and renders each linked kind 3063 asset
- New ZapstoreAssetContent component: shows MIME-type icon, platform/arch
badges, file size, SHA-256 hash, commit hash, supported NIPs, and APK
certificate hashes
- Register both kinds in NoteCard, PostDetailPage, extraKinds, CommentContext,
ExternalContentHeader, and NotificationsPage label/icon maps
- Route kind 3063 to the Zapstore relay in NostrProvider and useEvent
- Kind 3063 is excluded from feeds (display-only on direct navigation)
Older accounts had onboarding_done migrated to blobbi_onboarding_done=true
before the first-hatch tour existed. When the user has exactly 1 egg and
no baby/adult companions, skip the profileOnboardingDone gate so those
accounts can still enter the tour. The localStorage isCompleted check
still prevents re-triggering for users who already finished it.
This is a temporary migration safeguard. The long-term fix is a dedicated
blobbi_first_hatch_tour_done tag.
No imports remained pointing at the @/lib/blobbi* or @/hooks/use{ProjectedBlobbiState,BlobbisCollection,BlobbiMigration} paths.
Delete the transitional re-exports and the dead hook copies so only
src/blobbi/core/lib/ and src/blobbi/core/hooks/ remain as the single
source of truth.
- Convert src/lib/blobbi*.ts files to thin re-exports from canonical
src/blobbi/core/lib/ sources, eliminating duplicated logic
- Remove unused emoji, title, description props from TasksPanelProps
and their call site in BlobbiMissionsModal
- Remove dead direction state from MissionSurfaceCard (was always 'right')
- Remove unused onContinue prop from FirstHatchTourCard and call site
Remove the invalidateQueries call in markAsRead that raced with the
setQueriesData(false) update. The invalidation triggered an immediate
refetch whose queryFn closure still held the old notificationsCursor
(from a render before the settings cache update propagated). That stale
refetch re-queried the relay with the old since value, found the same
unread events, returned true, and overwrote the false just set --
causing the dot to reappear.
The setQueriesData(false) call provides the immediate UI update. The
60-second poll and real-time subscription naturally re-evaluate once
the cursor has fully propagated.
Adopting a first Blobbi egg should not mark onboarding as complete —
the user still needs to go through the first-hatch tutorial. Removed
the premature blobbi_onboarding_done:'true' write from adoptPreview()
in useBlobbiOnboarding.
The flag is now set to 'true' only when the first-hatch tour reaches
its final step (egg_hatching), right after the hatch mutation succeeds.
This is the correct semantic: onboarding means the full tutorial is
done, not just that the user created a profile or adopted an egg.
The keyboard-aware repositioning of dialogs was too aggressive and broken.
Removes the CSS rule, dialog-keyboard-aware class, and global keyboard
detector mount. The useKeyboardVisible hook is preserved for ArticleEditor.
The onboarding completion flag was stored as a generic 'onboarding_done'
tag on the kind 11125 Blobbonaut profile, while the first-hatch tour
relied solely on device-local localStorage. This caused issues with
multi-account usage on the same browser.
Changes:
- New profiles write 'blobbi_onboarding_done' (not 'onboarding_done')
- Parsing reads 'blobbi_onboarding_done' first, falls back to old tag
- Auto-migration: useBlobbonautProfileNormalization detects old tag
and replaces it with the new one on next profile republish
- MANAGED_BLOBBONAUT_PROFILE_TAG_NAMES includes both tags so the
merge logic can remove the old one during migration
- Tour activation now accepts profileOnboardingDone flag from the
Blobbonaut profile as the authoritative completion source;
localStorage remains a secondary fallback for in-progress UI state
- BlobbiPage passes profile.onboardingDone to the activation hook
When the user's hatch post is detected, the tour card now stays on
the 'show_hatch_card' step for 2 seconds showing a celebratory
completed state (large checkmark, 'Post shared!', 'Continuing in a
moment...') before auto-advancing to 'egg_glowing_waiting_click'.
Previously the effect called goTo() immediately on post detection,
so the checkmark was never visible — the card jumped straight to
the tap-egg phase.
Changes:
- BlobbiPage.tsx: wrap the goTo() in a 2s setTimeout
- FirstHatchTourCard.tsx: redesign completed state with centered
checkmark, bold success text, and 'continuing' hint; remove the
manual Continue button (auto-advance handles progression);
update title/description to reflect the confirmed state
Both Current Focus and Daily Bounties sections are now collapsible
via Radix Collapsible, defaulting to open. Section headers stay
visible when collapsed and show summary info at a glance:
- Current Focus: Hatch/Evolve badge + progress count (e.g. 2 / 5)
- Daily Bounties: coin progress + green dot for claimable count
A subtle animated chevron rotates on toggle. The collapsible
animation uses new collapsible-down/up keyframes added to the
Tailwind config (mirrors the existing accordion pattern but uses
--radix-collapsible-content-height).
Settings row stays non-collapsible to keep it simple.
- Add ExpandableMissionCard: shared component with compact collapsed
state (icon + title + progress ring) and full-width expanded state
with details, progress bar, action links, claim buttons
- Rework TasksPanel as a 2-col (3-col on sm+) grid of task cards;
each card maps its task id to a specific lucide icon (Palette,
Droplets, MessageSquare, Heart, UserPen, Activity)
- Rework DailyMissionsPanel as the same grid; each card maps its
action type to an icon (Utensils, Moon, Camera, Mic, etc.)
- Only one card expanded at a time per section
- Add MissionTypeLegend popover in the header (? icon) explaining
Daily / Hatch / Evolve mission types with color-coded dots
- Pass category prop (hatch | evolve | daily) through to cards for
per-type accent colors (sky / violet / amber)
- Keep all existing behavior: claim, reroll, stop, CTA buttons
- Remove all Collapsible wrappers; sections are always visible
- Restructure layout: Current Focus (hatch/evolve) on top, Daily
Bounties below, settings toggle at footer
- Flatten TasksPanel: remove Card/CardHeader chrome, use minimal
rows with soft rounded backgrounds and inline action links
- Lighten DailyMissionsPanel: compact mission rows, smaller claim
buttons, muted claimed state, no heavy border cards
- Add empty focus state with Compass icon when no active process
- Sticky header with quest-themed subtitle
- ~100 fewer lines across the three files
The mission now completes when the user either:
- Edits custom profile tabs (kind 16769, existing behavior)
- Updates profile metadata (kind 0, new)
Both paths require the event's created_at to be after the evolution
start timestamp (stateStartedAt), so pre-existing events won't
auto-complete the task.
Updated UI copy: 'Edit Your Profile' / 'Update your profile info or
customize your profile tabs'.
Replace isEditMode guard with originalSlug comparison so the collision
check is skipped when republishing an article with the same slug it was
loaded with, but still runs if the user changes the slug to one that
would overwrite a different article.
- Add rounded-xl to Dialog and AlertDialog (was sm:rounded-lg only)
- Add consistent gap-2 to footer buttons on mobile (was no gap)
- Use w-[calc(100%-2rem)] for mobile side margins
- Push dialogs to top of viewport only when keyboard is visible via
.keyboard-visible class on <html>, toggled by useKeyboardVisible
- Mount useKeyboardVisible globally in MainLayout so the class is
always available for CSS-only consumers
- Trigger silent draft save when title or editor loses focus
- Add onBlur prop to MilkdownEditor, wired to both WYSIWYG and source textarea
- Mark saved immediately after local write instead of waiting for relay
- Show persistent cloud icon in status; pulses while relay sync is in flight
Previously, drafts were only saved to localStorage on relay failure.
If the relay accepted the event but hadn't indexed it yet for queries,
the draft would show 'Saved' but not appear under My Articles. Now
we always persist locally first for instant visibility, then sync to
the relay in the background.
initialValueRef was only set once on mount, so toggling back from
source mode reinitialized Milkdown with stale content. Keep
initialValueRef and lastExternalValue in sync with the current value
so remounts and the replaceAll guard work correctly.
The replaceAll effect tried to access editorViewCtx while in source
mode where the ProseMirror view isn't mounted, causing a 'Context
editorView not found' error. Skip the sync when sourceMode is active
and add a try/catch for the initial render race.
- Hide tab bar in write mode on mobile, replace with slim back+title header
- Hide publish FAB when keyboard is visible (was floating over content)
- Collapse metadata (summary, slug, tags) behind a 'Details' toggle on mobile
- Hide header image and stats bar when keyboard is up to maximize writing area
- Add useKeyboardVisible hook using Visual Viewport API
Custom emoji images with non-1:1 aspect ratios were being stretched
into a square. Added object-contain to preserve natural aspect ratio
within the bounding box. Moved text sizing classes to parent containers
for reaction emoji bubbles so unicode emojis still size correctly.
- Mission surface card now has an X dismiss button (onHide prop)
that hides it via localStorage ('blobbi:mission-card-visible')
- BlobbiMissionsModal gains a 'Show mission card on main page'
toggle at the bottom, reflecting the same preference
- Both controls share the same state: hiding from the card or
toggling from the modal are equivalent
- More dropdown now conditionally shows items: if an action
(Blobbies, Items, Missions, Photo, Companion) is visible in
the bottom bar, it is skipped in More to avoid duplication;
if removed from the bar, it appears in More so no action
becomes inaccessible
VersionCheck and Toaster were rendering outside the BrowserRouter in App.tsx,
so the <Link> in the version update toast had no Router context. Moved both
into AppRouter.tsx inside BrowserRouter. Also truncate changelog excerpt
to 60 chars with ellipsis for cleaner toast display.
Bottom bar simplification:
- Default to 3 visible items: Blobbies (left), Main Action (center),
More (right). Items/Missions/Photo moved into More dropdown.
- All existing actions (Set as Companion, Evolve/Hatch, View Blobbi,
dev tools) remain in More with existing guards.
- 'Edit action bar' entry in More opens the new editor.
Editable action bar preferences:
- New preference model (action-bar-preferences.ts) with localStorage
persistence, validation, and migration support.
- Candidates: Blobbies, Missions, Items, Take Photo, Set as Companion.
- Up to 3 custom visible slots (Main Action + More are fixed).
- Each slot can be shown/hidden, reordered, or highlighted.
- ActionBarEditor modal for editing with reset-to-default option.
Mission surface card:
- MissionSurfaceCard renders below the Blobbi visual, above the bar.
- Shows one mission at a time with badge (Hatch/Evolve/Daily),
progress bar, description, and coin reward for dailies.
- Priority: hatch/evolve tasks first, then unclaimed daily missions.
- Auto-rotates every 5s when multiple cards; manual tap cycles.
- 'View all missions' link opens existing missions modal.
- Hidden during first-hatch tour (preserves tour behavior).
- Move click hint emoji to centered overlay with larger size (text-4xl)
so users clearly see it over the egg, not tucked in a corner
- Keep crack overlay visible during egg_opening state by including
'opening' in tourShowCrack and mapping it to crack level 3
- The crack SVG lives inside the shell div, so it inherits the
opening animation (scale/blur/fade) and disappears with the shell
- Suppress shake animation during opening so it doesn't conflict
with the smooth open sequence