@rbxts/services needs no configuration: the specifier is aliased to loom’s own service singletons,
and every export is the same object game.GetService(...) returns — never a copy.
import { HttpService, RunService, UserInputService } from "@rbxts/services";
HttpService === game.GetService("HttpService"); // trueWhat loom implements
| Service | What loom provides |
|---|---|
CollectionService | The real tag registry — AddTag, HasTag, GetTagged and the added/removed signals. Code-set tags only; there is no Studio tag editor. |
ContextActionService | BindAction / BindActionAtPriority / UnbindAction as no-ops. |
Debris | AddItem(instance, lifetime) on a real timer — the instance really is destroyed. |
GuiService | SelectedObject with selection signals, GetGuiInset, ReducedMotionEnabled. |
HttpService | GenerateGUID and the JSON pair — see below. |
ContentProvider | PreloadAsync and RequestQueueSize. Added in 0.12.0. |
Players | LocalPlayer with a pre-built PlayerGui, plus UserId, DisplayName and GetUserThumbnailAsync since 0.12.0. |
RunService | RenderStepped / Heartbeat / PostSimulation / Stepped, BindToRenderStep, IsStudio / IsRunning / IsClient / IsServer. |
StarterGui | A real container; SetCore / GetCore / SetCoreGuiEnabled / GetCoreGuiEnabled as no-ops. |
TextService | GetTextSize / GetTextBoundsAsync — see below. |
TweenService | Create and real tween playback — see Animation. |
UserInputService | Input signals, GetMouseLocation, GetFocusedTextBox, capability flags, and since 0.12.0 the key and touch state readers (IsKeyDown, GetKeysPressed, IsMouseButtonPressed). |
Workspace | CurrentCamera with a live ViewportSize. Reachable as game.Workspace since 0.12.0, like every other service. |
Then there are the services that are only containers in a client. They are exported as ordinary
instances so a tree can be parented into them: Lighting, ReplicatedFirst, ReplicatedStorage,
ServerScriptService, ServerStorage, SoundService, StarterPack, StarterPlayer and Teams.
AnalyticsService, DataStoreService, LocalizationService, LogService, MarketplaceService, MessagingService, PolicyService, Stats, TeleportService and TextChatService are exported but not implemented. Each needs a Roblox server on the other end, and inventing an answer for UserOwnsGamePassAsync would be worse than saying nothing.
They resolve to a warned stub: one console warning at startup, then a throw naming the member on the line that calls it. Leaving the name unexported would be a build error, taking down a preview whose only sin was importing a service beside the ones it uses.
To stand one up yourself, point a shim at
@rbxts/services and re-export loom’s singletons alongside your own.
TextService
import { TextService } from "@rbxts/services";
const bounds = TextService.GetTextSize( "Hello world", 18, Enum.Font.SourceSans, new Vector2(200, 1000),);GetTextSize(text, fontSize, font, frameSize) measures through the same font stack the renderer
paints with. What a component reserves and what the label occupies come from one place. Wrapping
is greedy at word boundaries and a zero frameSize.X means “no frame”. GetTextBoundsAsync(params)
reads the same measurement off a GetTextBoundsParams instance and does not yield.
The metrics are the browser’s, so shaping and rounding differ from the engine by a glyph here and there. Which typeface answers is the host’s to install. See Fonts and text metrics. The filtering methods are absent: moderation is a server call loom will not make.
HttpService
import { HttpService } from "@rbxts/services";
const id = HttpService.GenerateGUID(false);GenerateGUID(wrapInCurlyBraces?) returns a lowercase RFC 9562 version 4 UUID in canonical
8-4-4-4-12 form. wrapInCurlyBraces defaults to true as in Roblox, so GenerateGUID(false)
returns the bare 36 characters.
Entropy comes from the Web Crypto API — crypto.randomUUID() where available (secure contexts
only), otherwise crypto.getRandomValues() with the version and variant bits set explicitly.
Without Web Crypto it throws rather than generating a weak identifier:
[loom] HttpService.GenerateGUID requires the Web Crypto APIJSONEncode / JSONDecode are JSON.stringify / JSON.parse. Loom’s values are JavaScript
values, so what roblox-ts writes as an array or object encodes as it does in Studio.
JSONEncode(undefined) yields "null", and a malformed JSONDecode input throws rather than
returning undefined.
A preview never issues requests on your behalf, so GetAsync, PostAsync and RequestAsync throw by name rather than silently doing nothing.
UrlEncode is absent on purpose: the engine encodes more than encodeURIComponent does, and a near-miss encoder is worse than an omission.
Datatype helpers worth knowing
Color3.fromHex accepts exactly six RGB hex digits, either case, with or without one leading #, and
converts through the same path as Color3.fromRGB:
const accent = Color3.fromHex("#6366F1");CSS shorthand, alpha channels, 0x notation and stray whitespace are rejected with a located loom
error rather than reinterpreted as another colour.
Color3:ToHex() is its inverse: six lowercase digits with no leading #, each channel clamped
and rounded to the nearest 255th.
Color3.fromRGB(99, 102, 241).ToHex(); // "6366f1"Color3.fromHex(colour.ToHex()) === colour; // by valueToHSV() destructures as a tuple and Color3.fromHSV(h, s, v) is its inverse. Vector2 carries
Unit / Dot / Cross / Lerp / Min / Max / Abs, plus its xAxis / yAxis constants.
Vector3 carries the equivalents, and UDim2 a Lerp. UDim has none, because it has none in the
engine.