FERRETGame engine over Babylon.js
Ferret

Assets and .ferret packages

Skill ferret-packages · download all skills · SKILL.md

When to use#

Packing a game's levels, loading content from a URL or a file, signing or encrypting it, caching downloads, or reasoning about the security of loaded content.

What exists#

  • FerretPackage, packPackage, PackageManifest, validatePackageManifest, validatePackage: the format and its own checks.
  • Signing and keys: generateSigningKey, signManifest, verifyManifestSignature, generateEncryptionKey, createEncryption.
  • Sources: urlSource, httpFolderSource, folderSource, bytesSource, blobSource.
  • Catalogs and streaming: buildCatalog, signCatalog, loadCatalog, CatalogClient (in levels), travel with a transition.
  • Cache: PersistentCache with backends (IndexedDB, storage, memory), LRU by package, pins, quota, partials, downloadedContentItem for a menu entry.
  • CodePolicy: a package that carries code runs under it.
  • The asset library (docs/concepts/asset-library.md): textures, PBR materials, characters and clip sets as .ferret packages of kind assets, found by id in a catalog (/lib/ferret-assets/, or FERRET_ASSETS). Take from it instead of copying files out of another project: AssetLibrary (in levels) with list, material(id, { variant }), texture(id), character(id, { tier }), preload; the viewer's ?library shows every item. Items are built from UE exports by tools/asset-lib/make.mjs, never by hand.
  • Running code: code.entry in ferret.json (one bundled ES module under code/ exporting install(ctx)), installCode / CodeLoader.require(id) (dependencies first, policy, sha256 of the module, install once; the engine comes as ctx.ferret, the shared globalThis.Ferret), commands pkg.require and pkg.loaded.

Steps to publish#

  1. Pack the level folder with packPackage (see API reference for options).
  2. Sign with a developer key; the owner of the keys signs and encrypts, an agent only prepares unsigned drafts.
  3. Build and sign a catalog if levels are fetched remotely.
  4. Load with installPackages; the loader checks signatures, hashes and paths before anything is used.

Check afterwards#

validatePackage is clean; a tampered file is refused; a second load is served from the cache; quota errors are handled (QuotaError).

What usually goes wrong#

  • Putting private keys in the repo or in a draft; keys are the developer's.
  • Paths with .. or absolute paths in the manifest: refused by the loader by design.
  • A package with code and no CodePolicy decision.
  • Assuming the cache is unlimited: it evicts by package and has a quota.

Files#