1
0
Fork
You've already forked Studiola
0
forked from meshula/Studiola
No description
  • Go 57%
  • C++ 15.6%
  • Objective-C++ 13.4%
  • Zig 8.6%
  • CMake 2.4%
  • Other 3%
stephan_gfx 366adfabbc Recurse into host directory with build and clean make targets ( #6 )
authored-by: ssteinbach <ssteinbach@users.noreply.github.com>
Reviewed-on: meshula/Studiola#6 
2026年05月24日 19:09:52 +02:00
TemplateCpp
TemplateHostCpp Add app bundling and codesigning workflow 2026年05月17日 23:54:30 -07:00
TemplateZig Update build.zig to reach into the install subdir ( #5 ) 2026年05月24日 04:36:18 +02:00
tools Recurse into host directory with build and clean make targets ( #6 ) 2026年05月24日 19:09:52 +02:00
.gitignore Improve local repo workflow 2026年05月23日 21:04:29 -07:00
configure.sh
install.sh Improve local repo workflow 2026年05月23日 21:04:29 -07:00
README.md
TODO.md

Studiola

Studiola is an umbrella workspace for a family of C++ creative-tooling libraries, a host application, and a growing set of plugins. Everything in this directory is built and installed together by a single orchestrator (tools/studiola-build) so that the host and its plugins share one install prefix, one set of headers, and one runtime layout.

The workspace is organized as flat sibling directories rather than a monorepo, because the individual components also live on their own and are usable outside Studiola.

What's in the box

Foundation libraries

  • LabText — small text / s-expression parsing utilities.
  • LabCamera — camera math and interactive camera controllers.
  • LabGL — OpenGL / Metal rendering utilities and sample showcases.
  • LabDb9 — graph database layer used by memex-style tools.
  • LabLlama — llama.cpp wrapper exposing model hosting to the framework.

Host

  • MeshulaLab — the Studiola host application (built as Studiola). It provides the Studio / Activity / Provider architecture, the plugin loader, the CSP (ZeroMQ) transaction pump, ImGui-based UI, font and resource resolution, and a macOS .app bundle layout.

Plugins

  • StudiolaColor — color-science activities (spectral locus, Macbeth chart) and a ColorProvider.
  • StudiolaEffekseer — Effekseer particle effects, packaged as an EffectStudio with its EffectViewer activity and provider.
  • StudiolaMemex — a memex/knowledge-graph plugin backed by LabDb9 and LabLlama, aggregating several activities into a single plugin.

Third-party foundations

These are cloned into the workspace by the wizard or studiola-build --fetch whenever something depends on them:

  • llama.cpp — large language model runtime (required by LabLlama).
  • oneTBB, OpenSubdiv, USD — the OpenUSD stack, for eventual StudiolaUSD plugin work. Built with a no-python, shared-libs recipe derived from tinyusd/recipes/macos-dynamic-nopy (github: meshula/tinyusd).

Architecture

The host exposes a stable C descriptor ABI (LabGetPluginDescriptor) that plugins implement. A plugin descriptor enumerates the studios, activities, and providers it ships, plus factory functions to create and destroy them. The host loads plugins by walking upward from the executable looking for a sibling plugins/ directory — the same walk-up strategy is used for resources/fonts/, so one convention handles the dev tree, installed prefix, and .app bundle shapes uniformly. A Studio may request activities it does not own (the host wires them up) and instantiate the ones it does.

Quickstart

Requirements:

  • macOS (arm64) — Linux/Windows support exists in the host but the orchestrator's current deployment story targets macOS.
  • CMake ≥ 3.26, Ninja, a recent clang, git, Go 1.22+ (to build the orchestrator and the configure wizard).

This repository is a workspace manifest, not a monorepo. It contains only the build orchestrator and docs. The actual component sources (LabText, LabGL, MeshulaLab, StudiolaColor, ...) live in their own upstream repos and are cloned into a workspace directory that you choose — typically a sibling of this repo.

Cold-clone workflow:

git clone https://codeberg.org/meshula/Studiola.git
cd Studiola
# Launch the configure wizard. The script builds the Go binaries on
# first run (and rebuilds them when sources or the embedded registry
# change), then opens a TUI for selecting components and picking a
# workspace directory.
./configure.sh

In the wizard:

key action
[space] toggle a plugin
[w] set the workspace directory (where repos clone to)
[p] choose target platform (macos, ios, ios-simulator)
[n] scaffold a new plugin (see below)
[a] add a plugin from an external git URL
[o] toggle online / offline mode
[r] set the offline repo root (path to local mirrors)
[u] populate — fetch / sync the offline root
[enter] provision the workspace and build

When you press [enter], the wizard writes studiola-config.toml at the workspace root, copies tools/ into the workspace, clones the selected components, and runs the build. Plugins are installed into <workspace>/install/plugins/ and the host is installed at <workspace>/install/bin/Studiola.

configure.sh is also the right way to re-enter the wizard on an existing workspace — pass the saved config to prepopulate selections:

./configure.sh --config <workspace>/studiola-config.toml

Authoring a new plugin in the wizard

Press [n] to open the new-plugin form. Fill in:

  • Plugin name — the on-disk directory and CMake target (e.g. StudiolaMyPlugin).
  • Component — the class prefix for the roles (e.g. My produces MyProvider, MyActivity, MyStudio).
  • Roles — toggle Provider / Activity / Studio with [space].
  • Language — C++ or Zig (radio).

The right-hand panel previews exactly what will be scaffolded: the classes that will be generated and the file list. Press [enter] to create the plugin in the workspace. The wizard writes CMakeLists.txt, studiola-plugin.toml, the role source files, and a smoke test (or the Zig equivalents).

Offline workflow

The component registry lives at tools/studiola/registry.toml and is embedded into the configure / build binaries (override with the STUDIOLA_REGISTRY env var). Offline mode lets you build entirely from a local mirror of every repo it lists.

  1. Press [r] and point at a directory containing one clone per component, named to match the registry (LabText/, LabCamera/, MeshulaLab/, etc.). The path is recorded in studiola-config.toml whether or not offline mode is on, so the breadcrumb survives between sessions.
  2. Press [u] to open populate. The left panel shows the selected configuration; the right panel shows the git status of each repo in the offline root ( up to date, ↑n ahead, ↓n behind, diverged, missing, · no upstream / detached HEAD).
  3. [enter] clones missing repos from upstream and runs git fetch on the rest, concurrently. [r] re-checks status without touching the network.
  4. Press [o] to toggle offline. While offline, [enter] install clones the workspace from your local mirror instead of upstream — no network required.

Repos cloned by populate use --depth 1 and the registered ref; if you want full history, re-clone the offline mirror by hand and the wizard will leave it alone.

Headless build (no wizard)

The orchestrator can also run standalone, the way the wizard does internally. It expects a workspace that already has components checked out:

cd <workspace>
./tools/studiola-build/studiola-build --fetch # clone what's missing
./tools/studiola-build/studiola-build # build everything
./install/bin/Studiola # run the host

--fetch honours the same registry as the wizard. Other useful flags:

./tools/studiola-build/studiola-build --list # show plan
./tools/studiola-build/studiola-build --plugins X,Y # subset build
./tools/studiola-build/studiola-build --dry-run # print, don't run
./tools/studiola-build/studiola-build --clean # wipe build/ + install/
./tools/studiola-build/studiola-build --bundle # inject into .app

Directory layout

Studiola/ this repo
├── configure.sh first-run launcher
├── tools/
│ ├── studiola/ shared Go package
│ │ └── registry.toml component registry
│ ├── studiola-build/ headless orchestrator
│ ├── studiola-configure/ TUI wizard
│ └── studiola-git/ git helper
└── TemplateCpp/ TemplateZig/ new-plugin scaffolds
<workspace>/ chosen via [w] in wizard
├── studiola-config.toml saved selections + mode
├── LabText/ LabCamera/ LabGL/ foundation libs
├── LabDb9/ LabLlama/
├── MeshulaLab/ host (Studiola)
├── StudiolaColor/ StudiolaEffekseer/ StudiolaMemex/ plugins
├── llama.cpp/ oneTBB/ OpenSubdiv/ USD/ fetched foundations
├── tools/ copied from Studiola
├── build/
│ └── <Component>/ per-component build dirs
└── install/ shared install prefix
 ├── bin/Studiola
 ├── lib/ foundation dylibs
 ├── plugins/ plugin dylibs
 ├── include/
 └── resources/fonts/

Per-component build directories live side-by-side under build/; the shared install prefix is install/ (a peer of build/, not nested inside it). Foundations install their exports into install/lib/cmake/<Package>/ so downstream find_package calls resolve against the workspace install, not against any system prefix. The orchestrator passes CMAKE_PREFIX_PATH=<install> on every configure to enforce that. Cross-compiled builds get suffixed sibling prefixes (e.g. install-ios-simulator/).

Authoring a plugin by hand

The wizard's [n] flow above is the path of least resistance. If you'd rather hand-roll a plugin (or you're integrating a pre-existing repo), drop a studiola-plugin.toml next to your CMakeLists.txt:

name = "StudiolaYourPlugin"
kind = "plugin"
depends = ["LabGL", "MeshulaLab"]
[build]
system = "cmake"
[build.cmake]
generator = "Ninja"
config = "Release"
[install]
artifacts = ["lib/**"]
bundle_subdir = "Contents/PlugIns/StudiolaYourPlugin"

Implement LabGetPluginDescriptor in your plugin (see StudiolaColor or StudiolaEffekseer for worked examples). The orchestrator will discover the plugin on its next run. No bookkeeping anywhere else in the workspace is needed.

Acknowledgments

The fetched third-party components retain their own licenses and remain owned by their upstream projects. Studiola's own code is licensed per-repository — see each component's LICENSE file.