A first file
A .shot file is a ModuleScript minus the boilerplate: plain Luau on top, one declaration under it.
You'll learn the project folder, a module, a script, and your first check, build and run.
The project
@client enabledstarts the client@server enabledstarts the servermodule CoinsWatch out Make these folders and files yourself (shot new makes one-file projects; page 1 says why), and run every shot command from inside MyProject.
A module
The table is the declaration; its functions are written inside it:
--!strictlocal SUFFIX = " coins"local Coins = {}function Coins.Format(amount: number): string return tostring(amount) .. SUFFIXendreturn Coins
types script.Parent.Typeslocal SUFFIX = " coins"module Coins = { function Format(amount : number) : string return tostring(amount) .. SUFFIX end}
What it compiles toWallet/Coins.luau
--!strict local Types = require(script.Parent.Types) export type Coins = Types.Coins local SUFFIX = " coins" local Coins : Coins = {} :: any local module = Coins function Coins.Format(amount : number) : string return tostring(amount) .. SUFFIX end return Coins
types script.Parent.Typespoints the file at its folder's types (every file but scripts and Types itself).- Plain Luau above the declaration is copied as it is: services, requires, constants, local functions.
- The file name is the declared name. The compiler adds
--!strictand thereturn. - The table is typed:
Coins's type goes into the folder's Types module, so other files seeFormat's real signature.
--!strict if true then return {} end --[[$public]] export type Coins = { Format : (amount : number) -> string, }
Tip The Types module only holds types, so it returns at once and never runs.
A script
A file whose first line is @server or @client is a script: it runs by itself when the game starts. @shot is ReplicatedStorage.Shot.
local ReplicatedStorage = game:GetService("ReplicatedStorage")local Coins = require( ReplicatedStorage.Shot.Wallet.Coins)print(Coins.Format(25))
@server enabledlocal Coins = require(@shot.Wallet.Coins)print(Coins.Format(25))
What it compiles toInit/Server.server.luau
--!strict local Coins = require(script.Parent.Parent.Wallet.Coins) print(Coins.Format(25))
Init/Client.shot is the same with @client enabled; for now it only prints client started.
Check, build, run
0 errors (4 files checked, 2.8 s)
4 files written to ../build, 0 errors
Tip ../build holds ReplicatedStorage/Shot/... in the Rojo layout, ready for Studio. Every compiled file these pages show is in there.
To run without Studio, add a scenario in MyProject/Scenarios/: it plays the game in a mock Roblox and never ships. world:Boot() starts the scripts, world:AddPlayer joins a player, world:Step runs frames (page 13 lists every call).
-- Hello: start the game with one player and read what it printed. return function(world) world:Boot() world:AddPlayer("Ana") world:Step(0.1) end
==== Hello [server print] 25 coins [client:Ana print] client started ==== summary Hello OK (2 lines, 0 errors, 0.1s virtual) 1 of 1 scenario(s) passed
Make Format return amount instead of the text and run shot check. It answers ./Wallet/Coins.shot:7:3 TypeError: Expected this to be 'string', but got 'number', at the line you wrote.
