Preload
Preload warms every asset your game registered through ContentProvider:PreloadAsync in batches, narrating progress on the bus so a loading screen can render it. It’s one half of the kernel’s pay-instance-costs-once pair; the other half, Pool, recycles live Instances instead of warming assets ahead of time.
Mental model
Section titled “Mental model”The framework already knows most of the assets your game will touch: AudioKit banks and AnimKit banks each expose assetIds(). Preload.run gathers those, plus any extra content-id strings or whole Instances you pass, dedupes the ids, and feeds them to ContentProvider:PreloadAsync in batches on a spawned thread:
- Gather + dedupe. String ids dedupe by value (an id in both a bank and your
Assetslist preloads once). Instances pass through untouched —PreloadAsyncresolves their asset references itself. - Batch. Slices of
BatchSize(default 16) go to the preloader sequentially. Batching bounds how much onePreloadAsynccall bites off, and a per-batchpcallisolates failures: a batch that throws is warned ([Preload] batch failed: ...) and skipped, and the pass continues with the next batch. - Narrate. Every per-asset callback publishes
Preload.Progresswith running counts. Assets that fetch with a non-Successstatus are collected intoFailed— a missing asset id never aborts the warm-up. - Finish.
Preload.Donepublishes, the handle flipsDone = true, and every thread blocked inawait()resumes.
run() returns immediately with a live handle; await() is for flows that must block until warm (hold the loading screen, then start the round).
-- src/Client/Bootstrap.luaulocal ReplicatedStorage = game:GetService("ReplicatedStorage")local Preload = require(ReplicatedStorage.ChloeKernel.Preload)
return function(kernel) local Gui = Instance.new("ScreenGui") Gui.IgnoreGuiInset = true local Bar = Instance.new("Frame") Bar.Size = UDim2.fromScale(0, 0.02) Bar.Position = UDim2.fromScale(0, 0.98) Bar.BackgroundColor3 = Color3.fromRGB(145, 139, 255) Bar.Parent = Gui Gui.Parent = game:GetService("Players").LocalPlayer:WaitForChild("PlayerGui")
kernel.Bus:subscribe("Preload.Progress", function(_, loaded, total) Bar.Size = UDim2.fromScale(loaded / total, 0.02) end) kernel.Bus:subscribe("Preload.Done", function(_, loaded, total, failed) if #failed > 0 then warn(`{#failed} assets failed to preload`) end Gui:Destroy() end)
local Warmup = Preload.run(kernel, { -- Banks = { Audio, Anims }: pass your AudioKit/AnimKit instances (anything with :assetIds()) Assets = { "rbxassetid://9046898403", "rbxassetid://129423030", workspace }, -- ids and/or whole Instances }) Warmup:await() -- block this flow until warm; everything above already rendersendThe loading screen is also the right moment to run DeviceBench: Preload occupies the network while the bench uses the idle CPU.
API reference
Section titled “API reference”| Member | Description |
|---|---|
Preload.run(kernel, options?) → handle |
Publishes Preload.Started synchronously, then batches on a spawned thread. Needs kernel.Bus. |
Options (all optional):
| Field | Default | Description |
|---|---|---|
Assets |
{} |
Content-id strings and/or Instances. Strings dedupe; Instances pass through. |
Banks |
{} |
Anything with an :assetIds() → { string } method — AudioKit, AnimKit, or your own registry. |
BatchSize |
16 |
Assets per PreloadAsync call. |
Preloader |
ContentProvider:PreloadAsync |
Injectable (assets, callback(assetId, ok)) for specs. |
Handle:
| Field / method | Description |
|---|---|
handle.Done |
true once every batch has run. |
handle.Loaded |
Assets that have completed a fetch callback (success or failure). |
handle.Total |
Asset count fixed at gather time. |
handle.Failed |
Array of asset ids whose fetch status was not Success. |
handle:await() |
Yields the calling coroutine until done; returns immediately if already done. |
Bus topics
Section titled “Bus topics”| Topic | Payload | Fired |
|---|---|---|
Preload.Started |
(total) |
Once, synchronously inside run() — subscribe before calling run or you miss it. |
Preload.Progress |
(loaded, total, assetId, ok) |
Per asset, as each fetch resolves. |
Preload.Done |
(loaded, total, failed) |
Once, after the last batch. failed is the array of failed ids. |
Design notes
Section titled “Design notes”Totalis fixed whenrun()gathers — assets registered into a bank afterwards are not picked up. Register banks first, preload last.- Dedupe applies to string ids only. The same Instance passed twice is preloaded twice (harmless — the second fetch is a cache hit).
- Multiple
run()calls are independent passes with independent handles and bus narration; there is no global queue.