Viewport and selection
viewportControl Studio's 3D view and selection: focus the camera, select instances, raycast, audit UI, measure text, and snapshot interfaces to verify Roblox builds visually.
Instructions
Works with the 3D view and the Studio selection.
select sets, extends or shrinks what is highlighted in Studio. Select what you just built or changed — it shows the user the result, and puts the instance under Studio's own move and scale handles. studio_status reports the current selection; this sets it.
focus aims the Studio camera at an instance and frames it so the whole thing is on screen. This is what makes screenshot worth having: a picture of wherever the camera happened to be answers nothing, while a picture of the thing you just built answers 'does it look right', which no amount of reading properties can. Build, focus, screenshot.
The distance is computed from the subject's size and the camera's field of view, so a doorway and a whole map both arrive filling a similar share of the frame. from changes the angle you view it from, and padding how tightly it is framed.
camera sets or reads the camera directly, for shots framing cannot express — standing inside a room, or looking along a corridor.
raycast fires a ray through the world and reports the first thing it hits, with position, surface normal, distance and material. This answers 'what occupies this space', which the data model alone cannot: use it to find the ground under a spawn point, or check whether a gap is clear before placing something.
ui audits a whole interface for the faults that are invisible in the data model: elements off the side of the screen, elements covering each other, zero-size elements, text too small to read, and text that overflows its label. A button positioned off a phone screen has a perfectly correct Position and Size — nothing about the instance is wrong, it is just somewhere nobody can reach.
It measures against whatever device is currently emulating, so the way to use it is twice: once as-is, then device op="set" a phone and again. Layout is live in edit mode — no playtest needed.
textbounds measures how big a piece of text actually renders. Point it at a TextLabel, TextButton or TextBox with path and it reads that label's own text, font, size and width and answers whether the text fits inside it. Give text and size directly and it just measures. There is no other honest way to answer 'will this label overflow' — character counts ignore the font, and font size is not a width.
uisnap records every UI element under path (default StarterGui, or the PlayerGui with target="client"): layout, absolute position and size, colours, fonts, text, images, strokes, corners and padding, and returns a snapshot id. Take one before restyling a UI, then call uisnap again with compareTo set to that id: the reply lists what was added, removed and changed, property by property, including what you did not mean to touch. Every call stores a new id, so passes chain.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| x | No | pick: normalized X in the full uncropped viewport. | |
| y | No | pick: normalized Y in the full uncropped viewport. | |
| at | No | focus only: look at this point instead of an instance, e.g. "0, 10, 0". | |
| op | Yes | 'focus' points the camera at something and frames it, 'camera' sets it explicitly, 'select' changes the Studio selection, 'textbounds' measures rendered text, 'raycast' queries the world, 'ui' audits an interface, 'uisnap' snapshots one and diffs it against an earlier snapshot. | |
| font | No | textbounds only: an Enum.Font name, e.g. "GothamMedium". Defaults to the label's. | |
| from | No | focus only: direction to view from, e.g. "0, 1, 0" for directly above or "1, 0, 0" from the side. Defaults to a raised three-quarter view. | |
| mode | No | select only: replace the selection, extend it, or remove from it. | set |
| path | No | focus: the instance to look at. ui/uisnap: the UI root to read. textbounds: the label. | |
| text | No | textbounds only: the string to measure. Defaults to the label's own text. | |
| paths | No | select only: instances to select. An empty array clears the selection. | |
| ignore | No | raycast only: instances the ray passes through. | |
| lookAt | No | camera only: the point to aim at. | |
| origin | No | raycast only: where the ray starts, e.g. "0, 50, 0". | |
| player | No | client only: player name; required with multiple players. | |
| target | No | client: read the actual player's playtest VM. Use the playtest server studioId. | studio |
| padding | No | focus only: how much room to leave around the subject. 1 is tight. | |
| position | No | camera only: where to put the camera, e.g. "0, 20, 30". | |
| richText | No | textbounds only: treat the text as rich text. Defaults to the label's setting. | |
| studioId | No | Target Studio; omit for the active one. | |
| textSize | No | textbounds only: font size in pixels. Defaults to the label's. | |
| compareTo | No | uisnap only: id of an earlier snapshot to diff the new one against. | |
| direction | No | raycast only: which way it points, e.g. "0, -1, 0" for straight down. | |
| wrapWidth | No | textbounds only: wrap at this width. 0 means do not wrap. Defaults to the label's width. | |
| fieldOfView | No | camera only: field of view in degrees. Lower is more zoomed in. | |
| maxDistance | No | raycast only: how far to look, in studs. |