Files
Oxide/docs/projects.md
T
Homer 48003ffea4 Editor: native folder picker for New/Open Project
Stage-10 editor-UX follow-up ("typing the path by hand is very hard to
use"). Both project dialogs gain a Browse… button that opens the native
folder picker via rfd's xdg-portal backend — pure Rust, one build works
on Wayland and X11 through xdg-desktop-portal. The dialog runs on a
helper thread reporting over an mpsc channel (polled once per frame in
Shell::build), so the editor keeps rendering while the picker is up;
one pick at a time, and the typed path field remains as a fallback for
portal-less environments.

GUI piece — needs an eye-check (on both Wayland and Xorg) before
promotion to main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 20:47:12 +02:00

3.5 KiB

Project System

oxide_engine::project defines what a game is, on disk: a project. A project is a root directory containing a project file plus a defined folder layout. The format lives in the engine (not the editor) because the exported runtime and the Stage-16 packer read it too — the editor just adds the create/open/save UI.

Layout

my-game/
├── project.oxide      # the project file (RON)
├── scenes/            # scene files
├── assets/            # meshes, textures, audio, …
└── scripts/           # game scripts

The project file records the project name, the engine version it was saved with, the enabled modules, and per-project settings.

Create, open, save

use oxide_engine::project::Project;

// Scaffold a new project (creates the folders + project file).
let mut project = Project::create("/path/to/my-game", "My Game")?;

project.enable_module("render");
project.save()?;

// Reopen later — by directory or by the project file path.
let project = Project::open("/path/to/my-game")?;
assert_eq!(project.name(), "My Game");
assert!(project.is_module_enabled("render"));
# Ok::<(), oxide_engine::project::ProjectError>(())

Path helpers (scenes_dir(), assets_dir(), scripts_dir(), project_file_path()) resolve locations against the root. create refuses to overwrite an existing project; open reports NotFound when there is no project file.

Settings storage

Per-project settings are stored as opaque per-section RON blobs keyed by section name, which keeps the project format independent of any particular settings schema:

# use oxide_engine::project::Project;
# let mut project = Project::create(std::env::temp_dir().join("oxide_doc_proj"), "x").unwrap();
project.set_settings_section("editor", "(theme:\"dark\")");
assert_eq!(project.settings_section("editor"), Some("(theme:\"dark\")"));

The typed settings framework serializes its sections to and from these strings, so a section round-trips through the project file without this module knowing the section's shape.

The editor's New / Open dialogs

The editor's File ▸ New Project… / Open Project… dialogs wrap Project::create/Project::open. Each path field has a Browse… button opening the native folder picker (rfd with the xdg-portal backend — one pure-Rust build serves both Wayland and X11 through xdg-desktop-portal). The dialog runs on a helper thread so the editor keeps rendering while it is up; the picked folder lands back in the field, which stays hand-editable — if no portal service is running the picker simply doesn't appear and the typed path still works.

Recent projects

RecentProjects is a small most-recently-used list, persisted globally as an editor preference (not inside any project). It de-duplicates and caps:

use oxide_engine::project::RecentProjects;

let mut recent = RecentProjects::new(10);
recent.record("/path/to/my-game");
// recent.save("~/.config/oxide/recent.ron")?; / RecentProjects::load(...)
assert_eq!(recent.entries().len(), 1);

Who consumes this

Consumer Stage Use
Editor 6 New/Open/Save Project UI, recent list, Project panel/asset browser
File watcher 6 watches scenes/, assets/, scripts/ for live reload
Settings framework 6 persists per-project sections into the project file
Exported runtime / packer 16 reads the layout + enabled modules to bundle the game