Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add portals-labs/portals-plugin-claude --skill portals-guardian-avatarsgit clone --depth 1 https://github.com/portals-labs/portals-plugin-claudeWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/portals-labs/portals-plugin-claude/portals-guardian-avatars)<a href="https://agentmods.dev/skills/portals-labs/portals-plugin-claude/portals-guardian-avatars"><img src="https://agentmods.dev/badge/skills/portals-labs/portals-plugin-claude/portals-guardian-avatars/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/portals-labs/portals-plugin-claude/portals-guardian-avatars"><img src="https://agentmods.dev/badge/skills/portals-labs/portals-plugin-claude/portals-guardian-avatars.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00197 | $0.02214 |
| Opus 5 | $0.00098 | $0.01107 |
| Sonnet 5 | $0.00039 | $0.00443 |
| Haiku 4.5 | $0.00020 | $0.00221 |
Grade A, and why
portals-guardian-avatars scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 62 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Guardian avatars
The Guardian avatar SDK renders the same avatars players wear across Portals. It is a Three.js library, not a renderer: the game owns the scene, camera, and render loop, and the SDK adds avatars to it. Reach for it instead of hand-rolling a character whenever a 3D game wants a player avatar.
Read references/guardian-avatars.md for the full API, code examples, versioning, and local-development setup. For targeting reticles, cast telegraphs and world markers built within the sandbox rules, read references/ability-vfx.md. Types for autocomplete: https://portals.to/portals-sdk/guardians.d.ts — the source of truth for the API.
Wiring
Portals stamps the SDK into every processed preview and published bundle. Load it beside the Portals SDK; never edit, bundle, or ship a copy:
<script src="./_portals/sdk.js"></script>
<script src="./_portals/guardians-sdk.js"></script>
<script src="./game.js"></script>
const { THREE, PortalsAvatars } = await PortalsGuardians.ready();
Module-based games can skip the loader and import { PortalsAvatars } from '@portals/avatars' instead — Portals writes the import map that resolves @portals/avatars, three, and three/addons/. Map the bare specifier at guardians-sdk.module.js, never at the guardians-sdk.js loader. Both routes load the same module and can be mixed. Only three addons are hosted: controls/OrbitControls.js, loaders/GLTFLoader.js, utils/BufferGeometryUtils.js.
Rules that are easy to get wrong
- Call
avatars.update(dt)once per frame or nothing animates. - Anything that writes bones runs AFTER
avatars.update(dt). That call is the mixer tick, and it rewrites every bone local from the clips.Ragdoll.update(),aimWeapon()andapplyPose()stepped before it are silently overwritten — nothing errors; it just does not work. - Take
THREEfrom the SDK, not from a CDN. There is exactly one shared instance; the game CSP keepsscript-srcat'self', so a second copy will not load and would break instance checks anyway. - Assets resolve through Portals. Published games run under
connect-src 'self'; the SDK rewrites asset URLs onto managed same-origin paths automatically. Two exceptions need action: run a wearable'sthumbnailthroughresolveAssetUrlbefore using it in an<img>(img-srcis'self'too), and equip an externally hosted wearable as a catalog item with itsidrather than a bare URL, since the item proxy addresses it by inventory item id. - Pin the version. Only editor and AI-builder games are frozen on the avatar SDK version they were first stamped with. A push from this plugin, a zip import or a GitHub build replaces the whole bundle and re-stamps the SDK at the current platform release, so an unpinned pushed game can change version on any push. Pin
{ "guardiansSdk": "0.36.0" }inportals.jsonat the project root; the pin wins on every path. Pinning an unreleased version fails the publish. Features below are marked with the release they shipped in — a game pinned lower does not have them. - Ground and collision are yours to supply. The defaults are a flat floor at
y = 0and free movement.SceneCollideris the quickest real level — register level geometry only, never avatars, and callcollider.refresh()after adding or removing meshes. With existing physics, passgetGroundHeight,resolveMovement,raycast, andcheckClearancedirectly. - Ledge grabbing needs
raycast. Without it nothing is climbable. Both shoulders must find the ledge, so a ledge narrower than the character cannot be grabbed, and the probe only runs while airborne — the player always jumps or falls into a climb. Since 0.36.0 a wall standing in front of the ledge rejects the grab, so a wall is never climbed through. - Swimming is the game's toggle. The SDK has no idea where a level's water is: call
controller.setSwimming(true, { surfaceY })at the water's edge andsetSwimming(false)exactly at the boundary on the way out. - Clips load on demand.
createAvatarresolves as soon as the body is on screen; the locomotion GLB downloads on first movement.animations.play()returnsfalseuntil the clip's bytes arrive — that is not an error;await ensure()for certainty. Callavatars.preloadAnimations()to pay the cost behind a loading screen. - Clean up with
avatars.dispose()when leaving a scene, oravatars.removeAvatar(avatar)/avatars.removeNPC(npc)for one.
What ships with it
2 files beside SKILL.md in the same directory: the scripts, references and assets a skill reads on demand. Not counted in the per-session cost; read them before you install if any of them is executable.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 2d ago Changed 2dc9e40580d7
- 12d ago First seen · 62 lines · 197 tokens per session scan A 27202a09f102
portals-guardian-avatars is a skill published in the GitHub repository portals-labs/portals-plugin-claude (4 stars, last pushed 3d ago), licensed ISC. It adds 197 tokens to every session and 2,214 once invoked, about $0.0010 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other skills, from other repositories
worker-visualizer
A real-time data/particle/simulation visualizer whose heavy compute runs in a Web Worker (off the main thread), optionally sharing memory with the UI via SharedArrayBuffer, and renders to a canvas at 60fps. Produced as a single self-contained index.html. Use when the brief asks for a "web worker", "simulation"…
react-three-fiber
React Three Fiber 3D renderer for json-render. Use when working with @json-render/react-three-fiber, building 3D scenes from JSON specs, rendering meshes/lights/models/environments, or integrating Three.js with json-render catalogs.
vgpu
Build, debug, test, and optimize WebGPU projects using vgpu, its CLI, or @vgpu packages. Use for vgpu API questions, WGSL workflows, browser or Node rendering, integrations, testing, and performance work.
matterjs
Use when implementing 2D physics interactions with Matter.js, including Engine/World setup, Render/Runner configuration, adding bodies and constraints, and scroll/interaction-friendly canvas scenes.
html-to-ugui
A pipeline for turning HTML interface prototypes into Unity UGUI Prefabs, which are reusable Unity interface objects. It uses browser-rendered layout data to preserve positions, images, text, controls, and device-adaptation intentions.
threejs-game-director
Entrypoint for building, upgrading, and finishing Three.js browser games. Routes work across the sibling threejs- skills for gameplay, graphics, UI, 3D/image/audio asset generation, debugging, and release. Use for build-a-game, upgrade, polish, premium, AAA, high-fidelity, showcase, from-scratch, endless runner…