@pixygon/social
Shared social features for Pixygon applications — friends, profiles, PixyGo, levels, achievements
Install
# .npmrc @pixygon:registry=https://ppm.pixygon.io/ npm install @pixygon/social@1.6.1
Versions
| Version | Published | Integrity |
|---|---|---|
| 1.6.1 latest | 2026-09-30 | sha512-kG/SxMBZnEFWF1n… |
| 1.6.0 | 2026-06-15 | sha512-EKwV4CsNCUBAlJH… |
| 1.5.0 | 2026-05-14 | sha512-XUBhG+HvcdOOcrU… |
| 1.4.0 | 2026-04-30 | sha512-01q1OuPg0IV7Pzx… |
| 1.3.3 | 2026-04-25 | sha512-CDGX34w+tGDnJLc… |
| 1.3.2 | 2026-04-22 | sha512-HrYUyNSpSDBRe05… |
| 1.3.1 | 2026-03-28 | sha512-I8oT4PBPU1MNUHW… |
| 1.3.0 | 2026-03-28 | sha512-QV7catnWaBosJKG… |
| 1.2.1 | 2026-03-28 | sha512-t+2T1Nvt6UytNa4… |
| 1.2.0 | 2026-03-28 | sha512-34DTIkvnpOLnf2K… |
| 1.1.0 | 2026-03-28 | sha512-0lx8yu+2rZAJUQ/… |
| 1.0.0 | 2026-03-28 | sha512-nwXghRmV0tDoil2… |
@pixygon/social
The shared social layer for Pixygon apps — friends/followers, cross-app skill XP, challenges, PixyGo encounters, profile UI, and the share sheet. 7 repos depend on it (Tastebud, Kartograf, CoreFeed, SoloBattle, pixygon.io, pixiel.ai, lonnlyst.no).
It is deliberately not a new backend: everything is stored under the shared
savedata project 65481fec93ee5f866ade917f, so XP earned in one pearl shows
up in every other. Never build a new /v1/friends or /v1/challenges endpoint —
extend this package instead.
Two ways to use it
| Mode | What you need | Typical repo |
|---|---|---|
| Full social layer — friends, skills, challenges, PixyGo, profile pages | <SocialProvider config> at the app root | Tastebud, Kartograf, CoreFeed, SoloBattle |
| Share-only — just the share sheet on content | nothing; <ShareButton> is standalone | lonnlyst.no |
Retrofitting the full layer (≈15 minutes)
1. Install
npm i @pixygon/social
MUI 6+, @mui/icons-material, @emotion/* and React 18+ are peer deps — the
components are MUI-based.
2. Pick your appId
appId is a lowercase app slug, not an ObjectId — it keys the per-app XP
bucket and the app's colour/name in profile UI. It must be registered in the
package (src/utils/levels.ts → APP_NAMES + APP_COLORS):
kartograf · monstertask · corefeed · solobattle · tastebud
Adding a new app? Add it to those two maps (and a skill pack in
ALL_SKILLS / ALL_CHALLENGES if it has its own skills), publish, then use
it. Do not reuse another app's id — appId: 'pixygon' copied out of
pixygon.io merges your app's XP into the hub's bucket.
3. Mount the provider — below auth
The config needs a live token and user id, so SocialProvider must sit
inside AuthProvider. The estate pattern (src/providers/SocialProvider.tsx):
import { SocialProvider as PixygonSocialProvider } from '@pixygon/social/components'
import { useToken, useAuth } from '@pixygon/auth'
import type { SocialConfig } from '@pixygon/social'
const API_URL = import.meta.env.VITE_API_URL || 'https://api.pixygon.com/v1'
export function SocialProvider({ children }: { children: ReactNode }) {
const { getAccessToken } = useToken()
const { user } = useAuth()
const config: SocialConfig = {
appId: 'tastebud',
appName: 'Tastebud',
primaryColor: '#e879f9',
accentColor: '#38bdf8',
baseUrl: API_URL,
getToken: getAccessToken,
getUserId: () => (user as any)?._id ?? null,
}
return <PixygonSocialProvider config={config}>{children}</PixygonSocialProvider>
}
All seven fields are required. Without getToken/getUserId the hooks
fall back to the package default config (appId: 'pixygon', no token, no
user) and every request comes back empty — silently.
4. Use the hooks / components
import { useSkillsSync, useChallenges, useFriends, usePixyGo } from '@pixygon/social'
const { skillXp, appXp, totalXp, addSkillXp, addAppXp } = useSkillsSync() // auto-saves every 15s
addSkillXp('chef', 25)
const { progress, updateProgress, getAppCounts } = useChallenges()
updateProgress('tb_rate_50', ratedCount)
const { following, followers, toggleFollow } = useFriends()
const { encounters, collection, processEncounters } = usePixyGo({ userPosition, isTracking })
import { ProfileLayout, SkillsGrid, FriendsList, ChallengesList, ProfileCard, LevelBadge, UserAvatar }
from '@pixygon/social/components'
<Route path="/profile" element={<ProfileLayout />} /> // full tabbed profile page
5. Share sheet (works with or without the provider)
import { ShareButton } from '@pixygon/social/components'
<ShareButton
payload={{ url, title, description, hashtags, image, contentId }}
projectId="69ee9b3f7a116f8ba90d0890" // omit → the share isn't attributed
apiUrl="https://api.pixygon.com" // omit → share analytics is skipped entirely
userId={user?._id}
variant="pill"
/>
⚠ apiUrl here is the host without /v1 — the helper appends
/v1/analytics/share itself.
6. Verify it worked
node node_modules/@pixygon/social/verify.mjs
# or:
pearl verify social
It detects which mode the repo is in and checks accordingly: package installed,
<SocialProvider> mounted with all seven SocialConfig fields, a registered
non-placeholder appId, a real baseUrl — or, for share-only repos, that
<ShareButton> gets apiUrl + projectId. Exit 0 pass, 1 fail.
What verify cannot prove: that anything syncs. The hooks are no-ops until
getUserId() returns a real id, so the only end-to-end proof is signing in,
earning XP, and seeing it on the profile page (and in another app's profile —
that's the point of the shared project).
API
| Export | From | Use |
|---|---|---|
<SocialProvider config> | /components | the mount |
useSocialConfig() | . | read the active config |
useSkillsSync() | . | skillXp, appXp, totalXp, addSkillXp, addAppXp (15s autosave) |
useChallenges() | . | progress, updateProgress, getAppCounts |
useFriends() | . | following, followers, toggleFollow |
usePixyGo({userPosition, isTracking}) | . | encounters + collection book |
useUserSearch() | . | find users |
ProfileLayout, SkillsGrid, SkillCard, FriendsList, ChallengesList, ChallengeCard, ProfileCard, PixyGoList, LevelBadge, UserAvatar, ShareButton | /components | UI |
getLevel, getLevelProgress, getSkillLevel, getAppLevel, xpForLevel, MAX_LEVEL | . | level maths |
ALL_SKILLS, ALL_CHALLENGES, APP_NAMES, APP_COLORS, TIER_* | . | the registries |
buildShareUrl, tagUrl, tryNativeShare, copyShareUrl, reportShare | . | share helpers |
SocialConfig
{
appId: string // lowercase slug, registered in APP_NAMES/APP_COLORS
appName: string
primaryColor: string // this app's brand colour (use its @pixygon/design brand)
accentColor: string
baseUrl: string // https://api.pixygon.com/v1 (WITH /v1)
getToken: () => string | null
getUserId: () => string | null
}
Gotchas
- No provider = silent defaults.
useSocialConfig()falls back toappId: 'pixygon',getToken: () => null— requests go out anonymous and return nothing. Nothing throws. baseUrlincludes/v1;ShareButton'sapiUrldoes not. Easiest mistake in the package.- Skills live in one shared project.
useSkillsSyncwrites tosavedata/65481fec93ee5f866ade917f/<userId>/section/skillsregardless of your app. That's intentional (cross-app XP) — don't "fix" it to your own projectId or you break the whole point. appIdcollisions merge XP. See step 2.- Colours should come from the site's own brand in
@pixygon/design/tokens.mjs— don't leak another pearl's palette.
Publishing
npm run build && npm publish --access public