Commands#
Shell Creator registers one in-game command. Everything else happens inside its interface.
Command | Who | Description |
|---|---|---|
| Admins | Opens the shell manager: create, edit, export, teleport to and delete shells. |
| Debug only | Spawns the shell model and teleports you to its spawn point, as a housing script would. Exists only while |
<id>is the shell id shown under Shell Information in the manager — the number at the end ofqs_shells_<id>.
Client Exports#
The quickest way for another script to know whether the player is busy building — to keep a phone, radial menu, inventory or emote menu closed, or to skip a HUD update.
IsInShellcreatorBuilder
local isBuilding = exports['qs-shellcreator']:IsInShellcreatorBuilder()Returns true while the player is in the builder — including while they are walking through a preview of the build.
IsInShellcreatorPreview
local isPreviewing = exports['qs-shellcreator']:IsInShellcreatorPreview()Returns true only while the player is in Preview, on foot inside the unsaved build.
Example: block a phone while building
local function canOpenPhone()
if GetResourceState('qs-shellcreator') == 'started'
and exports['qs-shellcreator']:IsInShellcreatorBuilder() then
return false
end
return true
endChecking GetResourceState first keeps your script working on servers without Shell Creator.
State Bags#
The same two states are written to the player's state bag and replicated, so they can be read from the client and from the server, or watched with a change handler instead of polling.
Key | true while |
|---|---|
| The player is in the builder. |
| The player is previewing a build. |
Reading it on the client
local inBuilder = LocalPlayer.state.shellcreatorInBuilder == true
local inPreview = LocalPlayer.state.shellcreatorInPreview == trueReading it on the server
local inBuilder = Player(source).state.shellcreatorInBuilder == trueUseful to refuse a server action — a paycheck tick, an AFK kick, a job duty change — while that player is building.
Reacting to changes
local myBag = ('player:%s'):format(GetPlayerServerId(PlayerId()))
AddStateBagChangeHandler('shellcreatorInBuilder', myBag, function(_, _, value)
if value then
print('Builder opened')
else
print('Builder closed')
end
end)The handler only runs when the value changes, which is cheaper than checking every frame.
Client Events#
Local events fired on the player's own client at each step of a building session. Listen with AddEventHandler.
shellcreator:client:builderEntered
AddEventHandler('shellcreator:client:builderEntered', function(data)
print(data.editMode, data.buildingId)
end)Fires when the builder opens. editMode is true when an existing shell is being edited, and buildingId is its id (nil for a new build).
shellcreator:client:builderExited
AddEventHandler('shellcreator:client:builderExited', function(data)
print(data.editMode, data.buildingId)
end)Fires when the builder closes, saved or not. Restore here whatever you disabled on enter.
shellcreator:client:previewEntered
AddEventHandler('shellcreator:client:previewEntered', function()
print('Preview started')
end)Fires when the player starts walking through the build.
shellcreator:client:previewExited
AddEventHandler('shellcreator:client:previewExited', function()
print('Preview ended')
end)Fires when the preview ends — by holding G, or because the builder was closed.
Spawning a Shell From Your Own Script#
No export is needed to put a shell in the world. Spawn its model like any streamed shell and the interior is assembled around the object, and follows it if you move or rotate it:
local model = joaat('qs_shells_12')
lib.requestModel(model)
local shell = CreateObject(model, coords.x, coords.y, coords.z, false, false, false)
FreezeEntityPosition(shell, true)The player must be within 100 m of the object for the interior to build. To place them at the entrance, add the spawn point offset from the default export format (Integrations) to the object's coordinates.



