Loomreference

Services

The Roblox services loom implements for the browser — what each one provides, and why importing an unimplemented one is an error rather than a stub.

@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"); // true

What loom implements

ServiceWhat loom provides
CollectionServiceThe real tag registry — AddTag, HasTag, GetTagged and the added/removed signals. Code-set tags only; there is no Studio tag editor.
ContextActionServiceBindAction / BindActionAtPriority / UnbindAction as no-ops.
DebrisAddItem(instance, lifetime) on a real timer — the instance really is destroyed.
GuiServiceSelectedObject with selection signals, GetGuiInset, ReducedMotionEnabled.
HttpServiceGenerateGUID and the JSON pair — see below.
PlayersLocalPlayer with a pre-built PlayerGui.
RunServiceRenderStepped / Heartbeat / PostSimulation, IsStudio / IsRunning / IsClient.
StarterGuiA real container; SetCore / GetCore / SetCoreGuiEnabled / GetCoreGuiEnabled as no-ops.
TextServiceGetTextSize / GetTextBoundsAsyncsee below.
TweenServiceCreate and real tween playback — see Animation.
UserInputServiceInput signals, GetMouseLocation, GetFocusedTextBox, capability flags.
WorkspaceCurrentCamera with a live ViewportSize.

Plus the services that are only containers in a client, exported so a tree can be parented into them: Lighting, ReplicatedFirst, ReplicatedStorage, ServerScriptService, ServerStorage, SoundService, StarterPack, StarterPlayer and Teams. They have no behaviour to model, so before 0.7.0 they resolved to a warned stub; now they are ordinary instances.

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, so what a component reserves for a label and what the label then occupies come from one place. Wrapping is greedy at word boundaries and a zero frameSize.X means “no frame”, as in Roblox. The modern GetTextBoundsAsync(params) spelling reads the same measurement off a GetTextBoundsParams instance, and does not yield — there is nothing to wait for in a browser.

The caveat is the one that applies to all of loom’s text: the metrics are the browser’s, so shaping and rounding differ from the engine by a glyph here and there, and which typeface answers is the host’s to install — see Fonts and text metrics. The filtering methods (FilterStringAsync and friends) are absent: moderation is a server call loom will not make on anyone’s behalf.

HttpService

import { HttpService } from "@rbxts/services";
const id = HttpService.GenerateGUID(false);

GenerateGUID(wrapInCurlyBraces?) returns an RFC 9562 (RFC 4122) version 4 UUID, lowercase, in canonical 8-4-4-4-12 form, fresh on every call. wrapInCurlyBraces defaults to true as it does in Roblox, so GenerateGUID() returns {xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx} and GenerateGUID(false) returns the bare 36 characters.

Entropy comes from the Web Crypto API — crypto.randomUUID() when the browser offers it (it is secure-context only), otherwise crypto.getRandomValues() with the version and variant bits set explicitly. Never Math.random, never a timestamp or a counter. Without Web Crypto it throws rather than generating a weak identifier:

[loom] HttpService.GenerateGUID requires the Web Crypto API

JSONEncode(value) / JSONDecode(value) are JSON.stringify / JSON.parse. Loom’s values are JavaScript values, so what roblox-ts writes as an array or an object encodes exactly as it does in Studio. JSONEncode(undefined) yields "null"; a malformed JSONDecode input throws a loom error rather than returning undefined.

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 (#abc), alpha channels, 0x notation and stray whitespace are rejected with a located loom error rather than being silently reinterpreted as some other colour.

Color3:ToHex() is its inverse as of 0.7.0 — six lowercase digits with no leading #, each channel clamped and rounded to the nearest 255th, verified against a running engine rather than guessed at:

Color3.fromRGB(99, 102, 241).ToHex(); // "6366f1"
Color3.fromHex(colour.ToHex()) === colour; // by value

ToHSV() destructures as a tuple (const [h, s, v] = colour.ToHSV()) and Color3.fromHSV(h, s, v) is its inverse. The same release added Vector2’s Unit / Dot / Cross / Lerp / Min / Max / Abs and its xAxis / yAxis constants, the equivalents on Vector3, and UDim2:Lerp. UDim has no Lerp here because it has none in the engine either.