Skip to content

Peer frustums ​

PeerFrustum is a wireframe camera shape. PeerFrustumSync publishes an attached object's pose through @jolly-pixel/network and creates one frustum for each remote pose.

Standalone frustum ​

ts
import { PeerFrustum } from "@jolly-pixel/three";

const frustum = new PeerFrustum({
  color: "#43aa8b",
  displayName: "Alice",
  showNameBox: true
});

frustum.position.copy(remotePosition);
frustum.quaternion.copy(remoteQuaternion);
scene.add(frustum);

The shape points down local -Z.

OptionDefaultPurpose
fov50Vertical field of view in degrees
aspect16 / 9Width-to-height ratio
depth1.5Far rectangle distance in world units
neardepth * 0.2Near rectangle distance; must be above 0 and below depth
color"#43aa8b"Wireframe and label accent
showApexfalseConnect the origin to the near rectangle
displayNamenoneCreate a billboard label
showNameBoxfalseDraw a dark rounded label background

color, displayName, opacity, and showNameBox can be assigned after construction. The label property is null until a display name is provided. Call removeFromParent() and dispose() during teardown.

PeerFrustum.Defaults contains the process-wide defaults used by new instances.

PeerFrustumLabel is also exported for standalone labels. Its constructor requires displayName and color; showNameBox defaults to false. Those three fields and opacity are assignable properties. It extends THREE.Sprite and exposes dispose().

Sync room presence ​

ts
import * as network from "@jolly-pixel/network/client";
import { PeerFrustumSync } from "@jolly-pixel/three/network";

const client = new network.Client({ identity: { username } });
const room = client.room("my-room");
room.join();

const sync = new PeerFrustumSync({ room, parent: scene });
sync.attach(camera);

renderer.setAnimationLoop(() => {
  sync.update();
  renderer.render(scene, camera);
});
OptionDefaultPurpose
roomrequiredRoom used for presence
parentrequiredParent for remote frustums
presenceKey"frustum"Presence field for poses
throttleMs50Minimum delay between changed pose reports; 0 reports every change
hideWithin0Distance from the source below which a frustum is hidden
fadeWithin0Distance from the source below which a frustum fades toward hidden
labelprofile username, or "Guest"Resolve a remote display name
colorfrustum.colorResolve a remote color per peer
frustum{}Shared PeerFrustum options except displayName
requestFramenoneCalled after a remote pose shows, hides or removes a frustum, so a host rendering on demand draws it

The sync assigns no color of its own. Without a color callback every peer gets frustum.color, falling back to PeerFrustum.Defaults.color; the callback overrides it per peer. @jolly-pixel/three ships no palette, so resolve peer colors with your own allocator (createDefaultColorAllocator() covers the common case).

Call update() once per render tick. It publishes after a position or quaternion component changes by more than 1e-4 and the throttle interval has elapsed. A pose read inside the interval is kept and published when it ends, so the resting pose reaches peers even when no frame follows, as with a runtime rendering on demand. detach() drops that pending pose.

Proximity fade ​

A frustum you stand inside reads as noise on screen, so update() fades each peer by its distance to the attached source: opaque at fadeWithin and beyond, ramping linearly to hidden at hideWithin. Both default to 0, which leaves every frustum opaque; opt in by setting them. A pose landing next to the source fades on arrival rather than on the next tick, and detach() restores full opacity.

The fade drives PeerFrustum.opacity, which spans the wireframe and its label, clamps to 0..1, and turns the line material transparent below 1.

peerPose(clientId) returns a copy of the last pose applied to a peer, or undefined for an unknown peer, one whose pose is missing or malformed, and one that has left. Use it to move a local camera onto a peer's viewpoint.

detach() stops local pose reports but leaves remote frustums visible. refreshColors() reruns the color callback for current peers, and does nothing when no callback was given. destroy() detaches, removes room listeners, and disposes remote frustums.

The entry point exports PeerFrustumPose and decodePeerFrustumPose(value). The decoder returns undefined unless the value contains numeric position x, y, z fields and quaternion x, y, z, w fields. A missing or malformed remote pose hides its frustum.

The related exported types are PeerFrustumOptions, PeerFrustumDefaults, PeerFrustumLabelOptions, PeerFrustumSyncOptions, and PeerFrustumPose.