PPM

@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

VersionPublishedIntegrity
1.6.1 latest2026-09-30sha512-kG/SxMBZnEFWF1n…
1.6.0 2026-06-15sha512-EKwV4CsNCUBAlJH…
1.5.0 2026-05-14sha512-XUBhG+HvcdOOcrU…
1.4.0 2026-04-30sha512-01q1OuPg0IV7Pzx…
1.3.3 2026-04-25sha512-CDGX34w+tGDnJLc…
1.3.2 2026-04-22sha512-HrYUyNSpSDBRe05…
1.3.1 2026-03-28sha512-I8oT4PBPU1MNUHW…
1.3.0 2026-03-28sha512-QV7catnWaBosJKG…
1.2.1 2026-03-28sha512-t+2T1Nvt6UytNa4…
1.2.0 2026-03-28sha512-34DTIkvnpOLnf2K…
1.1.0 2026-03-28sha512-0lx8yu+2rZAJUQ/…
1.0.0 2026-03-28sha512-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

ModeWhat you needTypical repo
Full social layer — friends, skills, challenges, PixyGo, profile pages<SocialProvider config> at the app rootTastebud, Kartograf, CoreFeed, SoloBattle
Share-only — just the share sheet on contentnothing; <ShareButton> is standalonelonnlyst.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

ExportFromUse
<SocialProvider config>/componentsthe 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/componentsUI
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

Publishing

npm run build && npm publish --access public

All packages · packument JSON