Loomreference

Services

The Roblox services loom implements, and why the rest fail at the call rather than the import.

@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.
ContentProviderPreloadAsync and RequestQueueSize. Added in 0.12.0.
PlayersLocalPlayer with a pre-built PlayerGui, plus UserId, DisplayName and GetUserThumbnailAsync since 0.12.0.
RunServiceRenderStepped / Heartbeat / PostSimulation / Stepped, BindToRenderStep, IsStudio / IsRunning / IsClient / IsServer.
StarterGuiA real container; SetCore / GetCore / SetCoreGuiEnabled / GetCoreGuiEnabled as no-ops.
TextServiceGetTextSize / GetTextBoundsAsync — see below.
TweenServiceCreate and real tween playback — see Animation.
UserInputServiceInput signals, GetMouseLocation, GetFocusedTextBox, capability flags, and since 0.12.0 the key and touch state readers (IsKeyDown, GetKeysPressed, IsMouseButtonPressed).
WorkspaceCurrentCamera 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.

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 API

JSONEncode / 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.

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 value

ToHSV() 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.