featherfall/quill_core
A featherweight framework for Luau
Core
The core crate of Quill.
Defining singletons
A singleton is defined to be a table of any shape and type, with optionally an init and start method.
export type Singleton = {
init: ((Singleton) -> ())?,
start: ((Singleton) -> ())?,
[any]: any,
}
Init is executed after all modules are loaded and cannot yield.
Start is executed after all modules are initialized and can yield, as it's ran in another thread with task.spawn.
local MySingleton = {}
function MySingleton.init(self: self)
-- Initialize your properties and everything that other singletons may depend on here.
-- For example, you'd initialize your datastore wrapper or signals in this function.
end
function MySingleton.start(self: self)
-- Run your singletons' logic here.
-- For example, you'd put a game loop here.
end
-- Allows for easy typechecking of any properties and methods.
export type self = typeof(MySingleton)
return MySingleton
Defining modules
Modules are Quill extensions which can hook onto:
- Singleton lifecycles:
injected- called once a singleton has been injected by the user withQuill:with_singletonorQuill:with_singletonsloaded- called once a singleton's modulescript has been loaded by the module loader; injected modules are skipped by this, as the user passes a loaded singleton to the framework in place of a moduleinitialized- called once a singleton has been initialized; immediately if it doesn't have an:initmethod, or if it has one, after it was calledstarted- called once a singleton has been started; immediately if it doesn't have a:startmethod, or if it has one, after it was called
- Module loader phases:
pre_loading- called before any modules are loaded; injected modules are loaded prior to this, as the user passes a loaded singleton to the framework in place of a modulepost_loading- called after all modules were loadedpre_initialization- called before singletons are initializedpost_initialization- called after singletons are initializedpre_starting- called before singletons are startedpost_starting- called after singletons are started
Lifecycle hooks are called with a singleton and its current lifecycle:
type LifecycleHook = (lifecycle: Lifecycle, singleton: Singleton) -> ()
Phases are called with a list of all singletons currently attached to the framework and the current module loader phase:
type PhaseHook = (phase: Phase, singletons: { Singleton }) -> ()
Building and starting the framework
After creating quill with Quill.new, you may:
- Add Quill modules with
Quill:with_mod - Add modulescripts with
Quill:with_moduleandQuill:with_modules - Inject singletons with
Quill:with_singletonandQuill:with_singletons - Lastly, start Quill with
Quill:write
Ideally, you'd add Quill modules prior to anything else, as injecting singletons runs the injected lifecycle hooks for them.
For example:
local quill = require("@pkg/quill")
local rblx_lifecycles = require("@pkg/quill_rblx_lifecycles")
quill.new()
:with_mod(rblx_lifecycles.mod)
:with_modules(script.singletons:GetChildren())
:write()