FOS Tablet System — Standard
Version 2.1.0 · requires FOS Essentials Core 1.1.0 or later · also requires FOS Localization 1.0.0, FOS Teleport 1.0.0
A tablet players summon in front of them: teleport menu, local toggles, world rules, and a full moderation panel with roles, freeze, isolation, mute and a synchronised log.
Requires FOS Essentials Core 1.1.0, FOS Localization 1.0.0 and FOS Teleport 1.0.0.
Upgrading from an earlier version? Read CHANGELOG.md first — a prefab you
have modified does not carry over on its own.
Editions
Section titled “Editions”This pack ships in editions, each in its own folder:
Assets/FOS/TabletSystem/└── Standard/ ← you are hereA future Pro edition sits next to this one as Pro/, with its own assembly and its
own components. It adds components beside the Standard ones and talks to them through
their public API — it never replaces a component on the prefab. Upgrading therefore never
costs you the wiring you already did.
- Drop FOS Essentials > FOS Tablet System > Standard > FOSTabletSystem into your scene.
- Assign the isolation zone: an empty Transform somewhere out of the way. Without it, isolating a player does nothing.
- Assign the player registry (
FOSPlayerRegistry, from the Core) on the staff manager. It is optional, but without it the player list allocates an array on every join and leave. - Fill the restored values on the staff manager to match your world’s movement and voice settings. They are what a player gets back when unfrozen or unmuted, and they overwrite whatever they had.
- Fill your teleport destinations, your toggle groups and your rules.
Components
Section titled “Components”| Component | Role | Networking |
|---|---|---|
FOSTabletManager |
Summons, places and closes the tablet | none |
FOSTabletCaller |
Recalls the tablet to a fixed stand | none |
FOSTabletSettings |
Personal sliders, community settings, rules | manual |
FOSTabletToggleGroup |
Objects switched on and off together | none |
FOSTabletToggleButton |
Button driving one group | none |
FOSTabletStaffManager |
Roles, freeze, isolation, mute, authority | manual |
FOSTabletStaffRow |
One player’s row in the staff panel | none |
FOSTabletPermissions |
Per-role object visibility | none |
FOSTabletPermissionRow |
One player’s row in the role panel | none |
FOSTabletLogManager |
Synchronised moderation log | manual |
FOSTabletLogRow |
One log line | none |
The security model
Section titled “The security model”This is the part worth reading before shipping a world with it.
The owner of the staff manager is the only authority. Every moderation action is a
request sent to that owner through Network Calling. The owner checks the real calling
player with NetworkCalling.CallingPlayer, which cannot be spoofed, and only then writes.
A modified client can send the request; it will be refused.
Synced variables carry state, never commands. That is what makes late joiners safe: a
player who arrives applies the current state instead of replaying stale actions. A
SendCustomNetworkEvent is never replayed for them, which is exactly why the state does
not live in events.
Ownership is restricted to staff. If the owner leaves and VRChat drops the object on a visitor, the staff member with the lowest player id reclaims it — a deterministic rule, so one client acts, not all of them at once.
The first admin is the first player of the instance, locked by display name. Trusting the master would be a hole: the master changes every time someone leaves, and the admin would eventually land on a stranger. The instance creator is recognised as admin too, and the founder can never be demoted — not by a moderator, not by another admin.
Checks in the row components are interface checks only. They avoid sending a request that is going to be refused and stop a visitor clicking dead buttons. They are not a security barrier and do not pretend to be one.
What isolation is, and is not
Section titled “What isolation is, and is not”Isolation is a temporary confinement inside the current instance. A VRChat world cannot — and must not — enforce a persistent ban. Rejoining clears it, by design.
An isolated player is teleported to the isolation zone and sent back every two seconds if they walk out of its radius. Respawning does not release them either.
| Role | Value | Can |
|---|---|---|
| Visitor | 0 | nothing |
| VIP | 1 | nothing more; the role exists for the visibility rules |
| Moderator | 2 | freeze, isolate, mute, set roles up to moderator |
| Admin | 3 | all of it, plus promoting admins and the community settings |
Equal ranks can act on each other — two moderators can neutralise one another. That is a deliberate choice for the moment one of them goes wrong.
If the last admin leaves, the first moderator is promoted automatically. Without that succession, an instance loses moderation entirely until it is restarted.
Instance memory
Section titled “Instance memory”Moderator and admin roles are remembered for the current instance only, by display name. A staff member who crashes and comes back to the same instance gets their role again.
Nothing is stored between sessions or across instances. Different groups open instances of the same world, and permissions from one have no business leaking into another. VIP is not remembered, and isolation is deliberately not remembered either.
Per-role visibility
Section titled “Per-role visibility”FOSTabletPermissions shows and hides objects according to the local player’s role.
Roles are cumulative: a role gets everything shown to the roles below it. An admin sees the visitor, VIP and moderator objects without you copying them into four lists — that copying was the most common configuration mistake and the most tedious to undo.
The “hidden from” lists are exceptions for one role, applied last. An object that only appears in hidden from moderator is visible to everyone except moderators.
This is presentation, not protection. Hiding an object does not stop anyone reaching it another way.
Toggles
Section titled “Toggles”A FOSTabletToggleGroup holds a list of objects and one state, applied to all of them.
A FOSTabletToggleButton points at a group — directly, not through a string key.
Toggles are local on purpose. A comfort switch has no reason to be imposed on the rest of the instance, and synchronising it would spend bandwidth on something nobody asked for.
Several buttons can drive the same group: they register with it and their indicators stay in agreement.
Text and translations
Section titled “Text and translations”In-game text goes through FOS Localization. Assign the locale manager and give the translation keys:
| Where | Keys |
|---|---|
FOSTabletStaffManager |
four role names, in order: visitor, VIP, moderator, admin |
FOSTabletSettings |
standard rules, adult rules |
Without a locale manager, the fallback strings written next to those fields are used, and the tablet works in one language.
Any label of your own is a FOSLocalizedText like anywhere else in your world.
Teleporting
Section titled “Teleporting”Teleport buttons in the tablet are FOS Teleport components: one FOSTeleportButton per
destination, with its target Transform. This pack does not ship its own teleporter.
The one exception is teleport to a player in the staff panel: FOS Teleport aims at a fixed Transform in the scene, whereas that destination is a player who moves and may leave between the click and the arrival. It stays native here, and fails silently if the target is gone.
Scripting
Section titled “Scripting”Every entry point below takes no parameter, so any script can reach it with
SendCustomEvent.
| Call | On | Effect |
|---|---|---|
SummonTablet() / CloseTablet() |
FOSTabletManager |
Opens or closes the tablet |
RecallTablet() |
FOSTabletCaller |
Brings the tablet back to its stand |
FOSToggle() |
FOSTabletToggleGroup / FOSTabletToggleButton |
Flips a group |
FOSRoleOf(id) / FOSIsStaff(id) / FOSIsAdmin(id) |
FOSTabletStaffManager |
Reads a role |
FOSRequestFreeze/Isolation/Mute(id) |
FOSTabletStaffManager |
Requests an action |
FOSRequestRole(id, role) |
FOSTabletStaffManager |
Requests a role change |
FOSAdultContentIsOn() |
FOSTabletSettings |
Reads the adult content state |
Extension points
Section titled “Extension points”Three components publish state changes the same way. Call FOSRegister(this) on one, and
expose a public parameterless method of the matching name:
| Publisher | Event to expose |
|---|---|
FOSTabletStaffManager |
FOSApplyStaffState() |
FOSTabletToggleGroup |
FOSApplyToggleState() |
FOSLocaleManager |
FOSApplyLanguage() |
A listener should also apply itself once in its own Start: it can register after the
publisher has already set its initial state.
This is how the Pro edition plugs in, and how anything this pack does not cover plugs in too.
Notes and limits
Section titled “Notes and limits”- One staff manager per scene. Several would fight over the same players.
- Nothing persists between sessions. Roles live in the current instance only.
- Log size costs bandwidth. Every entry is synchronised; 30 is a sensible default.
- Restored values overwrite the player’s settings. Match them to your world.
- Quest and PC behave identically: there is no platform-specific code, and there could not be — Udon is compiled once for both.
