Scribe¶
The module you require and call. Scribe(options) compiles your template
and returns a { Server, Client } bundle. Use .Server on the server and
.Client on the client from the same shared module.
Scribe also exposes the field declarators (Scribe.Int, Scribe.Vector3,
…) you use inside a template, the visibility wrappers (Scribe.ServerOnly,
Scribe.Shared, Scribe.Session), and library-wide diagnostics.
local Scribe = require(ReplicatedStorage.Packages.Scribe)
return Scribe({
Template = { Coins = Scribe.Int(0, { Min = 0 }) },
ProfileStoreIndex = "PlayerData",
ProfileKeyPrefix = "PLAYER_",
})
Setup¶
.Version¶
The library version (e.g. "1.0.0").
.new¶
Compiles the template and builds the { Server, Client } bundle. Calling the
module directly (Scribe(options)) is sugar for this. Require the same
shared module on both the server and the client and use the matching half.
Visibility¶
.ServerOnly¶
Marks a root field server-only: it persists and is readable on the server, but is never replicated to any client. May also wrap a nested field to keep just that subtree server-side.
.Shared¶
Marks a root field shared: it replicates to every client (not just the owner), for public info like a display name or team.
.Session¶
Marks a root field session-only: replicated to the owner but never
persisted. Ideal for runtime state like InCombat that should reset on
rejoin.
Field Types¶
.Int¶
Declares an integer field. Non-integer writes round (or reject under
BoundsPolicy = "Reject"); out-of-range writes clamp. Bounded ints also
pack to a smaller wire width.
.Number¶
Declares a floating-point field with optional bounds.
.String¶
Declares a string field, optionally length-capped.
.Enum¶
Declares a string field restricted to a fixed set of members. Writes outside the set are rejected, and the value packs to a single byte.
.Timed¶
Declares a field with an expiry. Set it with field.SetTimed(value, seconds);
it auto-clears back to default when the timer lapses (firing Changed).
Great for boosters and temporary buffs.
.Dynamic¶
Declares a field whose default is produced by factory per profile rather
than frozen once at server start. Use it for values that must be evaluated for
each profile, like a creation timestamp:
CREATION_UNIX = Scribe.Dynamic(os.time),
JOINED_AT = Scribe.Dynamic(function() return DateTime.now() end), -- datatype, packed for you
Returning players keep their stored value; the factory only runs to seed the field on a brand-new profile (or one that gains the field after you add it to the template later). The field types as the factory's return type.
The factory must be pure. It is also called once at declaration time (while
your template module loads) to sample its return type, so it must be
side-effect-free and must neither yield nor error; keep it to plain producers
like os.time / DateTime.now. Anything that reserves an id, reads a store, or
has other side effects would fire that effect at module load with no profile
attached. Player-specific defaults (based on player.Name, a lookup, and so on)
belong in OnPlayerInit.
Scribe.Dynamic cannot sit inside a Scribe.Session root (a startup error):
Session data is rebuilt from its default every session, so a one-time seed has
nowhere to live. Use OnPlayerInit for per-session values.
.Vector3¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real Vector3.
.Vector2¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real Vector2.
.Vector3int16¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real Vector3int16.
.Vector2int16¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real Vector2int16.
.CFrame¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real CFrame.
.Color3¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real Color3.
.BrickColor¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real BrickColor.
.UDim¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real UDim.
.UDim2¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real UDim2.
.Rect¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real Rect.
.NumberRange¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real NumberRange.
.NumberSequence¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real NumberSequence.
.ColorSequence¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real ColorSequence.
.DateTime¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real DateTime.
.EnumItem¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real EnumItem.
.Font¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real Font.
.PhysicalProperties¶
Declares a Roblox datatype field. The value is stored and replicated as a
compact packed buffer; Get/Set convert at the boundary, so your code only
ever sees the real PhysicalProperties.
.Datatypes¶
Scribe.Datatypes: { Pack: (name: string, value: any) -> buffer, Unpack: (name: string, b: buffer) -> any }
Low-level pack/unpack helpers for the 17 datatypes, exposed so migrations can convert legacy representations to the packed form.
Diagnostics¶
.GetStatus¶
The current data-service health, derived from ProfileStore's error signals
with hysteresis. Also broadcast to clients via Client:GetServiceStatus.
.OnStatusChanged¶
Fires with the new status ("Healthy" | "Degraded" | "Outage") whenever
service health changes.
.OnIssue¶
Fires for every Error/Fatal log entry: the single hook to wire up developer alerting (Discord webhook, PagerDuty, …) from your own game code.
.AddLogSink¶
Registers an extra log sink. Scribe never sends logs anywhere itself. Add a sink to forward them to your own pipeline. Keep secrets in game code.
.GetRecentLogs¶
Scribe.GetRecentLogs(filter: { Level: LogLevel?, Category: LogCategory?, Code: LogCode?, Limit: number? }?) → { LogEntry }
Returns entries from the 512-entry ring buffer, newest first, optionally
filtered by level/category/code. Code, Level, and Category are typed
string unions, so editors autocomplete valid values (see the Log Code
Reference for the full list of codes).
.GetMetrics¶
A snapshot of internal counters (saves, loads, receipt outcomes, queue
depths, …) for admin panels and load tests. Plain counters are numbers;
timing and size distributions are { Count, Average, Max } records.