Skip to content

Repository files navigation

@privchat/cocos

PrivChat SDK adapter for Cocos Creator 3.8.x LTS+. Default zero-resource programmatic chat UI plus a node-binding renderer for projects that need designer/Prefab control.

Status: 0.1.0-alpha · API surface frozen between 0.1.x stable minor versions; 0.1.x-beta may break. See docs/superpowers/specs/2026-05-06-privchat-cocos-v01-design.md for the full design.

Install

npm i @privchat/cocos @privchat/sdk

cc is a peer provided by your Cocos Creator project.

Quick start (programmatic UI)

import { Component, Node, _decorator } from 'cc';
import { PrivchatCocos, PrivchatDarkTheme } from '@privchat/cocos';
import { PrivchatClient } from '@privchat/sdk';

const { ccclass, property } = _decorator;

@ccclass('MyChatScene')
export class MyChatScene extends Component {
  @property(Node) chatRoot!: Node;
  private mounted: { dispose: () => void } | null = null;

  async start() {
    const client = new PrivchatClient(/* ... */);
    await client.connect();
    await client.authenticate(uid, token, deviceId);

    this.mounted = PrivchatCocos.mountChatView(this.chatRoot, {
      client,
      channelId: '10001',
      channelType: 1,
      theme: PrivchatDarkTheme,
    });
  }

  onDestroy() {
    this.mounted?.dispose();
  }
}

Custom UI (node-binding)

import { instantiate, Label } from 'cc';

PrivchatCocos.bindChatView({
  client,
  channelId: '10001',
  channelType: 1,
  nodes: { root, messageContent, inputBox, sendButton },
  hook: {
    renderMessage(item, _i, _container) {
      // Use your own Prefab; return the created Node.
      const node = instantiate(yourBubblePrefab);
      node.getComponentInChildren(Label)!.string = item.fallbackText;
      return node;
    },
  },
});

Theming

ThemeConfig covers colors, radius, spacing, fontSize. Pass your own when calling mountChatView:

PrivchatCocos.mountChatView(root, {
  client,
  channelId: 'c1',
  channelType: 1,
  theme: {
    colors: { /* override any subset; full default in src/chat/chat-theme.ts */ },
    radius: { bubble: 14, input: 12 },
    spacing: { xs: 4, sm: 8, md: 12, lg: 16 },
    fontSize: { message: 15, time: 11, input: 15 },
  },
});

Errors / Toasts

The library never owns global UI. Subscribe explicitly:

  • onError(err) — unrecoverable errors (auth, RPC failure, sustained disconnect)
  • onToast(msg) — soft messages ("发送失败", "加载历史失败")

ChatView itself shows inline status (failed bubble, history-load failed banner) via the ViewModel.

Multi-instance

Multiple mountChatView calls share the same PrivchatClient cache but maintain independent UI state (input draft, scroll position, virtual list pool).

Dispose

mountChatView returns { dispose, viewModel, controller }. Call dispose() from your Component's onDestroy(). Idempotent — safe to call twice.

Switching conversations (production pattern)

For game UIs that keep a chat panel mounted across navigations (split-screen layouts, sidebar chat, ChatPanel-style hosts), do not dispose and remount the view every time the user picks a different friend / room. Instead, hold on to the controller returned by mountChatView and call:

await controller.setChannel(nextChannelId, nextChannelType);

ChatController.setChannel is the supported API for in-place channel swaps:

  • Bumps channelEpoch so any in-flight start() / loadMore() / send() capturing the old epoch short-circuits cleanly when its await resolves.
  • Tears down only the per-channel observeConversation subscription, not the controller-lifetime composite — listeners, error handler, toast hook, and self uid are preserved.
  • Resets the view-model to an empty state for the new channel and runs start() against it. The renderer subscribed to the controller re-renders automatically — no UI re-creation, no flash.
  • Cache-first behavior carries over: the local IndexedDB window is shown first, then the server's latest window replaces it.

Use setChannel whenever the chat surface is reused. Use a fresh mountChatView only when the chat region itself is being torn down (scene swap, full-screen back navigation).

Demo note: the bundled privchat-cocos-demo uses a push-pop page flow (chat → back → friends → another friend → chat). The friends page reclaims the same root node, so the demo intentionally dispose+remounts on each navigation to keep lifecycle simple. This is not the recommended pattern for shipping product UIs.

Manual E2E

See examples/cocos-starter/README.md.

Roadmap

Version Theme
v0.1 Programmatic ChatView
v0.1.1 Contact list (mountContactList + SdkFriendsSource), Room subscription headless API (createRoomSubscriptionController), lazy nickname/avatar fetch via account/user/detail (this release)
v0.2 Prefab-binding enhancements: custom MessageRenderer, avatar image loader, navigation callbacks
v0.3 IM polish: dynamic-height bubbles, image messages, scroll anchor preservation, SDK room_publish_received event surface (cross-package)
v0.3.5 Embeddable ChatPanel (see below) — keep-alive / hide-reuse lives here, not on the basic ChatView path
v0.4 Platform evaluation: extract @privchat/cocos-ui if a second consumer arrives

Future: Embeddable ChatPanel (v0.3.5)

v0.1 exposes a single ChatView (one channel, message list + input). Real games often need to combine a conversation list with a detail view. The host game owns container placement and orientation policy@privchat/cocos will render whichever mode you ask for into the Node you provide.

Planned API (v0.3.5):

PrivchatCocos.mountChatPanel(containerNode, {
  client,
  mode: 'split' | 'conversationList' | 'conversationDetail',
  // ... mode-specific options
});

Three modes:

  • conversationDetail — single channel's messages + input. Equivalent to mountChatView; preserved for API symmetry.
  • conversationList — conversation/contact list only. Host receives onSelectConversation(conv) and decides what to do (open another panel, navigate, etc.).
  • split — left list + right detail, with built-in select-and-show wiring. For landscape game side-panels, PC/tablet large screens.

What the library will NOT do (these stay with the host game):

  • Auto-detect orientation / aspect ratio
  • Manage half-screen / floating-overlay / fullscreen layout
  • Provide back-button / page navigation
  • Show toasts or modal dialogs

The library renders into the container the host provides. Layout, overlays, and orientation belong to the game's UI system. v0.1 already follows this model with mountChatView; v0.3.5 only widens the scope of what's renderable.

License

Apache-2.0.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages