add, install, lockfile, and requiring modules.
Installing packages
A package is a versioned, reusable unit of game code and content — Lua modules, scenes, prefabs, and assets that several games can share. Packages exist so common gameplay (health, inventory, camera) and common art (prototype textures) are written once and depended on, instead of copied between projects. This page explains how to add, install, update, and use packages in your own game, with examples on "Skyforge" at games/my_game.
What a package contains
Every package is a directory with a manifest describing what it is and what it needs:
{
"format_version": 1,
"name": "demi.gameplay.health",
"version": "1.2.0",
"engine": "^1.0.0",
"dependencies": {
"demi.gameplay.events": "^1.0.0"
},
"public_modules": ["demi.gameplay.health"],
"files": ["scripts/demi/gameplay/health.lua"]
}
| Field | Meaning |
|---|---|
format_version | Always required. Documents without it are rejected. |
name | The package's identity in the registry, for example demi.gameplay.health. |
version | The release version of this package, in semantic versioning form (major.minor.patch). |
engine | The engine version range this package supports. |
dependencies | Other packages this one needs, each with a version constraint. |
public_modules | Module names other projects may require. Everything else in the package is private to it. |
files | The files the package ships: scripts, scenes, prefabs, assets. |
Why public_modules? Because a package should hide its internals. You depend on its declared API surface; its helper files can change without breaking your game.
Declaring a dependency
Dependencies live in demi.project.json and are managed with the package commands:
"package_registry": "https://demiengine.de",
"packages": {
"demi.gameplay.health": "^1.0.0",
"kenney.textures.prototype": "^1.0.0"
}
package_registry— where package names are resolved.packages— direct dependencies with version constraints.^1.0.0means "any 1.x release at 1.0.0 or newer, below 2.0.0".
Add one from the command line:
demi package add demi.gameplay.health@^1.0.0
package add name@constraint— resolves the name against the registry and records the constraint as a direct dependency.- Returns
0and updates the project'spackagesmap anddemi.packages.lock.json.
Remove one with demi package remove name, which drops the direct dependency and re-resolves the lock file.
Installing into the project
Declaring a dependency records intent; installing places the resolved files where the game can load them.
demi package install
package install— resolves every dependency and installs the package files into.demi/packages.--locked— installs exactly the versions pinned indemi.packages.lock.jsonand fails rather than re-resolving. Use this in continuous integration so builds are reproducible.--offline— installs from the local cache only, with no network access. Returns1when a needed version is not cached.--dry-run— prints the install plan and exits without writing anything.
Two files and one folder are involved:
| Path | Role |
|---|---|
demi.project.json | Declares what you want: names and constraints. |
demi.packages.lock.json | Pins what you got: exact resolved versions and their hashes. Commit this file. |
.demi/packages | A derived install folder. Safe to delete; install recreates it. |
Why pin a lock file? Because "it worked on my machine" is not a build. The lock file makes two installs of the same project byte-identical in dependency content.
Updating and inspecting versions
demi package update demi.gameplay.health
package update [name]— re-resolves dependencies within their declared constraints and refreshes the lock file. With a name, updates that package only; with no name, updates every package.
demi package list
demi package outdated --format json
package list— prints every resolved version currently installed.package outdated— prints resolved versions that have a newer release satisfying the constraint.--format json— the same listing as JSON for scripts and tools.
Both exit 0 when the dependency state is consistent.
Using package modules from Lua
Installed packages are loaded through their public modules, named exactly as in the manifest:
local GameplayEvents = require("demi.gameplay.events")
local Health = require("demi.gameplay.health")
local health = Health.new(GameplayEvents.new())
health:add(self.id, 100)
print(health:get(self.id).current) -- current hit points as a number
require("demi.gameplay.health")— loads the package's public module and returns its API table.- Call shapes depend on the package: each package documents its own functions and return values. The pattern is always "require the public module, call its functions, read its return values".
Requiring a module that is not a declared public module fails with a clear error — the package's private files are not part of the contract.
Engine services follow the same import style (require("demi.input"), require("demi.transform3d"), and so on); package modules simply live under their own namespace.
Package families
The public catalog organizes packages into families. Names say what they cover:
| Family | Examples | What you get |
|---|---|---|
demi.gameplay.* | health, controllers, projectiles, interactions, inventory, encounters, camera, traversal, third_person, destruction, core | Reusable gameplay systems as Lua modules and prefabs. |
demi.ui.* | language_file, localization | HUD language files and localization helpers. |
demi.network.lobby | lobby | Lobby and matchmaking flows for sessions. |
kenney.textures.prototype | prototype textures | Placeholder art assets for grayboxing. |
Each family ships its own manifest, public modules, and tests. Run a package's tests before adopting a new version:
demi package test .demi/packages/demi.gameplay.health
package test [dir]— runs the package's declared Lua tests. Returns0on success,1on failure.
Next steps
- Add packages to Skyforge and read the lock file after: the exact versions land there immediately.
- Ship your own reusable system with Publishing packages.
- See every package command on the CLI reference, and the asset side of content in Assets & packages.