Package (asset type)
A package is a shippable, heterogeneous library folder. It bundles components, modules, scenes, presets, tools, and any other typed assets under a single addressable identity (@<owner>::<name>) that…
When to use one
- You're authoring a coherent feature suite (character controller stack, voxel engine, UI kit, animation library) and want to ship it as one install target.
- You want a stable identity worlds can opt into via
world.installLibraryand resolve sub-assets against (@<owner>::pkg.sub_module). - You want versioning + a per-package metadata layer that travels with the contents.
If you're authoring inside a single world and don't need a separate
install lifecycle, you don't need a package — drop your .component
/ .module / etc. directly in /zero/source/. Packages are for
cross-world distribution.
Where it lives
- Source:
/zero/source/.../<Name>.package/(or, for legacy packages, a folder containingpackage.yamlat its root). - Identity:
<Name>(the.packagesuffix collapses in identity — mirrors.module). A file at<Name>.package/<sub>/init.luauresolves under the same identity it would at<Name>/<sub>/init.luau. - Folder shape (container-style — open child set):
package.yaml— metadata (name, version, description). Required.README.md— instance documentation. Required.- Sub-asset folders: any combination of
.component/,.module/,.scene/,.preset/,.tool/,.toolbox/,.material/,.shader/, etc.
The validator permits unlisted children (allow_unlisted: true) by
design — packages are open containers.
How to create one
asset.create("package", "<Name>")
-- Creates: /zero/source/libs/@<owner>/<Name>.package/
-- package.yaml (metadata scaffold)
-- README.md (instance README template)
Then scaffold sub-assets inside it:
local pkg = asset.resolve("<Name>.package")
asset.create("component", "Spinner", { into = pkg })
asset.create("module", "util", { into = pkg })
How it operates
- Registration. Writing
package.yamlindexes the package with the package registry. - Install.
world.installLibrary("@<owner>::<name>")resolves the package and mounts its identity in the current world. Once installed, sub-assets are require-able as@<owner>::<name>.<sub_module>. - Sub-asset resolution. Because
.packagecollapses in identity, sub-asset paths work whether the package folder is suffixed (<Name>.package/<sub>) or not (<Name>/<sub>). - Uninstall.
world.uninstallLibrary("@<owner>::<name>")removes the package's mount; sub-asset references become unresolved. - Metadata.
package.yaml::nameoverrides the folder stem if present (rare);version+descriptionare surfaced in the package index. - Hot reload. Edits to sub-assets hot-reload as normal; edits to
package.yamlreload package metadata.
Discovery
asset.list("package")— every registered package.asset.inspect("<name>")— sub-asset catalog, source, this type README.cat /zero/source/<Name>.package— same summary.world.listLibraries()— packages currently installed in this world.
Authoring conventions
- Name packages by their feature (
voxels,thirdPersonController,dialogSystem), not by their owner — the owner is the@<owner>::scope prefix. - Cluster cohesive sub-assets together. A "character controller" package should ship the controller component, its preset configs, its supporting modules, and a demo scene — not just the component.
- Document the package's surface in
README.md— what install installs, what each sub-asset does, how they relate. Agents readingcat /zero/source/<Name>.packageget the full picture in one shot. - Version conservatively — breaking a package means breaking every world that installed it. Use semantic version bumps.
Common pitfalls
- Missing
package.yaml. Without it the folder isn't recognized as a package even if it has a.package/suffix. - Dependency installs. A package that depends on another package
must declare it (in
package.yaml::dependenciesonce supported) and the parent world must install dependencies in order. - Identity collapse. Sub-asset paths skip the
.packagesuffix. Don't include.packageinrequirestrings.
Referencing inside a package: the ~ rule
~ means this package, resolved structurally from the referring file's own
location. It is the only package-specific syntax. It is rename-safe (no package
name is ever written) and library-agnostic (it never names the host library, so
it survives @builtin being renamed or the package being mounted elsewhere).
~.tail maps to <pkg>.package/tail from anywhere inside the package.
| Referencing from | Use | Example |
|---|---|---|
| An asset/module inside this package | ~.tail | require("~.modules.myThing"), shader: "~.shaders.myThingBlend" |
| A different package under the same root | root-relative identity | require("@root::systems.otherPkg.modules.x") |
| A different library's public API (a deliberate external dependency) | @otherlib::… | require("@physics::modules.rigidbody") |
Never write @builtin:: (or any host-library name) to reference your own
package — that couples the package to the library it currently lives in and
breaks if the library is renamed or the files move. Use ~.. It works from
Luau require() and from asset-reference strings in data files (a material's
mat.yaml shader: field, a component's default asset ref); the engine
resolves it against the referring file's own package. In a .luau file holding
a ~. ref as a string, resolve it explicitly against your own path:
asset.resolve("~.materials.myThingStandard", "material", __FILE__).
~. is the package-relative self-reference; @root:: is the root-relative one
(the library root, or the world source tree for non-library content). The
core/requiring-modules guide covers the root model in full.
A package that ships substantial functionality should include a .guide asset
(a <name>.guide/guide.md folder anywhere under the package); the guides tool
discovers it live, so collaborators find the system the way they find built-in
guides. A package's test suite reaches the shared Test framework through its
enclosing asset: local Test = asset.containing(__FILE__).modules.shared
(asset.containing returns the deepest enclosing typed asset, the .testSuite,
not the outer .package).
Related types
- Any of
.component,.module,.scene,.preset,.tool,.toolbox,.material,.shader,.style,.service,.importer— packages bundle these.