MoGen Studio

A desktop editor for .mog scenes. Studio is a thin GUI on top of the same compile pipeline the CLI uses — every feature you can run from mogen <subcommand> is also available as a button or menu item. It adds a live 3D preview, a span-aware inspector, viewport gizmos, syntax highlighting, and a settings store so per-project knobs stick across sessions.

Window title is MoGen Studio. Settings live at ~/.config/mogen/settings.json on Linux (%APPDATA%\mogen\settings.json on Windows; ~/Library/Application Support/mogen/settings.json on macOS).


Launching

cargo run --release -p mogen-studio          # from a source checkout

# Or from a release artifact:
mogen-studio                                 # Linux tarball
open "/Applications/MoGen Studio.app"        # macOS .dmg
# On Windows: launch from the Start menu after running the .msi installer.

On first launch, Studio shows an onboarding dialog asking for a Gemini API key. You can skip it — every non-LLM feature still works without one — or paste a key in. The key is stored in the settings file and is the same value GEMINI_API_KEY would supply to the CLI.


The window at a glance

Studio's main view is a four-region layout:

region what it does
menu bar File / Edit / View / Generate / Options / Help, plus the active-tab strip just below
editor pane .mog source with live syntax highlighting, autocomplete, error squiggles, and a per-file diagnostics footer
3D viewer Live preview of the most recently built .mog, with translate/rotate/scale gizmos and click-to-select picking
inspector Selected-node attribute editor, material editor, texture roster, and per-file build options

The editor and viewer are separated by a draggable splitter; the inspector is a collapsible side panel.


Tabs and recent files

Multiple .mog files can be open simultaneously, one per tab.

  • The tab strip remembers order across sessions — closing Studio with three tabs open reopens all three on the next launch, with the last active tab focused.
  • Untitled buffers (no path yet) are not persisted across restarts, but they survive accidental re-runs of Studio because every change is held in memory.
  • File → Open Recent shows the last 12 opened paths, newest first. Items are removed automatically if the file no longer exists at that path.
  • Save / Save As use a native file dialog. New tabs default to "Untitled" and prompt for a path on first save.

The editor pane

The editor is a custom egui-based text view tuned for .mog. It does NOT use a pest-driven highlighter on every keystroke — instead, a loose tokeniser in highlight.rs colours kinds, strings, numbers, comments, and $param references, so mid-edit source still highlights even when the parser would reject it.

Features:

  • Syntax highlighting — kinds, attributes, strings, numbers, comments, $param references.
  • Autocomplete — typing a kind, attribute, or material name pops a fuzzy list. Tab / Enter accepts; Esc cancels; / moves the selection.
  • Indent on enter — opening a { block bumps the indent; closing brace de-indents in place.
  • Error squiggles — every diagnostic from the AST or graph validator gets an underline at the exact span the validator emitted. Hover for the message.
  • FindCtrl+F / ⌘F opens a find bar.
  • External-edit detection — if the file changes on disk while a tab is open, Studio prompts to reload (or keep your in-memory copy if you have unsaved changes).

The 3D viewer

A live preview built on eframe's wgpu backend. Loaded directly from the in-memory SceneGraph after each successful build — there's no intermediate GLB on disk for the preview.

Camera:

  • Left-drag orbits the focus point.
  • Middle-drag (or Shift+left-drag) pans.
  • Mouse wheel zooms.
  • ⌘0 / Ctrl+0 frames the whole scene.

Selection:

  • Left-click picks the node under the cursor (Möller–Trumbore ray cast against the rendered meshes). The selected node highlights both in the viewer and in the inspector.
  • Esc clears the selection.

Gizmos:

  • When a node is selected, a translate / rotate / scale gizmo handle floats over its origin in world space. The mode toggles in the View menu (or the gizmo widget itself).
  • Dragging a handle modifies pos / rot / scale on the selected node and writes the change back into the source .mog as a span-preserving edit. Other formatting in the file is left alone.

The inspector

The inspector binds the currently selected node to its attributes:

  • Per-attribute fields — drag-numeric inputs, vec3 spinners, colour pickers for material colours, dropdowns for enum-like attrs (anchor, axis, alpha_mode).
  • Material editor — every authored material gets a collapsing section. Edit base color, roughness, metallic, alpha mode, transmission, emissive, etc.; changes flow back to the source material "…" declaration via the same span-preserving edit machinery.
  • Texture roster — each material's texture slots show ✓ / ✗ markers based on whether the referenced PNG actually exists at the resolved path. Missing textures are visible before you try to build.
  • LOD scale slider — edits the top-level lod_scale (value=N) directive in place. Drag down to iterate quickly on big scenes; drag back to 1.0 and Studio removes the directive entirely so saved files stay clean.
  • Per-file export optionsinclude_animations, include_textures, merge_sibling_meshes (sticky per file).

Edits made in the inspector and via gizmos are persisted into the source file the next time you save. They are reflected in the editor text immediately, and they preserve every comment, blank line, and whitespace style elsewhere in the source.


Diagnostics

Every build runs the same dual validator the CLI uses (AST-level + graph-level). The diagnostics show up in three places:

  1. Error squiggles in the editor at the exact source span.
  2. Diagnostics footer under the editor — collapsible; auto-hides when there are no errors or warnings.
  3. Tab badges — a tab with errors gets a red dot; a tab with only info-level diagnostics looks clean.

mogen check --json and the studio share the same diagnostic format — the studio is a viewer for that JSON, dressed up as a UI.


Building

The Build button (or ⌘B / Ctrl+B) compiles the current tab to GLB and refreshes the 3D viewer. The output GLB lands at <file>.glb next to the source by default.

The build pipeline is the same one mogen build runs:

  1. Parse → AST → AST validation
  2. Lower → SceneGraph
  3. Graph validation
  4. Optional sibling-mesh merge (per-file merge_sibling_meshes setting)
  5. GLB export

Validation errors abort the build and surface in the diagnostics footer without writing a GLB.

F5 re-runs the validator only, without re-emitting a GLB. Useful when you've edited a .mog from outside Studio and want a quick diagnostic refresh.


LLM tools

The Generate menu mirrors the LLM-driven CLI subcommands. Each opens a small modal that collects a prompt and the relevant flags.

menu item CLI equivalent
New from prompt… (⌘⇧N) mogen generate
Modify… mogen modify
Animate… mogen animate
Repair mogen repair
Generate textures… mogen textures

Behaviour matches the CLI:

  • The repair loop runs in the background; progress is shown in the status line.
  • The generated .mog opens in a new tab (Generate) or replaces the current tab's contents (Modify / Animate / Repair).
  • Seeds are embedded in the DSL header so the same prompt + same seed re-emits the same scene. The seed field in each modal is pre-filled with the input file's existing seed when present.
  • Thinking level, model, temperature, and max_repair_iters come from Options → Models. Per-modal overrides live next to the prompt field for one-off tuning.

If gemini_api_key is empty in the settings, every LLM action prompts for a key first (the same onboarding dialog as on first launch).


Themes and preview shaders

UI themes (Options → Theme):

key label use
dark Dark classic dark editor
light Light bright office mode
sunset Sunset (warm) warm-toned
nord Nord (cool) cool-toned blue/grey — default
high-contrast High Contrast accessibility / projector

The theme name is stored in settings.json as a lowercase label so new variants can land without breaking older settings files. Empty / unknown labels fall back to Nord.

Preview shaders (View → Preview shader) control the 3D viewer only — they don't affect the exported GLB.

key label what it shows
standard Standard (PBR) full PBR with embedded textures — default
toon Toon (cel-shaded) hard-shaded NPR look
ps1 PS1 (retro dither) low-res, dithered, vertex-snapped
crt CRT (scanlines) post-process scanlines + bloom
matcap Matcap (clay) unlit material capture for sculpt-style review
wireframe Wireframe edges only, ignores materials

Wireframe is useful for inspecting topology after CSG or sibling-mesh merge. PS1 / CRT are for vibes.


Settings

The settings file is a JSON document stored at the OS-appropriate config path. It's safe to edit by hand — Studio reloads on next launch.

key meaning
gemini_api_key API key used by every LLM action.
gemini_model Heavy model id. Empty → gemini-pro-latest.
gemini_fast_model Fast model id used for low-stakes rewrites (Prompt Enhancer). Empty → gemini-flash-latest.
gemini_temperature Sampling temperature. null → library default (0.3).
thinking_level low / medium / high / xhigh. Empty → library default (high).
max_repair_iters LLM repair budget. null → library default (2).
seed_override Optional deterministic seed. null → derive from DSL header or random per call.
theme UI theme key (see above).
preview_shader Viewer shader key (see above).
last_opened Absolute path of the last .mog opened.
open_tabs Absolute paths of every titled tab open at last persist time.
recent_files Most-recently-opened paths, newest first. Capped at 12.
onboarded Set once the first-launch onboarding has been dismissed.

Untitled buffers are deliberately not persisted — there's nothing to key off — so a fresh Studio launch with only-untitled tabs comes up empty. Save first if you want them back.


Keyboard shortcuts

COMMAND is on macOS and Ctrl elsewhere. All shortcuts work globally; egui consumes them before the menu or editor see the key.

shortcut action
⌘N New untitled tab
⌘⇧N New from prompt (Gemini generate)
⌘O Open file…
⌘S Save active tab
⌘⇧S Save As…
⌘B Build active tab to GLB
F5 Re-run the validator without re-emitting the GLB
⌘W Close active tab
⌘0 Frame the scene in the 3D viewer
⌘, Open Options
⌘Q Quit (with prompt-to-save for dirty tabs)
Tab / Enter Accept autocomplete suggestion
Esc Dismiss autocomplete; clear viewer selection

Standard editing shortcuts (⌘C, ⌘X, ⌘V, ⌘A, ⌘Z, ⌘⇧Z) work in the editor pane.


File layout on disk

For a given project directory, Studio expects (and creates) the following layout:

my-project/
├── chair.mog              # source
├── chair.glb              # build output (next to the .mog by default)
└── textures/
    └── chair/             # mogen textures --textures-dir default
        ├── wood_base_color.png
        ├── wood_normal.png
        ├── wood_metallic_roughness.png
        └── wood_occlusion.png

Texture paths in material "…" declarations are resolved relative to the .mog file. The textures/<mog-stem>/ subdirectory is the default output of mogen textures so sibling .mogs with shared material names don't clobber each other.


See also