App shell
Vix UI provides app shell primitives for running server-rendered Vix interfaces inside desktop or WebView-style containers.
The app shell does not replace the web application.
It wraps a normal Vix web UI and opens it as an application window.
#include <vix/ui/shell/AppShell.hpp>
#include <vix/ui/shell/ShellConfig.hpp>2
Or use the UI umbrella header:
#include <vix/ui.hpp>When to use it
Use the app shell when you already have a Vix web page, dashboard, admin panel, internal tool, or mobile-ready UI and you want to run it like an app.
Typical use cases:
- desktop dashboards
- internal tools
- admin panels
- local-first tools
- server-rendered interfaces
- WebView-based desktop apps
- UI examples opened from a local Vix server
The important idea is simple:
Vix server-rendered UI -> local HTTP server -> app shell windowBasic shell configuration
ShellConfig describes the app window and the target URL.
vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
.set_name("Vix Desktop App")
.set_title("Vix Desktop Shell")
.set_host("127.0.0.1")
.set_port(8080)
.set_width(1200)
.set_height(800)
.set_resizable(true)
.set_fullscreen(false)
.set_devtools(true);2
3
4
5
6
7
8
9
10
The effective URL is built from the host and port:
std::cout << config.effective_url() << "\n";Output:
http://127.0.0.1:8080Start a shell
#include <iostream>
#include <vix/ui.hpp>
int main()
{
vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
.set_name("Vix Desktop App")
.set_title("Vix Desktop Shell")
.set_host("127.0.0.1")
.set_port(8080)
.set_width(1200)
.set_height(800)
.set_resizable(true)
.set_fullscreen(false)
.set_devtools(true)
.set_start_server(false);
vix::ui::AppShell shell = vix::ui::AppShell::make(config);
const vix::ui::Result<void> result = shell.start();
if (result.is_failed())
{
std::cerr << "failed to start desktop shell: "
<< result.error_message()
<< "\n";
return 1;
}
std::cout << "desktop shell started\n";
std::cout << "target url: " << shell.target_url() << "\n";
std::cout << "status: " << shell.status() << "\n";
return 0;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Run it:
vix run main.cppThis example expects the target server to already be running at:
http://127.0.0.1:8080Managed server mode
The app shell can also start a local server command before opening the window.
Use managed server mode when the shell should control the server process.
#include <iostream>
#include <string>
#include <vix/ui.hpp>
int main()
{
const std::string command =
"vix run ui_dashboard.cpp --force-server --run --port 8080";
vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
.set_name("Vix UI Server App")
.set_title("Vix UI Desktop Shell")
.set_host("127.0.0.1")
.set_port(8080)
.set_width(1200)
.set_height(800)
.set_resizable(true)
.set_fullscreen(false)
.set_devtools(true)
.set_start_server(true)
.set_server_command(command);
vix::ui::AppShell shell = vix::ui::AppShell::make(config);
const vix::ui::Result<void> result = shell.start();
if (result.is_failed())
{
std::cerr << "failed to start desktop shell: "
<< result.error_message()
<< "\n";
return 1;
}
return 0;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
In this mode, the app shell starts the server command and then opens the configured target URL.
Readiness check
For better startup behavior, the shell can wait until the server is ready.
#include <chrono>
#include <iostream>
#include <string>
#include <vix/ui.hpp>
int main()
{
const std::string command =
"vix run ui_dashboard.cpp --force-server --run --port 8080";
vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
.set_name("Vix UI Readiness App")
.set_title("Vix UI Desktop Readiness")
.set_app_id("com.vix.ui.readiness")
.set_app_version("0.8.0")
.set_vendor("Vix.cpp")
.set_host("127.0.0.1")
.set_port(8080)
.set_readiness_url("http://127.0.0.1:8080/health")
.set_startup_timeout(std::chrono::milliseconds(5000))
.set_wait_for_server(true)
.set_start_server(true)
.set_server_command(command)
.set_width(1200)
.set_height(800)
.set_resizable(true)
.set_devtools(true);
vix::ui::AppShell shell = vix::ui::AppShell::make(config);
std::cout << "starting local server:\n";
std::cout << " " << command << "\n";
std::cout << "waiting for readiness URL:\n";
std::cout << " " << config.effective_readiness_url() << "\n";
std::cout << "opening target URL:\n";
std::cout << " " << shell.target_url() << "\n";
const vix::ui::Result<void> result = shell.start();
if (result.is_failed())
{
std::cerr << "failed to start desktop shell: "
<< result.error_message()
<< "\n";
return 1;
}
std::cout << "desktop shell closed\n";
std::cout << "status: " << shell.status() << "\n";
return 0;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
This avoids opening the shell before the server is ready.
Using environment variables
For examples and local tools, the server command can come from an environment variable.
#include <cstdlib>
#include <iostream>
#include <string>
#include <vix/ui.hpp>
static std::string env_or_empty(const char *name)
{
const char *value = std::getenv(name);
if (value == nullptr)
{
return {};
}
return std::string(value);
}
int main()
{
const std::string command = env_or_empty("VIX_UI_SERVER_CMD");
if (command.empty())
{
std::cerr << "missing server command\n";
std::cerr << "usage:\n";
std::cerr << " VIX_UI_SERVER_CMD=\"<server command>\" ./app\n";
return 1;
}
vix::ui::ShellConfig config = vix::ui::ShellConfig::make()
.set_name("Vix UI Server App")
.set_title("Vix UI Desktop Shell")
.set_host("127.0.0.1")
.set_port(8080)
.set_width(1200)
.set_height(800)
.set_resizable(true)
.set_fullscreen(false)
.set_devtools(true)
.set_start_server(true)
.set_server_command(command);
vix::ui::AppShell shell = vix::ui::AppShell::make(config);
const vix::ui::Result<void> result = shell.start();
if (result.is_failed())
{
std::cerr << result.error_message() << "\n";
return 1;
}
return 0;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Run it:
VIX_UI_SERVER_CMD="vix run ui_dashboard.cpp --force-server --run --port 8080" \
vix run main.cpp2
Desktop command
The easiest way to run a Vix UI file as a desktop app is through the desktop command.
vix desktop run ui_dashboard.cpp --port 8080Example output:
info Building desktop server:
• /home/softadastra/tmp/ui/ui_dashboard.cpp
Vix Desktop
app Vix Desktop
target http://127.0.0.1:8080
mode dev (managed server)
Vix.cpp READY v2.7.0 run
> HTTP: http://localhost:8080/
- Status: ready
- Hint: Ctrl+C to stop the server2
3
4
5
6
7
8
9
10
11
12
This command builds the C++ UI server, starts it, and opens it through the desktop shell flow.
Example Vix UI server
A shell usually opens a normal Vix server-rendered page.
#include <vix/core.hpp>
#include <vix/ui.hpp>
int main()
{
vix::App app;
app.templates("templates");
app.get("/", [](vix::Request &req, vix::Response &res) {
(void)req;
const std::string flash =
vix::ui::FlashMessage::success("Vix UI dashboard is running.")
.set_title("Ready")
.set_dismissible(true)
.render();
auto view =
vix::ui::View("dashboard.html")
.set_title("Vix UI Dashboard")
.set("flash", flash)
.set("framework", "Vix.cpp")
.set("module", "vix::ui");
res.ui(view);
});
app.run(8080);
return 0;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Run it as a desktop app:
vix desktop run ui_dashboard.cpp --port 8080ShellConfig reference
Common configuration methods:
| Method | Purpose |
|---|---|
set_name(...) | Internal app name |
set_title(...) | Window title |
set_app_id(...) | App identifier |
set_app_version(...) | App version |
set_vendor(...) | Vendor name |
set_icon_path(...) | App icon path |
set_url(...) | Explicit target URL |
set_host(...) | Target host |
set_port(...) | Target port |
set_readiness_url(...) | URL used to check readiness |
set_startup_timeout(...) | Maximum readiness wait time |
set_wait_for_server(...) | Wait before opening the shell |
set_start_server(...) | Start a server command |
set_server_command(...) | Command used to start the server |
set_width(...) | Window width |
set_height(...) | Window height |
set_resizable(...) | Allow resizing |
set_fullscreen(...) | Start fullscreen |
set_devtools(...) | Enable developer tools |
Effective URL
When no explicit URL is set, the shell builds the target URL from host and port.
vix::ui::ShellConfig config;
config.set_host("127.0.0.1")
.set_port(8080);
std::cout << config.effective_url() << "\n";2
3
4
5
6
Output:
http://127.0.0.1:8080Use set_url(...) when you want full control:
config.set_url("http://127.0.0.1:8080/admin");Effective readiness URL
If a readiness URL is provided, the shell uses it.
config.set_readiness_url("http://127.0.0.1:8080/health");If no readiness URL is provided, the shell can fall back to the effective target URL.
std::cout << config.effective_readiness_url() << "\n";ServerProcess
ServerProcess is a small helper for starting and stopping a local server process.
vix::ui::ServerProcess process("sleep 30");
vix::ui::Result<void> start = process.start();
if (start.is_ok())
{
std::cout << "server pid: " << process.pid() << "\n";
}
process.stop();2
3
4
5
6
7
8
9
10
It is used by the app shell when managed server mode is enabled.
Most users do not need to use it directly unless they are building custom shell workflows.
ServerReadiness
ServerReadiness checks whether a server endpoint is reachable.
auto endpoint =
vix::ui::ServerReadiness::parse_url("http://127.0.0.1:8080/health");
if (endpoint.is_failed())
{
std::cerr << endpoint.error_message() << "\n";
return 1;
}
auto ready = vix::ui::ServerReadiness::check_once(endpoint.value());
if (ready.is_ok())
{
std::cout << "server is ready\n";
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
Wait for a server:
auto result =
vix::ui::ServerReadiness::wait(
"http://127.0.0.1:8080/health",
std::chrono::milliseconds(5000));
if (result.is_failed())
{
std::cerr << result.error_message() << "\n";
}2
3
4
5
6
7
8
9
Result handling
App shell operations return vix::ui::Result<void>.
Always check the result before assuming the shell started correctly.
const vix::ui::Result<void> result = shell.start();
if (result.is_failed())
{
std::cerr << result.error_message() << "\n";
return 1;
}2
3
4
5
6
7
Common workflows
Open an existing local server
Start your server first:
vix run ui_dashboard.cpp --force-server --run --port 8080Then open a shell that targets:
http://127.0.0.1:8080Let the shell start the server
Use:
config.set_start_server(true)
.set_server_command("vix run ui_dashboard.cpp --force-server --run --port 8080");2
Wait until the server is ready
Use:
config.set_wait_for_server(true)
.set_readiness_url("http://127.0.0.1:8080/health")
.set_startup_timeout(std::chrono::milliseconds(5000));2
3
Use the desktop command
vix desktop run ui_dashboard.cpp --port 8080This is the simplest workflow for Vix UI desktop examples.
Common mistakes
Opening the shell before the server is ready
If the page is blank or fails to load, enable readiness waiting.
config.set_wait_for_server(true)
.set_readiness_url("http://127.0.0.1:8080/health");2
Forgetting to start the server
If set_start_server(false) is used, the app shell only opens the target URL.
It does not start the Vix server.
config.set_start_server(false);Use this only when the server is already running.
Using the wrong port
The shell port and the server port must match.
config.set_port(8080);Run the server on the same port:
vix desktop run ui_dashboard.cpp --port 8080Missing health route
If the readiness URL is /health, the server should expose it.
app.get("/health", [](vix::Request &, vix::Response &res) {
res.json({"ok", true});
});2
3
Treating app shell as a native widget toolkit
The app shell is not a native UI toolkit.
It is designed to open web-first Vix UI applications inside an app window.
For UI rendering, use normal Vix routes, templates, HTML responses, forms, assets, live fragments, and PWA helpers.
What to remember
AppShell opens a configured URL as an application shell.
ShellConfig describes the app name, window, URL, server command, and readiness behavior.
ServerProcess can start and stop a local server.
ServerReadiness can wait until the server is reachable.
ShellConfig -> AppShell -> target URL
-> optional server process
-> optional readiness check2
3
For normal usage, prefer:
vix desktop run ui_dashboard.cpp --port 8080Next step
Continue with UI examples.
