Concept Studio — simple 2D/3D concept CAD for book ship art
Policies that keep the org coherent
name: Concept Studio CAD overview: Create Concept Studio in novolis-apps — a shipped WinExe for simple ship/concept modeling (C4D-style primitives, CAD materials, orthographic technical views). Includes Inno Setup installer and merge CI/CD release assets alongside Manuscript Studio. todos:
- id: apps-scaffold
content: Add src/ConceptStudio to novolis-apps (csproj, slnx, Directory.Packages.props, StudioChrome shell, JSON save/load); verify Linux CI build status: completed
- id: inno-ci-release
content: Extend merge.yml + build-installer.ps1 for Concept Studio publish/zip/Inno/SHA256; update release.md and getting-started.md status: completed
- id: primitive-bridge
content: Implement ConceptPrimitiveBuilder (box, sphere, cylinder, cone, wedge) wiring PolygonFactory/SceneBuilder + part hierarchy tree status: completed
- id: raylib-viewport
content: Port MeshBench Raylib viewport coordinator, orbit interaction, material presets, ship starter template status: completed
- id: ortho-views
content: Add Plan/Profile/Bow orthographic Raylib cameras, wireframe+edge overlay, multi-view layout, batch PNG export status: completed
- id: dimensions-svg
content: Add grid/snap, dimension annotations, SVG technical sheet exporter with title block status: completed
- id: quality-export
content: Port path-trace quality mode + high-res PNG; optional Manuscript Studio concept asset extension status: completed isProject: false
What you asked for vs what exists
| Need | Off-the-shelf gap | Novolis today |
|---|---|---|
| Simple 3D blockout (not FreeCAD) | Most tools are either toy (TinkerCAD) or heavy | Mesh Studio (MeshBench) — box/sphere, orbit preview, CAD-ish MaterialPresets |
| C4D-style primitives | — | Only box + sphere in MeshBench; cylinder/cone exist in math but unwired |
| CAD materials (matte hull, metal, glass) | Blender = node graphs | `MaterialPresets` — Standard / Metal / Glass / Emissive presets |
| 2D technical views + dimensions | LibreCAD = 2D only, no linked 3D | Missing — no ortho 3D camera, no dimension model, no SVG export |
| Book-ready exports | — | PNG via Silk 2D capture; path-trace quality mode in MeshBench |
| Shipped installer | — | Manuscript Studio pattern in `novolis-apps` — Inno + merge release |
Recommendation: Build a new shipped app in novolis-apps. Fork Mesh Studio viewport patterns from dogfooding; reuse Manuscript Studio shell, packaging, and CI/CD infrastructure.
flowchart TB
subgraph apps [novolis-apps]
CS[ConceptStudio WinExe]
MS[ManuscriptStudio WinExe]
MergeCI[merge.yml ci + release]
end
subgraph release [GitHub Release vY.M.m.B]
ZipCS[ConceptStudio zip]
SetupCS[ConceptStudioSetup exe]
ZipMS[ManuscriptStudio zip]
SetupMS[ManuscriptStudioSetup exe]
Sums[SHA256SUMS.txt]
end
CS --> MergeCI
MS --> MergeCI
MergeCI --> ZipCS
MergeCI --> SetupCS
MergeCI --> ZipMS
MergeCI --> SetupMS
MergeCI --> SumsProduct shape (deliberately small scope)
In scope (CAD-lite, not FreeCAD):
- Primitive parts: box, cylinder, cone, wedge, sphere, ground plane
- Numeric transforms (position, uniform/non-uniform scale, Y-axis rotation for v1)
- Part hierarchy with rename/group (e.g.
Ship > Hull > Bridge) - Material picker: Hull (matte), Metal, Glass, Emissive — maps to existing
MaterialPresets - 3D orbit viewport + fixed orthographic views (Plan / Profile / Bow)
- Dimension lines and labels on ortho sheets
- Export: PNG renders + SVG technical sheet
Explicitly out of scope (v1):
- Constraint solver, parametric history, boolean CSG, loft/surface NURBS
- DXF/DWG import, full 2D sketcher like LibreCAD
- Blender-style node materials or sculpting
- Exact naval architecture (stations, waterlines as parametric curves) — v2+ if needed
App location and repo wiring
| Decision | Choice | ||
|---|---|---|---|
| Repo | `novolis-apps` — shipped app alongside Manuscript Studio | ||
| Path | src/ConceptStudio/ | ||
| Solution | Add to `Novolis.Apps.slnx` | ||
| Bootstrap | Copy MeshBench Program.cs DI host + Manuscript Studio StudioChrome usage | ||
| Resizable layout | Copy `MarkdownAuthoringWorkspace` pattern (left tree \ | center viewport \ | right inspector + persisted column widths in settings.json) |
| Data root | %LocalAppData%\Novolis\Concept Studio\ (matches Inno install dir convention) | ||
| History | Optional v1.1: workspace/timeline packages; plain JSON save for MVP |
Package references (ConceptStudio.csproj)
Add to `Directory.Packages.props` (GPR 2026.1.*, nuget.org for Avalonia):
| Package | Role |
|---|---|
Novolis.Avalonia.Studio | Chrome, feedback |
Novolis.Avalonia.Raylib | Embedded 3D preview |
Novolis.Avalonia.Rendering | Rgba32FrameControl (quality mode) |
Novolis.Avalonia.Packaging.Inno | MSBuild NovolisGenerateInnoScript (PrivateAssets) |
Novolis.Raylib | Scene draw helpers |
Novolis.Rendering.Scene, .Materials, .Compile, .Runtime, .Backends.Igpu, .DependencyInjection | Scene compile + path trace |
Novolis.Rendering.Presentation.Silk | SilkOrbitCamera |
Avalonia 12, Microsoft.Extensions.Hosting | Shell |
NuGet-only: no ProjectReference into dogfooding or sibling repos. MeshBench code is copied/adapted into ConceptStudio, not referenced.
Design doc update
Add Concept Studio section to `docs/design.md` mirroring Manuscript Studio table.
CI/CD and Inno installer
Follow the established Manuscript Studio pattern (`merge.yml`, `build-installer.ps1`, `docs/release.md`).
Versioning
Single repo version from `build/version.json` + read-version action. Both apps share one GitHub Release tag (v{Y.M.m.B}) with distinct asset filenames.
Linux CI job (unchanged structure)
Existing ci job builds entire `Novolis.Apps.slnx` on Ubuntu. Concept Studio must compile on Linux even though release publish targets win-x64 only (Avalonia + no native P/Invoke at build time).
Windows release job — extend for two apps
Refactor `merge.yml` release job to publish both apps in one job (sequential steps, shared Inno Setup install):
flowchart LR
ciOk[ci success] --> pubMS[Publish ManuscriptStudio]
pubMS --> zipMS[Zip MS]
zipMS --> innoMS[Inno MS]
innoMS --> pubCS[Publish ConceptStudio]
pubCS --> zipCS[Zip CS]
zipCS --> innoCS[Inno CS]
innoCS --> sums[SHA256SUMS all 4 assets]
sums --> ghUpload[gh release upload --clobber]Concept Studio release env vars:
| Variable | Value |
|---|---|
APP_PROJECT | src/ConceptStudio/ConceptStudio.csproj |
APP_PUBLISH_DIR | artifacts/concept-studio/app |
INSTALLER_DIR | artifacts/concept-studio/installer |
STAGING_DIR | artifacts/concept-studio |
Inno MSBuild properties (via NovolisGenerateInnoScript):
| Property | Value |
|---|---|
NovolisInnoAppName | Concept Studio |
NovolisInnoAppExeName | ConceptStudio.exe |
NovolisInnoAppId | Novolis.ConceptStudio |
NovolisInnoDefaultGroupName | Concept Studio |
NovolisInnoInstallDirName | Novolis\Concept Studio |
NovolisInnoOutputBaseFilename | ConceptStudioSetup-{version}-win-x64 |
NovolisInnoScriptPath | {installerDir}\concept-studio.iss |
NovolisInnoAppSupportURL | https://github.com/Novolis-Platform/novolis-apps/issues |
NovolisInnoAppUpdatesURL | https://github.com/Novolis-Platform/novolis-apps/releases |
Release assets per merge to `main`:
| Asset | Pattern |
|---|---|
| Manuscript Studio installer | ManuscriptStudioSetup-{version}-win-x64.exe |
| Manuscript Studio portable | ManuscriptStudio-{version}-win-x64.zip |
| Concept Studio installer | ConceptStudioSetup-{version}-win-x64.exe |
| Concept Studio portable | ConceptStudio-{version}-win-x64.zip |
| Checksums | SHA256SUMS.txt (all four files) |
Release title: "Novolis Apps {version}" (or keep per-app title with both asset groups listed in notes).
Local build script
Generalize `scripts/build-installer.ps1`:
param(
[ValidateSet('ManuscriptStudio', 'ConceptStudio', 'All')]
[string]$App = 'All',
...
)Extract shared helper Publish-NovolisApp with per-app Inno property hashtable. Keeps local parity with CI.
Manual republish workflow
Update `release.yml` to match merge.yml (currently stale — still calls deleted generate-manuscript-studio-iss.ps1). Add workflow_dispatch input app: All | ManuscriptStudio | ConceptStudio.
Docs
Update `docs/getting-started.md`:
- Download Concept Studio installer from GitHub Releases
- Checksum verification (reuse SHA256SUMS pattern)
- Upgrade vs portable guidance
- SmartScreen note (unsigned, same as Manuscript Studio)
Update `docs/release.md` asset table.
Update `README.md` app list.
Verify before merge
dotnet build Novolis.Apps.slnx -c Release
pwsh scripts/build-installer.ps1 -App ConceptStudio
pwsh novolis-governance/scripts/verify-nuget-only.ps1Dependency order
Concept Studio pulls Novolis.Avalonia.Raylib, Novolis.Rendering.*, Novolis.Raylib from GPR. If dogfooding uses APIs not yet published, merge and publish upstream repos first (same rule as Manuscript Studio / Avalonia.Markdown).
Document model
Extend MeshBench's `MeshPartRecord` into a richer schema:
{
"parts": [
{
"id": "...",
"name": "Main hull",
"parentId": null,
"kind": "cylinder",
"transform": { "position": [0, 1, 0], "rotationY": 0, "scale": [4, 1, 12] },
"params": { "radius": 1, "height": 2 },
"material": "hull"
}
],
"annotations": [
{ "view": "profile", "type": "linear", "from": [0,0], "to": [24,0], "label": "120 m" }
],
"camera": { "yaw": 0.9, "pitch": 0.35, "distance": 40 }
}- `kind`:
box | cylinder | cone | wedge | sphere | group - `material`: enum →
MaterialPresets(Hull = high-roughness Standard, Metal, Glass, Emissive) - Groups: container nodes; children inherit no geometry until leaf primitives
- Units: meters internally; display scale factor for book (e.g. 1 unit = 10 m)
Phase 0 — Repo scaffold + CI (do first)
Goal: Empty-ish app that builds, installs, and releases before feature work.
- Create
src/ConceptStudio/— WinExe, AvaloniaMainWindowplaceholder,Program.cshost - Register in slnx +
Directory.Packages.props - Wire merge.yml release steps + generalized
build-installer.ps1 - Confirm Linux CI green + local Inno compile
- First merge produces Concept Studio zip + setup exe (placeholder UI is fine)
Exit criteria: GitHub Release contains Concept Studio assets; installer lands in %LOCALAPPDATA%\Programs\Novolis\Concept Studio.
Phase 1 — 3D blockout MVP
Goal: Block out a ship in minutes with primitives; orbit preview; save/load; PNG export.
1.1 App scaffold
MainWindow— 3-column resizable shell (Manuscript workspace pattern)- Left: part tree (add primitive, duplicate, delete, rename)
- Center: Raylib viewport (reuse `RaylibHostControl` + `ViewportModeCoordinator` pattern — copy into app)
- Right: inspector (debounced numeric fields like `PartInspectorPanel`)
1.2 Primitive tessellation bridge (new service)
Add ConceptPrimitiveBuilder in the app:
| Kind | Source | Output |
|---|---|---|
| box | SceneBuilder.AddBox | existing |
| sphere | MeshBench CreateUvSphere | copy from MeshBench |
| cylinder | PolygonFactory.CreateCylinder | proper indexed TriangleMesh tessellation |
| cone | PolygonFactory.CreateCone | same bridge |
| wedge | hand-built 5-vertex prism | app-local |
Wire into `SceneBuilder.AddMesh` with part Matrix4x4 from transform.
1.3 Interaction (MeshBench parity + ship scale)
- Orbit / pan / zoom / Fit (F)
- Shift+drag moves selected part on XZ
- Shortcuts:
Bbox,Ccylinder,Ncone,Ssphere,Ctrl+Dduplicate,Delete,Ctrl+Ssave - Default scene: elongated hull cylinder + bridge box + engine spheres (ship starter template)
1.4 Export
- PNG: Raylib framebuffer capture from embedded host (single perspective view)
- Save document to
%LocalAppData%\Novolis\Concept Studio\default-workspace\concept.json
Phase 1 exit criteria: User can block out a recognizable ship hull + superstructure, assign hull/metal materials, orbit smoothly, save/reopen, export PNG.
Phase 2 — Orthographic technical views
Goal: Plan, Profile, and Bow views derived from the same 3D document — the "LibreCAD half" of the tool.
2.1 Orthographic cameras in Raylib preview
Add ConceptViewMode toggle: Orbit | Plan | Profile | Bow
Implementation using `Novolis.Raylib.Runtime` `Camera`:
- Plan: camera above +Y looking down (XZ plane)
- Profile: camera on +X looking at YZ
- Bow: camera on +Z looking at XY
- Orthographic projection (
CAMERA_ORTHOGRAPHIC)
Reuse `RaylibSceneRenderer` pattern; extend to draw all primitive kinds.
2.2 Wireframe + hidden-line toggle
- Wireframe overlay:
DrawCubeWiresV/ line loops per mesh AABB or extracted edges - Flat shaded + edges: CAD-style (filled faces + black edge lines)
2.3 Multi-view sheet layout
Center viewport tabs or 2×2 grid: Perspective + Plan + Profile + Bow.
2.4 Export all views
Batch PNG export: {ship-name}-plan.png, -profile.png, -perspective.png
Phase 3 — Dimensions, grid, SVG technical sheets
Goal: Annotated drawings suitable for book insert pages.
3.1 Grid and snap
- Ortho views: meter grid overlay (major/minor lines)
- Snap selected part centers and edges to 0.5 m grid (Shift disables snap)
- Scale bar widget on each ortho view
3.2 Dimension annotations
New AnnotationRecord model (stored in document):
- Linear dimension between two world points, projected onto current ortho view
- Label text (auto-compute distance × unit scale)
- Avalonia vector overlay (
Canvas+Line+TextBlock) - Inspector: edit dimension endpoints and label override
3.3 SVG export (new code, app-local v1)
ConceptSheetExporter writes SVG with 3 ortho viewports + title block.
3.4 Optional 2D profile sketch (stretch)
Simple polyline on Profile view → extrude along X. Defer if Phase 1–2 sufficient.
Phase 3 exit criteria: Export a 3-view SVG/PDF sheet with at least two dimension callouts.
Phase 4 — Illustration quality + Manuscript Studio hook
Goal: Pretty hero renders for the book + workflow link to writing.
4.1 Quality render mode
Port MeshBench path-trace toggle (`PathTraceViewport`):
- Preview = Raylib (instant)
- Quality = ILGPU path trace with
MaterialPresets - Export high-res PNG (1920×1080 or user size)
4.2 Ship material presets
| Preset | Mapping |
|---|---|
| Hull | Standard(color, roughness: 0.85) |
| HullDark | Standard(dark, roughness: 0.9) |
| Metal | Metal(silver, 0.12) |
| Glass | Glass(tint, 0.02) |
| EngineGlow | Emissive(orange, 3) |
4.3 Manuscript Studio integration (same repo, later phase)
Add `ConceptAssetExtension` inside Manuscript Studio:
- Link chapter metadata
[!concept: my-ship]→ path toconcept.json - Preview pane embeds latest exported PNG/SVG
- Export pipeline copies concept sheet into
{dataRoot}/exports/{series}/{book}/concepts/
No cross-app ProjectReference — extension reads exported files from disk only.
Key files to reuse (copy/adapt, don't rewrite)
| Pattern | Path |
|---|---|
| Shipped app + Inno | `ManuscriptStudio.csproj` |
| Merge release job | `merge.yml` |
| Local installer script | `build-installer.ps1` |
| Mesh studio viewport | `MeshBench/MainWindow.cs` |
| Resizable shell | `MarkdownAuthoringWorkspace.cs` |
| Material presets | `Materials.cs` |
Platform constraints
- NuGet-only: All cross-repo refs via GPR
2026.1.*; run `verify-nuget-only.ps1` before done - No NuGet publish from novolis-apps:
IsPackable=false; release job ships GitHub Release assets only - Per-user install: Inno
PrivilegesRequired=lowest,%LOCALAPPDATA%\Programs\Novolis\Concept Studio - Cameras: App-local camera state (MeshBench pattern) for v1
- Coordinates: +Y up, ship length on Z, beam on X
Suggested ship blockout workflow (your book use case)
- Install Concept Studio from GitHub Releases (or run from portable zip)
- New document from Ship template (tapered hull cylinder + deck box + nacelle spheres)
- Orbit mode — rough proportions with numeric inspector (length 120 m, beam 18 m)
- Assign Hull / Metal / EngineGlow materials
- Switch to Plan + Profile — add dimension callouts
- Export SVG sheet for reference while writing; export Quality PNG for print edition
- (Later) link asset from Manuscript Studio chapter metadata
Risk / complexity notes
| Risk | Mitigation |
|---|---|
| GPR missing Raylib/Rendering APIs | Publish upstream before apps merge; pin versions in Directory.Packages.props |
| Release job duration doubles | Sequential publish in one Windows job; shared Inno Setup install step |
| Cylinder/cone tessellation quality | Unit tests; cap segment count (24) |
| SVG hidden-line correctness | v1: export all edges; good enough for concept sheets |
| Scope creep toward FreeCAD | Hard gate: no constraints, no booleans in v1–v3 |
| release.yml drift | Align with merge.yml MSBuild Inno target when touching CI |