Docs / Packages · v0.99.1

Packages

Packages

A package is a folder of things you can drop into any Floptle project: editor tools, scripts, art, prefabs, scenes, shaders — or all of them at once. Anybody can write one, and installing one is picking a folder, pasting a repository URL, or clicking Install in the browser.

Open Window ⏵ 📦 Packages.


Installing one

From What happens
a folder copied into <project>/packages/<id>/, so a teammate who clones the project gets it too
a repository cloned, then copied in exactly the same way. Needs Git on your PATH
the browser the catalogue on fopull.com; Install does the repository route for you
a link not copied — read where it lives. This is how you work on one

Everything installed is recorded in packages.ron at the project root, which is worth committing: it says which packages the project needs and where each one came from.

A package can be switched off without removing it — the checkbox beside its name. That is the first thing to try when something in the editor starts behaving oddly, and it never deletes anything.


Writing one

Window ⏵ 📦 Packages ⏵ ✚ Add ⏵ New Package. Give it an id and a name and you get a folder that already works:

text
packages/com.you.yourtool/
  package.ron       what it is, what it needs, what it may reach for
  editor/main.lua   runs in the editor
  scripts/          Lua your game can attach to nodes
  assets/           meshes, textures, prefabs, scenes, effects, shaders
  README.md

Press ⟲ Reload all after an edit and your changes are live.

To develop a package that lives outside a project — one you intend to share — put it anywhere on disk and use 🔗 Link folder from each project you want to try it in. Nothing is copied, so one edit reaches every project at once.

The manifest

Only id, name and version are required.

ron
(
    id: "com.you.grasstools",
    name: "Grass Tools",
    version: "1.2.0",
    description: "Scatter and paint grass on terrain.",
    author: (name: "You", url: "https://example.com"),
    license: "MIT",
    keywords: ["terrain", "vegetation"],

    // Which engine versions this works with. Leave it out and it claims all of
    // them, which is a claim worth making on purpose.
    engine: ">=0.55.0",

    // Other packages this one needs.
    dependencies: [ (id: "com.you.core", version: "^1.0") ],

    // What it ships. These are the defaults; name them only to change them.
    editor: ["editor"],
    scripts: ["scripts"],
    assets: ["assets"],

    // Optional extras, copied into the project when somebody asks for them.
    samples: [ (name: "Demo", path: "samples/demo", description: "A field") ],

    // Typefaces your editor panels can draw in — see editor-scripting.md.
    // Not a permission: the file is inside your own folder.
    fonts: [ (name: "Heading", path: "fonts/YourFace-Black.ttf") ],

    // What it may reach for. See below.
    permissions: [Network, Browser],
)

The id is the identity. Reverse-DNS, at least two parts, lowercase. It is what a dependency names, what pkg:// addresses resolve through, and what tells your grass apart from somebody else's.

Versions and ranges. A version is major.minor.patch, optionally with a pre-release tag (1.0.0-rc.1). A range is what a dependency or engine asks for:

Written Means
1.2.3 1.2.3 or any later compatible release — the same as ^1.2.3
=1.2.3 exactly 1.2.3
^1.2.3 ≥ 1.2.3, below the next breaking release (2.0.0; below 1.0 the caret narrows)
~1.2.3 ≥ 1.2.3, below 1.3.0
>=1.2, <1.5 both, joined
* anything released

A pre-release only ever satisfies a range that names one, so >=1.0.0 will not quietly install 2.0.0-alpha.

Permissions

A package declares what it may reach for. This is not decoration: an undeclared capability is absent from the package's Lua, not merely refused when it is called.

A package installed from a Git remote — the catalogue, or a URL somebody sent you — does not run until you allow it. If it declares any permission it arrives installed but switched off, with what it asked for on its row in 📦 Packages, and it starts running when you tick the box. Enabling a package runs its code, so that tick is the decision, and it should be made having read the list.

A package that declares nothing is enabled on arrival: it can read its own folder and nothing else, which is the standing every built-in tool already has. A confirmation nobody can act on only teaches people to click through the ones that matter.

Permission Gives the package
Network http.* — talking to a server, and the loopback listener a browser sign-in needs
Files reading and writing anywhere in the project (its own folder it can always read)
Browser ed.openUrl / sys.openUrl — opening a page in your browser

Listing on the catalogue is automatic once a submission passes its checks, so the moment you tick that box is the last point at which anybody looks at what a package wants. Read the list.

A project that arrives with packages already inside it is asked about too. A folder or a zip somebody sent you can carry packages/ with manifests that declare Files or Network, and nobody ticked a box for those. So the first time you open a project whose permission-asking packages you have not seen, they load with no permissions and a banner across the top of the editor names each one and what it asks for. Trust this project grants them what their manifests say and remembers that set of packages for that project; Keep them restricted leaves them loaded with nothing for the session. A withheld API is still there — http.get raises with the trust rule named, rather than reading as a package that forgot its manifest. Change a manifest and the project asks again.

floptle exec is not held to this: a script you named on your own command line is your own code, and it runs with everything.


Who made this, and was it any good

Packages are made and managed by their authors, not by Fopull. Listing on the catalogue is automatic: a submission that passes its structural checks goes live, and nobody has vouched for what the package does. A package is code that runs in your editor. Trust them at your own discretion — and read the reviews.

Reviews are the thing that replaces an approval nobody gave. A package's row in 🌐 Browse shows its score and how many reviews it is made of, or no reviews yet — which is a different statement from a bad score, and drawn differently. Open reviews on a row to read them. Each says which version it was written against, because a review of 1.0.0 is not a review of 3.0.0.

Writing one

You can review a package once you have it installed and enabled in a project. That is the whole gate, and it is deliberate: a package sitting there switched off has not been tried, and since v0.55.3 that is exactly how a package that asks for a permission arrives.

You need to be signed in. It is the same account as the Hub — one entry in your operating system's keyring, shared by the Hub, the editor and every game, so signing in anywhere signs you in everywhere. The Packages window shows who you are, and lets you sign out or sign in as somebody else.

Pick a rating out of five; words are optional, up to 2000 characters. The version you have installed goes with it. Posting again replaces your earlier review rather than adding a second one — you are allowed to change your mind — and remove my review takes it back.

Pointing the catalogue at your own registry gets you that registry's reviews too. Posting is only ever to fopull.com, though: the editor will not send your access token to another host.


Addressing a package's files

pkg://<id>/<path> finds a file in a package wherever that package happens to be — copied into the project, linked to a working copy on another disk, or shipped inside an exported build.

lua
node.material.texture = "pkg://com.you.grasstools/assets/blade.png"

Use it anywhere the engine takes an asset path.


What a package can hold

Editor tools. editor/*.lua runs in the editor: menus, panels, Scene-view overlays, world-space handles, scene edits with real undo. See editor-scripting.md.

Game scripts. scripts/*.lua can be attached to nodes exactly like the project's own. The project's scripts/ folder is searched first, so installing a package can never change what an existing script name means.

Assets. Anything the engine reads: models, textures, prefabs, scenes, .vfx.ron effects, .flsl shaders, tilesets, UI styles.

Samples. Extras that are not loaded — example scenes, a demo project, art nobody needs unless they ask. They are copied into <project>/samples/ on request, so a package can carry a hundred megabytes of demo without costing every project that installs it.

An assets-only package is a perfectly good package. It needs no Lua at all.


When one goes wrong

A package that will not load is skipped, loudly — the project still opens, the Console says what happened, and the row in 📦 Packages carries the reason. Same for a script that raises: the callback that raised stops being called rather than raising sixty times a second, and its panel says so instead of drawing.

Common ones:

  • "needs Floptle x.y.z and this is …" — the package's engine range does not include this build. Update the engine, or the package.
  • "needs com.x.y …, which is not installed" — a dependency is missing. Install it; load order is worked out for you.
  • "is in a dependency cycle" — two packages need each other. One of them has to stop.
  • "is listed as 1.0.0 but is really 1.1.0" — you edited a linked package's version. Harmless; the package's own manifest wins.

Publishing one

Put the package in a public Git repository — with package.ron at the root, or in a single subfolder — and anybody can install it from the URL today.

To have it appear in 🌐 Browse, submit it to the catalogue at fopull.com/packages. A catalogue entry names a repository and a revision per published version, so installing from the browser and installing from the URL are the same operation. A studio that would rather not publish can point the browser at its own catalogue instead — the URL is a box under Registry.


See also