# Projects

> How a Feather 2 project is stored on disk, opened, saved and split into levels.

Source: https://feather-engine.com/docs/concepts/projects/

A Feather 2 project holds every authored setting: scene objects, landscape, environment, materials,
scripts, Blueprints, prefabs, levels and the configuration of each game system. An `assets/` folder
beside it holds the imported files the project uses. A project is saved in one of two layouts.

**A project folder** (`<Name>.feather`) is the editor's default. The `.feather` file is a small
manifest, and everything else is split into readable files under `content/`, so changes are easy to
review in version control:

```text
My Game/
  My Game.feather                  manifest: name, seed, player start, level list
  content/
    levels/<level>/objects.json    each level's objects, landscape.json and environment.json
    scripts/<name>.rhai            world scripts as plain Rhai
    ui/screens/<name>.html, .css   game UI screens; also ui/widgets/, ui/templates/, ui/stylesheet.css
    data/<section>.json            content: assets, materials, sounds, prefabs, items, story…
    data/tables/<name>.json        data tables
    config/<section>.json          settings: physics, weather, input, game, build…
  assets/
    imported/
      <sha256>.glb
      tex-<sha256>.png
      snd-<sha256>.ogg
```

In the manifest and the JSON files, a value saved elsewhere is replaced by a reference such as
`{"$file": "content/levels/main/objects.json"}` (or `$text` for scripts and screens). Saving rewrites
only the files that changed and removes the ones the project no longer needs. Keep one `.feather`
project per folder: saving refuses a folder that already holds another one.

**A single file** (`project.feather.json`) holds the whole project in one JSON file. The examples and
game builds use this layout, and older projects open unchanged.

Imported files are named by their SHA-256 hash, so identical content is stored once.

## Create, open and save

1. Choose **File → New project…** to start from an empty level with a procedural meadow landscape.
2. Choose **File → Open project…** to open a `.feather` or `.feather.json` file, or **File → Open
   example** to open one of the bundled [examples](/docs/examples/).
3. Press **Cmd/Ctrl+S**, or choose **File → Save project**, to save. The first save of a new project
   asks for a location and offers **Feather project** (`.feather`) or **Single-file project (JSON)**.

When you save a new `<Name>.feather` into a folder that already holds other files, the editor puts it
in its own `<Name>/` folder there. To convert a single-file project, save it with `project.save` to a
path ending in `.feather`; a path ending in `.json` converts it back.

With the macOS app installed, double-clicking a `.feather` file in Finder opens it in the editor. On
any platform you can also pass the file to the editor: `feather-editor "My Game/My Game.feather"`.

Opening runs in the background. The editor shows its progress and keeps the current project until
the new one has loaded and passed validation. Cancelling or a failed load leaves the current project
and its undo history untouched.

Saving validates the whole project first, then copies every referenced asset into the `assets/`
folder beside the destination and writes each file atomically. A crash during a save never leaves
a half-written file. Opening verifies each asset's hash before loading it, so a project never depends
on the editor's private cache. A standalone texture that is missing from `assets/`, such as a library
texture left out of version control, does not stop the project from opening: it logs a warning and
the texture does not show until you import it again.

:::tip
Keep the project file, its `content/` folder (for a project folder) and `assets/` together. Move
or share the whole folder.
:::

## What a project contains

These are the top-level sections of a single-file project. A project folder keeps the same sections,
split into the files shown above.

| Section | Contents |
| --- | --- |
| `schema_version`, `name`, `seed` | Format version, display name and terrain seed |
| `objects` | Scene objects of the open level; see [Objects and groups](/docs/concepts/objects-and-groups/) |
| `landscape`, `environment`, `spawn_position`, `spawn_yaw` | Terrain, sky and lighting, and the player start of the open level |
| `assets`, `textures`, `sounds`, `fonts`, `materials` | Imported content and material assets |
| `prefabs` | The prefab library; see [Prefabs](/docs/concepts/prefabs/) |
| `levels`, `start_level` | Other levels and the level the game starts in |
| `world_scripts`, `data`, `game` | Game logic, data tables and game settings |
| System sections | One section per engine system, for example `physics`, `weather`, `combat`, `input`, `navigation`, `ai`, `items`, `story` and `localization` |

System sections are written only when they differ from their defaults, so a small project stays
small.

## Schema versions

New projects use schema 2, which supports [Groups](/docs/concepts/objects-and-groups/) and parent
relationships. Flat schema 1 projects still open, and upgrade to schema 2 when you first add a Group
or parent an object. Fields added in later engine versions load with default values.

## Levels

A project can contain several levels. Each level has its own objects, landscape, environment and
player start. Assets, materials, sounds, data tables, scripts, story, combat and input settings are
shared by every level.

The open level is the one the editor shows and the one all scene, landscape and environment commands
edit. The other levels wait in the `levels` section (in a project folder, under `content/levels/`).

1. Open **Window → Levels**.
2. Enter an id and a name, choose a **Flat** or **Meadow** base, and create the level. Alternatively,
   duplicate an existing level.
3. Click a level to open it for editing. Opening a level is an undoable edit.
4. Use **Make start** to choose where the game begins, and **Rename** or **Delete** to manage levels.
   The open level cannot be deleted. If no start level is set, the game starts in the open level.

At runtime, scripts switch levels with `load_level(id)`.

## Example: a door that takes the player to a second level

You'll add a cellar level and a sensor in the first level that loads it when the player walks in.
Start from a new project (**File → New project…**). Its only level has the id `main`.

1. Choose **Add → Cube**, name it `Cellar door` and set **Location** to `0`, `0`, `2`, between the
   player start and the direction it faces.
2. In **Details → Physics**, turn on **Sensor** so the player can walk into it.
3. In **Details → Script**, click **Add script**, replace the source with the script below and click
   **Apply script**.

   ```rust
   fn trigger_enter(other) {
       if other_is_player() {
           print("Down to the cellar");
           load_level("cellar");
       }
   }
   ```

4. Open **Window → Levels**. Under **New level**, enter `cellar` as the id and `The Cellar` as the
   name, choose **Flat**, and click **Create and open**.
5. Choose **Add → Crystal** so the cellar has something in it.
6. In the Levels list, click **Make start** next to **Main · main**, then click **Main · main** to
   open it again.
7. Press **Cmd/Ctrl+S** to save, then **Play** and walk forward into the cube.

Step 6 matters: while no start level is chosen, the game starts in whichever level is open, so
without it the game would start in the cellar.

Do the same from the command line:

```bash
feather-cli --workspace ./two-rooms command project.create \
  --json '{"name":"Two Rooms"}' --save project.feather.json

feather-cli --workspace ./two-rooms --project project.feather.json command scene.add \
  --json '{"kind":"Cube","name":"Cellar door","position":[0,0,2]}' --save project.feather.json

feather-cli --workspace ./two-rooms --project project.feather.json command scene.update --json '{
  "id": 1,
  "patch": {
    "physics": {"sensor": true},
    "script": {"source": "fn trigger_enter(other) {\n    if other_is_player() {\n        print(\"Down to the cellar\");\n        load_level(\"cellar\");\n    }\n}"}
  }
}' --save project.feather.json

feather-cli --workspace ./two-rooms --project project.feather.json command level.create \
  --json '{"id":"cellar","name":"The Cellar","base":"Flat","open":true}' --save project.feather.json

feather-cli --workspace ./two-rooms --project project.feather.json command scene.add \
  --json '{"kind":"Crystal","name":"Cellar crystal","position":[0,0,0]}' --save project.feather.json

feather-cli --workspace ./two-rooms --project project.feather.json command level.update \
  --json '{"id":"main","start":true}' --save project.feather.json
feather-cli --workspace ./two-rooms --project project.feather.json command level.open \
  --json '{"id":"main"}' --save project.feather.json
```

Check it worked:

```bash
feather-cli --workspace ./two-rooms --project project.feather.json command level.list
```

The result has `"open": "main"` and `"start": "main"`, and lists `cellar` and `main` with one object
each. To check the trigger, simulate walking forward:

```bash
feather-cli --workspace ./two-rooms --project project.feather.json command game.simulate \
  --json '{"frames":180,"inputs":[{"frame":0,"key":"W","pressed":true}]}'
```

The report's `logs` include `Cellar door [Script]: Down to the cellar`. The simulation runs one
level and does not perform the switch itself; press **Play** in the editor to see the cellar load.

## Limits

| Limit | Value |
| --- | --- |
| Single-file project | 16 MiB |
| Project folder | 16 MiB per file, 64 MiB in total |
| Objects in a project | 100,000 |
| Levels | 64 |
| Level ids | Lowercase letters, digits, `-` and `_`; up to 48 characters |

## Undo and revisions

Every change to the project is a transaction: it is validated as a whole, applied atomically and
recorded as one undo step. Each change also advances the document's revision number, which
automation uses to detect conflicting edits. Opening a project clears the undo history. See
[Agents overview](/docs/agents/overview/).

## Automate it

```bash
# Create a level, open it and save the project.
feather-cli --workspace ./my-game --project project.feather.json command level.create \
  --json '{"id":"caves","name":"The Caves","base":"Flat","open":true}' \
  --save project.feather.json

feather-cli --workspace ./my-game --project project.feather.json command level.list

# Convert the single-file project into a project folder (written into ./my-game).
feather-cli --workspace ./my-game --project project.feather.json command project.save \
  --json '{"path":"My Game.feather"}'
```

`project.open` and `--project` accept either layout. The editor can also validate a project without
opening a window:

```bash
cargo run --bin feather-editor -- --project my-game/project.feather.json --check
```
