This commit is contained in:
Joe 2026-02-02 12:08:47 -06:00
parent a9b4f8e83b
commit e6efc04756
8494 changed files with 495610 additions and 0 deletions

View file

@ -0,0 +1,80 @@
---
title: Activity History
description: Activity History is a log of key configuration, publish, and edit activities within a place.
---
**Activity History** is a shared log of key changes within an experience. Each entry tells you what changed, who changed it, and when they made the change.
1. From Studio's **Window** menu, open **Activity History**. Events are displayed in chronological order, with the most recent appearing first.
<img src="../assets/studio/general/Activity-History.png" width="360" alt="A view of the Activity History window showing various changes and updates." />
1. If you have a large number of events, you can filter them by type or collaborator.
1. If you want to manage the configuration or get more details on a change, use the **&ctdot;** menu next to each event to get a link to the setting in either Studio or the Creator Hub.
## Event reference
Most events are visible in both Studio and the experience's **Activity History** page on the [Creator Dashboard](https://create.roblox.com/dashboard/creations), although some are only visible in one location or the other.
### Place configuration
Event | Shown in Studio | Shown in Creator Hub
:--- | :---: | :---:
Place published | &check; | &check;
Place name changed | &check; | &check;
Place description changed | &check; | &check;
Place added to experience | | &check;
Place removed from experience | | &check;
**Allow place to be copied as a template using Create Place API** changed | &check; | &check;
**Allow place to be updated using Save Place API** changed | &check; | &check;
### Place edits
Event | Shown in Studio | Shown in Creator Hub
:--- | :---: | :---:
Script draft committed | &check; |
### Experience configuration
Event | Shown in Studio | Shown in Creator Hub
:--- | :---: | :---:
Experience changed to public or private | &check; | &check;
Experience name changed | &check; | &check;
Experience description changed | &check; | &check;
Experience archived | &check; | &check;
Age recommendation questionnaire updated | &check; | &check;
**Shut down all servers** used | &check; | &check;
Playable devices changed | &check; | &check;
**Enable Studio Access to API Services** enabled or disabled | &check; | &check;
### Monetization settings
Event | Shown in Studio | Shown in Creator Hub
:--- | :---: | :---:
**Paid Access** enabled or disabled | &check; | &check;
Paid access price changed | &check; | &check;
**Allow Private Servers** enabled or disabled | &check; | &check;
Private servers price changed | &check; | &check;
### Notifications
Event | Shown in Studio | Shown in Creator Hub
:--- | :---: | :---:
Notification string created | | &check;
Notification string deleted | | &check;
Notification string updated | | &check;
For more information, see [Experience notifications](../production/promotion/experience-notifications.md).
### Collaboration permissions
Event | Shown in Studio | Shown in Creator Hub
:--- | :---: | :---:
Collaborator added with edit or play permissions | &check; | &check;
Collaborator permissions level changed | &check; | &check;
Collaborator removed | &check; | &check;
Group given play permissions | &check; | &check;
Group with play permissions removed | &check; | &check;
Group role's permissions to this experience changed | &check; | &check;
For more information, see [Roles and permissions](../projects/groups.md#roles-and-permissions).

View file

@ -0,0 +1,226 @@
---
title: Creator Store queries
description: Creator Store Queries let you externally query the Creator Store and Marketplace Catalog.
---
You can search Roblox's assets outside Studio by accessing the Creator Store API. Use the [Creator Store API](#creator-store-api) to query Studio assets, such as meshes, models, and audio, and the [Marketplace API](#marketplace-api) to query avatar assets on the Marketplace.
Each API requires a URL and custom search parameters for that specific catalog. If both URL and parameters are valid, the API returns a JSON format with the results of your search.
## Creator Store API
For information on making calls to the Creator Store API for search, see Toolbox Service in the [Open Cloud reference](../../cloud/features/creator-store.md#toolbox-service).
## Marketplace API
You can query avatar items from the Marketplace using the following URL:
`https://catalog.roblox.com/v1/search/items/details?[params]`
You can replace `[params]` with the appropriate [query parameters](#query-parameters) to customize your search.
### Query parameters
You can specify search parameters by appending a series of parameters and values to the URL, each separated by a `&`.
Use the following parameters to query the Marketplace:
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Type</th>
<th>Options and Values</th>
</tr>
</thead>
<tbody>
<tr>
<td>Category</td>
<td>byte</td>
<td>`0` = Featured<br />`1` = All<br />`2` = Collectibles<br />`3` = Clothing<br />`4` = BodyParts<br />`5` = Gear<br />`11` = Accessories<br />`12` = AvatarAnimations<br />`13` = CommunityCreations</td>
</tr>
<tr>
<td>CreatorType</td>
<td>byte</td>
<td>`1` = User<br />`2` = Group<br /><br />Queries using `CreatorType` also require the `CreatorTargetId` parameter.</td>
</tr>
<tr>
<td>CreatorTargetId</td>
<td>long</td>
<td>The user or group ID depending on the CreatorType provided.<br /><br />Queries using `CreatorTargetId` also require the `CreatorType` parameter.</td>
</tr>
<tr>
<td>CreatorName</td>
<td>string</td>
<td>Search by creator name. If `Enum.CreatorType` is not provided, search is for users only.</td>
</tr>
<tr>
<td>Cursor</td>
<td>string</td>
<td>Each search response contains a `nextPageCursor` if there is a next page and `previousPageCursor` if there is a previous page. Pass either of these values in the Cursor parameter of your next query to get the next or previous page of results. The cursor is valid if the other query parameters remain the same.</td>
</tr>
<tr>
<td>Genres</td>
<td>byte</td>
<td>Specifies the genre for the search. The recommended approach to filtering on genres is to match the URL of a catalog page.<br /><br />`1` = TownAndCity<br />`2` = Medieval<br />`3` = SciFi<br />`4` = Fighting<br />`5` = Horror<br />`6` = Naval<br />`7` = Adventure<br />`8` = Sports<br />`9` = Comedy<br />`10` = Western<br />`11` = Military<br />`13` = Building<br />`14` = FPS<br />`15` = RPG</td>
</tr>
<tr>
<td>Keyword</td>
<td>string</td>
<td>Standard keyword search.</td>
</tr>
<tr>
<td>Limit</td>
<td>int</td>
<td>Number of results to return. Values are currently limited to 10, 28, and 30.</td>
</tr>
<tr>
<td>MaxPrice</td>
<td>int</td>
<td>The maximum price in Robux of items in the query.</td>
</tr>
<tr>
<td>MinPrice</td>
<td>int</td>
<td>The minimum price in Robux of items in the query.</td>
</tr>
<tr>
<td>SortAggregation</td>
<td>byte</td>
<td>`1` = PastDay<br />`3` = PastWeek<br />`4` = PastMonth<br />`5` = AllTime</td>
</tr>
<tr>
<td>SortType</td>
<td>byte</td>
<td>`0` = Relevance (Default)<br />`1` = Favorited<br />`2` = Sales<br />`3` = Updated<br />`4` = PriceAsc <br />`5` = PriceDesc </td>
</tr>
<tr>
<td>Subcategory</td>
<td>byte</td>
<td>`0` = Featured<br />`1` = All<br />`2` = Collectibles<br />`3` = Clothing<br />`4` = BodyParts<br />`5` = Gear<br />`9` = Hats<br />`10` = Faces<br />`12` = Shirts<br />`13` = TShirts<br />`14` = Pants<br />`15` = Heads<br />`19` = Accessories<br />`20` = HairAccessories<br />`21` = FaceAccessories<br />`22` = NeckAccessories<br />`23` = ShoulderAccessories<br />`24` = FrontAccessories<br />`25` = BackAccessories<br />`26` = WaistAccessories<br />`27` = AvatarAnimations<br />`37` = Bundles<br />`38` = AnimationBundles <br />`39` = EmoteAnimations<br />`40` = CommunityCreations<br />`41` = Melee<br />`42` = Ranged<br />`43` = Explosive<br />`44` = PowerUp<br />`45` = Navigation<br />`46` = Musical<br />`47` = Social<br />`48` = Building<br />`49` = Transport<br />`54` = HeadAccessories<br />`55` = ClassicTShirts<br />`56` = ClassicShirts<br />`57` = ClassicPants<br />`58` = TShirtAccessories<br />`59` = ShirtAccessories<br />`60` = PantsAccessories<br />`61` = JacketAccessories<br />`62` = SweaterAccessories<br />`63` = ShortsAccessories<br />`64` = ShoesBundles<br />`65` = DressSkirtAccessories<br />`66` = DynamicHeads</td>
</tr>
</tbody>
</table>
The following URL will search for the first 10 "Gear" items in "Accessories" sorted by all-time ("SortAggregation") and relevance ("SortType") created by Roblox ("CreatorTargetId" and "CreatorType"):
`https://catalog.roblox.com/v1/search/items/details?Category=11&Subcategory=5&CreatorTargetId=1&CreatorType=User&SortType=0&SortAggregation=5&Limit=10`
### Response fields
API responses return in a JSON format. The response provides asset details in the `data` key using the following fields:
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>assetType</td>
<td>One of the following asset type values (only returned if the item is an asset).<br /><br />`2` = T-Shirt<br />`8` = Hat<br />`11` = Shirt<br />`12` = Pants<br />`17` = Head<br />`18` = Face<br />`19` = Gear<br />`25` = Arms<br />`26` = Legs<br />`27` = Torso<br />`28` = RightArm<br />`29` = LeftArm<br />`30` = LeftLeg<br />`31` = RightLeg<br />`41` = HairAccessory<br />`42` = FaceAccessory<br />`43` = NeckAccessory<br />`44` = ShoulderAccessory<br />`45` = FrontAccessory<br />`46` = BackAccessory<br />`47` = WaistAccessory<br />`48` = ClimbAnimation<br />`49` = DeathAnimation<br />`50` = FallAnimation<br />`51` = IdleAnimation<br />`52` = JumpAnimation<br />`53` = RunAnimation<br />`54` = SwimAnimation<br />`55` = WalkAnimation<br />`56` = PoseAnimation<br />`61` = EmoteAnimation</td>
</tr>
<tr>
<td>bundleType</td>
<td>The bundle type ID (only returned if the item is a bundle). Possible values are `BodyParts` and `AvatarAnimations`.</td>
</tr>
<tr>
<td>creatorName</td>
<td>The creator's name.</td>
</tr>
<tr>
<td>creatorTargetId</td>
<td>The creator's ID.</td>
</tr>
<tr>
<td>creatorType</td>
<td>The item's creator type.</td>
</tr>
<tr>
<td>description</td>
<td>The item description.</td>
</tr>
<tr>
<td>favoriteCount</td>
<td>The favorite count of an item.</td>
</tr>
<tr>
<td>genres</td>
<td>List of the item's genres. Possible values include `All`, `Tutorial`, `Scary`, `TownAndCity`, `War`, `Funny`, `Fantasy`, `Adventure`, `SciFi`, `Pirate`, `FPS`, `RPG`, `Sports`, `Ninja`, and `WildWest`.</td>
</tr>
<tr>
<td>id</td>
<td>The ID of the item.</td>
</tr>
<tr>
<td>itemRestrictions</td>
<td>List of the item's restrictions. Possible values include `ThirteenPlus`, `LimitedUnique`, `Limited`, and `Rthro`.</td>
</tr>
<tr>
<td>itemStatus</td>
<td>List of the item's status flags. Possible values include `New`, `Sale`, `XboxExclusive`, `AmazonExclusive`, `GooglePlayExclusive`, `IosExclusive`, and `SaleTimer`.</td>
</tr>
<tr>
<td>itemType</td>
<td>The item type. Possible values are `Asset` or `Bundle`.</td>
</tr>
<tr>
<td>lowestPrice</td>
<td>The lowest reseller price of the item (only returned if the item is resellable).</td>
</tr>
<tr>
<td>name</td>
<td>The item name.</td>
</tr>
<tr>
<td>price</td>
<td>The listing price of the item (current price may differ if the item is resellable).</td>
</tr>
<tr>
<td>priceStatus</td>
<td>The price status of an item that is not on sale. Possible values are `Free`, `OffSale`, or `NoResellers`.</td>
</tr>
<tr>
<td>purchaseCount</td>
<td>The purchase count of an item.</td>
</tr>
<tr>
<td>unitsAvailableForConsumption</td>
<td>The unit available for consumption of a limited unique item.</td>
</tr>
</tbody>
</table>
The following is an example of expected return output for a single item:
```json
{
"keyword": null,
"previousPageCursor": null,
"nextPageCursor": "2_1_c541d05046b5c1c78a5d386b5e302243",
"data": [
{
"id":527373900,
"itemType":
"Asset",
"assetType":42,
"name":"Restless Souls Bandana",
"description":"This bandana won't help you blend in with ghosts, but at least you'll be stylish.",
"productId":41270974,
"genres":[
"Scary",
"Adventure"
],
"itemStatus":[],
"itemRestrictions":[],
"creatorType":"User",
"creatorTargetId":1,
"creatorName":"Roblox",
"price":300,
"favoriteCount":15943,
"offSaleDeadline":null
}
]
}
```

View file

@ -0,0 +1,83 @@
---
title: In-Experience asset creation
description: Explains how to allow users to create and save assets in your experience.
---
With the in-experience asset creation feature, you can allow your users to save creations they made in your experience to their inventories. Your users can use these in-experience creations just like any other asset. Additionally, these creations attribute to your experience when displayed on the Roblox platform, so any user can use the attribution link to come to your experience and create their own.
For example, you can enable users to create custom creatures as pets in your experience, and allow them to save their favorite pets to their inventories. You have full control to specify which objects users can modify and save from your experience. Users in turn can display their creations on their profiles with attribution to your experience, boosting visibility of your experience.
## Supported asset types and limits
Just like all assets on the platform, in-experience creations are subject to [asset moderation](../../projects/assets/index.md#asset-moderation). Currently, you can only allow users to create [packages](../../projects/assets/packages.md) from your experience. These packages can't contain any scripts or private assets, such as audio, video, and nested packages. If the system detects scripts or private assets in a package that can be saved by users, it blocks the in-experience save action by hiding the save prompt for users.
When you are running or testing your experience and add scripts or private assets as part of an in-experience creation, it fails to save and prompts error messages to the Studio [Output window](../../studio/output.md) or the [Developer Console](../../studio/developer-console.md).
## Enabling in-experience asset creation
To enable in-experience asset creation for your users, use the `Class.AssetService:PromptCreateAssetAsync()` API method in a server-side script, along with other creation logic. Specify which instances in your experience you want to enable this functionality, set a custom trigger (such as a UI icon) for invoking the method, and listen for client remote events for saving assets.
`Class.AssetService:PromptCreateAssetAsync()` takes the following parameters:
- A `Class.Player` object representing the user who submits an asset creation.
- An `Class.Instance` object representing the asset for creation.
- The `Enum.AssetType`, which is currently limited to `Enum.AssetType.Model`.
When the server invokes `Class.AssetService:PromptCreateAssetAsync()`, it prompts a **Submit Package** dialog on the client, so the user who triggers the save action can enter a name and description for the package. Roblox provides the dialog UI out-of-the-box, as the save workflow is a platform-level functionality.
The following example server-side script prompts users to save a car that they paint in an experience:
```lua title="Example Script for In-Experience Asset Creation"
-- Define the AssetService variable
local AssetService = game:GetService("AssetService")
-- Set up PromptCreateAssetAsync() for prompting the submission dialog
local function CreateAsset(player, instance)
local complete, result, assetId = pcall(function()
return AssetService:PromptCreateAssetAsync(player, instance, Enum.AssetType.Model)
end)
if complete then
if result == Enum.PromptCreateAssetResult.Success then
print("successfully uploaded, AssetId:", assetId)
else
print("Received result", result)
end
else
print("error")
print(result)
end
end
-- Car painting logic omitted
-- Add an event handler
local function onUserPublish(player, promptObject)
-- User saves the car instance with the experience's default color
if promptObject.Name == "car" then
CreateAsset(player, car)
elseif promptObject.Name == "CarPaintYellow" or promptObject.Name == "CarPaintBlue" or promptObject.Name == "CarPaintBlack" or promptObject.Name == "CarPaintRed" then
PaintCarColor(promptObject.Name)
end
end
PublishEvent.OnServerEvent:Connect(onUserPublish)
```
[In-Experience Creation Demo Arena](https://www.roblox.com/games/12992503026/In-Experience-Creation-Demo-Arena) showcases an example on how you can use this feature. You can join the demo to walk through the in-experience creation workflow as a user, or edit the place in Studio to reference the design.
## Post-creation and attribution
After users create and save an asset from your experience, they can find it in the following places:
- Their [My Inventory](https://en.help.roblox.com/hc/en-us/articles/360000463726-How-to-View-or-Hide-Your-Inventory-in-a-Browser) page.
- The **Creations** tab of their [Profile](https://en.help.roblox.com/hc/en-us/articles/203313660-All-About-Profiles-Blurbs-and-Profile-Customization) page.
- The **Development Items** tab under their Creator Dashboard [Creations](https://create.roblox.com/dashboard/creations?activeTab=Model) page.
- The **Inventory** tab of their [Toolbox](../../projects/assets/toolbox.md) in Studio.
When users see in-experience creations on their connections' profiles or inventories, they see attribution to the original experience in which the asset was created. Users can click on the attribution link to redirect to the experience page, so they can join the experience and create their own.
<Alert severity="warning">
Attribution is currently tied to a specific version of the created asset. If a user saves a package from an experience and further edits in Studio to create a new version, attribution no longer displays for the new version.
</Alert>

View file

@ -0,0 +1,353 @@
---
title: Assets
description: An overview of how assets work on the platform.
---
Almost everything in Roblox is represented as a cloud-based asset with a unique corresponding ID. This ID is typically in the form of `rbxassetid://[ID]`, which gets applied to various instances as a property that's appropriate for that particular asset type. For example, `Class.Texture`, `Class.MeshPart`, and `Class.AudioPlayer` instances reference image, mesh, and audio assets through their respective `Class.Texture.ColorMapContent|ColorMapContent`, `Class.MeshPart.MeshId|MeshId`, and `Class.AudioPlayer.Asset|Asset` properties.
<GridContainer numColumns="3">
<figure>
`rbxassetid://7229442422`
<img src="../../assets/modeling/textures-decals/Texture-Example-Grafitti04.png" alt="A decal asset of a young woman with a button for an eye." width="90%" />
</figure>
<figure>
`rbxassetid://6768917255`
<img src="../../assets/modeling/meshes/Base-Mesh-In-Marketplace.png" alt="An untextured treasure chest MeshPart asset." width="90%" />
</figure>
<figure>
`rbxassetid://9125402735`
<audio controls><source src="../../assets/studio/general/Boom-Impact.mp3" type="audio/mpeg"></source></audio>
</figure>
</GridContainer>
This cloud-based asset system allows you to store assets through Roblox and reuse them across the platform in various contexts, such as in different objects and places, without maintaining local copies as part of each saved Studio experience. You can find millions of project assets in the [Creator Store][CreatorMarketplaceURL], equip avatar assets in the [Marketplace][MarketplaceURL], or you can create your own assets and [import](#asset-management) them directly into Studio through the asset management tools.
When you import assets, they must pass a [moderation](#asset-moderation) check before users can see and interact with them in published experiences. After Roblox approves imported assets, you can choose to retain ownership of their usage on the platform or make them publicly available as detailed in [Asset permissions](#asset-permissions).
## Asset types
All [asset types](/reference/engine/enums/AssetType) available on the platform generally fall into one of three categories:
- Assets that map to project-level items. You can find and configure these assets for specific experiences on the [Creator Dashboard][CreatorDashboardURL].
- Assets that are objects, or that change the appearance or behavior of objects within places. You can [import](#asset-management) these assets or find them in the [Creator Store][CreatorMarketplaceURL].
- Assets that change the body, clothing, or animation of avatars and non-playable characters. You can find these assets in the [Marketplace][MarketplaceURL].
Every asset type works differently depending on where it lives on the platform. See the following sections for information on how to use each asset type for [experiences](#for-experiences), [places](#for-places), and [avatars](#for-avatars).
### For experiences
There are three asset types that map to project-level items. These asset types are unique to the experience that they map to, meaning they are non-transferable to other projects.
- **Places** — Every experience has one or more [places](../../projects/index.md#places), or individual 3D worlds. Each place is represented by a [data model](../../projects/data-model.md) that describes the place's 3D world and logic.
- **Badges** — A [badges](../../production/publishing/badges.md) is a special award you can gift users when they meet a goal within an experience, such as completing a difficult objective or playing for a certain amount of time.
- **Passes** — A [pass](../../production/monetization/passes.md) is a monetization product that allows you to charge a one-time Robux fee in order for users to access special privileges within an experience, such as entry to a restricted area, an in-experience avatar item, or a permanent power-up.
### For places
In general, there are two categories of asset types for places that you can either [import](#asset-management) or find in the [Creator Store][CreatorMarketplaceURL]:
- Assets that exist as objects within the data model, such as [models](../../parts/models.md) and [meshes](../../parts/meshes.md).
- Assets that you apply as an object's property, such as audio, images, fonts, and videos.
For more information on both types of these assets for places, such as where and how you can use them in Studio, reference the following table.
<table>
<thead>
<tr>
<th>Asset&nbsp;Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Model**</td>
<td>A `Class.Model` is a container object for geometric groupings such as `Class.BasePart|BaseParts`, `Class.MeshPart|MeshParts`, and other `Class.Model` objects. Models can also contain objects such as `Class.Script|Scripts`. Whenever you group objects together in Studio, they automatically become a `Class.Model` object. For more information, see [models](../../parts/models.md).</td>
</tr>
<tr>
<td>**Mesh**</td>
<td>A `Class.MeshPart` is a type of part object that includes a physically-simulated custom mesh. For more information, see [meshes](../../parts/meshes.md).</td>
</tr>
<tr>
<td>**Audio**</td>
<td>An `Class.AudioPlayer` instance loads and plays an audio file and passes the output through a `Class.Wire` to an `Class.AudioEmitter` or `Class.AudioDeviceOutput`. For more information, see [audio assets](../../audio/assets.md) and [audio objects](../../audio/objects.md).</td>
</tr>
<tr>
<td>**Image**</td>
<td>Images are used in several ways within a place, including [textures/decals](../../parts/textures-decals.md) on parts, [image labels](../../ui/labels.md), [mesh textures](../../parts/meshes.md#adding-textures), textures for [custom materials](../../parts/materials.md), textures for [special effects](../../environment/index.md#special-effects), and more.</td>
</tr>
<tr>
<td>**Font**</td>
<td>`Class.TextButton`, `Class.TextLabel`, and `Class.TextBox` objects display typography in a specific style when you apply a font asset ID. You cannot import fonts, but the [Creator Store][CreatorMarketplaceURL] offers over 80 different fonts for your use.</td>
</tr>
<tr>
<td>**Video**</td>
<td>A `Class.VideoFrame` object displays a video through its `Class.VideoFrame.Video|Video` asset property. See [video frames](../../ui/video-frames.md) for more information.</td>
</tr>
</tbody>
</table>
### For avatars
There are three categories of asset types for avatars that you can find in the [Marketplace][MarketplaceURL] and equip to avatars:
- **Body Parts** — Assets that represent sections of the avatar character model, such as its head, torso, or legs.
- **Clothing and Accessories** — Assets that represent clothing and accessories on top of body parts.
- **Animations** — Assets that animate the avatar character model, such as how it runs, jumps, or swims.
Every [character](../../characters/index.md) model contains a `Class.HumanoidDescription` object with asset IDs for the character's body parts, clothing, accessories, and animations. By default, a user's playable character references their personal Roblox avatar, but you can apply a custom `Class.HumanoidDescription` if desired. For more information, see [character appearance](../../characters/appearance.md).
## Packages
Within Studio, you can convert single assets or asset hierarchies into **packages** and reuse them in multiple experiences, letting you optimize asset management across your entire team or across multiple projects. When a package is updated, you or your team members can update specific copies to the most current version, update all copies across an experience, or set specific copies to auto update.
For more information, see [packages](../../projects/assets/packages.md).
## Asset URIs
Assets and other content stored outside of the current place are identified through **Uniform Resource Identifiers** (URIs) which are formatted strings that point to a file stored online, within the Roblox application package, or saved to the client's device.
The basic structure is a **scheme** followed by `://` and a **path** that varies according to the scheme.
<span><Chip label='[Scheme]://[Path]' color='primary' size='large' /></span><br/>
The Roblox Engine supports several custom URI schemes for referencing content stored on the platform.
### rbxassetid
`rbxassetid` points to a user-uploaded asset on Roblox. This format is a common standard for properties such as `Class.Decal.ColorMapContent`, `Class.ParticleEmitter.Texture`, and `Class.AudioPlayer.Asset`.
<GridContainer numColumns="3">
<figure>
<figcaption><Chip label='rbxassetid://7229442422' color='primary' size='large' /></figcaption>
<br />
<img src="../../assets/modeling/textures-decals/Texture-Example-Grafitti04.png" alt="A decal asset of a young woman with a button for an eye." width="90%" />
</figure>
<figure>
<figcaption><Chip label='rbxassetid://3845386987' color='primary' size='large' /></figcaption>
<br />
<img src="../../assets/lighting-and-effects/particle-emitter/Texture-Indicated.jpg" alt="Three particle emitters emit red, blue, and yellow particles over jar assets that sit on top of a stone tower. The red particles are highlighted." width="90%" />
</figure>
<figure>
<figcaption><Chip label='rbxassetid://9125402735' color='primary' size='large' /></figcaption>
<br />
<audio controls>
<source src="../../assets/studio/general/Boom-Impact.mp3" type="audio/mpeg"></source></audio>
</figure>
</GridContainer>
### rbxasset
`rbxasset` points to Roblox's content folder on the user's device, for example:
<span><Chip label='rbxasset://textures/face.png' color='primary' size='large' /></span><br />
The content folder's location depends on the user's operating system:
<Tabs>
<TabItem label="Windows">
`%LOCALAPPDATA%\Roblox\Versions\<version>\content`<br />
(alternatively `C:\Program Files (x86)\Roblox\Versions\<version>\content`)
</TabItem>
<TabItem label="Mac">
`Applications/RobloxStudio.app/Contents/Resources/content`
</TabItem>
</Tabs>
### rbxthumb
`rbxthumb` points to a thumbnail image for the provided asset. Its string format takes a thumbnail type (`type`), an asset ID (`id`), and width/height (`w`/`h`).
<span><Chip label='rbxthumb://type=Asset&id=24813339&w=150&h=150' color='primary' size='large' /></span><br />
<table size="small">
<thead>
<tr>
<th>Type (`type`)</th>
<th>Expected `id` Value</th>
<th>Supported Sizes (`w`&times;`h`)</th>
</tr>
</thead>
<tbody>
<tr>
<td>`Asset`</td>
<td>ID for a 2D or 3D asset</td>
<td scope="row">150&times;150, 420&times;420</td>
</tr>
<tr>
<td>`Avatar`</td>
<td>ID for a Roblox user (`Class.Player.UserId`)</td>
<td scope="row">48&times;48, 60&times;60, 100&times;100, 150&times;150, 180&times;180, 352&times;352, 420&times;420, 720&times;720</td>
</tr>
<tr>
<td>`AvatarBust`</td>
<td>ID for a Roblox user (`Class.Player.UserId`)</td>
<td scope="row">50&times;50, 60&times;60, 75&times;75, 100&times;100, 150&times;150, 180&times;180, 352&times;352, 420&times;420</td>
</tr>
<tr>
<td>`AvatarHeadShot`</td>
<td>ID for a Roblox user (`Class.Player.UserId`)</td>
<td scope="row">48&times;48, 60&times;60, 100&times;100, 150&times;150, 180&times;180, 352&times;352, 420&times;420</td>
</tr>
<tr>
<td>`BadgeIcon`</td>
<td>ID for a [badge](../../production/publishing/badges.md#locating-badge-ids)</td>
<td scope="row">150&times;150</td>
</tr>
<tr>
<td>`BundleThumbnail`</td>
<td>ID for a [Marketplace][MarketplaceURL] bundle such as a [character](https://www.roblox.com/catalog?Category=17), [head](https://www.roblox.com/catalog?Category=4&Subcategory=66), or [shoes](https://www.roblox.com/catalog?Category=3&Subcategory=64)</td>
<td scope="row">150&times;150, 420&times;420</td>
</tr>
<tr>
<td>`FontFamily`</td>
<td>ID for a font in the [Creator Store](../../production/creator-store.md) or [Toolbox](../../projects/assets/toolbox.md) inventory</td>
<td scope="row">1200&times;80</td>
</tr>
<tr>
<td>`GameIcon`</td>
<td>ID for an experience (`Class.DataModel.GameId`); shows the experience's [icon](../../production/publishing/experience-icons.md)</td>
<td scope="row">50&times;50, 150&times;150</td>
</tr>
<tr>
<td>`GamePass`</td>
<td>ID for a [pass](../../production/monetization/passes.md#locating-pass-ids)</td>
<td scope="row">150&times;150</td>
</tr>
<tr>
<td>`GameThumbnail`</td>
<td>ID for an experience (`Class.DataModel.PlaceId`); shows the experience's primary [thumbnail](../../production/publishing/thumbnails.md)</td>
<td scope="row">256&times;144, 384&times;216, 480&times;270, 576&times;324, 768&times;432</td>
</tr>
<tr>
<td>`GroupIcon`</td>
<td>ID for a [group](../../projects/groups.md)</td>
<td scope="row">150&times;150, 420&times;420</td>
</tr>
<tr>
<td>`Outfit`</td>
<td>ID gathered from an `Class.OutfitPages` table</td>
<td scope="row">150&times;150, 420&times;420</td>
</tr>
</tbody>
</table>
```lua title="Apply Avatar Head Shot Thumbnail"
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local playerGui = player.PlayerGui
local screenGui = Instance.new("ScreenGui")
screenGui.Parent = playerGui
local imageLabel = Instance.new("ImageLabel")
imageLabel.AnchorPoint = Vector2.new(0, 0)
imageLabel.Size = UDim2.new(0, 150, 0, 150)
imageLabel.Position = UDim2.new(0, 16, 0, 16)
imageLabel.BorderSizePixel = 0
imageLabel.BackgroundColor3 = Color3.new(0, 0, 0)
imageLabel.BackgroundTransparency = 0.8
imageLabel.Parent = screenGui
local success, content, isReady = pcall(function()
return Players:GetUserThumbnailAsync(player.UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size352x352)
end)
if success then
-- Apply thumbnail content to image label
imageLabel.Image = content
-- Crop thumbnail to circle
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(1, 0)
corner.Parent = imageLabel
end
```
### rbxgameasset
`rbxgameasset` points to an asset uploaded through the [Asset Manager](../../projects/assets/manager.md). It allows access to assets by a user‑friendly name instead of ID, so if you upload an image named `Potion.png`, you can reference it as:
<span><Chip label='rbxgameasset://Images/Potion' color='primary' size='large' /></span><br />
In the above example, `Images` is the category/folder that appears in the [Asset Manager](../../projects/assets/manager.md) and `Potion` is the asset name, minus its extension.
<Alert severity="warning">
`rbxgameasset` only works for the current experience. If you paste a parent object that utilizes the asset into another experience, the asset will not load (or will load a different asset if you've uploaded one with the same name to that other game). If you need an asset to work across multiple experiences, use `rbxassetid` instead of `rbxgameasset`.
</Alert>
### rbxhttp
`rbxhttp` is shorthand for `Class.ContentProvider.BaseUrl`, for example:
<span><Chip label='rbxhttp://Thumbs/Avatar.ashx?x=100&y=100&format=png' color='primary' size='large' /></span>
### rbxtemp
`rbxtemp` allows you to refer `Class.File|Files`. Use `Class.File:GetTemporaryId()` to generate a valid `rbxtemp` URL. For example:
<span><Chip label='rbxtemp://1' color='primary' size='large' /></span>
### https / http
`https` or `http` points to the exact location of something on the internet. It only works on Roblox-approved domains and raises an error if you use it elsewhere.
<span><Chip label='https://www.roblox.com/asset/?id=9723979220' color='primary' size='large' /></span>
## Asset permissions
An asset's privacy status determines who has permission to use the asset within their experiences. By default, all assets are **private** when you or your [group](../../projects/groups.md) members import them into Studio. If you want to grant everyone access to the asset ID, you must distribute the asset to the [Creator Store][CreatorMarketplaceURL].
<Alert severity="warning">
Special privacy rules and workflows apply to **audio** and **video** assets. See [asset privacy](../../projects/assets/privacy.md) for details on sharing these asset types among connections and experiences.
</Alert>
## Asset moderation
Roblox performs both human and automated asset moderation on a proactive and reactive basis to ensure assets adhere to the [Community Rules](https://en.help.roblox.com/hc/articles/203313410), [Terms of Use](https://en.help.roblox.com/hc/articles/115004647846), and [Digital Millennium Copyright Act](../../production/publishing/dmca-guidelines.md) (DMCA). If any asset violates these moderation policies, such as including discriminatory or adult content, the Moderation team flags and removes the asset to protect users from harmful or non-compliant content. This process generally happens within a few hours after you import the asset.
If an asset is still in the moderation queue when you publish your experience, users cannot see or interact with the asset until Roblox approves it. If the asset doesn't pass moderation, you will receive a [notification](https://en.help.roblox.com/hc/en-us/articles/360020870412-Understanding-Moderation-Messages) explaining why the asset cannot be on the platform in its current state. For more information, see Working with Assets - Asset Moderation.
<Alert severity="warning">
To maintain community safety and civility, Roblox may take down experiences and/or terminate accounts that maliciously import or publish non-compliant assets.
</Alert>
## Asset management
Roblox offers several tools to import, store, and publish your assets:
<table>
<thead>
<tr>
<th>Tool</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>[Asset Manager](../../projects/assets/manager.md)</td>
<td>Imports and stores [images](../../parts/textures-decals.md), [meshes](../../parts/meshes.md), [audio](../../audio/assets.md), and more. Only displays assets that you've imported into the currently opened experience.</td>
</tr>
<tr>
<td>[Toolbox](../../projects/assets/toolbox.md)</td>
<td>Stores every asset that you or your [groups](../../projects/groups.md) have ever imported into Studio, regardless of what experience you currently have open. Also includes assets from the [Creator Store][CreatorMarketplaceURL], allowing you to quickly drop user-generated assets directly into your experiences.</td>
</tr>
<tr>
<td>[3D Importer](../../art/modeling/3d-importer.md)</td>
<td>Imports 3D models from third-party modeling tools as a custom `Class.Model` instance. </td>
</tr>
</tbody>
</table>
## Archive assets
To further help with organization, you can archive most asset types in the **Creations** &rang; **Development Items** section of the [Creator Dashboard][CreatorDashboardURL]. To archive an item, hover over an asset's thumbnail, click the **&ctdot;** button, and select **Archive** from the context menu.
<img src="../../assets/creator-dashboard/Options-Button-Asset.png" width="200" alt="Options button indicated for an asset." />
After you archive an asset, it disappears from the website and is no longer usable or visible in Roblox experiences, including your own.
<Alert severity = 'warning'>
For more information on how archiving works with Marketplace items, see [moderation](../../marketplace/moderation.md#archive-assets).
</Alert>
[CreatorMarketplaceURL]: https://create.roblox.com/store
[MarketplaceURL]: https://www.roblox.com/catalog
[CreatorDashboardURL]: https://create.roblox.com/dashboard/creations

View file

@ -0,0 +1,490 @@
---
title: Asset Manager
description: The Asset Manager lets you manage places and bulk import assets into your experience.
---
import BetaAlert from '../../includes/beta-features/beta-alert.md'
The **Asset Manager**, accessible from Studio's **Window** menu or **Home** tab, lets you manage [places](../../production/publishing/publish-experiences-and-places.md) and bulk import assets into your experience, including [images](../../parts/textures-decals.md), [meshes](../../parts/meshes.md), [packages](../../projects/assets/packages.md), [audio](../../audio/assets.md), and [models](../../parts/models.md).
## Current
<Alert severity="info">
The following sections outline the current Asset Manager. The [V2 Beta](#v2-beta) is documented below.
</Alert>
### Asset folders
Assets are organized within folders based on their type. You can switch between **grid view** and **list view** by clicking the view toggle button.
<img src="../../assets/studio/asset-manager/View-Toggle.png" width="460" alt="The Asset Manager window with the View toggle button highlighted." />
### Importing assets
The **bulk import** tool is ideal for importing up to 50 files in one batch. Imported assets enter the moderation queue and are only visible to you within their respective [folder](#asset-folders) and within the **Inventory** tab of the [Toolbox](../../projects/assets/toolbox.md).
<img src="../../assets/studio/asset-manager/Import-Button-V1.png" alt="The Asset Manager window with the Bulk Import button highlighted." width="360" />
<table>
<thead>
<tr>
<th>Asset&nbsp;Type</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Image**</td>
<td>You can import images in `.png`, `.jpg`, `.gif`, `.tga`, or `.bmp` format for use as [textures/decals](../../parts/textures-decals.md) on parts, [image labels](../../ui/labels.md), [mesh textures](../../parts/meshes.md#adding-textures), textures for [custom materials](../../parts/materials.md), textures for [special effects](../../environment/index.md#special-effects), and more.</td>
</tr>
<tr>
<td>**Mesh**</td>
<td>You can bulk import meshes in either `.fbx` or `.obj` format, although this workflow does not support complex meshes such as those with rigging, skinning, or animation data. For complex meshes, it's recommended that you use the [3D&nbsp;Importer](../../art/modeling/3d-importer.md).</td>
</tr>
<tr>
<td>**Audio**</td>
<td>You can import audio assets that you are certain you have permission to use in `.ogg`, `.mp3`, `.flac`, or `.wav` format. If you're uncertain whether you have permission to use an audio file, the [Creator Store](../../production/creator-store.md) has a variety of free-to-use audio, including more than 100,000 professionally-produced audio assets. See [Audio Assets](../../audio/assets.md) for details.</td>
</tr>
</tbody>
</table>
### Insert assets
You can insert assets into the [Explorer](../../studio/explorer.md) window hierarchy by dragging-and-dropping or by right-clicking the asset name/tile and selecting **Insert**.
Behavior of dragging-and-dropping into the 3D viewport varies by asset type:
<table>
<thead>
<tr>
<th>Asset&nbsp;Type</th>
<th>Drag-and-Drop Behavior</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Image**</td>
<td>If hovering over a valid parent object like a `Class.BasePart`, creates a new `Class.Decal` inside that parent with its `Class.Decal.ColorMapContent|ColorMapContent` property preset to the asset ID.</td>
</tr>
<tr>
<td>**Mesh**</td>
<td>Inserts the asset as a new `Class.MeshPart` in the workspace with its `Class.MeshPart.MeshId|MeshId` property preset to the asset ID.</td>
</tr>
<tr>
<td>**Audio**</td>
<td>Creates a new `Class.Sound` object in the workspace with its `Class.Sound.SoundId|SoundId` property preset to the asset ID.</td>
</tr>
<tr>
<td>**Package**</td>
<td>Inserts a copy of the package into the workspace.</td>
</tr>
</tbody>
</table>
### Quick actions
Quick actions are accessible by right-clicking an asset name/tile and selecting a context option.
<Tabs>
<TabItem label="Places">
<table>
<thead>
<tr>
<th>Quick Action</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Rename**</td>
<td>Lets you enter a new name for the place.</td>
</tr>
<tr>
<td>**Copy&nbsp;ID&nbsp;to&nbsp;Clipboard**</td>
<td>Copies the place ID to the clipboard.</td>
</tr>
<tr>
<td>**View History**</td>
<td>Opens the place version history, letting you view previous commits (publish actions) and their date/time. If desired, you can roll back to a previous version by selecting it and clicking the <b>Open</b> button.</td>
</tr>
<tr>
<td>**Remove From Game**</td>
<td>Completely removes the place from the experience. Not applicable to the [starting place](../../production/publishing/publish-experiences-and-places.md#change-start-place).</td>
</tr>
</tbody>
</table>
</TabItem>
<TabItem label="Images">
<table>
<thead>
<tr>
<th>Quick Action</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Edit Asset**</td>
<td>Lets you edit general details such as the image title and description.</td>
</tr>
<tr>
<td>**Rename Alias**</td>
<td>Renames the image alias in the **Asset Manager**.</td>
</tr>
<tr>
<td>**Insert**</td>
<td>Inserts the image into the selected instance (or the workspace).</td>
</tr>
<tr>
<td>**Copy&nbsp;ID&nbsp;to&nbsp;Clipboard**</td>
<td>Copies the image ID to the clipboard.</td>
</tr>
<tr>
<td>**Remove From Game**</td>
<td>Removes the image from the **Asset Manager** but does not remove its instances from the experience.</td>
</tr>
</tbody>
</table>
</TabItem>
<TabItem label="Meshes">
<table>
<thead>
<tr>
<th>Quick Action</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Edit Asset**</td>
<td>Lets you edit general details such as the mesh title and description.</td>
</tr>
<tr>
<td>**Rename Alias**</td>
<td>Renames the mesh alias in the **Asset Manager**.</td>
</tr>
<tr>
<td>**Insert**</td>
<td>Inserts the mesh into the workspace.</td>
</tr>
<tr>
<td>**Insert With Location**</td>
<td>Inserts the mesh into the workspace, retaining location data stored during the mesh import process.</td>
</tr>
<tr>
<td>**Copy ID to Clipboard**</td>
<td>Copies the mesh ID to the clipboard.</td>
</tr>
<tr>
<td>**Copy&nbsp;Mesh&nbsp;ID&nbsp;to&nbsp;Clipboard**</td>
<td>Copies the mesh `Class.MeshPart.TextureID` to the clipboard.</td>
</tr>
<tr>
<td>**Remove From Game**</td>
<td>Removes the mesh from the **Asset Manager** but does not remove its instances from the experience.</td>
</tr>
</tbody>
</table>
</TabItem>
<TabItem label="Packages">
<table>
<thead>
<tr>
<th>Quick Action</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Insert**</td>
<td>Inserts a copy of the package into the workspace.</td>
</tr>
<tr>
<td>**View on Website**</td>
<td>Opens up your browser to the package asset page.</td>
</tr>
<tr>
<td>**Copy&nbsp;ID&nbsp;to&nbsp;Clipboard**</td>
<td>Copies the package ID to the clipboard.</td>
</tr>
<tr>
<td>**Package Details**</td>
<td>Lets you manage basic package details, access permissions, and package versions.</td>
</tr>
</tbody>
</table>
</TabItem>
<TabItem label="Audio">
<table>
<thead>
<tr>
<th>Quick Action</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Edit Asset**</td>
<td>Lets you edit general details such as the audio title and description.</td>
</tr>
<tr>
<td>**Rename Alias**</td>
<td>Renames the item alias in the **Asset Manager**.</td>
</tr>
<tr>
<td>**Insert**</td>
<td>Inserts the audio as a `Class.Sound` object into the selected instance (or the workspace).</td>
</tr>
<tr>
<td>**Copy&nbsp;ID&nbsp;to&nbsp;Clipboard**</td>
<td>Copies the audio file ID to the clipboard.</td>
</tr>
<tr>
<td>**Remove From Game**</td>
<td>Removes the audio from the **Asset Manager** but does not remove its instances from the experience.</td>
</tr>
</tbody>
</table>
</TabItem>
</Tabs>
### Asset inspection
You can closely inspect an image, mesh, package, or audio file by hovering over its thumbnail in [grid view](#asset-folders) and clicking the "magnify" icon, or by right-clicking its name in [list view](#asset-folders) and selecting **Asset&nbsp;Preview**.
<img src="../../assets/studio/asset-manager/Asset-Inspect-Icon.png" width="400" alt="A preview view of an asset in the Asset Manager. The Insect Asset icon is highlighted." />
When previewing 3D assets like meshes, you can move the virtual camera around to get a better view from all angles. For videos, you can preview the entire video in the popup.
<Grid container spacing={3}>
<Grid item>
<video src="../../assets/studio/general/3D-Asset-Preview.mp4" controls width="315"></video>
</Grid>
<Grid item>
<table size="small">
<thead>
<tr>
<th>Action</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>Left mouse button&nbsp;+ drag</td>
<td>Rotate around the object.</td>
</tr>
<tr>
<td>Right mouse button&nbsp;+ drag</td>
<td>Pan left, right, up, or down.</td>
</tr>
<tr>
<td>Mouse scroll wheel</td>
<td>Zoom in or out.</td>
</tr>
</tbody>
</table>
</Grid>
</Grid>
In the lower-right corner of the preview frame, the **composition** button reveals the full hierarchy of the asset including `Class.Script|Scripts`, `Class.MeshPart|MeshParts`, `Class.Animation|Animations`, and more.
<img src="../../assets/studio/general/Preview-Panel-Hierarchy.png" width="560" alt="A preview view of an asset in the Asset Manager, and the full hierarchy of the asset displays underneath the 3D representation. The Asset Composition icon is highlighted." />
## V2 Beta
<BetaAlert betaName="Revamped Asset Manager" leadIn="The revamped Asset Manager is currently in beta. Enable it through " leadOut="." components={props.components} />
### Inventory sorting
Assets are sorted by various **inventories** as selected through the collapsible menu on the left side of the window. If you don't see the sorting list, click the expand/collapse button in the lower‑left area of the window.
<img src="../../assets/studio/asset-manager/Inventory-Sorts.png" width="800" alt="A preview of how inventories are sorted in the left navigation of the Asset Manager." />
- **Shared With Experience** — Assets that are [shared with the open experience](../../projects/assets/privacy.md#to-experiences).
- **Places In Experience** — The experience's current [places](../../production/publishing/publish-experiences-and-places.md).
- **My Inventory** — Assets imported to your own user account, [shared with you](../../projects/assets/privacy.md#to-creators), or acquired from the [Creator Store](../../production/creator-store.md).
- **Group Inventories** — Assets imported into [groups](../../projects/groups.md) you own or groups you belong to (assuming you have sufficient [permissions](../../projects/groups.md#roles-and-permissions) within the group), or assets [shared with the groups](../../projects/assets/privacy.md#to-groups). Right‑clicking over a group reveals a context menu with the following options:
<table size="small">
<tbody>
<tr>
<td>**Hide Group**</td>
<td>Hides the group from the sidebar.</td>
</tr>
<tr>
<td>**Customize Groups**</td>
<td>Allows you to choose the groups which appear in the sidebar and search filter options.</td>
</tr>
<tr>
<td>**Refresh Groups**</td>
<td>Refreshes the list of groups that you're eligible to show or hide.</td>
</tr>
</tbody>
</table>
### Asset display options
In the main panel, assets for the selected [inventory](#inventory-sorting) are displayed. To toggle the view type, click on the **view&nbsp;type** button and select either **List** or **Grid**. While in grid view, asset tiles can be resized through the slider widget.
<img src="../../assets/studio/asset-manager/Display-Options.png" width="800" alt="Diagram of the view type button and options in the Asset Manager." />
In **List** view, click on a column header to order assets by that detail and resize columns by dragging the separator bar between them.
<img src="../../assets/studio/asset-manager/List-View-Ordering.png" width="800" alt="Diagram of how columns can be ordered and resized in List view within the Asset Manager." />
<Alert severity="info">
Columns can be toggled on or off by right‑clicking in the header bar region. While columns cannot be reordered by dragging, you can toggle any column off and then toggle it back on to add it as the furthest column to the right.
</Alert>
In **Grid** view, ordering is controlled through the **sort** button:
<img src="../../assets/studio/asset-manager/Grid-View-Ordering.png" width="600" alt="Location of the sort button for Grid view within the Asset Manager." />
### Asset type filters
The **filter items** button lets you control which assets are displayed.
<img src="../../assets/studio/asset-manager/Asset-Type-Filters.png" width="600" alt="Location of the filter button in the Asset Manager." />
<table size="small">
<thead>
<tr>
<th>Filter Type</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Asset Type**</td>
<td>**Animation**&nbsp;| **Audio**&nbsp;| **Decal**&nbsp;| **FontFamily**&nbsp;| **Image**&nbsp;| **Mesh**&nbsp;| **MeshPart**&nbsp;| **Model**&nbsp;| **Place**&nbsp;| **Plugin**&nbsp;| **Video**</td>
</tr>
<tr>
<td>**Creator**</td>
<td></td>
</tr>
<tr>
<td>**Source**</td>
<td>**Creator Store**&nbsp;| **Shared With Me**&nbsp;| **Uploaded**</td>
</tr>
<tr>
<td>**Is Package**</td>
<td></td>
</tr>
<tr>
<td>**Only&nbsp;Archived**</td>
<td></td>
</tr>
</tbody>
</table>
### Asset import
The **import** button lets you import up to 50 files in one batch. Imported assets enter the moderation queue and, upon approval, are added to the inventory of the user/group that owns the experience.
<img src="../../assets/studio/asset-manager/Import-Button.png" width="600" alt="Location of the import button in the Asset Manager." />
<table>
<thead>
<tr>
<th>Asset&nbsp;Type</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Image**</td>
<td>You can import images in `.png`, `.jpg`, `.gif`, `.tga`, or `.bmp` format for use as [textures/decals](../../parts/textures-decals.md) on parts, [image&nbsp;labels](../../ui/labels.md), [mesh&nbsp;textures](../../parts/meshes.md#texture), textures for [custom&nbsp;materials](../../parts/materials.md#custom-materials), textures for [special&nbsp;effects](../../effects/index.md), and more.</td>
</tr>
<tr>
<td>**Mesh**</td>
<td>You can import meshes in either `.fbx` or `.obj` format, although this workflow does not support complex meshes such as those with rigging, skinning, or animation data. For complex meshes or `.gltf` format, it's recommended that you use the [3D&nbsp;Importer](../../art/modeling/3d-importer.md).</td>
</tr>
<tr>
<td>**Audio**</td>
<td>You can import audio assets in either `.ogg`, `.mp3`, `.flac`, or `.wav` format. See [Audio Assets](../../audio/assets.md#import-audio) for details.</td>
</tr>
<tr>
<td>**Video**</td>
<td>You can import video assets in either `.mp4` or `.mov` format if all of the [requirements](../../ui/video-frames.md) are met.</td>
</tr>
</tbody>
</table>
### Insert and quick actions
Quick actions are accessible by right‑clicking an asset name/tile and selecting an option from the context menu. Note that places offer unique actions versus other assets.
<Tabs>
<TabItem label="General">
<table>
<thead>
<tr>
<th>Action</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Insert**</td>
<td>Lets you select from either **Insert&nbsp;at&nbsp;Camera** or **Insert&nbsp;at&nbsp;Asset&nbsp;Position** for spatial 3D assets (non‑spatial assets like audio are simply inserted into the `Class.Workspace` or the currently selected [Explorer](../../studio/explorer.md) instance). Does not appear for **FontFamily** or **Plugin** assets.</td>
</tr>
<tr>
<td>**Edit Asset**</td>
<td>Opens the asset configuration window to edit details such as the asset title, description, and more. Does not appear for **FontFamily** or **Plugin** assets.</td>
</tr>
<tr>
<td>**Copy Asset ID**</td>
<td>Copies the asset ID to the clipboard, convenient for pasting the ID into an object's property value such as `Class.AudioPlayer.AssetId` or `Class.MeshPart.MeshId`.</td>
</tr>
<tr>
<td>**View&nbsp;in&nbsp;Browser**</td>
<td>Opens your browser to the asset's page.</td>
</tr>
<tr>
<td>**Install**&nbsp;/ **Update**&nbsp;/ **Report**</td>
<td>Applicable only for **Plugin** assets. Installs, updates, or reports the plugin, respectively.</td>
</tr>
</tbody>
</table>
</TabItem>
<TabItem label="Places">
<table>
<thead>
<tr>
<th>Action</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Open**</td>
<td>Opens the place in another Studio session if it's not the currently open place.</td>
</tr>
<tr>
<td>**Rename**</td>
<td>Lets you enter a new name for the place.</td>
</tr>
<tr>
<td>**View History**</td>
<td>Opens the place version history, letting you view previous commits (publish actions) and their date/time. If desired, you can roll back to a previous version by selecting it and clicking the **Open** button.</td>
</tr>
<tr>
<td>**Remove&nbsp;From Experience**</td>
<td>Completely removes the place from the experience. Not applicable to the [starting place](../../production/publishing/publish-experiences-and-places.md#change-start-place).</td>
</tr>
<tr>
<td>**Copy Asset ID**</td>
<td>Copies the place's `Class.DataModel.PlaceId|PlaceId` to the clipboard.</td>
</tr>
<tr>
<td>**View&nbsp;in&nbsp;Browser**</td>
<td>Opens your browser to the place's page.</td>
</tr>
</tbody>
</table>
</TabItem>
</Tabs>

View file

@ -0,0 +1,26 @@
---
title: Monetize your creator assets
description: An overview of creator assets and the Creator Store.
---
## Create and sell Studio plugins
You can create and sell Studio [plugins](../../studio/plugins.md) to the creator community through the [Creator Store](../../production/creator-store.md). A plugin is an extension that adds additional features or functionality to [Roblox Studio](../../studio/index.md) and helps improve creator workflows. You can either offer plugins for free or sell them for a minimum of $4.99 USD. Roblox offers a market-leading revenue share for these sales, as only taxes and payment processing fees are deducted. For more information, see [Sell on the Creator Store](../../production/sell-on-creator-store.md).
Creator assets promote collaboration and resource sharing, and help developers create better and more dynamic experiences.
<table>
<thead>
<tr>
<th>Feature</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>[Plugins](../../production/sell-on-creator-store.md)</td>
<td>Generate real-world income by selling plugins on the Creator Store. Plugins are tools designed to improve development workflows.</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,303 @@
---
title: Packages
description: Packages allow you to reuse single assets or asset hierarchies across experiences.
id: packages
---
To keep assets organized and reusable across your team or across multiple projects, you can group your instances and convert them into reusable **packages**. Packages make the overall process of building worlds faster and more ergonomic, but they also help with consistency, deduplication, collaboration, and versioning:
- Easily [update all copies](#mass-updates) of a package to the latest version, or only [update specific copies](#update-outdated-copies).
- Set packages to [automatically update](#automatic-updates) whenever there's a new version.
- Give collaborators **Edit** or **Use** permissions to the contents of a package.
- View the full version history for a package, compare versions, and restore old versions.
The most efficient workflow is to [create a package](#create-packages), [share it](#share-and-access-levels) with any collaborators, and [set it to auto-update](#automatic-updates). And you don't have to wait for a model to be "done" before using it in a package. Even if the package is a placeholder on top of a simple shape, you can use it to [greybox your environment](../../tutorials/curriculums/environmental-art/greybox-your-environment.md) and then have the placeholder copies automatically update as you publish more detailed versions.<br /><br />
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/AzKZy2BqIh8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
## Create packages
<Alert severity="warning">
If you want to create a package with restricted assets that you don't have [explicit permission](../../projects/assets/privacy.md#view-permissions) to use, you can still create the package but those specific restricted assets will **not** be visible or audible at runtime unless the experience itself has permission to use those assets.
</Alert>
You can create a package from any single object or any single parent and children branch of objects. If you want to create a package for a single object, add it to a `Class.Model` grouping first so that you can add, remove, or scale child objects within the package later without breaking the package.
To create a package:
1. In the [Explorer](../../studio/explorer.md) window or 3D viewport, right-click the object(s) you want to turn into a package and, in contextual menu, select **Convert&nbsp;to&nbsp;Package**.
1. In the new window, fill in the package details. In particular, if you're working in a [group](../../projects/groups.md), set **Ownership** to the appropriate group in which you have permission to create/edit group experiences.
<Alert severity="warning">
Ownership transfers are **not** supported by the asset system, so carefully consider the owner when creating a package.
</Alert>
1. Click **Submit**.
1. After the conversion completes, the object receives a "chain link" symbol in the [Explorer](../../studio/explorer.md) window to identify it as a package. Additionally, you can see a new `Class.PackageLink` object parented to the object.
<img src="../../assets/studio/packages/Package-Structure-Explorer.png" alt="A maple tree model in the Explorer window with the package icon next to it." width="320" />
1. <Chip label="OPTIONAL" size="small" variant="outlined" /> Select the `Class.PackageLink` object and enable `Class.PackageLink.AutoUpdate|AutoUpdate` in the [Properties](../../studio/properties.md) window. Note how the icon changes to indicate that the package is set to automatically update.
<Alert severity="error">
Do not delete or move the `Class.PackageLink` object! Doing so for any package copy converts the copy back into a normal object and loses package capabilities, such as ability to update itself when there's a new version.
</Alert>
## Insert packages
To insert a package that doesn't already exist in the current place, you must **initially** insert it from the [Toolbox](../../projects/assets/toolbox.md):
- From **Inventory** ⟩ **My Packages** for packages that you've published to or obtained from the [Creator Store](../../production/creator-store.md), as well as packages that a connection owns and has given you [permissions](#share-and-access-levels) to use.
- From **Creations** ⟩ **Group Packages** for packages published by members of your [group](../../projects/groups.md) (including yourself).
<GridContainer numColumns="2">
<figure>
<img src="../../assets/studio/toolbox/Inventory-My-Packages.png" alt="A close up view of the Toolbox with both the Inventory tab and the assets dropdown menu highlighted." width="360" />
<figcaption>Toolbox ⟩ Inventory ⟩ My Packages</figcaption>
</figure>
<figure>
<img src="../../assets/studio/toolbox/Creations-Group-Packages.png" alt="A close up view of the Toolbox with the Creations tab highlighted." width="360" />
<figcaption>Toolbox ⟩ Creations ⟩ Group Packages</figcaption>
</figure>
</GridContainer>
Once you've inserted a package into a published place's data model, it appears in the [Asset Manager](../../projects/assets/manager.md) and remains there even if you later delete all copies of it.
<Alert severity="warning">
Be careful when inserting assets that you didn't create into your experiences, as they can contain malicious scripts. Save your experience first and then investigate any scripts within unfamiliar assets so that you can easily revert back to the place version.
</Alert>
## Modify packages
You can edit packages and their children just like other objects. Modifying packages disables [auto‑update](#automatic-updates) until you [publish](#publish-package-changes) or [revert](#revert-package-changes) the changes.
Most edits flag the package as modified, although the following changes are **not** considered package modifications:
- Changing the **name** of the root node.
- Changing the **position** or **rotation** of the root node of a package that is a `Class.BasePart`, `Class.Model`, or `Class.GuiObject`.
- Changing the `Class.LayerCollector.Enabled|Enabled` property of a root node `Class.GuiObject` such as a `Class.ScreenGui`, `Class.SurfaceGui`, or `Class.BillboardGui`.
- Changing a part reference of a `Class.Weld` inside the package that references an instance outside of the package.
Once modified, packages with unpublished changes get a modified icon in the [Explorer](../../studio/explorer.md) window:
<img src="../../assets/studio/packages/Package-Modified.png" alt="The Explorer window with an icon that identifies unpublished package changes." width="320" />
### Add or update configurations
You can include [instance attributes](../../studio/properties.md#instance-attributes) at the root of a package to customize its behavior. When you publish a package, the current set of attributes/values will become the package's **default configurations**. On any given **copy** of a package, those attribute values can be changed on a per‑instance basis, and those changed are noted through **bold italics**. When package copies are [updated](#update-outdated-copies), modified configuration values will be preserved, while other attributes will be updated to the latest default value.
<img src="../../assets/studio/packages/Package-Configured-Attributes.png" width="320" alt="The Attributes section of the Properties window showing one attribute value modified and noted through bold italics." />
<Alert severity="info">
Currently the only way to handle configuration values is to add scripts in the package which read and apply behavior based on the configuration at runtime.
</Alert>
<Alert severity="info">
If you simply want to update the default **values** for configurations, you can change those attribute values and republish the package (the package will **not** be flagged as modified in this case). If you want to publish other modifications but not change the default configuration values, you should publish on a package without any value changes, or revert the configurations to their defaults before you publish.
</Alert>
### Nested packages
You can nest packages inside of other packages to maintain and collaborate on complex hierarchies, such as a series of vehicle mechanics which can be modified independently of the vehicle's parent package.
If you modify a nested package, both the nested package **and** the parent package are considered as modified. You must [publish changes](#publish-package-changes) to any **nested** package before you're allowed to publish changes to its **parent** package, since publishing the parent would mark it as current/unmodified and conflict with the nested package's modifications.
### Package scripts
Each script within an **unmodified** package is read-only and shows a notification on the top with a hyperlink to unlock the script.
<img src="../../assets/studio/packages/Script-Unlock-Link.png" alt="A script tab with a yellow notification that you can click to modify the script that's within an unmodified package." width="840" />
Clicking the hyperlink:
- Flags the package as modified regardless of whether you edit the script.
- Removes the notification/hyperlink from **other** scripts within the package.
Once the package is published and moved to an **unmodified** state, the scripts under it become read‑only with a hyperlink to modify.
## Publish package changes
You can publish any change to a package as a new version, making your updates available to other package copies throughout the place and across all experiences. It's **not** required to publish a modified package before publishing a place because the modified version is saved along with the place for future iteration.
To publish changes to a package:
1. In the [Explorer](../../studio/explorer.md) window or 3D viewport, right-click the modified copy and select **Publish&nbsp;to&nbsp;Package**.
1. If a package copy has [auto-update](#automatic-updates) turned on, it immediately pulls in the updated version when you open the place that contains them. Other copies get a "download" symbol that indicates an update is available. You can [individually update](#update-outdated-copies) or [mass-update](#mass-updates) all copies.
<img src="../../assets/studio/packages/Package-Update-Available.png" alt="Icons next to packages that have a potential update." width="320" />
1. <Chip label="OPTIONAL" size="small" variant="outlined" /> Add a description of your changes:
1. Right-click the package and select **Package Details**.
1. In the **Asset Configuration** window, select **Versions**.
1. Under your most-recent change, select **Add**.
1. Describe your changes, then click the **Submit** button.
## Update outdated copies
You can update outdated package copies to the most recent version, or you can continue to use the older version.
1. In the [Explorer](../../studio/explorer.md) window, locate outdated copies by the "download" symbol. You can also select the outdated copy in the 3D viewport.
<img src="../../assets/studio/packages/Package-Update-Available.png" alt="Icons next to packages that have a potential update." width="320" />
1. Right-click an outdated copy and select **Get Latest Package**. You can also select multiple packages, right-click, and **Get Latest For Selected Packages**.
### Mass updates
Extensive use of packages may result in many package copies across multiple places in an experience. In addition to [individual syncing](#update-outdated-copies) and [automatic updates](#automatic-updates), you can update all copies of a package through **mass updating**.
1. <Chip label="RECOMMENDED" size="small" variant="outlined" color="success" /> Close other Studio instances with any of the experience's places open; this prevents another unsaved instance of a place from potentially overwriting your updates.
1. In the [Explorer](../../studio/explorer.md) window or 3D viewport, right-click the desired package and select **Update All**.
1. Choose all places in the experience or some subset of places and click **Update**.
<Alert severity="info">
Mass updating packages automatically **saves** the selected places but does not **publish** them. Additionally, to prevent unintended overwrites, mass updating does not affect [modified](#modify-packages) versions of a package; after the mass update completes, Studio displays a warning with the number of packages that it did **not** update, if any.
</Alert>
### Automatic updates
To make syncing easier, you can set a package copy to update automatically whenever a newer version is published. Auto-update of the package copies will take place when a place is opened in Studio.
1. In the [Explorer](../../studio/explorer.md) window, expand the package's hierarchy tree and select its `Class.PackageLink` object.
<img src="../../assets/studio/packages/PackageLink-Explorer.png" alt="A close up view of a package in the Explorer window with its PackageLink object highlighted." width="320" />
1. In the [Properties](../../studio/properties.md) window, enable the `Class.PackageLink.AutoUpdate|AutoUpdate` property. If you have [nested packages](#nested-packages), this property only applies to the highest-level parent package, meaning automatic updates only occur when the **parent** package is updated.
<Alert severity="warning">
Automatic updating does not apply to [modified](#modify-packages) package copies. Once you modify a package instance, its **AutoUpdate** property becomes disabled and is ignored.
</Alert>
## Share and access levels
You can grant permission to connections, experiences, groups, or specific group user roles so that they can freely use your packages in their creations. For more information on asset access, see [Asset privacy](privacy.md).
<Alert severity="warning">
If you share a package with restricted assets that you don't have [explicit permission](../../projects/assets/privacy.md#view-permissions) to use, you can still share the package but those specific restricted assets will **not** be visible or audible at runtime unless the connection, experience, or group has permission to use those assets.
</Alert>
<Tabs>
<TabItem key = "1" label="To collaborators">
To change package permissions for a collaborator, such as a connection or group:
1. In the [Explorer](../../studio/explorer.md) window, [Toolbox](../assets/toolbox.md), or [Asset Manager](../assets/manager.md), right-click the desired package and select **Package Options**&nbsp;⟩ **Package Details**.
1. In the **Asset Configuration** window, select **Permissions**.
1. Using the search bar, input and select a collaborator that you want to grant permission to use your package, then choose a permission level.
<table>
<thead>
<tr>
<th>Permission</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Use & View**</td>
<td>The collaborator can use and view (but not edit) the current and previous package versions. Once you provide a collaborator with this ability, you cannot revoke access to a copy they already inserted into their experience; revoking access prevents reinsertion or package updates, but package copies in their data model remain intact.</td>
</tr>
<tr>
<td>**Edit**</td>
<td>The collaborator can use, view, and edit the current and previous package versions, including publishing changes to it.</td>
</tr>
</tbody>
</table>
</TabItem>
<TabItem key = "2" label="To experiences">
To grant package access to an experience, the experience must be editable to either you or a group that you belong to in which you have the **Create and edit group experiences** role permission.
To change package permissions for an experience:
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
1. In the upper tab bar, select **Development Items**, then click **Models & Packages**.
1. Select the package you want your experience to have permission to use. The package's **Configure** page displays.
1. In the package's left-hand navigation, select **Permissions**. The package's **Permissions** page displays.
1. From the **Experiences** tab, click the **Add experiences** button.
1. Type the experience's universeID into the **Enter Universe IDs** input, then click the **Add** button. The experience displays beneath the input with its access visible.
<Alert severity="info">
If you want to give multiple experiences permission to use your restricted access at the same time, you can enter multiple universeIDs as long as you separate them with a comma.
</Alert>
1. Click the **Done** button to finalize your package asset access permissions.
</TabItem>
</Tabs>
## Revert package changes
Instead of undoing an entire series of package changes one by one, you can [revert unpublished changes](#revert-unpublished-changes) in one action, restore a package to a previous [version](#restore-to-published-version), or revert changes to specific [configurations](#revert-configurations).
### Revert unpublished changes
To undo an entire series of **unpublished** changes:
1. In the [Explorer](../../studio/explorer.md) window, locate modified copies by the dot on their package icons. You can also select modified copies in the 3D viewport.
<img src="../../assets/studio/packages/Package-Modified.png" alt="The Explorer window with an icon that identifies unpublished package changes." width="320" />
1. Right-click a single modified copy and select **Undo Changes to Package**, or select multiple copies (at least one of them modified), right-click, and select **Undo Changes to Selected Packages**.
### Restore to published version
To restore a package to a **previously published** version:
1. In the [Explorer](../../studio/explorer.md) window, [Toolbox](../assets/toolbox.md), or [Asset Manager](../assets/manager.md), right-click the desired package and select **Package Options**&nbsp;⟩ **Package Details**.
1. In the **Asset Configuration** window, select **Versions**. The window displays details for each published version, including the date and time of publication, along with any descriptions of the changes.
1. Click the checkmark next to the version you want to restore and click **Submit**.
<Alert severity="warning">
Reverting changes to a package does not reset the configuration to the default. See [revert configurations](#revert-configurations).
</Alert>
### Revert configurations
To revert any [configuration](#add-or-update-configurations) attribute to its default, select **Reset** from its options menu in the **Attributes** section of the [Properties](../../studio/properties.md) window.
<img src="../../assets/studio/packages/Package-Configured-Attributes-Reset.png" alt="The Attributes section of the Properties window with the attribute's option menu expanded." width="320" />
## Compare package versions
When a package has multiple versions, you can compare changes between versions using the diff viewer. The tool has a package hierarchy menu that indicates all added, removed, or modified instances between versions using corresponding icons, including the following features:
- **Visual Overview** shows the visual differences of the 3D rendering under different camera positions. It's the default view for packages with a 3D object (models, parts) as the root object, and it's currently only available for the root object.
- **Properties** shows changes of properties and attributes. It's the default view for packages with a non-3D object (scripts, lights, 2D objects) as the root object, and it's available for all instances in a package.
- **Script** shows line-by-line script differences. It's available for packages containing scripts, regardless of whether the script is the root object or not.
To compare package versions:
1. In the [Explorer](../../studio/explorer.md) or 3D viewport, right‑click the target package and select **Package Options**&nbsp;⟩ **Compare Package Versions**.
1. By default, the window compares changes between your local copy and the latest version. Use the two dropdown menus to compare different versions.
<img src="../../assets/studio/packages/Compare-Versions-Selector.png" alt="A close up view of an example diff viewer. The compare settings are highlighted." width="840" />
<Alert severity="warning">
Some older versions might be incompatible with the package diff tool.
</Alert>
1. After selecting versions:
1. To compare the visual renderings of the root model, if applicable, select the **Visual Overview** tab and adjust the camera control for your desired angle. Controls are synchronized across views:
- Pan the camera using left mouse clicks.
- Rotate the camera using right mouse clicks.
- Zoom in and out the camera with the mouse wheel.
- Recenter using the keyboard shortcut <kbd>F</kbd>.
1. To compare properties and attributes of an instance, select the instance and the **Properties** tab.
1. To compare script differences for a package that is a script or contains scripts, use the **Script** tab.
<Alert severity="warning">
This tool only allows you to compare script changes between the current version and the latest published or local version, without indicating the collaborators who made the change.
</Alert>
<Alert severity="info">
Alternatively, you can open the script diff tool directly by right‑clicking the target package in the [Explorer](../../studio/explorer.md) window or 3D viewport and selecting **View Script Changes**.
</Alert>

View file

@ -0,0 +1,280 @@
---
title: Asset privacy
description: Explore how the asset privacy system lets you control which Roblox creators can use your assets in their experiences.
---
The **asset privacy system** lets you control how creators and experiences can use and distribute your models, meshes, images, decals, audio, video, and animation assets on Roblox. Assets can have one of two access privacy types:
- **Restricted** — Creators or experiences can only use the asset after the asset owner grants permission.
- **Open Use** — Any creator or experience can use the asset.
If a creator or experience doesn't have permission to use an asset, it cannot load in Studio, and a clickable error message displays in the [Output](../../studio/output.md) window. If a creator has permission to use an asset but the experience they're working on does not, clicking the error message displays a pop-up window to allow the creator to grant permission to the experience for any restricted assets.
When an asset is open use, Roblox doesn't need to check its permissions when it loads into an experience because every creator and experience can freely use it. However, when an asset is restricted, Roblox **always** checks its permissions when it loads into an experience or when a creator takes an action on the asset, such as inserting it into Studio, sharing it with another creator, or listing it on the [Creator Store](../../production/creator-store.md).
<Alert severity="info">
The asset privacy system controls which creators and experiences can use the asset, but others can still see its metadata, such as its name and description.
</Alert>
## Restrict permissions
<Alert severity="info">
You can list your or your group's restricted assets by themselves or as a dependency of a restricted asset on the Creator Store. This allows creators to use your assets as you list them under models, mesh parts, or packages, and disallows them from accessing and repackaging your restricted asset dependencies.
</Alert>
Every model, mesh part, and animation that you create are restricted **by default** to ensure that no one else can use your assets unless you explicitly grant permission to a creator, group, or experience, or list them on the Creator Store. If you want to extend this default permission to meshes, images, and decals, you must opt-in to the **Asset Privacy** beta.
### Beta opt-in
Individual creators and groups can opt into the beta via Creator Dashboard to apply permissions to newly created assets by default. Users and groups who are opted into the beta have their Images, Meshes, and Decals created as **Restricted** as default.
<Tabs>
<TabItem key = "1" label="As a creator">
To restrict your mesh, image, and decal assets on creation through the Asset Privacy beta:
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
1. In the top-right corner of the page, click on your username and select **Settings**.
1. In the left-hand navigation, select **Advanced**.
1. In the **Asset Privacy** section, enable the **Opt-in to restrict assets on creation** toggle. Every non-avatar asset you create is now restricted by default.
</TabItem>
<TabItem key = "2" label="As a group">
<Alert severity="warning">
You can only complete this process if you are the group owner.
</Alert>
To restrict your group mesh, image, and decal assets on creation through the Asset Privacy beta:
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
1. In the upper-left, expand the account switcher and select your group.
1. Expand the account switcher again, select **Settings** under the group's name, then select **Group Profile**.
1. In the **Asset Privacy** section, enable the **Allow restricted assets on creation** toggle. Every non-avatar asset your group creates is now restricted by default.
</TabItem>
</Tabs>
After opting into the beta, you can verify the asset permission of any newly uploaded asset in the asset configuration page:
<img src="../../assets/creator-dashboard/Asset-Toggle.png" alt="The landing page for asset permissions with the Collaborators tab selected." width="60%" />
Selecting **Open Use** warns that once an asset has been set to **OpenUse**, it cannot be set back to **Restricted**.
<img src="../../assets/creator-dashboard/Asset-Make-OpenUse.png" alt="The landing page for asset permissions with the Collaborators tab selected." width="60%" />
After setting to **Open Use**, the asset displays its current asset access permission.
<img src="../../assets/creator-dashboard/Asset-OpenUse.png" alt="The landing page for asset permissions with the Collaborators tab selected." width="60%" />
### Decals
All `Class.Decal|Decals` are linked to an `Image`, which means a `Decal` can only be set to OpenUse if its `Image` dependency is OpenUse. Otherwise the following warning displays:
<img src="../../assets/creator-dashboard/Asset-Decals-Warning.png" alt="The landing page for asset permissions with the Collaborators tab selected." width="60%" />
### Avatar assets
Avatar assets, such as accessories, clothing, and bodies, require all dependent textures and meshes to be `OpenUse` when uploading the Avatar asset to the Marketplace.
If you are opted into the beta and use a newly imported model in an avatar asset, you will be prompted to set your restricted texture and mesh dependencies to `OpenUse` during Marketplace [upload](../../marketplace/publish-to-marketplace.md#upload-an-asset):
<GridContainer numColumns = "2">
<figure>
<img src="../../assets/creator-dashboard/Asset-Avatar-Restricted.png" alt="The landing page for asset permissions with the Collaborators tab selected." width="100%" />
<figcaption>
If your avatar item or bundle contains any restricted primitive assets, you must convert them to Open Use.
</figcaption>
</figure>
<figure>
<img src="../../assets/creator-dashboard/Asset-Avatar-Success.png" alt="The landing page for asset permissions with the Collaborators tab selected." width="100%" />
<figcaption>
If your entire avatar item has correct permissions, you can continue to upload and publish your avatar item to the Marketplace.
</figcaption>
</figure>
</GridContainer>
## Grant permissions
In order for a collaborator, such as an individual creator or group, or an experience to use one of your restricted assets, you must explicitly grant permission before it's visible or audible at runtime. Once a collaborator or experience has **explicit** permission to use a restricted asset, they also receive **implicit** permission to use the asset in a variety of additional scenarios. For more information, see the following subsections.
### To collaborators
To grant a collaborator permission to use one of your restricted assets, the following must be true depending on if you are granting permission to another creator or a group:
- The creator must be your [connection](https://en.help.roblox.com/hc/en-us/articles/203313580-How-to-Make-Friends) on the platform, or
- You must have [Edit all group experiences](../../projects/groups.md#roles-and-permissions) permission in that group.
If you meet these conditions and explicitly grant the collaborator permission,
- The creator gains implicit permission to use the asset in any of their individual or group-owned experiences, and the ability to grant other experiences permission to use the restricted asset.
- All group members with edit access gain permission to use the asset in experiences owned by that group.
Once a collaborator has permission to use one of your restricted assets, they can insert the asset from the **Inventory** and/or **Creation** tab of the [Toolbox](../../projects/assets/toolbox.md), or by using the restricted asset ID in the [Properties](../../studio/properties.md) window.
<GridContainer numColumns="2">
<figure>
<img src="../../assets/studio/toolbox/Inventory-Tab.png" width="360" alt="A close up view of the Toolbox with the Inventory tab highlighted." />
<img src="../../assets/studio/toolbox/Creations-Tab.png" width="360" alt="A close up view of the Toolbox with the Creations tab highlighted." />
<figcaption>Inserting a restricted asset through the Toolbox</figcaption>
</figure>
<figure>
<img src="../../assets/studio/properties/Enter-Private-Asset-ID.png" width="320" alt="A close up view of the Properties window with the Asset property highlighted." />
<figcaption>Inserting a restricted asset in the Properties window</figcaption>
</figure>
</GridContainer>
However, if a collaborator wants to use the restricted asset in a script, or if they want to save or publish a template place that includes the restricted asset, the collaborator must also give the [experience](#to-experiences) itself permission to use the asset. If the creator or group member doesn't complete this step, the asset isn't visible or audible during runtime, and a clickable error message displays in the **Output** window.
To grant a collaborator permission to use a restricted asset in any of these scenarios:
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
1. In the upper tab bar, select **Development Items**, then click one of the following tabs:
- **Models & Packages**
- **Audio**
- **Decals**
- **Images**
- **Videos**
- **Meshes**
- **MeshParts**
- **Animations**
1. Select the asset you want your collaborator to have permission to use in their experiences. The asset's **Configure** page displays.
1. In the asset's left-hand navigation, select **Permissions**. The asset's **Permissions** page displays.
1. From the **Collaborators** tab, click the **Add collaborators** button.
<img src="../../assets/creator-dashboard/Permissions-Collaborators.png" alt="The landing page for asset permissions with the Collaborators tab selected." width="80%" />
1. Using the search bar, input and select a connection or group that you want to grant permission to use your restricted asset. The creator or group displays beneath the search bar with their access type.
<img src="../../assets/creator-dashboard/Add-Collaborators.png" alt="The Add Collaborators pop-up menu." width="60%" />
1. **(Optional)** If your selected asset type is a model or package, you can choose one of the following access types:
- **Use** - The collaborator receives permission to use the asset in their experiences.
- **Edit** - The collaborator receives permission to edit the asset's metadata, such as its name and description.
1. Click the **Done** button to finalize your asset access permissions.
### To experiences
<Alert severity="error">
Once an experience has permission to use a restricted asset, you cannot revoke access to the asset.
</Alert>
To grant an experience permission to use one of your restricted assets, the experience must be editable to either you or a group that you belong to in which you have the [Edit all group experiences](../../projects/groups.md#roles-and-permissions) permission.
After you or a collaborator with permission grants an experience access to use a restricted asset, anyone who has **Edit** access to that experience gains implicit permission to:
- Copy and paste the asset into another place file within that experience.
- Use its asset ID in the **Properties** window or in scripts within any place file within the experience.
<Alert severity="info">
When you grant permission to an experience by inserting it into a collaborator’s experience, the asset is also automatically shared with the experience's owner.
</Alert>
The following tabs walk you through the process of either granting one or more experiences access to a single restricted asset, or granting an experience access to one or more restricted assets.
<Tabs>
<TabItem key = "1" label="On an asset level">
To grant an experience permission to use a restricted asset:
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
1. In the upper tab bar, select **Development Items**, then click one of the following tabs:
- **Models & Packages**
- **Audio**
- **Decals**
- **Images**
- **Videos**
- **Meshes**
- **MeshParts**
- **Animations**
1. Select the asset you want the experience to have permission to use. The asset's **Configure** page displays.
1. In the asset's left-hand navigation, select **Permissions**. The asset's **Permissions** page displays.
1. From the **Experiences** tab, click the **Add experiences** button.
<img src="../../assets/creator-dashboard/Permissions-Experiences.png" alt="The landing page for asset permissions with the Experiences tab selected." width="80%" />
1. Type the experience's universeID into the **Enter Universe IDs** input, then click the **Add** button. The experience displays beneath the input with its access visible.
<Alert severity="info">
If you want to give multiple experiences permission to use your restricted access at the same time, you can enter multiple universeIDs as long as you separate them with a comma.
</Alert>
<img src="../../assets/creator-dashboard/Add-Experiences.png" alt="The Add Experiences pop-up menu." width="60%" />
1. Click the **Done** button to finalize your asset access permissions.
</TabItem>
<TabItem key = "2" label="On an experience level">
To grant an experience permission to use many restricted assets in the previous scenarios:
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
1. Select one of your or your group's experiences. The experience's overview page displays.
1. In the experience's left-hand navigation, navigate to the **Configure** section, then select **Permissions**. The asset's **Permissions** page displays.
1. In the **Enter asset IDs** input, type every asset ID you want the experience to have access to separated by commas, then click the **Add** button. All restricted assets the experience has access to display beneath the input with the asset's name, asset ID, owner, and asset type.
1. At the bottom of the page, click the **Save Changes** button.
</TabItem>
</Tabs>
## View permissions
You can view every restricted asset that your or your group's experiences have permission to use by reviewing the experience's **Permissions** page on the Creator Dashboard.
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
1. Select one of your or your group's experiences. The experience's overview page displays.
1. In the experience's left-hand navigation, navigate to the **Configure** section, then select **Permissions**. The asset's **Permissions** page displays.
1. **(Optional)** You can download the data for offline processing by clicking the download arrow button.
## Revoke permissions
<Alert severity="warning">
Unconnecting a creator does not automatically revoke permissions to use a restricted asset.
</Alert>
If you revoke restricted asset permission for a connection, they can no longer use the asset in any **additional** experiences. However, if they have used the restricted asset in their experiences, the experiences continue to have access to the restrictued asset.
To revoke permission for a creator to use a restricted asset in any additional experience that isn't currently using the asset:
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
1. In the upper tab bar, select **Development Items**, then click one of the following tabs:
- **Models & Packages**
- **Audio**
- **Decals**
- **Images**
- **Videos**
- **Meshes**
- **MeshParts**
- **Animations**
1. Select the asset you want to revoke permission for one or more creators to use in their own experiences. The asset's **Configure** page displays.
1. In the asset's left-hand navigation, select **Permissions**. The asset's **Permissions** page displays.
1. From the **Collaborators** tab, locate the creator you want to revoke permission from, then click the Access dropdown next to their username. Additional options display.
1. Click the **Remove** button. A pop-up displays to confirm that you want to revoke permission from the collaborator.
1. From the pop-up, click the **Remove** button.
## Open permissions
<Alert severity="error">
Opening an asset's permissions is irreversible. Once you set an asset to open use, it **cannot** be reset to the restricted privacy type.
</Alert>
While opting in to the **Asset Privacy** beta allows you to restrict your or your group's mesh, image, and decal assets on creation, you are still able to open their permissions so that any creator or experience to freely access and use them in their projects.
To open permissions for your or your group's mesh, image, or decal asset through the Asset Privacy beta:
1. Follow the steps to opt-in to the Asset Privacy beta in [Restrict permissions](#restrict-permissions).
1. Back in the [Creator Dashboard](https://create.roblox.com/dashboard/creations), navigate to the upper tab bar, select **Development Items**, then click either **Decalss**, **Images**, or **Meshes**. All of your decal, image, or mesh assets display.
<Alert severity="warning">
If you want to set a decal asset to open use, you must set its image dependency to open use **first**, otherwise the Asset Privacy system will block you in future steps.
</Alert>
1. Select the asset that you want to every creator and experience to freely use in their projects. The asset's **Configure** page displays.
1. In the **Asset Access** section, enable **Open Use**. A pop-up displays asking you to confirm this permanent change.
1. In the pop-up, click the **Make Open Use** button. Anyone on Roblox can now use your asset.

View file

@ -0,0 +1,118 @@
---
title: Toolbox
description: The Toolbox contains a selection of assets made by Roblox or Roblox community members.
id: toolbox
---
import ToolboxFindUse from '../../includes/studio/toolbox-find-use.md'
The **Toolbox**, accessible from Studio's **Window** menu or **Home** tab toolbar, contains a selection of [models](../../parts/models.md), [images](../../parts/textures-decals.md), [meshes](../../parts/meshes.md), [audio](../../audio/assets.md), [plugins](../../studio/plugins.md), [videos](../../ui/video-frames.md), and fonts made by Roblox or Roblox community members. It also includes all of the creations that you've personally published or those which were published by [groups](../../projects/groups.md) you belong to.
<img src="../../assets/studio/general/Toolbar-Toolbox.png" width="800" alt="Toolbox highlighted in Studio's toolbar." />
The toolbox contains four distinct sections:
<Tabs>
<TabItem label="Creator Store">
<figure>
<img src="../../assets/studio/toolbox/Creator-Store-Tab.png" width="360" height="121" alt="A close up view of the Toolbox with the Creator Store tab highlighted." />
The **Creator Store** section contains models, decals, meshes, audio, plugins, videos, and fonts made by Roblox or Roblox community members. See [Creator Store](../../production/creator-store.md) for more information.
</figure>
</TabItem>
<TabItem label="Inventory">
<figure>
<img src="../../assets/studio/toolbox/Inventory-Tab.png" width="360" height="121" alt="A close up view of the Toolbox with the Inventory tab highlighted." />
The **Inventory** section contains models, decals, meshes, audio, packages, videos, plugins, animations, and fonts that you've personally published, those which were published by [groups](../../projects/groups.md) you belong to, or those taken from the [Creator Store](../../production/creator-store.md).
</figure>
</TabItem>
<TabItem label="Recent">
<figure>
<img src="../../assets/studio/toolbox/Recent-Tab.png" width="360" height="121" alt="A close up view of the Toolbox with the Recent tab highlighted." />
The **Recent** tab is similar to **Inventory** except that filters your recently used models, decals, meshes, audio, videos, and animations.
</figure>
</TabItem>
<TabItem label="Creations">
<figure>
<img src="../../assets/studio/toolbox/Creations-Tab.png" width="360" height="121" alt="A close up view of the Toolbox with the Creations tab highlighted." />
The **Creations** tab is similar to **Inventory**, with the important distinction that it filters models, decals, meshes, audio, plugins, and animations that you've personally published or those which were published by [groups](../../projects/groups.md) you belong to. You can [configure](#asset-configuration) all assets in this section directly within Studio.
</figure>
</TabItem>
</Tabs>
## Find and use assets
With millions of assets available, it's helpful to narrow the search results to find exactly what you are looking for. To browse and use assets:
<ToolboxFindUse components={props.components} />
## Asset configuration
Right-clicking an asset and selecting **Edit Asset** opens the **Asset Configuration** window. In this window, you can edit the asset's details or restore it to a previous version.
<Alert severity="info">
Asset configuration is only possible for assets you've personally published or those which were published by [groups](../../projects/groups.md) you belong to. The **Creations** tab is particularly useful for filtering assets in this way.
</Alert>
## Troubleshooting
The toolbox runs through a web view. If you're experiencing any of the following issues, run the associated troubleshooting steps.
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">General Issues</Typography></AccordionSummary>
<AccordionDetails>
<Alert severity="warning">
Make sure there are no active instances of Roblox Studio running before running these steps.
</Alert>
<table>
<thead>
<tr>
<th>Windows</th>
</tr>
</thead>
<tbody>
<tr>
<td>
1. [Reinstall](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) your Windows WebView2 installation.
2. Delete the WebView2 data folder found at `%LOCALAPPDATA%\Roblox\RobloxStudio\WebView2`. Studio will automatically recreate this folder when it opens.
</td>
</tr>
</tbody>
<thead>
<tr>
<th>Mac</th>
</tr>
</thead>
<tbody>
<tr>
<td>Delete the WebKit data folders found at `~/Library/WebKit/com.Roblox.RobloxStudio` and `~/Library/Caches/com.Roblox.RobloxStudio/WebKit`. Studio will automatically recreate these folders when it opens.</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Audio Not Working</Typography></AccordionSummary>
<AccordionDetails>
<table>
<thead>
<tr>
<th>Windows</th>
</tr>
</thead>
<tbody>
<tr>
<td>
1. Right click the speaker icon in the taskbar.
2. Click **Open Volume Mixer**.
3. Make sure that **Microsoft Edge WebView2** is not muted.
</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</BaseAccordion>

View file

@ -0,0 +1,128 @@
---
title: Client-server runtime
description: An overview of the client-server model in Roblox.
---
## Server
Roblox experiences are multiplayer by default and run in a client-server model.
The Roblox **server** is the ultimate authority for maintaining the experience's
state, and is responsible for keeping all connected clients in sync with the
server.
<figure>
<img
alt="A server grouping with connections to three client devices."
src="../assets/scripting/client-server/Client-Server-Model.png"
width="100%" />
<figcaption>Server with connections to three client devices</figcaption>
</figure>
## Client
When an experience runs, Roblox copies a version of the "edit" data model that
you built and published from Studio and runs it on Roblox servers as the
"runtime" data model.
Connected clients also receive a copy of the runtime data model and any
initialization of the player occurs, such as initializing a player's backpack
(inventory) or local user interface. When an experience has
`Class.Workspace.StreamingEnabled` set to true, the server initially only sends
a subset of content under `Class.Workspace` that is closest to the client. The
client then renders the 3D world and begins running any
applicable scripts.
<figure>
<img
alt="A diagram that maps objects between 'edit' and 'runtime' data models."
src="../assets/scripting/client-server/Data-Model-Mapping.png"
width="720" />
<figcaption></figcaption>
</figure>
## Replication
The server constantly updates connected clients, keeping everything in sync
across the server and clients through a process called **replication**, which
synchronizes the data model, physics simulation, and chat messages. Replication
logic exists on both the client and server to ensure synchronization.
<Tabs>
<TabItem label="Data">
Data model changes can occur in a variety of cases, such as when something in the 3D
world is created or a property of the 3D world changes. This typically occurs
when a script on the server or client makes a change that needs to be reflected
on the other side of the client-server boundary. The following diagrams show
common scenarios for data replication.
<GridContainer numColumns="3">
<figure>
<Chip label="Client &rarr; Server" size="large" color="primaryBrand" variant="outlined"
style={{fontSize:"110%", width:"100%"}}/><br /><br />
<img src="../assets/scripting/client-server/Remote-Flow-Client-Server.png" width="100%" alt="A diagram of one client communicating with the server." />
<figcaption>Communication from any client to the server. For example, a client presses the <kbd>P</kbd> key to drink an invisibility potion, and tells the server to make that player's character invisible to all other players.</figcaption>
</figure>
<figure>
<Chip label="Server &rarr; Client" size="large" color="success" variant="outlined"
style={{fontSize:"110%", width:"100%"}}/><br /><br />
<img src="../assets/scripting/client-server/Remote-Flow-Server-Client.png" width="100%" alt="A diagram of the server communicating with one client." />
<figcaption>Communication from the server to one specific client. For example, a player joins the experience and the server populates that player's inventory with a set of items.</figcaption>
</figure>
<figure>
<Chip label="Server &rarr; All Clients" size="large" color="secondary" variant="outlined"
style={{fontSize:"110%", width:"100%"}}/><br /><br />
<img src="../assets/scripting/client-server/Remote-Flow-Server-All-Clients.png" width="100%" alt="A diagram of the server communicating with all connected clients." />
<figcaption>Communication between the server and all connected clients. For example, displaying a countdown timer to all participants in a race.</figcaption>
</figure>
</GridContainer>
</TabItem>
<TabItem label="Physics">
Roblox uses a rigid body physics engine, which is responsible for
calculating the movement and interactions of parts in the 3D world. By default,
all parts in Roblox are rigid bodies and participate in simulated physics,
unless otherwise specified. You can also group multiple parts together into
assemblies, which the physics engine treats as a single rigid body.
<br/>
<Grid container spacing={0}>
<Grid item XSmall={4} XLarge={3}>
<img src="../assets/physics/assemblies/Assembly-Example-Block.png" alt="A single block part in the shape of a cube that represents a single assembly." width="100%" />
<figcaption>1&nbsp;assembly; 1&nbsp;part</figcaption>
</Grid>
<Grid item XSmall={4} XLarge={3}>
<img src="../assets/physics/assemblies/Assembly-Example-Avatar.png" alt="A player character that represents a single assembly of 18 individual parts." width="100%" />
<figcaption>1&nbsp;assembly; 18&nbsp;parts</figcaption>
</Grid>
<Grid item XSmall={8} XLarge={6}>
<img src="../assets/physics/assemblies/Assembly-Example-Ship.png" alt="A pirate ship mesh that represents a single assembly of 179 individual parts." width="100%" />
<figcaption>1&nbsp;assembly; 179&nbsp;parts</figcaption>
</Grid>
</Grid>
<br/>
Roblox replicates physics simulation data between the server and clients when
necessary. To assist with simulation performance, Roblox can assign ownership of
assemblies to a specific client or server. This means that the client or server
can be responsible for simulating the physics of that assembly. Other clients
receive updates about the assembly's position and movement from the owning
client or server. Ownership typically happens automatically, but you can assign
it directly for fine-tuned responsiveness.
<figure>
<video src="../assets/physics/network-ownership/Visualization-Demo.mp4" controls width="90%" alt="A player character walks around collecting glowing objects on the floor. Part ownership is indicated with colored outlines."></video>
<figcaption>Part ownership indicated through colored outlines</figcaption>
</figure>
</TabItem>
<TabItem label="Chat">
Roblox replicates chat messages between the server and client. The server is
responsible for filtering chat messages and deciding which messages to replicate
to other clients. For example, the server may filter out messages that contain
profanity or are too long.
<video src="../assets/players/in-experience-text-chat/Player-Conversation-Bubbles.mp4" controls width="90%" alt="Two characters talk to each other through chat bubbles above their heads in a spooky blue environment."></video>
</TabItem>
</Tabs>
<Alert severity="success">
Most players on Roblox experience between 100–300 milliseconds of network latency. [Roblox Studio](../studio/index.md) playtesting runs with a default of no latency, but you can change **Incoming&nbsp;Replication&nbsp;Lag** in the **Network** section of Studio's settings (<kbd>Alt</kbd><kbd>S</kbd> on Windows; <kbd>⌥</kbd><kbd>S</kbd> on Mac) to `0.1`–`0.3` to better simulate how replication latency will affect your experience.
</Alert>

View file

@ -0,0 +1,324 @@
---
title: Collaboration
description: Studio's built-in collaboration tools let creators contribute independently, or work together with a team.
---
Creating a high-quality experience demands many skills such as modeling, scripting, user interface design, and audio production. It's unlikely that one person has all of these skills, which makes collaboration between different roles an essential part of the development workflow.
With Studio's **built-in** **collaboration tools**, creators can contribute to experiences independently on their own time, or work together with their team all at the same time.
<img src="../assets/studio/collaboration/Collaborative-Session.jpg" alt="Three creators working together in a collaborative session, each with different color markers to demonstrate what objects they're currently editing in the environment." />
## Manage collaborators
Collaborators you add to an experience have permission settings that correspond to their level of access to the experience. As follows are the different user permission settings:
<table>
<thead>
<tr>
<th>Permission</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Owner**</td>
<td>User is the owner of the experience and has permission to configure other users' permissions.</td>
</tr>
<tr>
<td>**Edit**</td>
<td>User has permission to edit the experience. This also grants the user **Play** permission.</td>
</tr>
<tr>
<td>**Play**</td>
<td>User has permission to play the experience privately.</td>
</tr>
<tr>
<td>**No&nbsp;Access**</td>
<td>User does not have either **Edit** or **Play** permissions.</td>
</tr>
</tbody>
</table>
There are some small differences when managing collaborators in [group‑owned experiences](#group-owned-experiences) vs. [user‑owned experiences](#user-owned-experiences).
### Group-owned experiences
For [group](../projects/groups.md) experiences, only the group owner or members with sufficient permissions can manage the group's roles, either across **all group experiences** or on a **per‑experience** basis. Such users can also add individual collaborators to group‑owned experiences in the same workflow as [user‑owned](#user-owned-experiences) experiences, but only for **Play** access.
<Tabs>
<TabItem label="All group experiences">
If you're the group owner or a member with sufficient permissions, you can configure collaboration across **all** group experiences, for example grant **Edit** permission to an "Audio&nbsp;Artist" group role so they can fine-tune audio playback across multiple group experiences.
1. From the [Creator Dashboard](https://create.roblox.com/dashboard/creations), expand the account switcher in the upper‑left and select the group.
1. Expand the account switcher again, select **Settings** under the group's name, then select **Roles**.
1. Enable [Edit all group experiences](../projects/groups.md#roles-and-permissions) for roles that should have editing permission. Remember to click **Save Changes** for each role that you change.
In Studio's **Manage Collaborators** window for any group-owned experience, eligible roles display **Edit** permission but are muted to indicate that you can't change the permission level from Studio.
<img src="../assets/studio/general/Toolbar-Manage-Collaborators.png" width="800" alt="Studio's mezzanine bar with the Collaborate button highlighted." />
<img src="../assets/studio/collaboration/Edit-Permission-All-Group-Experiences.png" width="760" alt="Manage Collaborators window showing permission level selection for each group role." />
</TabItem>
<TabItem label="Per-experience">
If you're the group's owner, you can grant permissions on a per-experience basis to roles that do not have those permissions across all group experiences. For example, you can temporarily grant **Edit** permission to an "FX&nbsp;Artist" group role so they can fine-tune visual effects before an experience's public release.
1. In Studio's **Manage Collaborators** window for any group-owned experience, select **Edit** from the permissions dropdown for the desired roles. Remember that you can only modify roles that do **not** already have edit permission across all group experiences.
<img src="../assets/studio/general/Toolbar-Manage-Collaborators.png" width="800" alt="Studio's mezzanine bar with the Collaborate button highlighted." />
<img src="../assets/studio/collaboration/Edit-Permission-Per-Experience.png" width="760" alt="Manage Collaborators window showing permission level selection for each group role." />
2. Click **Save** for your collaboration settings to take effect. All group members within the modified roles should now have **Edit** permission for this experience only; this action won't grant them equal permission to other group experiences.
</TabItem>
</Tabs>
### User-owned experiences
For user-owned experiences, you can grant **Play** access to any user or [group](../projects/groups.md), but you can only grant **Edit** permission to Roblox connections.
To give **Edit** permission to a connection for an experience that you own:
1. With the experience open in Studio, click the **Collaborate** button on the right side of the mezzanine bar.
<img src="../assets/studio/general/Toolbar-Collaborate.png" width="800" alt="Studio's mezzanine bar with the Collaborate button highlighted." />
1. Type into the search bar at the top to search for a collaborator to add. A dropdown appears listing matching collaborators, with connections indicated by the **Connection** label. Select the collaborator to add.
<img src="../assets/studio/collaboration/Collaborator-Search.png" width="760" alt="Manage Collaborators window showing search query for a Roblox connection." />
1. Select **Edit** from the permissions dropdown for the connection, then click **Save** for your collaboration settings to take effect.
## Access a session
Those who have permission to edit an experience can join a collaborative session as follows:
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
1. Locate the experience depending on whether it's [group-owned](#group-owned-experiences) or [user-owned](#user-owned-experiences).
<Tabs>
<TabItem label="Group-Owned Experience">
1. Select the group from the upper‑left selector menu.
2. Make sure **Creations** is selected on the left and **My Experiences** in the main panel.
<Grid container spacing={1} alignItems="center">
<Grid item><Chip label="My Experiences" color="primary" size="medium" /></Grid>
<Grid item><Chip label="Shared With Me" color="secondary" size="medium" /></Grid>
</Grid>
</TabItem>
<TabItem label="User-Owned Experience">
1. Select your personal account from the upper‑left selector menu.
2. Make sure **Creations** is selected on the left and **Shared With Me** in the main panel.
<Grid container spacing={1} alignItems="center">
<Grid item><Chip label="My Experiences" color="secondary" size="medium" /></Grid>
<Grid item><Chip label="Shared With Me" color="primary" size="medium" /></Grid>
</Grid>
</TabItem>
</Tabs>
1. Hover over the experience's tile and click the **Edit in Studio** button to collaborate.
<img src="../assets/creator-dashboard/Edit-Button-Experience.png" width="200" alt="A close up view of an experience tile with the Edit in Studio button highlighted." />
### View collaborators
While working in a collaborative session, you can see the current collaborators in the upper-right corner of Studio, each with a unique assigned color that's consistent across all collaborators' devices.
<img src="../assets/studio/general/Toolbar-Current-Collaborators.png" width="800" alt="Studio's menu bar with icons of the current collaborators highlighted." />
To view more details on the current collaborators, click on any of the icons to open the **Live Collaborators** window. In this window, you can see whether a user is active or inactive inside Studio, as well as an indication of where the user is working. Users become inactive if they do not use Studio for more than 5 minutes.
<img src="../assets/studio/collaboration/Live-Collaborators-Status.png" width="280" alt="Live Collaborators window with icons of current collaborators, as well as their activity status." />
### Selection visualization
By default, selected code in the [Script Editor](../studio/script-editor.md) and selected objects in the 3D viewport are highlighted with the unique color assigned to each collaborator. Additionally, the [Explorer](../studio/explorer.md) window marks selected objects with dots in these assigned colors to indicate selection by other collaborators.
<Grid container spacing={2}>
<Grid item>
<img src="../assets/studio/collaboration/User-Color-Parts.jpg" width="420" alt="A viewport view of a block part pyramid. The parts near the top of the pyramid are highlighted in green to signify that the collaborator with the green color has the parts selected in their Studio instance." />
</Grid>
<Grid item>
<img src="../assets/studio/collaboration/User-Color-Explorer.png" width="320" alt="A close up view of the three block part objects in the Explorer window. There is a green circle near the objects to signify that the collaborator with the green color has the parts selected in their Studio instance." />
</Grid>
</Grid>
To make all collaborators' selections invisible to only you while still seeing their work, uncheck **Show collaborator selections** at the bottom of the [Live Collaborators](#view-collaborators) window.
<img src="../assets/studio/collaboration/Live-Collaborators-Toggle-Selections.png" width="280" />
### Join collaborators
To quickly jump to a location in the workspace or to the exact line in a script that a collaborator is editing, hover over their name in the [Live Collaborators](#view-collaborators) window and click **Join**.
<img src="../assets/studio/collaboration/Live-Collaborators-Join.png" width="280" />
## Comments
Roblox Studio has a **comments** feature that lets you pinpoint an object in the 3D viewport and start a conversation with your collaborators, leave to-do notes, and more. Comments update in real time which lets you and your team receive and respond to feedback without disrupting your workflow in Studio. You can also receive personalized [notifications](#notifications) to help you stay on top of feedback, even when you're not using Studio.
### Workflow
To create a comment, click the **Comment** button on the right side of Studio's mezzanine (keyboard shortcut <kbd>C</kbd>).
<img src="../assets/studio/general/Toolbar-Comments.png" alt="Studio's mezzanine bar with the Comments button highlighted." width="800" />
In the viewport, your cursor turns blue. Click on any object that inherits from `Class.BasePart` (most do, including `Class.Terrain`), type your comment, and click **Submit**.
<img src="../assets/studio/collaboration/Comments-Cursor.jpg" alt="Blue comment cursor in the viewport." width="800" />
<Alert severity="info">
To **tag** a collaborator in your comment, use the `@username` syntax. You can tag any collaborator in the group for a [group‑owned](#group-owned-experiences) experience or any user with **Play** or **Edit** permissions in a [user‑owned](#user-owned-experiences) experience.
</Alert>
Comments appear in the **Comments** window, accessible from Studio's **Window**&nbsp;⟩ **Collaboration** menu, with the most recent comments at the top. From within the **Comments** window, you can:
- Single-click on a comment to show the full conversation in the 3D viewport.
- Double-click on a comment to zoom in on it in the viewport.
- Use the **&ctdot;** menu in the upper-right corner to show resolved comments, filter for only the comments that you've been tagged in, or hide comments in the viewport.
- Resolve comments as you and your team address them. After you resolve a comment, it disappears from both the viewport and the main list, but it isn't completely gone; you can always un‑resolve it later.
<img src="../assets/studio/collaboration/Comments-Window.png" width="360" />
### Notifications
To help you stay on top of feedback even when you're not using Studio, you'll receive an **email digest** that recaps all recent activity. Each email digest provides a simple overview of comment activity per place, including:
- When someone mentions (tags) you in a comment, for example `@username`.
- When someone comments in a thread that you previously replied to or were mentioned in.
- When someone resolves a thread that you previously replied to or were mentioned in.
From within the email overview, simply click **View in Studio** to go directly to the conversation in Roblox Studio.
<Alert severity="info">
You're always in control of both the type and source of comments which make up email digests. Mentions and reply notifications are on by default, while resolution notifications are off. You can also unsubscribe from a specific place or thread if you don't need updates.
</Alert>
## Collaborative scripting
In a collaborative session, you can code together in real time through [live scripting](#live-scripting), or you can [draft](#drafts-mode) scripts in a more focused environment before committing them to a collaborator-shared repository.
### Live scripting
**Live Scripting** lets collaborators code together in real time. In the [Script Editor](../studio/script-editor.md), each collaborator's cursor color matches their assigned color in the [Live Collaborators](#view-collaborators) window.
<Grid container spacing={2}>
<Grid item>
<img src="../assets/studio/collaboration/Live-Scripting-Cursors.png" width="520" alt="Script Editor window showing cursors for two collaborators, colored according to their assigned color in the Live Collaborators window." />
</Grid>
<Grid item>
<img src="../assets/studio/collaboration/Live-Collaborators-Status.png" width="280" alt="Live Collaborators window with icons of current collaborators, as well as their activity status." />
</Grid>
</Grid>
While live scripting, edits are auto‑saved every 5 minutes just like place edits, and a collaborator can manually save a script at any time with <kbd>Ctrl</kbd><kbd>S</kbd> (<kbd>⌘</kbd><kbd>S</kbd>). Saved or auto‑saved versions are logged in the [Script History](#view-script-history) window.
<Alert severity="info">
Live Scripting is **enabled** by default. If you and your team prefer to collaborate on scripts in an environment similar to source control, explore [Drafts](#drafts-mode) mode.
</Alert>
### Drafts mode
Through **Drafts** mode, you can independently edit and test scripts without affecting the experience for others. After you finish drafting a script, you can [commit](#commit-drafts) it to the shared repository and use [collaborative testing](../studio/testing-modes.md#collaborative-testing) to test the committed version with others.
<Alert severity="warning">
Drafts Mode is **disabled** by default. To enable it, open Studio's **File**&nbsp;⟩ **Experience Settings** window, select the **Other** tab, and turn on **Enable Drafts Mode**.
Note that all collaborators will need to exit the session for the change to take effect. Alternatively, you can [disable collaboration](#disable-collaboration) and then reenable it to restart the session.
</Alert>
#### Commit drafts
Once you've edited a script, it appears in the **Drafts** window, a non‑default window which you must add to a [custom tab](../studio/ui-overview.md#custom-tabs) in Studio's toolbar.
<img src="../assets/studio/collaboration/Drafts-Window.png" alt="The Drafts window with two drafted script instances." width="360" />
Drafts are saved to your local file system and persist between Studio sessions on the same machine. To commit your local edits to the repository, left-click a script, or hold <kbd>Shift</kbd> and left-click to select multiple scripts. Then click **Commit** to commit all selected scripts.
<img src="../assets/studio/collaboration/Drafts-Commit.png" alt="The Drafts window with the Commit button highlighted." width="360" />
#### Compare and merge changes
If another collaborator commits changes to the same script that you're editing, an icon with a green **&CirclePlus;** symbol appears in the **Drafts** window. To view their changes, right‑click the script and select **Compare With Server**.
<img src="../assets/studio/collaboration/Drafts-Compare.png" alt="The Drafts window with the green plus icon highlighted to the left of a changed script, and the right-click popup window showing with the Compare With Server option highlighted." width="360" />
In the **(Diff)** tab that opens in the [Script Editor](../studio/script-editor.md), code that other collaborators changed or deleted appears in red, while code that you updated appears in green.
<img src="../assets/studio/collaboration/Drafts-Diff-Result.png" alt="A close up view of lines that were edited by different collaborators." width="800" />
To merge their changes into your script:
1. In the **Drafts** window, right‑click the script and select **Merge From Server**.
<img src="../assets/studio/collaboration/Drafts-Merge.png" alt="The Drafts window right-click popup window showing with the Merge From Server option highlighted." width="360" />
1. In the merge window, you can pick which code to keep, or make manual edits.
- Check **Draft** to keep your changes, or leave it unchecked to discard them.
- Check **Server** to merge the committed changes into your draft, or leave it unchecked to ignore them.
- Check **Other** to manually edit the script and save the changes to your draft.
1. Once you've previewed the merge resolution, click **Merge All** to update your local script.
#### Restore deleted scripts
If a collaborator deletes a script that you're editing, an icon with a red **&#8856;** symbol appears in the **Drafts** window. To restore the script, right‑click it and select **Restore Script**. Scripts are restored to the place's **Workspace** tree, so you may need to manually re‑parent them back to their original location.
<img src="../assets/studio/collaboration/Drafts-Restore.png" alt="The Drafts window with the red cross icon highlighted to the left of a deleted script, and the right-click popup window showing with the Restore Script option highlighted." width="360" />
### View script history
All script changes, whether saved by a collaborator, auto-saved, or committed by a collaborator through [Drafts](#drafts-mode) mode, are logged in the **Version History** window. To access it:
1. Right-click the script in the [Explorer](../studio/explorer.md) window and select **View Script History**.
2. In the **Version History** window that opens, you'll see all committed versions of the script, the commit date, which collaborator committed, and more. From this window, the following actions are possible:
<Tabs>
<TabItem label="Compare With Previous">
To compare any version (except the oldest) with its previous version, select it and click **Compare With Previous Version**. In the **(Diff)** tab that opens in the [Script Editor](../studio/script-editor.md), code from the newer version appears in green while code from the older version appears in red.
</TabItem>
<TabItem label="Compare Selected">
To compare any **two** versions, hold <kbd>Ctrl</kbd> or <kbd>⌘</kbd> and select both, then click **Compare Selected Versions**. In the **(Diff)** tab that opens in the [Script Editor](../studio/script-editor.md), code from the newer version appears in green while code from the older version appears in red.
</TabItem>
<TabItem label="Open">
If the version **Comment** indicates just one script was committed, select it and click **Open Script** to open it in the [Script Editor](../studio/script-editor.md).
If the version **Comment** indicates more than one script was committed (commonly the result of an auto‑save on multiple unsaved scripts), you can click **Show** within the version's row to open a popup displaying the script(s) and their respective version. Then, from the version history window, click **Open All Scripts From Batch** to open them in the [Script Editor](../studio/script-editor.md).
</TabItem>
</Tabs>
## Save and publish
During a collaborative session, Studio automatically saves the project to the cloud every four minutes.
## Revert to previous versions
The owner of an experience can revert changes made by other editors. See [here](../projects/configure-experiences.md#access-version-history) for instructions.
<Alert severity="error">
Be careful when reverting changes. If anyone is currently editing the experience in a collaborative session, their changes may still auto‑save and overwrite the revert action. To ensure that nobody else is editing the place when you revert, [disable collaboration](#disable-collaboration).
</Alert>
You might also want to check [Activity History](activity-history.md). This view provides a chronological event log that improves team visibility into key experience settings.
## Disable collaboration
**Team Create** is the core Studio feature that enables collaboration. Workflows that involve the [Manage Collaborators](#manage-collaborators) dialog will automatically enable the feature, but you can manually disable it if necessary.
1. If the [Live Collaborators](#view-collaborators) window isn't already open, click on any of the collaborator icons to open it.
<img src="../assets/studio/general/Toolbar-Current-Collaborators.png" width="800" />
2. In the bottom-right corner of the window, click the **&ctdot;** button and select **Disable Team Create**.
<img src="../assets/studio/collaboration/Live-Collaborators-Disable.png" width="280" />
3. When prompted, confirm ending the session to reload the place in a non‑collaborative state.

View file

@ -0,0 +1,113 @@
---
title: Configure experiences and places
description: Explains how to configure experiences.
---
You can configure most experience and place-level settings from the [Creator Dashboard][creatordashboard], a hub that lets you manage and access all of your Roblox creations in one place. It's useful to explore the left-hand navigation to see every configuration possible, such as those for [localization](../production/localization/index.md), [analytics](../production/analytics/index.md), and [monetization](../production/monetization/index.md), but the following sections highlight notable workflows for most experiences.
## Generate content descriptors
The **Maturity & Compliance Questionnaire** contains a set of questions about the type of content players can possibly encounter within your experience, as well as how frequently it occurs. Your answers give Roblox an understanding of the content in your experience and ensure that the experience is available to the appropriate audience on the [Home](https://www.roblox.com/home) and [Discover](https://www.roblox.com/discover) pages according to each player's age group and regional content policies.
For step-by-step instructions on how to fill out the questionnaire, see [content maturity & compliance](../production/promotion/content-maturity.md).
## Set age and geography restrictions
You can set restrictions so that only players over a certain age or from specific regions can play and discover your experiences. This is particularly helpful when you want to age up your audience without including mature content to age gate through content maturity labels.
To set age and geography restrictions:
1. Navigate to the [Creator Dashboard][creatordashboard].
1. Click on the thumbnail of the experience for which you want to set age and geography restriction. The experience's **Overview** page displays.
1. In the left-hand navigation, navigate to **Audience** ⟩ **Access Settings**.
1. In the **Age** section, set **Minimum age** to the youngest age a player can have to access your experience.
1. In the **Region** section, enable every region that can access your experience.
1. At the bottom of the page, click the **Save Changes** button.
## Copy landing page link
After you publish your experience, Roblox generates a landing page for the experience referred to as the experience's **main details page**. You can access and copy this link from either the [Creator Dashboard][creatordashboard] or the Roblox app, then share it with others so they can play your experience.
<Tabs>
<TabItem label="Creator Dashboard">
1. Hover over an experience's thumbnail, click the **&ctdot;** button, and select **Copy URL**.
<img src="../assets/creator-dashboard/Options-Button-Experience-Public.png" width="200" />
1. Share the copied URL with others as a direct link to the experience's landing page featuring a **play** button.
<img src="../assets/publishing/experiences-places-assets/Experience-Page-Example.jpg" width="1120" />
</TabItem>
<TabItem label="Roblox app">
1. Open the Roblox app on your mobile device.
1. Locate the experience, typically under the **Continue** header on the home screen, and tap its tile to open the info screen.
1. In the lower-left corner of the screen, click the **&ctdot;** button and select **Share** to open your device's sharing options.
<img src="../assets/promotion/misc/Experience-Mobile-Share.png" width="390" />
</TabItem>
</Tabs>
## Edit collaborator permissions
When creating and collaborating on experiences as part of a [group](./groups.md), abilities granted to group members are dependent on their **role permissions**. Owners or other group members with sufficient permissions can adjust play/edit/publish access and more on a per‑experience level, such as allowing a limited group role the ability to edit a specific experience even if that role cannot edit all experiences.
<Alert severity="info">
For step-by-step instructions on how to edit collaborator permissions, see [roles and permissions](./groups.md#roles-and-permissions).
</Alert>
## Access version history
Roblox automatically retains saved versions of each place for version control and backup purposes. To access and revert to a previously saved version of any place within an experience:
1. Navigate to the [Creator Dashboard][creatordashboard] and click on the thumbnail of the experience. The experience's **Overview** page displays.
1. In the left-hand navigation, navigate to **Configure** ⟩ **Places**.
1. On the **Places** page, click the thumbnail of the place you'd like to revert to a previous version.
1. In the left-hand navigation, click **Version History**.
1. Locate and select the version to revert to, then click the **Restore** button. Confirm the action to restore to that version.
<Alert severity="warning">
Note that restoring a place to a previous version does **not** automatically publish the changes. If the place has been [released to the public](../production/publishing/publish-experiences-and-places.md#make-experience-public) and you want to overwrite its live/public version with the reverted version, open the place in Studio, publish it, and then [restart your servers](./update-experiences.md#restart-servers) for updates.
</Alert>
## Allow copying
By default, all private and public experiences are locked so that you or your [group](./groups.md) are the only creators who have permission to edit its place files. However, if you want to allow other creators to be able to access an editable copy of your experience for their own creation process, you can **uncopylock** the experience. This is particularly helpful when you create templates or reference files for open use.
To allow the community to access an editable copy of your experience:
1. Navigate to the [Creator Dashboard][creatordashboard].
1. Click on the thumbnail of the experience you want to allow players to copy. The experience's **Overview** page displays.
1. In the left-hand navigation, navigate to **Configure** ⟩ **Places**.
1. Click the **start place** marked with a star icon. The place's **Basic Settings** page displays.
<img src="../assets/creator-dashboard/Places-Start-Place-Icon.png" width="200" alt="Start place tile indicated in Places display on the Creator Dashboard" />
1. In the place's left-hand navigation menu, select **Permissions**.
1. Enable **Allow users to download a copy of this Place**.
1. Click the **Save Changes** button. Your experience is now uncopylocked and creators can access an editable copy of it from the experience's main page by clicking the **&ctdot;** button and selecting **Edit in Studio**.
<img src="../assets/publishing/experiences-places-assets/Edit-Place-In-Studio.jpg" width="780" />
## Allow strong language
You can enable strong language and relax the text chat filter in your experiences for older players audiences. Doing so also adds a tag above your experience page to warn other players that your experience may include strong language:
<img src="../assets/publishing/experiences-places-assets/Maturity-Label-Strong-Language.jpg" width="780" alt="Label indicating the experience contains strong language" />
Regardless of whether or not you activate the toggle, players do not face moderation consequences just for using strong language in chat or voice in experiences with Restricted content maturity labels, but they cannot violate [Community Standards](https://en.help.roblox.com/hc/en-us/articles/203313410#safety) and [Terms of Use](https://www.roblox.com/info/terms). For example, players can type an expletive if they are scared by a monster, but they cannot abuse another player using strong language or otherwise.
<Alert severity="warning">
In-experience assets and experience metadata cannot contain strong language, even if the toggle is on and your experience has a Restricted content maturity label. If you include strong language in your assets or experience page, your experience will be moderated.
</Alert>
To allow strong language between players in text chat within your experience:
1. Navigate to the [Creator Dashboard][creatordashboard] and click on the thumbnail of the experience in which you want to allow strong language. The experience's **Overview** page displays.
1. In the left-hand navigation, navigate to **Audience** ⟩ **Communication Settings**.
1. Enable the **Allow Strong Language** toggle, then press the **Save Changes** button. Players within your experience can now use strong language in text chat.
[creatordashboard]: https://create.roblox.com/dashboard/creations

View file

@ -0,0 +1,173 @@
---
title: Cross-platform development
description: Consolidated overview of cross-platform recommendations to help you design a Roblox experience that's accessible and enjoyable on all platforms.
---
import BetaAlert from '../includes/beta-features/beta-alert.md'
Roblox is inherently **cross‑platform**, as players can discover and join experiences on their phone or tablet, then later continue where they left off on their PC or console. To support an expanding suite of platforms, you should build user interfaces that seamlessly adapt to the input type (touch, gamepad, mouse/keyboard), screen size, and device orientation. This guide, the [adaptive design](../production/publishing/adaptive-design.md) guide, and the linked resources can help you design a true cross‑platform experience that's compatible, accessible, and enjoyable on **all** platforms.
<Alert severity="info">
To explore a pre-made experience that showcases the following cross‑platform design concepts, check out the [Interactivity Showcase](https://www.roblox.com/games/132115384567250/).
</Alert>
## Input
A carefully designed experience should support all primary input types, including mouse and keyboard, touch, and gamepads.
### Cross-platform actions
<Alert severity="success">
Support all primary input types (mouse/keyboard, touch, and gamepads) using the [Input Action System](../input/input-action-system.md).
</Alert>
To simplify cross‑platform inputs, Roblox provides the [Input Action System](../input/input-action-system.md) to define **actions** such as "jump," "sprint," or "shoot" and set up **bindings** for multiple hardware inputs to drive those actions. You do not need to think about all the technical aspects of hardware inputs and when to listen for specific input triggers; you simply define which inputs perform which actions.
<img src="../assets/publishing/cross-platform/Input-Actions-Jump.png" />
### Input type detection
<Alert severity="success">
Ensure that UI elements respond and adapt to the player's **primary** input type as detailed in [input type detection](../input/index.md#input-type-detection). Also consider [assistive hints](#assistive-hints) to help players understand specific input changes.
</Alert>
In cross-platform development, it's important that you determine and respond to the primary input type a player is using, normally to ensure that [UI elements](../ui/index.md#ui-objects) like on‑screen buttons and menus work elegantly and support interaction across devices.
For example, a touch‑enabled device assumes touch is the **default** input and that touch buttons may appear for actions, but a player may choose to connect a bluetooth gamepad. In this case, touch remains a valid input, but you can assume the player wants to switch to the connected gamepad as the **primary** input type and possibly use touch as a backup input for on‑screen UI.
### Assistive hints
Based on the [primary input type](#input-type-detection), it's recommended that you include **assistive UI hints** whenever possible. For example, when selecting tools to equip, display input‑specific hints such as <kbd>1</kbd>–<kbd>5</kbd> when the player is using a keyboard, or gamepad trigger hints when the player is using a gamepad.
<Tabs>
<TabItem label="Keyboard Input">
<img src="../assets/publishing/cross-platform/Inventory-Selection-Keyboard.jpg" width="840" height="473" />
</TabItem>
<TabItem label="Gamepad Input">
<img src="../assets/publishing/cross-platform/Inventory-Selection-Gamepad.jpg" width="840" height="473" />
</TabItem>
</Tabs>
The `Class.UserInputService:GetImageForKeyCode()|GetImageForKeyCode()` and `Class.UserInputService:GetStringForKeyCode()|GetStringForKeyCode()` methods are helpful in gathering a platform‑specific image or string to use in a UI hint, such as the following examples:
<table>
<thead>
<tr>
<th>Key Code</th>
<th>Xbox Image</th>
<th>PlayStation Image</th>
<th>String</th>
</tr>
</thead>
<tbody>
<tr>
<td>`Enum.KeyCode.ButtonA`</td>
<td><img src="../assets/publishing/cross-platform/ButtonA-Xbox.png" width="24" style={{marginBottom: 0, paddingBottom: 0}} /></td>
<td><img src="../assets/publishing/cross-platform/ButtonA-PS.png" width="24" style={{marginBottom: 0}} /></td>
<td>`ButtonA`</td>
</tr>
<tr>
<td>`Enum.KeyCode.ButtonX`</td>
<td><img src="../assets/publishing/cross-platform/ButtonX-Xbox.png" width="24" style={{marginBottom: 0}} /></td>
<td><img src="../assets/publishing/cross-platform/ButtonX-PS.png" width="24" style={{marginBottom: 0}} /></td>
<td>`ButtonX`</td>
</tr>
<tr>
<td>`Enum.KeyCode.One`</td>
<td>n/a</td>
<td>n/a</td>
<td>`1`</td>
</tr>
<tr>
<td>`Enum.KeyCode.Five`</td>
<td>n/a</td>
<td>n/a</td>
<td>`5`</td>
</tr>
</tbody>
</table>
## User interface
A well-designed user interface is essential for players on all platforms to interact with your experience.
### Position and size
<Alert severity="success" style={{marginBottom: 8}}>
Ensure that all UI elements are visible on all screen sizes and orientations.
</Alert>
<Alert severity="success">
Ensure that all buttons/controls are interactable and that they are not blocked or obscured by [device cutouts or Roblox UI elements](../ui/position-and-size.md#cross-platform-factors).
</Alert>
All UI elements should be [positioned](../ui/position-and-size.md#position) and [sized](../ui/position-and-size.md#size) appropriately to ensure visibility and interactivity across multiple screen sizes. Positioning UI elements by `Datatype.UDim.Scale|Scale` is a common approach since it's based on a **percentage** of the screen's **X** and **Y** bounds, not a pixel value (pixels can vary arbitrarily by both number and density across devices). You can also utilize the element's `Class.GuiObject.AnchorPoint|AnchorPoint` to set its positional origin. For example, the UI container holding the gem/coin counters in the following image is positioned at an **X** scale of `1` (right) and **Y** scale of `0` (top) with an upper‑right anchor point.
<img src="../assets/publishing/cross-platform/Position-Scale.jpg" width="840" />
`Datatype.UDim.Scale|Scale` is also recommended for **sizing** UI elements, such as making a UI container span 75% width on every screen. However, 75% would render to a huge size on 4K&nbsp;TVs for console players, so it's recommended that you explore [screen size adaptation](#screen-size-adaptation) as a way to adapt UI layouts across different viewports.
### Screen size adaptation
<Alert severity="success">
Adapt UI to various display sizes by checking and listening for changes to the viewport display size.
</Alert>
With a multitude of possible screen sizes accessible to the Roblox platform, attempting to predict screen size by pixels often leads to misinterpretation. To assist in determining a player's screen size to adapt the size/position of UI elements, Roblox provides the read‑only `Class.GuiService.ViewportDisplaySize|ViewportDisplaySize` property which represents the internally‑categorized rendering size of the viewport.
<table>
<thead>
<tr>
<th>`Class.GuiService.ViewportDisplaySize|ViewportDisplaySize`</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
<tr>
<td>`Enum.DisplaySize.Small|Small`</td>
<td>Most tablet/mobile/handheld devices</td>
</tr>
<tr>
<td>`Enum.DisplaySize.Medium|Medium`</td>
<td>Most laptops and monitors</td>
</tr>
<tr>
<td>`Enum.DisplaySize.Large|Large`</td>
<td>Most TVs or larger</td>
</tr>
</tbody>
</table>
For more native customization, you can use the UI [Style Editor](../ui/styling/editor.md) to configure [themes](../ui/styling/editor.md#style-themes) for the various `Class.GuiService.ViewportDisplaySize|ViewportDisplaySize` values, including tokens for text sizes, container sizes, and any other sizing/measurement tokens to suit your needs.
<img src="../assets/publishing/cross-platform/Screen-Size-Themes.png" width="840" />
### Layout containers
<Alert severity="success">
Use layouts to organize individual UI components and ensure that containers adjust responsively to the children elements within them.
</Alert>
For easier UI organization, you should use **layout components** to organize children. When using layout [containers](../ui/frames.md), make sure that the children are legible, [accessible](#accessibility), and non‑cluttered. A common layout component is `Class.UIListLayout`, which positions sibling `Class.GuiObject|GuiObjects` into rows or columns and adjusts accordingly whenever you add or remove a sibling object.
You should also consider the distribution and relative positioning of elements within layout containers for the best user experience. Integrating [flex](../ui/list-flex-layouts.md#flex-layouts) into a list layout is a powerful way to [equally fill/distribute](../ui/list-flex-layouts.md#equal-fill-or-distribution) or [align/stretch](../ui/list-flex-layouts.md#alignment) items across their line, or [flex specific items](../ui/list-flex-layouts.md#flex-individual-items) across a variable space.
<img src="../assets/engine-api/classes/UIListLayout/FillDirection.png" width="720" alt="UIListLayouts illustrating FillDirection of either horizontal or vertical." />
### Accessibility
<Alert severity="success">
Ensure that all text is legible on all screens. Also make sure all UI has [sufficient contrast](../production/publishing/accessibility.md#color-contrast) and that [nothing relies solely on color](../production/publishing/accessibility.md#color-non-reliance) to distinguish an action or outcome.
</Alert>
Even with UI elements [properly sized](#position-and-size) across all device screen sizes, the overall experience should meet [accessibility standards](../production/publishing/accessibility.md) for players with impaired vision or color blindness. Text size can factor heavily into the legibility of text‑based UI, so you should include a [text size constraint](../ui/size-modifiers.md#text-size) to ensure text doesn't become illegible (too&nbsp;small) or visually too large on larger screens like 4K&nbsp;TVs.
For more tips on accessibility, see [here](../production/publishing/accessibility.md).
## Final tips & tricks
As you work toward a full cross‑platform experience, consider the following tips and tricks:
- Device emulation is essential to designing an optimal experience on Roblox. Utilize the built‑in [Device Emulator](../studio/testing-modes.md#device-emulation) and [Controller Emulator](../studio/testing-modes.md#controller-emulation) to emulate various devices and gamepads directly in Studio.
- Roblox's [UI styling](../ui/styling/index.md) pipeline, similar to CSS, lets you declare and globally apply overrides to UI instance properties. Along with the integrated [Style Editor](../ui/styling/editor.md), you can set up a complete and easy‑to‑modify user interface.
- Once your experience is effectively cross-platform, explore native features like haptic feedback on [mobile](../input/mobile.md#haptic-feedback) and [gamepads](../input/gamepad.md#haptic-feedback), touch gestures such as `Class.UserInputService.TouchSwipe|TouchSwipe` and `Class.UserInputService.TouchPinch|TouchPinch`, or accelerometer and gyroscope functionality on `Class.UserInputService.AccelerometerEnabled|AccelerometerEnabled` and `Class.UserInputService.GyroscopeEnabled|GyroscopeEnabled` devices.

View file

@ -0,0 +1,335 @@
---
title: Data model
description: Explains the hierarchy of objects that describe everything about a place.
---
<iframe width="800" height="450" src="https://www.youtube-nocookie.com/embed/3Q0R1-Xkw9U" title="YouTube video player" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<br />
Every place is represented by a data model, a hierarchy of objects that describe
everything about the place. The data model contains all objects that make up the
3D world, such as parts, terrain, lighting, and other environmental elements. It
also contains objects that can control runtime behavior, such as scripts that
modify properties, call methods and functions, and respond to events that enable
dynamic behavior and interactivity.
The Roblox Engine uses the data model as a source of truth for a place's state,
so it can simulate and render it on client devices. For more information on how
the Roblox Engine interprets the data model, see [Client-Server
Runtime](/projects/client-server).
## Objects
<iframe width="800" height="450" src="https://www.youtube-nocookie.com/embed/FzmFAm00A8g" title="YouTube video player" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<br />
You place and organize objects in the data model to describe a place in Roblox.
Every object in Roblox inherits from the `Class.Instance` class, which defines
generic properties, methods, and events that are common to all objects. Objects
also define their own characteristics depending on the functionality the object
provides. There are many categories of objects with a wide variety of uses, but
you'll frequently work with `Class.BasePart` and `Class.LuaSourceContainer`
objects, commonly referred to as parts and scripts.
For a comprehensive list of all the features of the Roblox Engine, see the
[reference documentation](/reference/engine).
### 3D building blocks
`Class.BasePart` is the core class for physically-simulated 3D building blocks in the world. It defines the properties and methods common to all physical objects with properties like position, size, and orientation.
<table>
<thead>
<tr>
<th>Object</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>`Class.Part`</td>
<td>A primitive [part](../parts/index.md) that can take the shape of a block, ball, cylinder, wedge, or corner wedge.</td>
</tr>
<tr>
<td>`Class.MeshPart`</td>
<td>An imported [mesh](../parts/meshes.md) from 3D modeling software like Maya or Blender.</td>
</tr>
<tr>
<td>`Class.TrussPart`</td>
<td>A truss beam that characters can climb like a ladder.</td>
</tr>
</tbody>
</table>
While you can theoretically create a fully functional Roblox experience using
just simple parts, you'll most likely import [meshes](../parts/meshes.md) and combine primitive parts into more complex objects and structures through [solid
modeling](/parts/solid-modeling).
### Scripts
You can add interactivity and behavior to your place's 3D world and define logic
with scripts. You write scripts in the Luau programming language to do things
like moving parts, calling other scripts, and responding to events. Because
Roblox works in a client-server model, you can run scripts on the server,
client, or have them communicate across the network boundary.
- A `Class.Script` object represents a script that can only run on the server.
- A `Class.LocalScript` object represents a script that can only run on the
client.
- A `Class.ModuleScript` object represents a reusable script that you can
`Global.LuaGlobals.require()` from both
server and client scripts.
For scripts to behave properly, you must place them in the correct containers in
the data model. For more information, see the [Server](#server) and [Client](#client) sections.
## Object organization
While you have a lot of flexibility in how you organize your data model, the
Roblox Engine expects certain objects to be in certain **container services**
which are objects that have specific behaviors and can affect the behaviors of
the objects they contain. The main categories of container services include:
- **Workspace** — `Class.Workspace` stores all objects that render in the 3D
world.
- **Environment** — Containers like `Class.Lighting` and `Class.SoundService`
that contain objects for environmental settings and elements.
- **Replication** — Containers for content and logic that replicates between the
server and client, such as `Class.ReplicatedStorage` and
`Class.ReplicatedFirst`.
- **Server** — Containers for server-side only content and logic, such as
`Class.ServerScriptService` and `Class.ServerStorage`.
- **Client** — Containers for client-side content and logic, such as
`Class.StarterPlayer` and `Class.StarterGui`.
- **Chat** — Containers for objects that enable chat features, such as
`Class.VoiceChatService` and `Class.TextChatService`.
<Alert severity="info">
The Roblox Engine has many more services that provide
built-in functionality that you can call within your scripts. The Roblox Engine
doesn't give these services special treatment in the data model. For more
information, see [services](../scripting/services.md).
</Alert>
In addition, you can further organize your objects with the following objects:
- **Folders** — A `Class.Folder` is for organizational purposes and doesn't
define any behavior. For example, you can use folders to group similar objects
like a set of scripts in server storage.
- **Models** — A `Class.Model` is mainly intended for geometric groupings of
parts, such as grouping together a desk set that includes a chair, table, and
a lamp. To organize more complex sets, you can even nest models within models.
### Workspace
`Class.Workspace` contains all objects that make up a place's 3D world. You can
add objects to the workspace to customize your 3D world, such as base parts,
mesh parts, and models. Clients render everything that appears in this container
and nothing outside of it, so you can control what users see and interact with
in your place. Although not actually rendered, you can also add scripts that are
parented to the parts and models that they are associated with. By default, the
workspace is pre-populated with a `Class.Terrain` and `Class.Camera` object.
<h4>Camera</h4>
`Class.Camera` determines how the client views the 3D world. By default, there
is one camera in the workspace, but you can add multiple camera objects for
creating different perspectives and views. Every client takes these settings and
creates its own camera view that the server can't directly modify.
For example, you can set a camera to follow user movements or stay fixed in a
particular location. You can also adjust the field of view, distance, and angle
to create different visual effects of how users view your 3D world.
For more information, see [customize the camera](../workspace/camera.md).
<h4>Terrain</h4>
`Class.Terrain` lets you create landscapes for your place. You can apply a
material to the terrain to simulate desired natural environments, such as grass,
water, sand, or a custom material. Though you can only have one terrain object
for your 3D world and apply one material to that terrain, you can use the
[Terrain Editor](../studio/terrain-editor.md) to edit regions of your
terrain.
For more information, see [environmental terrain](../parts/terrain.md).
### Environment
Custom lighting can make your 3D world much more immersive and realistic. The `Class.Lighting` service contains objects that control global lighting settings of your place, such as `Class.Atmosphere` for simulating atmospheric effects or `Class.Sky` to alter the sun, moon, and stars in your environments. In addition, you can use [light sources](../effects/light-sources.md) to emit light from specific objects.
Adding [audio](../audio/index.md) to your experiences is also crucial for elevating your experiences to new heights. By strategically using positional and non-positional audio, you can immerse players into your worlds, provide them useful feedback for their actions, and direct their attention to what they need to do to be successful in their objectives.
### Replication
**Replication** is the process of the server synchronizing the state of your
place with all connected clients. The Roblox Engine intelligently and
automatically replicates data, physics, and chat messages between the server and
client for many cases, but you can also specify certain objects to replicate by
placing them in specific containers.
<h4>ReplicatedFirst</h4>
`Class.ReplicatedFirst` contains objects that you want to replicate to a client
when it joins your place. It typically contains objects that are essential to
initialize a player, such as client-side `Class.LocalScript` objects and the
objects associated with the scripts. All content in this container is replicated
from the server to the client only once.
<h4>ReplicatedStorage</h4>
`Class.ReplicatedStorage` contains objects that are available to both the server
and connected clients. Any changes that occur on the client persist but won't be
replicated to the server. The server can overwrite changes on the client to
maintain consistency. This container is typically used for `Class.ModuleScript`
objects that need to be shared and accessed by both `Class.Script` (server-side)
and `Class.LocalScript` (client-side) objects. In addition, you can use this
container to replicate any objects that don't need to exist in the 3D world
until needed, such as a `Class.ParticleEmitter` for cloning and parenting to all
incoming character models.
For more information on how replication works, see [client-server runtime](../projects/client-server.md).
### Server
The data model defines dedicated containers for server-side only objects that
are never replicated to the client. This allows the server to affect client
behavior and state without exposing the server's objects and logic to the
client.
<Alert severity="info">
You can use remote events and functions to allow
client-side communication with the server.
</Alert>
<h4>ServerScriptService</h4>
`Class.ServerScriptService` contains `Class.Script` objects,
`Class.ModuleScript` objects that are required by server scripts, and other
scripting-related objects that are only meant for server use. If your scripts
require other, non-scripting objects, you must place them in
`Class.ServerStorage`. Scripts in this container are never replicated to
clients, which allows you to have secure, server-side logic.
<h4>ServerStorage</h4>
`Class.ServerStorage` contains objects that are only meant for server use. You
can use this container to store objects that you want to clone and parent to the
workspace or other containers at runtime. For example, you can store large
objects such as maps in this container until they are needed and move them into
the workspace only when required. This lets you decrease client network traffic
on initial join.
<Alert severity="info">
Scripts don't run when they are parented to this
container, but scripts inside `Class.ServerScriptService` can access and run
`Class.ModuleScript` objects in this container.
</Alert>
### Client
The client container services are meant for objects that are replicated to every
connected client. This category of containers replicate to every connected
client and typically contain 3D objects and associated `Class.LocalScript`
objects. All objects you store in these containers are non-persistent across
sessions and reset every time a client rejoins. You can put objects in these
containers such as player GUIs, client-side scripts, and other objects that are
only relevant to the client.
When a client connects to a server, the `Class.Players` container service
listens for users joining your place and creates a `Class.Player` object for
every client. The server copies the objects from the client containers in the
edit data model to the corresponding location in the runtime data model inside
the `Class.Players` object. The following table describes the original container
it resides on in the container and the resulting container they are copied to on
the client:
<table>
<thead>
<tr>
<th>Edit data model</th>
<th>Runtime data model</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>`Class.StarterPack`</td>
<td><code>Player.Backpack</code></td>
<td>Scripts that set up the player's inventory and generally contain `Class.Tool` objects but often contains local scripts as well.</td>
</tr>
<tr>
<td>`Class.StarterGui`</td>
<td><code>Player.PlayerGui</code></td>
<td>Scripts that can manage the player's local GUI. When a player respawns, the contents of PlayerGui are emptied. The server copies the objects inside StarterGui into the PlayerGui.</td>
</tr>
<tr>
<td>`Class.StarterPlayerScripts`</td>
<td><code>Player.PlayerScripts</code></td>
<td>General purpose scripts for the client. For example, if you want to create special effects on the client when certain conditions are met, you can place a local script in this container to do that. The server cannot access this container.</td>
</tr>
<tr>
<td>`Class.StarterCharacterScripts`</td>
<td><code>Player.Character</code></td>
<td>Scripts that are copied to the client when they spawn. These scripts do not persist when the player respawns.</td>
</tr>
<tr>
<td>`Class.ReplicatedFirst`</td>
<td></td>
<td>The contents of this container are replicated to all clients (but not back to the server) first, before anything else.</td>
</tr>
</tbody>
</table>
<Alert severity="info">
For more information on edit and runtime data models, see [client-server runtime](./client-server.md#client).
</Alert>
<Alert severity="warning">
You don't add `Class.Player` objects to the `Class.Players` container
service explicitly.
</Alert>
### Chat
<h4>TextChatService</h4>
`Class.TextChatService` represents the service that handles various,
in-experience text chat tasks, such as managing channels, decorating messages,
filtering text, creating commands, and developing custom chats interfaces.
For more information, see [text chat overview](../chat/in-experience-text-chat.md).
<h4>VoiceChatService</h4>
`Class.VoiceChatService` represents the proximity-based voice chat
feature that simulates realistic communication based on how close you are to
other users. You can use this service to toggle the feature on and off.
For more information, see [voice chat](../chat/voice-chat.md).
## Folders and models
There are two primary methods for grouping objects in the data model:
**folders** and **models**. Both are containers for objects, but they have
different purposes.
- **Folders** are best for storing sections of an environment, such as the lobby or a combat arena.
- **Models** are used for sets of objects, such as a desk set that includes a chair,
table, and a lamp. To organize more complex sets, nest models inside models.
You should always name your objects descriptively. This makes it easy to
find and modify objects later on if needed.
<GridContainer numColumns="2">
<figure>
<img src="../assets/studio/explorer/Example-Organized-Folders-In-Workspace.png" alt="The Explorer window with a demonstration of a folder organization structure." width="320" />
<figcaption>Objects organized into `Class.Folder|Folders`</figcaption>
</figure>
<figure>
<img src="../assets/studio/explorer/Example-Maps-In-Workspace-ServerStorage.png" alt="The Explorer window with a demonstration of a model organization structure in several services." width="320" />
<figcaption>Various "map" models to swap between `Class.Workspace` and `Class.ServerStorage`</figcaption>
</figure>
</GridContainer>

View file

@ -0,0 +1,121 @@
---
title: Experience ownership transfer
description: Transfer ownership of an experience to other Roblox users or groups.
---
With **experience ownership transfer**, you can transfer your experiences to [groups](./groups.md) you have publish access to. This unlocks all of the features available to groups, including permissions and revenue management, and allows you to efficiently manage your content as your team scales and your priorities shift.
## Prerequisites
Before making a transfer or accepting a transfer, you must first:
- Verify your email address.
- Upload your private `Class.ModuleScript|ModuleScripts` and `Class.InsertService|InsertService` asset usages to the group you're transferring the experience to. If the experience uses packages where the package owner is a user and not a group, you might have to recreate those packages or replace them with packages that are already owned by a group.
<Alert severity="info">
As a best practice, if you're using Open Cloud API keys for the experience, create an API key as the new owner with the name `RobloxTransferApiKey`. During the transfer, the relevant scopes are added to this new key and removed from the original key. You can then use a feature flag to allow your backend services to start using the new key after the transfer is complete.
</Alert>
## Transfer an experience
To transfer an experience to a group:
1. Go to [Creations](https://create.roblox.com/dashboard/creations) and choose the experience you want to transfer.
2. Go to **Configure** ⟩ **Settings**.
3. Click **Initiate ownership transfer**.
4. In the **Transfer Details** dialog, carefully read and acknowledge the implications of the transfer. Then, click **Next**.
5. Select a group to transfer the experience to. You must be able to publish experiences to this group.
6. Verify the transfer by entering the experience name.
7. Click **Initiate transfer**. The **Content Settings** page updates to include the pending group's username.
<Alert severity="warning">
Once the group accepts the transfer, Roblox makes your experience private and closes all servers associated with it. The transfer process typically completes in a few minutes but may take longer for complex experiences.
</Alert>
<Alert severity="info">
To cancel a pending transfer, click **Cancel transfer request** in the **Content Settings** page.
</Alert>
## Receive a transferred experience
To receive a transferred experience:
1. Go to the experience page of the experience you're receiving. You can navigate to this page by clicking the transfer request notification you received when the experience's current owner initiated the transfer, or by directly getting the overview page link from the current owner.
2. In the **Transfer Details** dialog, carefully read and acknowledge the implications of the transfer. Then, click **Next**.
3. Verify the transfer by entering the experience name.
4. Click **Accept transfer**.
<Alert severity="warning">
Once your group accepts the transfer, Roblox makes the experience private and closes all servers associated with it. The transfer process typically completes in a few minutes but may take longer for complex experiences.
</Alert>
5. After the transfer to your group is complete, set up any new permissions you need and make the experience public again.
## Frequently asked questions
<BaseAccordion>
<AccordionSummary>
<Typography variant="subtitle2">What kind of information does the transferred experience retain?</Typography>
</AccordionSummary>
<AccordionDetails>
The transferred experience retains its old experience ID, place ID, and URL.
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary>
<Typography variant="subtitle2">Do transfer requests expire?</Typography>
</AccordionSummary>
<AccordionDetails>
Yes, transfer requests expire after 7 days.
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary>
<Typography variant="subtitle2">How often can the same experience be transferred?</Typography>
</AccordionSummary>
<AccordionDetails>
After receiving a transferred experience, you must wait 30 days to transfer that experience again.
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary>
<Typography variant="subtitle2">Can changes be made to an experience that's transferring?</Typography>
</AccordionSummary>
<AccordionDetails>
You can continue making changes to the experience until the new group owner accepts the transfer and the transfer process begins. Changes you make during the active transfer process specifically aren't carried over.
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary>
<Typography variant="subtitle2">What happens to credit card information when an experience is transferred?</Typography>
</AccordionSummary>
<AccordionDetails>
Roblox removes credit card information when you transfer an experience.
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary>
<Typography variant="subtitle2">What happens to revenue from private server subscriptions when an experience is transferred?</Typography>
</AccordionSummary>
<AccordionDetails>
The group you transferred your experience to receives the revenue from any existing private server subscriptions. This revenue does not respect any group or experience revenue splitting.
New private server subscriptions respect revenue splitting.
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary>
<Typography variant="subtitle2">Does transferring an experience impact discovery?</Typography>
</AccordionSummary>
<AccordionDetails>
Transferring an experience doesn't impact search as long as the experience title remains the same, the new group owner is not a moderated account, and the experience is made public again after the transfer.
Note that transferring an experience can impact discovery for up to 24 hours after the new group owner makes the experience public again.
</AccordionDetails>
</BaseAccordion>

View file

@ -0,0 +1,163 @@
---
title: Third-party tools
description: These popular tools for managing Roblox projects as a set of local files can enhance developer productivity.
---
For professional development studios, setting up third-party tools and investing in automation can dramatically improve developer productivity. Roblox's cloud-first approach has many advantages, but moving certain portions of the development workflow **outside** of the cloud can help larger teams track changes over time, review code, and use the languages and tools with which they're already familiar.
- If you just want to use an external text editor or keep code in version control, [Script Sync](../scripting/sync.md) is a great choice.
- If you want to manage your entire project as a set of local files, this page covers some tools and strategies.
<Alert severity="info">
Although this page covers several popular tools, it shouldn't be taken as a strict recommendation of them. Every team has different needs, so this page is intended to help you examine ways to improve your workflow rather than tell you to download anything in particular.
The tools on this page are not maintained by Roblox and can change or stop working at any time.
</Alert>
## The syncing problem
At its core, using external tools with Roblox is a _syncing_ problem:
- You want your Roblox instances to exist as files on disk so that you can use your own tools to work on them.
- You have to get your files back into your Roblox project after you've finished working on them.
- If someone else changed those same files in the meantime, you have to handle any conflicts.
For the whole solution to feel seamless and automatic, you need to a) listen for changes to files and b) incorporate these changes back into Studio.
Rather than Roblox's cloud-first approach, Rojo allows for a "file system-first" approach. It extracts instances in your project into external files. Then it runs a server. The Rojo plugin connects to the server to synchronize those files with Studio.
## Install Rojo with Foreman
You can manually download and run a Rojo binary, but that approach runs the risk of different developers on your team using different Rojo versions. A better solution is to use a tool manager like [Foreman](https://github.com/Roblox/foreman), which uses a configuration file—a list of repositories and versions—to make the installation and upgrade process consistent across machines.
Because it manages your baseline development environment rather than the packages within your project, Foreman is more akin to [nvm](https://github.com/nvm-sh/nvm) than [npm](https://www.npmjs.com/), but the comparison isn't perfect. A simple `foreman.toml` file looks like this:
```toml
[tools]
rojo = { github = "rojo-rbx/rojo", version = "7.4.1" }
wally = { github = "UpliftGames/wally", version = "0.3.2" }
```
Then you install these tools with `foreman install`. In addition to a global `foreman.toml` file, Foreman supports per-project files, so you can easily use different versions of Rojo, Wally, or any other tool for different projects and keep your entire team on those same versions.
When a tool releases a new version, you then explicitly bump the version number in your `.toml` file, use Foreman to perform the upgrade, test the new version, and downgrade if it causes any problems. For commands and installation instructions, see [Foreman](https://github.com/Roblox/foreman?tab=readme-ov-file#installation).
## Run Rojo
After you install Rojo with Foreman, what you've really installed is the Rojo server. The next step is to install the Rojo plugin for Roblox Studio:
```bash
rojo plugin install
```
Then generate the project structure for your new experience and build it:
```bash
rojo init my-new-experience
cd my-new-experience
rojo build -o my-new-experience.rbxl
```
Alternatively, you can [port an existing experience](https://rojo.space/docs/v7/getting-started/existing-game/). Either way, after you have a project, start the Rojo server:
```bash
rojo serve
```
In Roblox Studio, open the `.rbxl` file you just built, start the Rojo plugin, and connect to your now-running server, at which point you can start making changes in your preferred text editor and watch those changes automatically sync back to Studio.
![Visual Studio Code with a Rojo project open.](../assets/scripting/external-tools/external-tools-vscode.png)
![The Rojo plugin and Studio Explorer side-by-side.](../assets/scripting/external-tools/external-tools-rojo-plugin.png)
Rojo projects have certain naming requirements for files, numerous configuration options, and some limitations, all of which are covered in the [Rojo documentation](https://rojo.space/docs/v7/).
## Package managers
Roblox has a robust set of included APIs, but if you want to make use of community software packages in a consistent, reproducible way, you need a package manager. [Wally](https://wally.run/) is a popular option. You can install it through Foreman, just like Rojo.
Within your experience's Rojo directory, run `wally init`. Then add your desired packages to `wally.toml`. The file might look like this:
```toml
[package]
name = "my-home-directory/my-new-experience"
version = "0.1.0"
registry = "https://github.com/UpliftGames/wally-index"
realm = "shared"
[dependencies]
react = "jsdotlua/react@17.1.0"
react-roblox = "jsdotlua/react-roblox@17.1.0"
cryo = "phalanxia/cryo@1.0.3"
```
Then run `wally install`. Wally creates a `Packages` directory and downloads the specified packages there. The final step is to add the `Packages` directory to Rojo so that its contents sync back to Roblox. Open `default.project.json` and add the path. For simplicity, this example adds the entire directory to `Class.ReplicatedStorage` so that all packages are available to all scripts, but you might prefer to add specific packages to `Class.ServerScriptService` or `Class.StarterPlayerScripts`:
```json
{
"name": "my-new-experience",
"tree": {
"$className": "DataModel",
"ReplicatedStorage": {
"Shared": {
"$path": "src/shared"
},
"Packages": {
"$path": "Packages"
}
},
...
}
}
```
Then you can require packages within your scripts just like any other `Class.ModuleScript`:
```lua
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local React = require(ReplicatedStorage.Packages.react)
local ReactRoblox = require(ReplicatedStorage.Packages["react-roblox"])
local handle = Instance.new("ScreenGui", Players.LocalPlayer.PlayerGui)
local root = ReactRoblox.createRoot(handle)
local helloFrame = React.createElement("TextLabel", {
Text = "Hello World!",
Size = UDim2.new(0, 200, 0, 200),
Position = UDim2.new(0.5, 0, 0.5, 0),
AnchorPoint = Vector2.new(0.5, 0.5),
BackgroundColor3 = Color3.fromRGB(248, 217, 109),
Font = Enum.Font.LuckiestGuy,
TextSize = 24
})
root:render(helloFrame)
```
Like most other software projects, the goal is that contributors can clone a repository, install Foreman, run a few commands, and have the same development environment as the rest of the team.
<Alert severity="success">
For a detailed walkthrough of using React to create a Roblox UI, see [React + Roblox](https://devforum.roblox.com/t/how-to-react-roblox/2964543).
</Alert>
## Version control
Having a set of plain text files on your computer unlocks a variety of capabilities, but the primary one is _version control_. You can store your files in a [Git](https://git-scm.com/) or [Mercurial](https://www.mercurial-scm.org/) repository; host remote repositories and review code changes in [GitHub](https://github.com), [GitLab](https://gitlab.com), or [Bitbucket](https://bitbucket.org); and use whichever text editor you like.
[Visual Studio Code](https://code.visualstudio.com) and [Cursor](https://cursor.com) have the largest extension ecosystem, but [Sublime Text](https://www.sublimetext.com) and [Notepad++](https://notepad-plus-plus.org), and [Vim](https://www.vim.org) are all popular choices. Whichever editor you choose, matching the capabilities of the Studio script editor will require some extensions.
You might also consider adding:
- A linter like [selene](https://github.com/Kampfkarren/selene) to catch common issues and enforce coding standards
- A code formatter like [StyLua](https://github.com/JohnnyMorganz/StyLua)
- A language server like [Luau Language Server](https://github.com/JohnnyMorganz/luau-lsp) for autocompletion, type checking, and more
- [Open Cloud](../cloud/guides/index.md) scripts (not synced to Studio) to [update a published experience](/cloud/reference/Universe#Cloud_UpdateUniverse) or [restart servers](/cloud/reference/Universe#Cloud_RestartUniverseServers)
## Undo everything
Because third-party tools sync changes back to Roblox Studio rather than replacing it, no part of this workflow involves any lock-in. At any time, you can stop using one or all of these tools and go back to editing your experience exclusively in Studio. The lack of risk makes experimenting with third-party tools particularly appealing.

View file

@ -0,0 +1,28 @@
---
title: Group guidelines
description: Rules and owner accountability for Roblox groups.
---
If you are the owner of one or more [groups](./groups.md), carefully read through the following expectations for managing your groups.
## Roblox rules
Roblox groups and **all content uploaded to them** must follow Roblox's [Community Standards](https://en.help.roblox.com/hc/en-us/articles/203313410-Roblox-Community-Standards) and [Terms&nbsp;of&nbsp;Use](https://en.help.roblox.com/hc/en-us/articles/115004647846-Roblox-Terms-of-Use). Content uploaded to groups that is subject to the Community Standards includes, but is not limited to:
- Assets
- Avatars
- Experiences
## Owner accountability
Group owners play a crucial role in maintaining a safe and positive environment within their groups.
- Group owners should make a reasonable effort to address and mitigate harmful behavior within their communities and groups.
- Group owners are responsible for utilizing Roblox-provided moderation tools such as [activity history](./groups.md#group-activity-history) to proactively ensure a healthy environment and moderate potentially violative content.
## Violations and consequences
Groups that violate Roblox's [Community Standards](https://en.help.roblox.com/hc/en-us/articles/203313410-Roblox-Community-Standards) may face enforcement actions such as warnings, restrictions on features, temporary locks, and&nbsp;&mdash; for repeat or severe violations&nbsp;&mdash; permanent removal. Group owners can [appeal](https://en.help.roblox.com/hc/en-us/articles/360000245263-Appeal-Your-Content-or-Account-Moderation) any enforcement actions if they believe they were incorrect.
- **Member Violations** — While group owners are not **directly** penalized for member violations, repeated failure to address violations within a group can result in future restrictions on group ownership. An owner whose group is permanently removed will not be able to own a new group for 90 days. Multiple permanent removals will result in a complete loss of group ownership privileges for the owner.
- **Owner Violations** — Group owners who are found to be using their group to promote or facilitate violations of Roblox's Community Standards (through uploading or encouraging the upload of violative content) will face enforcement actions on their own accounts and possibly the permanent deletion of their group.

View file

@ -0,0 +1,370 @@
---
title: Groups (teams)
description: Explains Roblox groups and how to collaborate with multiple creators on the same experience.
---
A Roblox **group** allows multiple creators to work on the same experience, use the same assets, share profits, and give credit to all contributors.
<Alert severity="error">
Group ownership of experiences helps creators collaborate and operate as independent studios. If a conflict arises within a group, Roblox cannot help arbitrate or resolve disagreements.
</Alert>
## Group creation
Creating a group costs 100 Robux. New groups maintain certain capabilities on the legacy [Groups](https://www.roblox.com/communities) pages, but improved workflows and options for [configuring roles/permissions](#roles-and-permissions) and inviting members are only available on the [Creator Dashboard](https://create.roblox.com/dashboard/creations).
<Alert severity="warning">
Before creating a group, carefully read through the [rules and expectations](./group-guidelines.md) for group management.
</Alert>
To create a new group:
1. Navigate to the [Creator Dashboard](https://create.roblox.com/dashboard/creations), expand the account switcher in the upper‑left, and click the **+** button.
<img src="../assets/creator-dashboard/Group-Create-Group-Button.png" width="257" alt="Create Group button on the Creator Dashboard" />
2. On the **Create Group** page, upload an image for the group logo and enter the group name.
3. When ready, click the **Purchase** button. Once the group is created, you'll be directed to the group profile page where you can modify the group's details, including adding up to three social links.
## Roles and permissions
Group members can be assigned one or multiple **roles** within a group, and each role has **permissions** which specify the abilities of its members.
<Alert severity="warning">
Role configuration is only accessible if you're the group owner or you have permission to create, configure, and assign group roles.
</Alert>
<Alert severity="error">
Roles created using the legacy [Groups](https://www.roblox.com/communities) pages will continue to operate on the legacy system and can only be managed through the legacy workflow. If permissions were granted to a legacy role, **the member will continue to have those permissions**, so it's recommended that you revoke permissions/roles in the legacy system and then migrate members to the new system.
</Alert>
1. From the [Creator Dashboard](https://create.roblox.com/dashboard/creations), expand the account switcher in the upper‑left and select the group.
2. Expand the account switcher again, select **Settings** under the group's name, then select **Roles**.
3. For each role, carefully confirm the permissions under the **Permissions** tab.
<img src="../assets/creator-dashboard/Group-Roles-Permissions-Tab.png" width="780" alt="Permissions tab indicated for a group role on the Creator Dashboard." />
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Group Permissions</Typography></AccordionSummary>
<AccordionDetails>
<table>
<tbody>
<tr>
<td width="40%">**Add or remove group members**</td>
<td>Members with this role can [invite](#manage-members) and [remove](#member-removal) other members.</td>
</tr>
<tr>
<td>**Add or remove [role] role members**</td>
<td>Members with this role can give or remove the role to/from other members in the group. This permission is useful for roles that should have some management permissions but not at the super‑admin level.</td>
</tr>
<tr>
<td>**Configure limited roles**</td>
<td>Members with this role can configure the roles they are assigned and assign permissions to those roles that they themselves have.</td>
</tr>
<tr>
<td>**Administrate all roles**</td>
<td>Members with this role can create, delete, and configure any role in the group. This is a super‑admin permission, as it provides nearly full access.</td>
</tr>
<tr>
<td>**Configure group profile**</td>
<td>Members with this role can update the group's name, description, and other metadata. Does not include transferring ownership, which only the owner can do.</td>
</tr>
<tr>
<td>**View group activity history**</td>
<td>Members with this role can view [group activity history](#group-activity-history).</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Experience Permissions</Typography></AccordionSummary>
<AccordionDetails>
<table>
<tbody>
<tr>
<td width="40%">**Playtest all group experiences**</td>
<td>Members with this role can play all experiences owned by the group, whether they're private or public. Optionally available as a [per‑experience permission](./configure-experiences.md).</td>
</tr>
<tr>
<td>**Edit all group experiences**</td>
<td>Members with this role can edit all experiences and [assets](../projects/assets/index.md) owned by the group and use all features in the [Data Stores Manager](../cloud-services/data-stores/data-stores-manager.md). Does not include editing an experience outside of a [collaborative](../projects/collaboration.md) session or saving a place from one experience into another experience. Optionally available as a [per‑experience permission](./configure-experiences.md).</td>
</tr>
<tr>
<td>**Edit and publish all group experiences**</td>
<td>Members with this role can both edit experiences, as above, and also publish experiences to Roblox. Optionally available as a [per‑experience permission](./configure-experiences.md).</td>
</tr>
<tr>
<td>**Monetize all group experiences**</td>
<td>Members with this role can manage monetization products such as [passes](../production/monetization/passes.md), [developer products](../production/monetization/developer-products.md), [subscriptions](../production/monetization/subscriptions.md), and more. Optionally available as a [per‑experience permission](./configure-experiences.md).</td>
</tr>
<tr>
<td>**View all analytics for group experiences**</td>
<td>Members with this role can access the [analytics](../production/analytics/index.md) of all experiences owned by the group, even if they don't have edit access. Optionally available as a [per‑experience permission](./configure-experiences.md).</td>
</tr>
<tr>
<td>**Create and configure share links**</td>
<td>Members with this role can create/configure [share links](../production/promotion/share-links.md).</td>
</tr>
<tr>
<td>**Create and configure experience events**</td>
<td>Members with this role can create/configure [experience events](../production/promotion/experience-events.md).</td>
</tr>
<tr>
<td>**Configure bans for all group experiences**</td>
<td>Members with this role can ban and manage banned users for all experiences owned by the group.</td>
</tr>
<tr>
<td>**List, create, update, and delete secrets for all group experiences**</td>
<td>Members with this role can see the list of [secrets](../cloud-services/secrets.md) and can create, update, and delete secrets for all experiences owned by the group. Optionally available as a [per‑experience permission](./configure-experiences.md).</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Group Revenue</Typography></AccordionSummary>
<AccordionDetails>
<table>
<tbody>
<tr>
<td width="40%">**View group revenue**</td>
<td>Members with this role can view the group Robux balance, any configured recurring split payouts, and revenue logging features.</td>
</tr>
<tr>
<td>**Configure and spend group revenue**</td>
<td>Members with this role can view all group revenue, as above, and also directly manage it. This includes setting up [recurring payouts](#recurring-payouts) and sending [one‑time payouts](#one-time-payouts) to collaborators.</td>
</tr>
<tr>
<td>**Create ad campaigns for the group**</td>
<td>Members with this role can advertise the group.</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Avatar Item Permissions</Typography></AccordionSummary>
<AccordionDetails>
<table>
<tbody>
<tr>
<td width="40%">**Configure avatar items**</td>
<td>Members with this role can configure avatar items such as clothing.</td>
</tr>
<tr>
<td>**Create avatar items**</td>
<td>Members with this role can create avatar items such as clothing.</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Open Cloud Permissions</Typography></AccordionSummary>
<AccordionDetails>
<table>
<tbody>
<tr>
<td width="40%">**Manage own API keys**</td>
<td>Members with this role can configure and upload their own [Open Cloud API keys](../cloud/auth/api-keys.md) to the group, but not configure everyone else's.</td>
</tr>
<tr>
<td>**Manage all API keys**</td>
<td>Members with this role can upload their own [Open Cloud API keys](../cloud/auth/api-keys.md) to the group, as well as configure everyone else's.</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Asset Permissions</Typography></AccordionSummary>
<AccordionDetails>
<table>
<tbody>
<tr>
<td width="40%">**View development items**</td>
<td>Members with this role can view development items owned by the group, for example **Audio**.</td>
</tr>
<tr>
<td>**Create and configure development items**</td>
<td>Members with this role can upload and configure asset development items such as **Decals**.</td>
</tr>
<tr>
<td>**Manage development item permissions**</td>
<td>Members with this role can configure permissions of development items, for example audio sharing.</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</BaseAccordion>
<BaseAccordion>
<AccordionSummary><Typography variant="subtitle2">Data Stores</Typography></AccordionSummary>
<AccordionDetails>
<table>
<tbody>
<tr>
<td width="40%">**View data stores for all group experiences**</td>
<td>Members with this role can view data stores for all group experiences through the [Data Stores Manager](../cloud-services/data-stores/data-stores-manager.md), but they cannot delete data. Optionally available as a [per‑experience permission](./configure-experiences.md).</td>
</tr>
<tr>
<td>**Edit data stores for all group experiences**</td>
<td>Members with this role can delete specific keys within data stores for all group experiences through the [Data Stores Manager](../cloud-services/data-stores/data-stores-manager.md). Optionally available as a [per‑experience permission](./configure-experiences.md).</td>
</tr>
<tr>
<td>**Delete data stores for all group experiences**</td>
<td>Members with this role can delete entire data stores for all group experiences through the [Data Stores Manager](../cloud-services/data-stores/data-stores-manager.md). Optionally available as a [per‑experience permission](./configure-experiences.md).</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</BaseAccordion><br />
4. <Chip label="IMPORTANT" size="small" variant="outlined" color="warning" /> Click the **Save Changes** button to apply the permission settings.
5. <Chip label="OPTIONAL" size="small" variant="outlined" /> Click the **Settings** tab and choose a color for the role, then click **Save Changes**.
<img src="../assets/creator-dashboard/Group-Roles-Settings-Tab.png" width="780" alt="Settings tab indicated for a group role on the Creator Dashboard." />
<img src="../assets/creator-dashboard/Group-Roles-Role-Color.png" width="780" alt="Color options indicated for a group role on the Creator Dashboard." />
<Alert severity="info">
A role's **Settings** section is also where group owners and members with sufficient permissions can remove a role entirely through the **Delete Role** button.
</Alert>
## Manage members
<Alert severity="warning">
Member configuration is only accessible if you're the group owner or you have permission to manage other members and their roles.
</Alert>
Once [roles](#roles-and-permissions) have been configured for the group, members can be invited and assigned from either the **Members** tab within a specific role or from the **Collaboration**&nbsp;&rang; **Members** page.
<GridContainer numColumns="2">
<figure>
<img src="../assets/creator-dashboard/Group-Roles-Add-Members.png" width="400" alt="Add members button indicated for a group role on the Creator Dashboard." />
<figcaption>Collaboration &rang; Roles &rang; Members tab</figcaption>
</figure>
<figure>
<img src="../assets/creator-dashboard/Group-Members-Invite-Button.png" width="400" alt="Invite button indicated in the group's Members section on the Creator Dashboard." />
<figcaption>Collaboration &rang; Members &rang; Member tab</figcaption>
</figure>
</GridContainer>
From the add/invite popup, locate a creator by typing their username into the search field. Creators will be notified when invited to your group (a customizable setting within the creator notification system), or you can copy the **group link** and share it with invited creators through other means.
### Manage roles
To assign roles to a member, hover over their name, click the **Add&nbsp;Role** button, and then manage roles from the popup.
<img src="../assets/creator-dashboard/Group-Members-Assign-Role.png" width="840" alt="Assign roles to a group member on the Creator Dashboard." />
To quickly unassign a role from a member, hover over it and click the **&times;** button.
<img src="../assets/creator-dashboard/Group-Members-Unassign-Role.png" width="840" alt="Hover-over showing how to unassign a role from a group member on the Creator Dashboard." />
<Alert severity="error">
Currently, roles configured through the legacy [Groups](https://www.roblox.com/communities) pages appear for each member. If permissions were granted to a role through the legacy system, **the member will continue to have those permissions**, so it's recommended that you revoke permissions/roles in the legacy system and then migrate members to the new system.
</Alert>
### Member removal
To remove a member entirely, hover over their name, click the **&#8942;** button, and then select the removal option. A dialog will appear for you to confirm the action.
<img src="../assets/creator-dashboard/Group-Members-Remove-Member.png" width="840" alt="Hover-over showing how to remove a member from a group on the Creator Dashboard." />
## Manage payouts
If you're the group owner or you have the correct [permission](#roles-and-permissions) within **Group&nbsp;Revenue**, you'll find a **Payouts** page under **Finances** in the left navigation. Here, you can send one‑time payouts, as well as define percentage splits with other members.
<Alert severity="info">
Some groups may not have this page unlocked initially for various reasons, such as the age of the group or insufficient funds to payout.
</Alert>
<Alert severity="warning">
Payouts cannot be shared across group members for experiences that charge for [paid access in local currency](../production/monetization/paid-access-local-currency.md).
</Alert>
### One-time payouts
One-time payouts can be made to members in a batch, selecting a set amount for each. Safety features include 2FA challenges, confirmation dialogues, and checks around the eligibility of members being paid.
<img src="../assets/creator-dashboard/Group-Payouts-One-Time.png" width="880" alt="One-time payout button indicated in the Payouts section on the Creator Dashboard." />
Once you click the **Send Robux** button, you can choose payout recipients from the popup or upload a `.csv` spreadsheet file with the columns `userId` and `payoutInRobux`, for example:
<GridContainer numColumns="2">
<figure>
<table size="small">
<thead>
<tr>
<th>userId</th>
<th>payoutInRobux</th>
</tr>
</thead>
<tbody>
<tr>
<td>012345</td>
<td>5000</td>
</tr>
<tr>
<td>098765</td>
<td>7000</td>
</tr>
</tbody>
</table>
</figure>
<figure>
</figure>
</GridContainer>
### Recurring payouts
Recurring payouts can also be made across the entire group **and** per‑experience, assigning a percentage payout to each member before the remainder enters the group's overall balance.
<img src="../assets/creator-dashboard/Group-Payouts-Split-Options.png" width="880" alt="Split payout buttons indicated in the Payouts section on the Creator Dashboard." />
Consider the following scenario where a group experience **Laser Maze** is split 40%&ndash;30%&ndash;10% among three members, with a remainder of 20%.
<br />
<Grid container spacing={2}>
<Grid item XSmall={2} Medium={1} Large={1} XLarge={1}><img src="../assets/misc/Box-Label-A.png" width="40" style={{float:"right"}} /></Grid>
<Grid item XSmall={10} Medium={11} Large={11} XLarge={11} style={{marginTop:"4px"}}>
Assuming the experience earns 1000 Robux, the three members receive 400, 300, and 100 Robux respectively (40%&ndash;30%&ndash;10%).
</Grid>
</Grid>
<Grid container spacing={2}>
<Grid item XSmall={2} Medium={1} Large={1} XLarge={1}><img src="../assets/misc/Box-Label-B.png" width="40" style={{float:"right"}} /></Grid>
<Grid item XSmall={10} Medium={11} Large={11} XLarge={11} style={{marginTop:"4px"}}>
The remaining 200 Robux (20% of the experience split) passes onward to the **group split** percentages, defined at 20%&ndash;20%&ndash;10% among the same three members; they receive an additional 40, 40, and 20 Robux respectively.
</Grid>
</Grid>
<Grid container spacing={2}>
<Grid item XSmall={2} Medium={1} Large={1} XLarge={1}><img src="../assets/misc/Box-Label-C.png" width="40" style={{float:"right"}} /></Grid>
<Grid item XSmall={10} Medium={11} Large={11} XLarge={11} style={{marginTop:"4px"}}>
The remaining 100 Robux (50% of the group split) is placed in the group's overall balance.
</Grid>
</Grid>
<img src="../assets/creator-dashboard/Group-Payouts-Splits-Example.png" width="840" alt="Example flowchart of how experience splits are distributed to group members first, with remainder going factored into group splits for final distribution among the group." />
<Alert severity="warning">
Note that revenue from [private server](../production/monetization/private-servers.md) subscriptions does not change if you adjust split percentages at a later time, meaning that if a player buys a private server subscription, the split percentages at time of purchase will apply to that particular subscription forever (until it is canceled). This policy may be changed in the future.
</Alert>
## Group activity history
Group members with the **View group activity history** permission can view detailed activity such as role changes and publishing actions from the **Activity&nbsp;History** section under **Collaboration** on the Creator Dashboard. This is also a useful way for group owners to moderate activity that may violate [group guidelines](./group-guidelines.md).
## Intellectual property protection
Group members with permission to edit all group experiences can enable the [Place Copying](./configure-experiences.md#allow-copying) setting for a creation, potentially allowing the entire Roblox community to copy it and use assets within it. To help protect intellectual property in a group, the owner or members with sufficient permissions should:
- Confirm that each member is [assigned the appropriate role](#manage-roles).
- Check that each group role has the correct [permissions](#roles-and-permissions).
- Confirm that the [Place Copying](./configure-experiences.md#allow-copying) setting is disabled before private assets are added.

View file

@ -0,0 +1,98 @@
---
title: Projects
description: An overview of projects and experiences in Roblox.
---
A Roblox project is a collection of [places](#places), [assets](#assets), [settings](#settings), and other resources that together represent an **experience**. Roblox stores your projects in the cloud for convenient collaboration, editing, and version control. You create and manage projects with [Roblox Studio](../studio/index.md), an all‑in‑one IDE that provides building, scripting, testing, and publishing tools.
## Places
Experiences on Roblox are made up of individual **places**, comparable to scenes in Unity or maps in Unreal Engine. Each place contains all components for that portion of the experience, including its specific environment, parts, meshes, scripts, and user interface.
See the pages for [creating and publishing](../production/publishing/publish-experiences-and-places.md), [configuring](./configure-experiences.md), and [updating](./update-experiences.md) experiences and places for details.
<figure>
<img src="../assets/publishing/experiences-places-assets/Experience-Hierarchy.png" alt="An experience grouping of three individual places with unique environments." width="800" />
</figure>
Every place is represented by a **data model**, a hierarchy of objects that describe everything about the place. The Roblox Engine uses the data model as a source of truth for a place's state, so it can simulate and render it on client devices. For more information on how the engine interprets the data model, see [Client-server runtime](../projects/client-server.md).
Proper, intentional object organization within the data model is essential for
functionality and maintenance of your project. For more information on what
objects are available and how to organize and use them, see
[Data model](../projects/data-model.md).
## Assets
In Roblox, assets such as images, meshes, and audio are stored as **cloud-based assets**, so you don't need to bundle local copies into a saved Studio experience. Each asset in the cloud is assigned a unique **asset&nbsp;ID** from which multiple experiences can utilize them. You can create assets directly in Studio, such as models, or import assets like images, audio, and meshes from other tools.
<GridContainer numColumns="3">
<figure>
`rbxassetid://7229442422`
<img src="../assets/modeling/textures-decals/Texture-Example-Grafitti04.png" alt="A decal asset of a young woman with a button for an eye." width="90%" />
</figure>
<figure>
`rbxassetid://6768917255`
<img src="../assets/modeling/meshes/Base-Mesh-In-Marketplace.png" alt="An untextured treasure chest MeshPart asset." width="90%" />
</figure>
<figure>
`rbxassetid://9125402735`
<audio controls><source src="../assets/studio/general/Boom-Impact.mp3" type="audio/mpeg"></source></audio>
</figure>
</GridContainer>
By default, assets are private to your experience and you can use an asset in any place by referencing its ID. You can also distribute them to the community in the [Creator Store](https://create.roblox.com/store/), so others can use them as well.
For more information on how to import and publish assets, see [Assets](../projects/assets/index.md).
## Packages
[Packages](../projects/assets/packages.md) are reusable object hierarchies that you can define and reuse in multiple places across multiple experiences. For any large project, packages offer the following benefits:
- Packages can be used as asset kits, allowing you to duplicate a set of objects as needed.
- Packages make it easier to update assets. For instance, a package can include a tree that's duplicated many times in an environment. If you need to make a change, such as swap textures for the tree, it can be updated once in the package instead of for each individual instance.
- A package can start with graybox assets, and eventually be replaced with final art assets. When assets are replaced, they retain all original positions and orientations.
## Settings
Experience settings are managed from the [Creator Dashboard](https://create.roblox.com/dashboard/creations) or within Studio, including:
- **Basic Info** &mdash; Basic information about the experience, such as its name, description, and genre. Much of the information here is used in your experience's listing.
- **Communication** &mdash; Settings which enable eligible users to use [voice chat](../chat/voice-chat.md) or animate their avatar via their camera within your experience.
- **Permissions** &mdash; Configures who can access your experience. New experiences begin as **private** and can only be edited and joined by you and members of your [group](../projects/groups.md) with the correct permissions. When appropriate, you can [release](../production/publishing/publish-experiences-and-places.md#make-experience-public) the experience to the public.
- **Monetization** &mdash; Options for earning revenue from your experience, as outlined in [Monetization](../production/monetization/index.md).
- **Localization** &mdash; Configuration for different [languages and regions](../production/localization/index.md).
- **Avatar** &mdash; Settings related to avatars, such as avatar scaling and
clothing overrides.
## Collaboration
With Studio's **built-in collaboration tools**, team members can contribute to
experiences independently on their own time, or alongside others. Key features
include:
- Group admins can manage which members have access to collaborate and which do
not, effectively maintaining proper roles within a large team.
- Collaborators can build alongside other team members in real time and
automatically see changes made by others.
- Collaborators can independently edit the same scripts that others may be
editing, test locally, and commit their changes to the cloud-based project
when ready.
For more information, see [Collaboration](../projects/collaboration.md).
## Testing
Your [team](../projects/groups.md) can instantly test an experience on PC, mobile, VR, and other devices you wish to support through the Roblox app; no need to compile builds, deploy to app stores, or await app store approval.
Studio offers a suite of options for testing an experience before releasing it to the public:
- **Rapid playtesting** that provides a close simulation of the experience
running on the Roblox application.
- **Multi-client simulation** for comparing how each client "sees" other clients
within the experience.
- **Device emulation** that provides insight on how controls operate on a mobile
device or how on-screen UI displays on different screens and aspect ratios.
- **Collaborative playtesting** with members of your team.
For more information on each testing option, see [Studio testing modes](../studio/testing-modes.md).

View file

@ -0,0 +1,65 @@
---
title: Place files
description: Learn how to manage and optimize your place files in Roblox.
---
Each Roblox experience consists of one or more [places](index.md#places), and Studio uploads your place data to Roblox's servers whenever you save or publish to Roblox in the **File** menu.
You might also want to export local copies of places for use with a version control system or other [external tools](external-tools.md). To export your place in Studio, select **Save&nbsp;to&nbsp;File** or **Download&nbsp;a&nbsp;Copy** from the **File** menu. Studio offers two file formats:
- `.rbxl` is the binary place file format. This format is compact, but not human-readable.
- `.rbxlx` is the XML-based place file format, which is quite a bit larger on disk than the binary format.
## Size limit
Roblox supports places up to 100 MB (104,857,600 bytes). Beyond that limit, **Save to Roblox** and **Publish to Roblox** might fail. The data that Studio uploads to Roblox is slightly smaller than the `.rbxl` file format, so you can export your place to `.rbxl` to get a sense of its size.
Very few places, even the most complex ones, reach this limit, and when they do, it's often due to inefficiencies in the place. See [Troubleshooting](#troubleshoot-place-file-size).
### Auto-recovery files
If saving to Roblox fails due to the file size limit, Studio automatically generates a backup of your place called a **recovery file**. The frequency of auto-recovery backups depends on whether your experience has [collaboration](collaboration.md) enabled:
- If you have collaboration enabled and saving to Roblox fails, Studio backs up the last three save attempts as recovery files on your system.
- If collaboration is disabled, Studio uses **Auto-Recovery** settings from [Studio Settings](../studio/setup.md#customization).
On Windows, recovery files are located in `C:\Users\Admin\AppData\Local\Roblox\RobloxStudio\AutoSaves`.
On Mac, you can find them in `/Users/your-username/Library/Application Support/Roblox/RobloxStudio/AutoSaves/`.
## Troubleshoot place file size
If you reach the 100 MB limit on your place file, there's likely an underlying issue that you can troubleshoot. Try the following steps.
### Safety check
Check the models in your place and their attached scripts for any obfuscated or unclear text. This text does not compress well and might even be a malicious backdoor into your place. Roblox moderation systems actively filter out these models, but if you happen to find one, delete the model from your place, find the model on the [Creator Store](https://create.roblox.com/store/models), and report it immediately.
### Redundant parts
Unreferenced or hidden assets can accumulate over time and unnecessarily increase file size.
1. See if any models or groups of parts are taking up more space than others:
1. Export your place file and note its size on disk.
1. Open the file in Roblox Studio.
1. Copy and paste the models or groups of parts that you suspect are inordinately large.
1. Save the file again and note its increase in file size.
1. Check for redundant parts (parts of the same size and shape with the same position) or instances (redundant `Class.SurfaceAppearance|SurfaceAppearances`, textures, etc.) and delete them. The Creator Store has plugins that can help you identify these cases.
### Simplify terrain
Reducing or simplifying terrain can significantly reduce place size and improve performance. Avoiding excessive terrain features like dense forests or complex hills helps make experiences run faster and more efficiently. Of course, the experience should match your artistic vision, but consider the following optimizations:
1. Horizontal layers of the same material/occupancy compress much better than sloped layers. If possible, try to limit subsurface detail to horizontal layers.
1. Turn on **Show Wireframe Rendering** from Studio's **View** menu and check for messy holes or misplaced water under the terrain surface. These mistakes can increase compressed size.
1. There are community plugins that optimize non-visible blocks of terrain for better compression, such as [this one](https://create.roblox.com/store/asset/133396894381603/Terrain-File-Size-Optimizer).
### Collision fidelity
`Enum.CollisionFidelity.Box|Box` and `Enum.CollisionFidelity.Hull|Hull` collision fidelity are more memory efficient than the default. Select your meshes, open the [Properties](../studio/properties.md) window, and change the **CollisionFidelity** values as appropriate for your use case.
### Teleports
If other size reduction strategies fail, you can break your place into multiple, smaller places and link them through [teleports](teleport.md). Serialization and upload happen at the place level, so this approach lets you grow your universe place by place over time instead of trying to maintain a single, massive place.

View file

@ -0,0 +1,270 @@
---
title: Server authority model
description: The server authority model lets you build responsive cheat-free competitive experiences such as FPS, racing, sports, and combat.
---
import BetaAlert from '../../includes/beta-features/beta-alert.md'
<BetaAlert betaName="Server Authority Core API" leadIn="The server authority model and its associated APIs are currently in beta. Enable them in Studio through " leadOut="." components={props.components} />
<Alert severity="error">
As this feature is currently in beta, you should **not** publish a server‑authoritative experience. Your players' clients will not yet have support for server authority APIs, so the published experience will not work correctly.
</Alert>
In a **server authority model**, the server is the single **source of truth** for the entire experience state, and clients are only trusted to report their own inputs. This architecture is the core netcode foundation of a fair, competitive experience because it prevents entire classes of cheating like flyhacks or speedhacks by never trusting a client to report its own position or state.
## Advantages
In a naive server-owned system, clients would simply send their inputs to the server and display the results of the experience sent back by the server. While technically correct, such a system would face significant **input latency** because every player action would have to travel to the server, be processed, and have the result sent back to the client before it could be displayed. For most experiences, especially those fast‑paced, that round‑trip delay would cause gameplay to feel laggy, unresponsive, and unplayable.
In Roblox's **server authority** model, latency is compensated for by having clients instantly [predict](#client-prediction) the effects of their inputs in addition to sending them to the server. For example, when a player presses a key, the client doesn't wait for the server to respond; instead it **predicts** a few frames ahead of the last known server state. This allows the client to show the result of the input action instantly, effectively hiding network latency and making the experience feel responsive.
Sometimes the client will get its prediction wrong ([misprediction](#client-misprediction)) and, because of network latency, the client will not know that it has made a mistake for a few frames. For example:
<Alert severity="warning" variant="outlined">
Your client predicts that you've moved forward, but on the server another player used a stun ability that stopped you from moving. The client and server now have different states.
</Alert>
When a misprediction is detected, the client must correct its prediction based on the server's **authoritative state**. If the authoritative state is different from the client's predicted state, the client must [roll back and resimulate](#rollback-and-resimulation) its predicted frames. This system of client‑side prediction, rollback, and resimulation is known as "latency&nbsp;compensation" and helps make server‑authoritative multiplayer experiences feel smooth and responsive.
<Alert severity="info">
Mispredictions are a **normal and expected** part of the server authority architecture because clients inherently cannot predict other players' inputs, so actions by other players will always trigger some amount of misprediction. When tuned correctly, the resulting corrections are small and should be imperceptible to players. Read further on [advanced techniques](./techniques.md) to smooth out and mask network artifacts.
</Alert>
## Setup
As the server authority model requires certain other engine technologies to function correctly, you must first set the following properties on the `Class.Workspace` object in the [Explorer](../../studio/explorer.md):
1. `Class.Workspace.NextGenerationReplication` must be enabled
2. `Class.Workspace.PlayerScriptsUseInputActionSystem` must be enabled
3. `Class.Workspace.SignalBehavior` must be `Enum.SignalBehavior.Deferred|Deferred`
4. `Class.Workspace.UseFixedSimulation` must be enabled
5. `Class.Workspace.StreamingEnabled` must be enabled
6. `Class.Workspace.AuthorityMode` must be `Enum.AuthorityMode.Server|Server` (all of the above must be set first)
## Concepts
The server authority system runs on a few core concepts as follows.
### Client prediction
Through **client prediction**, the client simulates a few frames ahead of the last known server state to predict the effects of player inputs immediately. This hides input latency, but the prediction may later turn out to be incorrect ([client misprediction](#client-misprediction)) and thus require correction. The client tries to simulate just far enough ahead of the last known authoritative server state so that its inputs arrive on the server at the intended frame. The number of frames the client will predict ahead of the known server state is based on the latency behind the client and server.
### Client misprediction
When the client receives the authoritative state from the server, it checks that state against a historical record of what it predicted locally for that frame. When there is a difference between what the client [predicted](#client-prediction) and what the server actually did, this is a **misprediction**. Mispredictions can occur for several reasons, including shifts in network latency, other players acting in ways the client didn't anticipate, the experience running certain logic exclusively on the server, etc.
If the authoritative state is different from the client's predicted state, the client must [roll back and resimulate](#rollback-and-resimulation).
### Rollback and resimulation
When a client detects a [misprediction](#client-misprediction), it must reset to the server's authoritative state and then resimulate to jump back to its predicted frame. Based on the network latency, the client tries to simulate just far enough ahead of the last known authoritative server state so that its inputs arrive on the server at the intended frame.
```mermaid
block-beta
columns 1
block:Client
columns 7
ClientHeader("<span style="color:white;"><b>Client</b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>")
space:6
C1["3"]
C2["4"]
C3["5"]
C4["6"]
C5["<span style="font-size:80%">3 4 5 6</span> 7"]
C6["8"]
C7["9"]
end
block:Middle
columns 10
TimeStart("<span style="color:Grey; font-size:80%;">TIME</span>")
space:8
TimeEnd(" ")
space:10
end
block:Server
columns 7
ServerHeader(["<span style="color:white;"><b>Server</b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>"])
space:6
S1["1"]
S2["2"]
S3["3"]
S4["4"]
S5["5"]
S6["6"]
S7["7"]
end
TimeStart --> TimeEnd
C1 --"<span style="color:white; background-color:RoyalBlue;">&nbsp; Input (Frame 3) &nbsp;</span>"--> S3
S3 --"<span style="color:white; background-color:SeaGreen;">&nbsp; Server State (Frame 3) &nbsp;</span>"--> C5
style Client fill:RoyalBlue
style ClientHeader stroke-opacity:0, fill-opacity:0
style Middle fill-opacity:0, stroke-opacity:0
style TimeStart fill-opacity:75%, stroke-opacity:75%
style TimeEnd display:none
style Server fill:SeaGreen
style ServerHeader stroke-opacity:0, fill-opacity:0
```
<figure>
<figcaption>In the above diagram, the client is simulating 2 frames ahead of the server. It sends its inputs for frame 3 which arrive at the intended frame (3) on the server. The server sends the authoritative state for frame 3 and the client receives it on frame 7. The client discovers it mispredicted frame 3 so it resets to the server's frame 3 and resimulates frames 4, 5 and 6 before it simulates frame 7. Players may see a noticeable network artifact such as a sudden movement.</figcaption>
</figure>
In summary, the **client**:
1. Receives the **authoritative state** from the server and compares it against its own **predicted state**.
2. If the client's prediction was incorrect:
1. Client rolls back to the last known authoritative state received from the server.
2. Client resimulates from the authoritative state to its predicted state, re-applying any local inputs.
## Implementation
### Network ownership and prediction
In the server authority model, you're able to keep the core gameplay objects server‑owned without incurring the input latency cost normally associated with server ownership. Things like cars, player characters, or other gameplay‑critical objects can remain server‑owned, even when interacting with other players.
By default, Roblox will automatically predict the physics properties of `Class.BasePart|BaseParts` near the local player `Class.Player.Character|Character`, but if you want more fine‑grained control, you can explicitly force an instance's prediction on or off with `Class.RunService:SetPredictionMode()`.
<Alert severity="success">
Roblox synchronizes all relevant physics properties automatically.
</Alert>
### Simulation sync
In the server authority model, the client and the server must both run the core simulation, and the client's simulation needs to be able to [roll back and resimulate](#rollback-and-resimulation) when a [misprediction](#client-misprediction) occurs. To enable this, write your core logic inside functions bound through `Class.RunService:BindToSimulation()` in a `Class.ModuleScript` that's initialized on both the client and server.
<img src="../../assets/studio/explorer/ReplicatedStorage-Server-Authority.png" width="320" alt="Server authority setup" />
```lua title="Simulation (ModuleScript)"
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local Simulation = {}
Simulation.Initialize = function()
RunService:BindToSimulation(function(deltaTime)
-- Read player inputs
-- Update experience state
end)
end
return Simulation
```
```lua title="ServerLoader (Server Script)"
local Simulation = require(script.Parent)
Simulation:Initialize()
```
```lua title="ClientLoader (Client Script)"
local Simulation = require(script.Parent)
Simulation:Initialize()
```
During a resimulation, Roblox will re-run the functions bound to the simulation via `Class.RunService:BindToSimulation()|BindToSimulation()`. Processing player inputs, interacting with synchronized physics objects, and updating the core experience state should live inside those bound functions.
### State sync with attributes
Roblox automatically synchronizes all relevant physics properties on predicted instances. For custom data, [attributes](../../studio/properties.md#instance-attributes) are the primary way to synchronize instances marked as predicted; on such instances, any mismatch in attribute values between the server's source of truth and the client's prediction will trigger a full [rollback and resimulation](#rollback-and-resimulation).
<Alert severity="success">
Use attributes to store experience data that affects your core simulation, including player health, ammunition, inventory, or custom rules (see [limitations](#attribute-limits)).
</Alert>
<Alert severity="warning">
Only write to attributes on **predicted** instances from within functions bound through `Class.RunService:BindToSimulation()|BindToSimulation()` to ensure that Roblox can fully track relevant experience states and resimulate properly.
</Alert>
#### Attribute limits
In order to be replicated, an attribute must meet all of the following criteria:
- It is among the first 64 attributes on its `Class.Instance`.
- Its name contains at most 50 characters.
- If a string type attribute, its value contains at most 50 characters.
#### Physical properties
The server authority system predicts physical properties such as the ones below. Note that this is **not** an exhaustive list but rather an illustration of classes and property types that will be considered.
- `Class.BasePart` — `Class.BasePart.CFrame|CFrame`; `Class.BasePart.RotVelocity|RotVelocity`; `Class.BasePart.Velocity|Velocity` (if assembly root); `Class.BasePart.CurrentPhysicalProperties|CurrentPhysicalProperties`; `Class.BasePart.CanCollide|CanCollide`; `Class.BasePart.Mass|Mass`; `Class.BasePart.Size|Size`
- `Class.WeldConstraint` — `Class.WeldConstraint.Enabled|Enabled`; `Class.WeldConstraint.CFrame1|CFrame1`; `Class.WeldConstraint.CFrame2|CFrame2`
- `Class.Constraint` — `Class.Constraint.Enabled|Enabled`; any non-redundant readable/writable property
- `Class.Attachment` — `Class.Attachment.CFrame|CFrame`
- `Class.Motor` — `Class.Motor.CurrentAngle|CurrentAngle`; `Class.Motor.DesiredAngle|DesiredAngle`; `Class.Motor.MaxVelocity|MaxVelocity`
- `Class.Humanoid` — `Class.Humanoid.Jump|Jump`; `Class.Humanoid.MoveDirection|MoveDirection`; `Class.Humanoid.AutoRotate|AutoRotate`
- `Class.ControllerManager`
### Input actions
In a server-authoritative experience, the primary way for a client to affect the experience's state is through the [Input Action System](../../input/input-action-system.md). These inputs are sent to the server and are replayed during resimulation on the client. As a result, `Class.InputAction|InputActions` should be used for **all inputs that affect the core simulation** and they should be checked for sanity before they're processed.
<Alert severity="warning">
To reiterate, do not use traditional events like `Class.UserInputService.InputBegan` in the core simulation of a server-authoritative experience.
</Alert>
Note that `Class.InputContext|InputContexts` must be a descendent of a `Class.Player` so that the engine knows who has ownership over the `Class.InputContext`. Placement in `Class.StarterGui` is fine, since it replicates to the player's `Class.PlayerGui` at join time and effectively descends from that `Class.Player`.
<img src="../../assets/studio/explorer/StarterGui-InputContext-InputAction-InputBinding-All.png" width="320" />
Using this pattern, you can read `Class.InputAction|InputActions` for all players in `Class.RunService:BindToSimulation()` on both client and server to receive the same data for a given frame and record the previous frame's input in an [attribute](../../studio/properties.md#instance-attributes), for example to trigger a character sprint when a `CharacterSprint` input action is triggered.
Note that if you need to write custom data into the [Input Action System](../../input/input-action-system.md), you should use a function connected to `Class.RunService.RenderStepped` or `Class.RunService:BindToRenderStep()`, not `Class.RunService:BindToSimulation()`. Firing an `Class.InputAction` in `Class.RunService:BindToSimulation()|BindToSimulation()` can cause clients to produce incorrect results during a resimulation.
```lua
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Workspace = game:GetService("Workspace")
RunService:BindToRenderStep("CameraInput", Enum.RenderPriority.Last.Value, function()
-- Send the client camera's forward vector to the server through an InputAction
local cameraForwardInputAction = Players.LocalPlayer.PlayContext.CameraForward
local cameraForwardVector = Workspace.CurrentCamera.CFrame.LookVector
cameraForwardInputAction:Fire(cameraForwardVector)
end)
```
### Remote events
[Remote events](../../scripting/events/remote.md) can still be used within the server authority model to facilitate discrete communication between client and server. For example, servers can use remote events to broadcast data about players scoring points or picking up objects, and clients can use remote events as an alternative API for sending inputs to the server, such as for button presses or tapping objects in the 3D world.
### Animations, sounds, and effects
Client-side effects like animations and sounds must be written knowing that the client simulation is merely a prediction of the authoritative server state. `Class.RunService:BindToSimulation()|BindToSimulation()` limits what properties and methods can be called from within bound functions to help guide you in writing only to the synchronized simulation state. Displaying the results of this simulation, triggering effects and sounds, etc. should be done in a separate function connected to `Class.RunService.RenderStepped|RenderStepped` that reads the results of the simulation and triggers the desired effects.
Further guidance around rendering a predicted simulation is covered in the [advanced techniques](./techniques.md) guide.
## Example projects
In addition to this documentation, the following templates can help you get started:
<GridContainer numColumns="3">
<figure>
<a href="https://www.roblox.com/games/134686834388911/Racing-Server-Authority-Template"><img src="../../assets/misc/SA-Icon-Racing.jpg" /></a>
<figcaption>Racing</figcaption>
</figure>
<figure>
<a href="https://www.roblox.com/games/110687099504272/Soccer-Server-Authority-Template"><img src="../../assets/misc/SA-Icon-Soccer.jpg" /></a>
<figcaption>Soccer</figcaption>
</figure>
<figure>
<a href="https://www.roblox.com/games/90572444221193/Laser-Tag-Server-Authority-Template"><img src="../../assets/misc/SA-Icon-Laser-Tag.jpg" /></a>
<figcaption>Laser Tag</figcaption>
</figure>
</GridContainer>

View file

@ -0,0 +1,268 @@
---
title: Server authority advanced techniques
description: Advanced techniques for creating high-quality, smooth, multiplayer experiences using the server authority model.
---
import BetaAlert from '../../includes/beta-features/beta-alert.md'
This guide covers advanced techniques for creating high-quality, smooth, multiplayer experiences using the [server authority model](./index.md).
<BetaAlert betaName="Server Authority Core API" leadIn="The server authority model and its associated APIs are currently in beta. Enable them in Studio through " leadOut="." components={props.components} />
<Alert severity="error">
As this feature is currently in beta, you should **not** publish a server‑authoritative experience. Your players' clients will not yet have support for server authority APIs, so the published experience will not work correctly.
</Alert>
## Position smoothing
You can visually smooth out the position of mispredicted synchronized objects by rendering a different object than what is being simulated.
1. Make the **simulated** object invisible.
2. Make a **renderer** object as a massless, non‑collidable, visual‑only clone to track the simulated object.
3. Attach a script to the renderer object that smoothly tracks the position of the invisible, simulated object. This separation between rendering and simulation lets you alter the position of the renderer object to create a visually smooth experience.
In the following sample `Class.Script`, the rendered object (parent) smoothly tracks the simulated object. The rendered object is always slightly "behind" the simulated object which is typically fine but may be undesirable in certain situations.
```lua title="Smoothly Track BasePart Position with Renderer Part"
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local Workspace = game:GetService("Workspace")
-- Object to smoothly track
local smoothTarget:BasePart = Workspace.SimulatedPart
-- Visual object that will be smoothed
local renderer:BasePart = script.Parent
-- Time to smooth over; smaller means faster
local smoothTime = 0.07
-- Store data needed to compute the smooth position
local smoothVelocity = Vector3.new()
-- Disable the renderer object's physics
renderer.Massless = true
renderer.Anchored = true
renderer.CanCollide = false
RunService.RenderStepped:Connect(function(deltaTime: number)
-- Smoothly track the target object
local smoothPosition, smoothVelocity = TweenService:SmoothDamp(
renderer.Position,
smoothTarget.Position,
smoothVelocity,
smoothTime,
math.huge,
deltaTime)
renderer.Position = smoothPosition
end)
```
The [Soccer](https://www.roblox.com/games/110687099504272/Soccer-Server-Authority-Template) example experience uses a variation of this technique to more intelligently turn on and off position smoothing for the soccer ball. Specifically, the soccer ball only smooths its position when the simulated ball has "jumped" far enough away from the rendered ball. This approach provides the best of both worlds: the soccer ball has no visual latency under normal conditions, and the experience smoothly interpolates its position only after the simulated ball has unexpectedly jumped to a new location, likely due to a network artifact or server‑side change.
## Animations, sounds, and visual effects
In a predicted simulation, it's possible to trigger effects, sounds, or animations for events that the client predicted would happen but which never occurred on the server. The rendering system should be prepared to "undo" any mispredicted effects. For example, a client might predict that a grenade exploded and trigger a particle effect, but if another player diffused the grenade, the client should hide the particle effect.
A good strategy for rendering a predicted simulation is to synchronize a state machine pattern within the simulation loop and render changes to the state in a render step function. The following example simulates a grenade with a state machine pattern:
```lua title="Simple State Machine for Tracking a Grenade (ModuleScript)"
local Workspace = game:GetService("Workspace")
local module = {}
module.GrenadeStates = {
Idle = 0,
Lit = 1,
Exploded = 2,
Defused = 3,
}
module.GrenadeExplodeTime = 3.0
module.Initialize = function(grenade)
RunService:BindToSimulation(function(deltaTime)
-- Initialize empty grenade state
local grenadeState = grenade:GetAttribute("State")
if grenadeState == nil then
grenadeState = module.GrenadeStates.Idle
grenade:SetAttribute("State", grenadeState)
grenade:SetAttribute("Timer", 0.0)
end
-- Increment grenade timer
local timer = grenade:GetAttribute("Timer")
timer = timer + deltaTime
grenade:SetAttribute("Timer", timer)
-- Explode lit grenades
if grenadeState == module.GrenadeStates.Lit then
if timer >= module.GrenadeExplodeTime then
grenadeState = module.GrenadeStates.Exploded
grenade:SetAttribute("State", grenadeState)
grenade:SetAttribute("Timer", 0.0)
end
end
end)
end
return module
```
With the previous state machine in place, you can render grenade effects in a `Class.RunService.RenderStepped` connection within a separate script based on the synchronized grenade state:
```lua title="Render Particles and Sounds based on the Synchronized Grenade State"
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Simulation = require(ReplicatedStorage.Simulation)
local grenade = script.Parent
local previousGrenadeState = nil
-- Highlight instance to indicate grenade state
local highlight = Instance.new("Highlight")
highlight.Parent = grenade
highlight.FillTransparency = 1
highlight.OutlineTransparency = 1
highlight.DepthMode = Enum.HighlightDepthMode.Occluded
RunService.RenderStepped:Connect(function(deltaTime: number)
local grenadeState = grenade:GetAttribute("State")
local grenadeTimer = grenade:GetAttribute("Timer")
-- Emit the lit particles if the grenade is lit
grenade.LitEmitter.Enabled = grenadeState == Simulation.GrenadeStates.Lit
-- Play the explosion emitter if the grenade just exploded
if previousGrenadeState ~= grenadeState then
if grenadeState == Simulation.GrenadeStates.Exploded and grenadeTimer < 0.2 then
grenade.ExplosionEmitter:Emit(100)
grenade.ExplosionSound:Play()
end
previousGrenadeState = grenadeState
end
-- Change the grenade's highlight color based on the state and time
if grenadeState == Simulation.GrenadeStates.Lit then
highlight.FillColor = Color3.fromRGB(255, 0, 0)
highlight.FillTransparency = 1 - (grenadeTimer / Simulation.GrenadeExplodeTime)
elseif grenadeState == Simulation.GrenadeStates.Idle then
highlight.FillTransparency = 1
elseif grenadeState == Simulation.GrenadeStates.Exploded then
highlight.FillTransparency = 1
elseif grenadeState == Simulation.GrenadeStates.Defused then
highlight.FillColor = Color3.fromRGB(0, 255, 125)
highlight.FillTransparency = 0.5
end
end)
```
## Designing around network latency
Certain gameplay mechanics lend themselves better to networked multiplayer than other mechanics. Players will always have some delay between when another player performs an action and when they receive that player's input. The best way to create a super smooth multiplayer experience is to design your experience with these limitations in mind.
For example, an experience with slower acceleration on player movement will appear smoother than one with higher acceleration because the difference in position caused by the network latency of player input will be less than in an experience with higher acceleration.
As another example, a gameplay mechanic where players can **instantly** trigger a large explosion by pressing an input will have more network artifacts than if the explosion is delayed after the input, as if by lighting a fuse. This puts the resimulation on the fuse effect instead of on the explosion effect which is a less noticeable network artifact.
## Predicting other player inputs
By default, Roblox does not forward the inputs from each client to every other client. Whether this is right for your experience depends on its design:
- For basic humanoid movement, the default behavior means that other player characters' movements are not extrapolated from the authoritative server state and, as a result, other player characters will not mispredict but will render slightly in the past.
- In a racing game, by contrast, the default behavior means that clients will not know whether other players are applying the throttle or other inputs, so other cars may appear behind the local player even if they're actually ahead. To alleviate this, you can store player inputs in [attributes](../../studio/properties.md#instance-attributes) on the server and operate on those synchronized attributes client‑side using `Class.RunService:BindToSimulation()` as demonstrated in the following code sample and the [Racing](https://www.roblox.com/games/134686834388911/Racing-Server-Authority-Template) template. This approach lets you use attributes as inputs to your simulation to have fully replicated player inputs.
```lua title="Storing Player Input in Attributes (ModuleScript)"
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local module = {}
module.storePlayerInput = function(player:Player, humanoidRootPart:BasePart)
local inputContext:InputContext = player.PlayerGui.InputContext
local throttle = inputContext.DefuseAction:GetState()
humanoidRootPart:SetAttribute("Throttle", throttle)
-- Write any other inputs into attributes...
end
module.Initialize = function()
RunService:BindToSimulation(function(deltaTime)
if RunService:IsServer() then
-- Forward inputs from server to all clients
for _, player in Players:GetPlayers() do
local humanoidRootPart:BasePart = player.Character.HumanoidRootPart
local inputContext:InputContext = player.PlayerGui.InputContext
module.storePlayerInput(player, humanoidRootPart)
end
else
-- Write local player inputs as attributes
local player = Players.LocalPlayer
local humanoidRootPart:BasePart = player.Character.HumanoidRootPart
local inputContext:InputContext = player.PlayerGui.InputContext
module.storePlayerInput(player, humanoidRootPart)
end
-- Use the attributes as inputs to the game
for _, player in Players:GetPlayers() do
local humanoidRootPart:BasePart = player.Character.HumanoidRootPart
local throttle = humanoidRootPart:GetAttribute("Throttle")
if throttle then
-- Apply the throttle to the player's vehicle
end
end
end)
end)
return module
```
## Debugging
There are some new tools and techniques you can use to debug a server‑authoritative experience.
### Server authority visualizer
Pressing <kbd>Ctrl</kbd><kbd>Shift</kbd><kbd>F6</kbd> (Windows) or <kbd>⌘</kbd><kbd>Shift</kbd><kbd>F6</kbd> (Mac) opens Studio's **server authority visualizer** which shows several key pieces of information:
<table size="small">
<thead>
<tr>
<th width="35%">Details</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>**Instance prediction success rate**</td>
<td>The percentage of correctly predicted instances over the last 8 seconds.</td>
</tr>
<tr>
<td>**Input accept rate**</td>
<td>The percentage of all players' inputs that arrived on time on the server. Late inputs will lower this number.</td>
</tr>
<tr>
<td>**Client-server step delta**</td>
<td>The number of frames between the client and the server, including the join time of the client. The stability of this number represents the stability of your connection to the server.</td>
</tr>
<tr>
<td>**RCC heartbeat FPS**</td>
<td>The frame rate of the simulation on the server. If this number drops below 59, the server cannot keep up with the simulation and the experience will degrade in quality.</td>
</tr>
<tr>
<td>**Predicted instance count**</td>
<td>The number of instances your client is [predicting](./index.md#client-prediction).</td>
</tr>
<tr>
<td>**Input drop reason counts**</td>
<td>
The number of times the server has dropped an input for each reason:
- **[x] too old** — The inputs arrived late, meaning your network worsened or the client could not keep up with the simulation.
- **[x] out of order** — A networking bug occurred that caused your inputs to be rearranged and discarded.
- **[x] buffer full** — The server could not buffer your input. Either your network suddenly improved or the server could not keep up with the simulation.
</td>
</tr>
</tbody>
</table>
### Simulation radius
When relying on automatic prediction (`Enum.PredictionMode.Automatic`), you can visualize the prediction radius around your player character by enabling **Are&nbsp;Regions&nbsp;Enabled** in Studio's settings (<kbd>Alt</kbd><kbd>S</kbd> on Windows; <kbd>⌥</kbd><kbd>S</kbd> on Mac). The green cylinder indicates the range around your character in which instances are predicted, and its radius grows and shrinks based on the performance characteristics of the device.
<img src="../../assets/studio/debugging/Server-Authority-Simulation-Radius.jpg" width="800" alt="Simulation radius around player character with server authority running" />

View file

@ -0,0 +1,189 @@
---
title: Teleport between places
description: Explains how to use TeleportService to teleport users between different places in your experience.
---
If you want to build an experience with many distinct places, such as a fantasy world with multiple towns, castles, dungeons, and a vast forest, you can use `Class.TeleportService` to enable users to teleport between places in a universe, servers, or even to another experience.
<Alert severity="warning">
`Class.TeleportService` doesn't support playtesting in Roblox Studio. You must publish the experience and use it on the Roblox application for testing.
</Alert>
## Set up teleportation
To enable teleportation in your experience, use `Class.TeleportService:TeleportAsync()`. The method accepts three parameters:
- The `Class.DataModel.PlaceId|PlaceId` for users to teleport to.
- An array containing the `Class.Player` instances representing the users to teleport.
- An optional `Class.TeleportOptions` instance that contains custom properties for the `Class.TeleportService:TeleportAsync()|TeleportAsync()` call.
```lua
local Players = game:GetService("Players")
local TeleportService = game:GetService("TeleportService")
local TARGET_PLACE_ID = 1234 -- replace with your own place ID
local playerToTeleport = Players:GetPlayers()[1] -- get the first user in the experience
TeleportService:TeleportAsync(TARGET_PLACE_ID, {playerToTeleport}, teleportOptions)
```
<Alert severity="warning">
You can only call `Class.TeleportService:TeleportAsync()|TeleportAsync()` from server-side scripts. This limitation reduces client-side exploitation. If necessary, you can call `Class.TeleportService:Teleport()|Teleport()` from client-side scripts, but `Class.TeleportService:TeleportAsync()|TeleportAsync()` is the recommended method.
</Alert>
If you want to take precautions of handling errors when setting up teleportation, see how to [handle failed teleports](#handle-failed-teleports).
### Enable cross experience teleportation
For security purposes, teleporting a user from your experience to another experience owned by others fails by default. To enable cross experience teleportation, open the **Security** section of Studio's **File**&nbsp;⟩ **Experience Settings** window and enable **Allow Third Party Teleports**.
## Create custom teleport screens
When a user triggers a teleport, they see the standard Roblox loading screen as they wait for the new place to load in. You can add a custom teleport screen to improve immersion for users by calling `Class.TeleportService:SetTeleportGui()` on the client and pass through the `Class.ScreenGui` to use before teleporting the user. The following example sets a customized `Class.ScreenGui` located in `Class.ReplicatedStorage` as the loading screen when a teleport happens. It doesn't run any scripts inside of the `Class.ScreenGui`.
```lua
local TeleportService = game:GetService("TeleportService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local teleportGui = ReplicatedStorage.TeleportGui
TeleportService:SetTeleportGui(teleportGui)
```
## Customize teleport options
You can customize teleportations, such as [teleporting users to a specific server](#teleport-to-specific-servers) and [sending user data along with teleports](#send-user-data-along-with-teleports), by setting the `Class.TeleportOptions` instance and passing it to the `Class.TeleportService:TeleportAsync()` method.
### Teleport to specific servers
To teleport users to specific servers, set the target server using `Class.TeleportOptions` and pass it to the `Class.TeleportService:TeleportAsync()` method. If you don't specify a server, users are teleported into a matchmade public server. The information of the first user in the list is used to matchmake to that public server.
To teleport users to a specific public server, set the `Class.TeleportOptions.ServerInstanceId` property as a valid instance ID, which is a unique identifier for a public server.
```lua
local teleportOptions = Instance.new("TeleportOptions")
teleportOptions.ServerInstanceId = targetServerId
```
To teleport users to a specific reserved server, set a valid `Class.TeleportOptions.ReservedServerAccessCode`, which is a unique code for entering a reserved server.
```lua
local teleportOptions = Instance.new("TeleportOptions")
teleportOptions.ReservedServerAccessCode = reservedServerCode
```
To teleport users to a new reserved server, set `Class.TeleportOptions.ShouldReserveServer` to true.
```lua
local teleportOptions = Instance.new("TeleportOptions")
teleportOptions.ShouldReserveServer = true
```
### Send user data along with teleports
Teleporting a user between places discards any local data associated with that user. You can use the following approaches to handle data persistence between places.
- If your experience utilizes **secure** user data like in-experience currency or inventory, implement [data stores](../cloud-services/data-stores) or [memory stores](../cloud-services/memory-stores/index.md) to maintain data from place to place.
- To send basic **non-secure** data from place to place, call `Class.TeleportOptions:SetTeleportData()` before passing it to `Class.TeleportService:TeleportAsync()|TeleportAsync()`.
<Alert severity="warning">
Don't pass secure data using `Class.TeleportOptions:SetTeleportData()` because it has the risk of exploitation.
</Alert>
```lua
local teleportData = {
randomNumber = RNG:NextInteger(1, 100),
}
local teleportOptions = Instance.new("TeleportOptions")
teleportOptions:SetTeleportData(teleportData)
```
To get all data of a user arriving from a teleport on the server, use the `Class.Player:GetJoinData()` function, which returns a dictionary including the data associated with the user.
```lua
local Players = game:GetService("Players")
local function onPlayerAdded(player)
local joinData = player:GetJoinData()
local teleportData = joinData.TeleportData
local randomNumber = teleportData.randomNumber
print(player.Name .. "joined with the number" .. randomNumber)
end
Players.PlayerAdded:Connect(onPlayerAdded)
```
To retrieve only the teleport data on the client, you can use `Class.TeleportService:GetLocalPlayerTeleportData()`.
## Handle failed teleports
Like any API call that involves network requests, teleports can fail and throw an error. Wrap them in protected calls (`Global.LuaGlobals.pcall()`). Some failures benefit from retries, particularly those involving reserved servers, so we recommend retrying some number of times on failures.
Even if a call succeeds and the teleport initiates, it can still fail at the last moment without throwing an error and leave the user in the server. When this happens, it triggers the `Class.TeleportService.TeleportInitFailed` event.
The following example `Class.ModuleScript` defines a `SafeTeleport` function to teleport the user in a protected call with retry logic. It also has a `handleFailedTeleport` function to deal with situations in which the call was successful, but the teleport didn't occur.
```lua
local TeleportService = game:GetService("TeleportService")
local ATTEMPT_LIMIT = 5
local RETRY_DELAY = 1
local FLOOD_DELAY = 15
local function SafeTeleport(placeId, players, options)
local attemptIndex = 0
local success, result -- define pcall results outside of loop so results can be reported later on
repeat
success, result = pcall(function()
return TeleportService:TeleportAsync(placeId, players, options) -- teleport the user in a protected call to prevent erroring
end)
attemptIndex += 1
if not success then
task.wait(RETRY_DELAY)
end
until success or attemptIndex == ATTEMPT_LIMIT -- stop trying to teleport if call was successful, or if retry limit has been reached
if not success then
warn(result) -- print the failure reason to output
end
return success, result
end
local function handleFailedTeleport(player, teleportResult, errorMessage, targetPlaceId, teleportOptions)
if teleportResult == Enum.TeleportResult.Flooded then
task.wait(FLOOD_DELAY)
elseif teleportResult == Enum.TeleportResult.Failure then
task.wait(RETRY_DELAY)
else
-- if the teleport is invalid, report the error instead of retrying
error(("Invalid teleport [%s]: %s"):format(teleportResult.Name, errorMessage))
end
SafeTeleport(targetPlaceId, {player}, teleportOptions)
end
TeleportService.TeleportInitFailed:Connect(handleFailedTeleport)
return SafeTeleport
```
The `SafeTeleport` function receives the same arguments as the `Class.TeleportService:TeleportAsync()|TeleportAsync()` function. You can use the following `Class.ModuleScript` with the `SafeTeleport` function to perform teleports from anywhere in your experience to reduce failed teleports.
```lua
local Players = game:GetService("Players")
local ServerScriptService = game:GetService("ServerScriptService")
local SafeTeleport = require(ServerScriptService.SafeTeleport)
local TARGET_PLACE_ID = 1818 -- replace with your own place ID
local playerToTeleport = Players:GetPlayers()[1] -- get the first user in the game
SafeTeleport(TARGET_PLACE_ID, {playerToTeleport}, teleportOptions)
```

View file

@ -0,0 +1,38 @@
---
title: Release experience updates
description: Explains how to release updates for experiences.
---
When you publish an updated version of an experience to Roblox, players aren't immediately removed from old versions of the experience. Instead, you can migrate players to the updated version by restarting all of your outdated servers.
If you don't restart servers, players transition to the new version of the experience as the servers running old versions eventually empty and shut down. This option is non‑disruptive, but your player base might be playing different versions of the experience for a prolonged period of time; if your underlying player data format changes, you should probably restart servers.
For time-sensitive updates, you might prefer to deploy early, hide content behind a [config](../production/configs.md), and then change the config value to release your new content.
## Restart servers
To restart servers for release updates:
1. Go to [Creations](https://create.roblox.com/dashboard/creations) and select the experience you want to restart servers for.
2. Go to **Configure** ⟩ **Server Management**.
3. Select the places you want to restart.
4. Click **Restart Servers**.
5. In the **Confirm Server Restart** dialog:
1. Select one or both of the following restart options:
- **Restart only servers with outdated versions** to avoid restarting servers that are running the latest published place version.
- **Delay server restart** to delay the shutdown of servers and allow players a set time between 1 and 60 minutes to leave the experience on their own instead of being temporarily disconnected. This is also known as server bleed-off.
2. Click **Restart**.
<Alert severity="warning">
Unless you have an experience update workflow that is independent of place version, it's recommended that you always select **Restart only servers with outdated versions** to avoid unnecessarily disconnecting players.
</Alert>
After you restart servers, Roblox:
1. Stops all matchmaking to servers designated for shutdown. Players who join your experience by clicking the **Play** button will not be matched to these servers, but they can still join them by accepting invites, teleporting, or joining another user from their profile.
2. Waits for the configured delay time, if you selected the **Delay server restart** option.
3. Automatically teleports players to the updated version of the experience. All players on the same old server are sent to the same replacement server running the new version.
<Alert severity="info">
If you want to completely shut down your experience and not allow players to reconnect after you restart your servers, you must make the experience private.
</Alert>