Skip to content

Commit 7d9d2c7

Browse files
feat(editor): command and event console, rename the protocol feature
Adds an opt-in journal to the engine event system. set_journal_enabled turns it on, emit_event and the command dispatch record into it, and drain_journal takes what accumulated. A shipping build leaves it off and pays no record keeping cost. The editor turns it on and surfaces it as a command and event console, opened from View, Toggle command console. The top half is a live log of the participant cycle, every command applied and every event published, tagged by cycle and colored apart. The bottom half is a builder that constructs a participant command and submits it through push_command, the same path a script takes, so the panel both watches the cycle and drives it by hand. New protocol messages carry the log and the submitted command. Also renames the nightshade-api editor-protocol feature to protocol and editor-protocol-agent to protocol-agent. The feature is the whole editor wire format, not tied to the editor as its only consumer, so it is named for what it is. The scripting and editor agent docs are updated.
1 parent 5776d0e commit 7d9d2c7

20 files changed

Lines changed: 652 additions & 31 deletions

File tree

apps/editor/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ edition = "2024"
1313
[features]
1414
# The external agent relay (page <-> MCP bridge websocket). Off by default so a
1515
# deployed build never opens a localhost socket; enable for agent development.
16-
agent = ["nightshade-api/editor-protocol-agent"]
16+
agent = ["nightshade-api/protocol-agent"]
1717

1818
[dependencies]
1919
nightshade = { path = "../../crates/nightshade", features = [
2020
"networking",
2121
] }
2222
nightshade-api = { path = "../../crates/nightshade-api", default-features = false, features = [
23-
"editor-protocol",
23+
"protocol",
2424
] }
2525
leptos = { version = "0.7", features = ["csr"] }
2626
postcard = { version = "1", features = ["alloc"] }

apps/editor/desktop/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ default = ["agent", "networking"]
1818
# View menu toggle or the --mcp flag.
1919
agent = [
2020
"dep:nightshade-api",
21-
"nightshade-api/editor-protocol-agent",
21+
"nightshade-api/protocol-agent",
2222
"dep:enum2schema",
2323
"dep:tokio",
2424
"dep:tokio-tungstenite",

apps/editor/public/styles.css

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,3 +1417,181 @@ input[type="range"] {
14171417
background: var(--accent);
14181418
color: var(--bg);
14191419
}
1420+
1421+
/* Command and event console */
1422+
.console {
1423+
position: fixed;
1424+
right: 332px;
1425+
bottom: 30px;
1426+
width: 440px;
1427+
max-height: 52vh;
1428+
z-index: 40;
1429+
border: 1px solid var(--panel-border);
1430+
border-radius: 12px;
1431+
background: color-mix(in srgb, var(--panel) 92%, transparent);
1432+
backdrop-filter: blur(12px);
1433+
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.45);
1434+
transition: opacity 0.16s ease, transform 0.16s ease;
1435+
}
1436+
1437+
.console.closed {
1438+
opacity: 0;
1439+
transform: translateY(8px);
1440+
pointer-events: none;
1441+
}
1442+
1443+
.console-header {
1444+
display: flex;
1445+
align-items: center;
1446+
justify-content: space-between;
1447+
padding: 10px 14px;
1448+
border-bottom: 1px solid var(--panel-border);
1449+
}
1450+
1451+
.console-title {
1452+
font-size: 12px;
1453+
font-weight: 600;
1454+
letter-spacing: 0.04em;
1455+
text-transform: uppercase;
1456+
color: var(--text);
1457+
opacity: 0.7;
1458+
}
1459+
1460+
.console-clear {
1461+
font-size: 11px;
1462+
padding: 3px 10px;
1463+
border-radius: 6px;
1464+
border: 1px solid var(--panel-border);
1465+
background: transparent;
1466+
color: var(--text);
1467+
cursor: pointer;
1468+
}
1469+
1470+
.console-clear:hover {
1471+
border-color: var(--accent);
1472+
color: var(--accent);
1473+
}
1474+
1475+
.console-log {
1476+
flex: 1;
1477+
overflow-y: auto;
1478+
padding: 8px;
1479+
display: flex;
1480+
flex-direction: column;
1481+
gap: 2px;
1482+
font-family: ui-monospace, "Cascadia Code", "SF Mono", Menlo, monospace;
1483+
font-size: 11.5px;
1484+
min-height: 120px;
1485+
max-height: 32vh;
1486+
}
1487+
1488+
.console-row {
1489+
display: grid;
1490+
grid-template-columns: 38px 30px auto 1fr;
1491+
align-items: baseline;
1492+
gap: 8px;
1493+
padding: 3px 8px;
1494+
border-radius: 6px;
1495+
border-left: 2px solid transparent;
1496+
}
1497+
1498+
.console-row:hover {
1499+
background: color-mix(in srgb, var(--text) 6%, transparent);
1500+
}
1501+
1502+
.console-command {
1503+
border-left-color: #60a5fa;
1504+
}
1505+
1506+
.console-event {
1507+
border-left-color: var(--accent);
1508+
}
1509+
1510+
.console-cycle {
1511+
color: var(--text);
1512+
opacity: 0.4;
1513+
text-align: right;
1514+
}
1515+
1516+
.console-tag {
1517+
font-size: 9.5px;
1518+
text-transform: uppercase;
1519+
letter-spacing: 0.06em;
1520+
font-weight: 700;
1521+
}
1522+
1523+
.console-command .console-tag {
1524+
color: #60a5fa;
1525+
}
1526+
1527+
.console-event .console-tag {
1528+
color: var(--accent);
1529+
}
1530+
1531+
.console-label {
1532+
color: var(--text);
1533+
font-weight: 600;
1534+
white-space: nowrap;
1535+
}
1536+
1537+
.console-detail {
1538+
color: var(--text);
1539+
opacity: 0.6;
1540+
overflow: hidden;
1541+
text-overflow: ellipsis;
1542+
white-space: nowrap;
1543+
}
1544+
1545+
.console-builder {
1546+
display: flex;
1547+
flex-direction: column;
1548+
gap: 8px;
1549+
padding: 12px 14px;
1550+
border-top: 1px solid var(--panel-border);
1551+
}
1552+
1553+
.console-row-fields {
1554+
display: flex;
1555+
gap: 8px;
1556+
}
1557+
1558+
.console-row-fields.hidden {
1559+
display: none;
1560+
}
1561+
1562+
.console-select,
1563+
.console-input {
1564+
flex: 1;
1565+
min-width: 0;
1566+
padding: 7px 10px;
1567+
font-size: 12px;
1568+
border-radius: 7px;
1569+
border: 1px solid var(--panel-border);
1570+
background: var(--bg);
1571+
color: var(--text);
1572+
}
1573+
1574+
.console-entity {
1575+
max-width: 120px;
1576+
}
1577+
1578+
.console-select:focus,
1579+
.console-input:focus {
1580+
outline: none;
1581+
border-color: var(--accent);
1582+
}
1583+
1584+
.console-submit {
1585+
padding: 9px 12px;
1586+
font-size: 12px;
1587+
font-weight: 600;
1588+
border-radius: 8px;
1589+
border: 1px solid var(--accent);
1590+
background: var(--accent);
1591+
color: var(--bg);
1592+
cursor: pointer;
1593+
}
1594+
1595+
.console-submit:hover {
1596+
filter: brightness(1.08);
1597+
}

apps/editor/src/app.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use nightshade_api::editor::protocol::ClientMessage;
66
use crate::bridge::{Bridge, send};
77
use crate::components::browsers::BrowserOverlay;
88
use crate::components::command_palette::CommandPalette;
9+
use crate::components::console::Console;
910
use crate::components::inspector::Inspector;
1011
use crate::components::left_panel::LeftPanel;
1112
use crate::components::loader::Loader;
@@ -148,6 +149,7 @@ pub fn App() -> impl IntoView {
148149
<LeftPanel bridge state />
149150
<Viewport bridge state />
150151
<Inspector bridge state />
152+
<Console bridge state />
151153
<StatusBar state />
152154
<NavGizmo bridge state />
153155
<BrowserOverlay bridge state />

apps/editor/src/bridge.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ pub fn connect(offscreen: OffscreenCanvas, width: f32, height: f32, state: Edito
5252
WorkerMessage::Camera { right, up, forward } => {
5353
state.camera_basis.set([right, up, forward]);
5454
}
55+
WorkerMessage::CommandLog { entries } => {
56+
state.command_log.update(|log| {
57+
log.extend(entries);
58+
let overflow = log.len().saturating_sub(500);
59+
if overflow > 0 {
60+
log.drain(0..overflow);
61+
}
62+
});
63+
}
5564
WorkerMessage::Scene { rows } => state.scene.set(rows),
5665
WorkerMessage::Cameras { entries } => state.cameras.set(entries),
5766
WorkerMessage::Selected { detail } => {

apps/editor/src/components.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod browsers;
22
#[cfg(feature = "agent")]
33
pub mod chat;
44
pub mod command_palette;
5+
pub mod console;
56
pub mod fields;
67
pub mod inspector;
78
pub mod left_panel;

0 commit comments

Comments
 (0)