A multiplatform site previewer, following the orchestrator CommanderTurtle/orc and reproducing the deploy topology locally. It reads
.github/config/deploy-*.fs, creates one rendered working mirror per
SourceFolder, launches each framework's own development server, and keeps the
mirrors synchronized while source files are saved. It can also point one
standalone source directory at any canonical ORC GenerateConfig.fsx runtime.
It is separate from both ORC and the small one-tree orc-reactor. The ORC
checkout remains read-only.
Clone your repo, then natively preview 7 site frameworks, preserving realtime edits to the F# source code. Preview runs on reactor topology.
git clone https://github.com/CommanderTurtle/preview
cd preview
cargo build --release
Double-click target/release/orc-preview.exe (no arguments), or run
orc-preview --gui. The GUI is compiled into the same Cargo binary using
egui's native OpenGL renderer: no browser runtime, Electron, or GUI web server.
Explicit CLI arguments continue to run the original console workflow.
On Windows the EXE retains console-subsystem semantics so PowerShell waits and
receives exit codes. GUI mode immediately detaches that console; Explorer may
briefly show it during startup, but no console stays open beside the dashboard.
- Select sites and ports, then Start selected. Nothing launches automatically.
- Refresh re-renders one mirror, re-detects its framework, regenerates its launch configuration and restarts just that server. Use it after Zensical nav, Vite config or Jekyll YAML changes. Normal saves still use the existing watcher.
- Each site has Stop / Start, framework/status, port and an Open link. A responding TCP port is shown as running; this is not an HTTP health guarantee.
- Logs stay in the window, with per-site filtering, text search, follow, copy, save and clear. Memory is bounded to 4,000 lines; unusually verbose output may be dropped from the display. There are no per-server consoles in GUI mode.
- Stop session and closing the window stop the owned process trees before deleting disposable output. A stalled shutdown gets 12 seconds, then the GUI terminates only its own worker tree. Windows job objects contain descendants even when a launcher exits early. Source repositories are never deleted.
- Reuse framework downloads selects a shared cache; leaving it off gives a fresh disposable environment. Keep rendered mirrors also preserves native build/dependency folders. Switching either off does not delete an existing persistent folder. No generic recursive "clear cache" button is provided.
The dashboard reads the same .env / .env.example settings as the launcher.
It looks in the current Preview checkout, then beside/above the executable;
embedded defaults also let a copied EXE start without companion files. Paths
resolve relative to the selected settings file. Load, Reload, Save,
folder browsing and Discover sites make the configuration explicit. Settings
are saved only when requested. ORC_OUTPUT is an optional GUI-only output path.
An unchecked site is omitted from saved selections; Discover sites restores
all available targets to the selection list. Topology changes still stop the
coordinator safely; reload/discover and start a new session afterward.
orc-preview --gui --config C:\preview-settings\.env
orc-preview --gui --orc-dir C:\src\orc
# Existing direct / standalone CLI usage remains supported below.Internally the GUI owns one hidden coordinator. A private stdin/stdout protocol carries control actions and tagged logs; no network control port is opened. The coordinator uses the same renderer, theme cache, launch scripts and watcher as the CLI. Framework runtimes still need to be installed as described below.
Tests: cargo test covers settings, bounded logs, native layout and Windows
process cleanup. The opt-in real renderer/Bun test uses a disposable sample site,
not the user's deployment targets:
$env:ORC_TEST_RUNTIME = 'C:\src\orc\GenerateConfig.fsx'
cargo test --test managed_smoke -- --ignored --nocapturePreview runs the canonical renderer from the ORC checkout; there is no copied
or embedded GenerateConfig.fsx runtime in this repository. The common cases
are intentionally positional:
# One selected ORC site.
.\target\release\orc-preview.exe --orc-dir=C:\src\orc app 2000
# Several selected ORC sites, paired left-to-right with their ports.
.\target\release\orc-preview.exe --orc-dir=C:\src\orc app,docs,lab 2000,2001,2002
# An unrelated source folder, rendered by an explicitly pointed ORC runtime.
.\target\release\orc-preview.exe `
--single-dir=C:\src\other-site `
--runtime-dir=C:\src\orc\GenerateConfig.fsx `
--sharedstrings=true--single-dir defaults to port 4000; use --ports 4173 to choose another.
In topology mode, omitting the positional selection previews every discovered
deployment on consecutive ports beginning at 4000.
By default, rendered mirrors, launch files, downloaded frameworks, virtual
environments, and theme checkouts live in one unique temporary session and are
removed on normal exit or Ctrl+C. Add bare --cache to preserve reusable
framework downloads in .cache, or --cache C:\preview-cache to choose the
location. Add --output C:\preview\orc only when the rendered mirrors
themselves should survive.
Shared strings normally follow each deploy record's UseSharedStrings value.
--sharedstrings=true|false overrides it. For an external or unusually placed
catalog, select one site and pass --shared-file=C:\path\sharedstrings.fs.
Place the preview and orc checkouts beside one another using the default
layout, then run:
.\orc-server.ps1The launcher reads the Git-ignored .env when present and otherwise uses the
complete .env.example baseline directly.
The checked-in defaults resolve the adjacent ../orc/orc checkout and start the
canonical seven targets. It builds Preview when needed, creates a unique
rendered environment beneath the Windows temporary directory, and launches the
existing multi-server coordinator. Reusable themes and framework downloads live
inside that disposable environment by default. Ctrl+C stops every framework
process tree, then removes the rendered sites, generated launch files, package
downloads, virtual environments, theme checkouts, and the session directory
itself. Nothing is created in the ORC checkout: it remains an unbuilt, pristine
source clone without dist, node_modules, .venv, or framework output.
To preserve reusable framework downloads without preserving rendered sites,
set an explicit cache in .env:
ORC_CACHE=.orc-preview-cacheThat opt-in, Git-ignored directory retains the Zensical environment, Netdocs
binary, Ruby bundles, Bun package cache, and theme checkouts. Session output is
still deleted on shutdown. Leave ORC_CACHE= blank for the fully disposable
fresh-install lifecycle.
Site selection is explicit and independent of deploy-file sort order:
ORC_SITE_APP=app:4000
ORC_SITE_BLOG=blog:4111
ORC_SITE_DOCS=docs:4222
ORC_SITE_LAB=lab:4333
ORC_SITE_NET=net:4666
ORC_SITE_PAGES=pages:4444
ORC_SITE_VITE=vite:4555To activate an eighth site, add one line to .env. The value names the ORC
SourceFolder and its port; the setting name is a human-readable label:
ORC_SITE_PRETTIART=vite2:4777The matching source folder and .github/config/deploy-*.fs definition must
exist in the configured ORC checkout. No Preview code or positional port list
needs to change. Use .\orc-server.ps1 -RenderOnly to validate rendering and
cleanup without starting framework servers.
Required on PATH:
- Rust/Cargo and .NET for the preview binary and ORC renderer;
- PowerShell (
pwsh, or Windows PowerShell via--powershell powershell.exe) for the visible server consoles; - uv for Zensical projects;
- Ruby 3.4 and Bundler for Jekyll and GitHub Pages projects;
- Bun for Vite projects.
Netdocs is installed into the shared preview state automatically. It does not
alter the user's global .NET or PATH configuration.
Ports are assigned in sorted SourceFolder order. The current ORC tree sorts
as app, blog, docs, lab, net, pages, vite. Ports do not need to
be numerically sorted, so an existing six-site layout can retain its URLs:
.\target\release\orc-preview.exe `
--orc-dir C:\src\orc `
--output C:\preview\orc `
--ports 4000,4111,4222,4333,4666,4444,4555For explicit target selection, use named source-folder assignments. Unlike the legacy positional form, unselected deploy definitions are ignored:
.\target\release\orc-preview.exe `
--orc-dir C:\src\orc `
--output C:\preview\orc `
--sites app=4000,blog=4111,docs=4222,lab=4333,net=4666,pages=4444,vite=4555The output contains:
C:\preview\orc\
app\
blog\
docs\
lab\
net\
pages\
vite\
.orc-preview\ # launch scripts, manifests, and shared preview state
Each site folder is a deployment-like working mirror: rendered ORC files and
literal assets remain beside native framework output such as site, _site,
or dist. A startup reconciliation replaces only ORC-managed files, so native
dependency/build directories can remain warm.
One visible PowerShell console is opened per site. The existing framework
launchers bind to 0.0.0.0; Netdocs currently follows its upstream Kestrel
behavior and binds to loopback. The parent prints every loopback URL. Press
Ctrl+C in the parent console to close the complete process tree.
Use --render-only to create/reconcile mirrors and inspect the generated
launch scripts without opening servers.
Detection keeps the common deploy workflow's precedence:
appsettings.json— Netdocs;zensical.toml— a Python 3.12.10 uv environment, Zensical, andtomli-w;Gemfile— the project's Bundler/Jekyll environment;package.json— Bun and the package's Vite development script;- otherwise — implicit GitHub Pages/Jekyll.
A Netdocs target uses the upstream native self-contained executable and the
documented netdocs serve --config ./appsettings.json --port <port> flow. At
server startup, the shared preview cache checks the upstream latest-release
API and downloads a new Windows x64 or Linux x64 executable only when needed.
Multiple Netdocs targets share that installation and a startup lock, while
each target retains its own appsettings.json, docs/, configured siteDir,
watcher, and live-reload server.
The last case matters: ORC's app, lab, and pages targets are GitHub Pages
sites even though only pages currently renders an explicit _config.yml.
Only these otherwise-unclaimed targets use the shared, preview-only
github-pages bundle. Native Gemfile, Zensical, and Vite projects never enter
that compatibility path. The bundle supplies Pages behavior such as optional
front matter, default layouts, README indexes, relative links, and GitHub
Flavored Markdown. This is the local equivalent of the second Jekyll build
GitHub performs after ORC pushes a rendered tree to its target repository.
For an implicit Pages target, remote_theme: owner/repository[@ref] is resolved
to that Git repository. Supported default jekyll-theme-* selections resolve
to their official pages-themes repositories; an omitted selection uses the
GitHub Pages default pages-themes/primer. Identical selections share one
shallow checkout, and layered files use hard links where the filesystem
supports them. The preview refreshes each unique checkout once when it starts,
then layers only the theme's _layouts,
_includes, _sass, _data, and assets beneath the rendered site. Copying
is non-destructive: an ORC-rendered path always wins. Theme configuration,
Gemfiles, sample pages, and repository metadata are never imported, so a
theme cannot replace project configuration or content. Declared/default gem
theme settings remain active so their plugin dependencies load normally. For
a remote_theme, the server reads a preview-only copy of the ORC config with
only that fetch directive removed; the source _config.yml is not edited.
GitHub metadata uses the checkout's origin owner together with each
deployment's TargetRepo. Local-path clones are followed back to their
upstream checkout. If the owner cannot be inferred, set it explicitly before
starting:
$env:GITHUB_REPOSITORY_OWNER = "CommanderTurtle"The first implicit Pages launch installs the shared gem bundle. Later launches
reuse it. A project with its own Gemfile remains independent and uses its
native bundle. A theme Git checkout records the exact commit used and refreshes
on the next preview start. The launcher also carries a process-local Ruby 3.4
compatibility fix for the edit-link tag in the version of
jekyll-github-metadata pinned by GitHub Pages; no installed gem is modified.
Saving a file does not trigger a replacement build system. ORC overwrites only
the corresponding mirror file (or dependent pages after a helper change), and
Zensical, Jekyll, or Vite performs its normal rebuild/reload. A brief quiet
window coalesces editor save patterns and folder replacements; configure it
with --settle-ms.
Each deploy record's UseSharedStrings boolean is also honored locally. When
true, the preview loads that site's strings/sharedstrings.fs helper through
open SharedStrings before rendering its wrappers. Other sites are untouched,
and the helper never appears in their working mirrors.
When the deploy configuration itself changes, the parent shuts down cleanly. Restart it with a port for each newly discovered target.
