implements PLN-0081 shell hub packet migration

This commit is contained in:
bQUARKz 2026-05-25 14:16:07 +01:00
parent ae85ed4eff
commit 74df4b89ac
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
6 changed files with 175 additions and 57 deletions

View File

@ -5,7 +5,7 @@ use prometeu_hal::glyph_bank::GlyphBank;
use prometeu_hal::scene_viewport_cache::{CachedTileEntry, SceneViewportCache};
use prometeu_hal::scene_viewport_resolver::{LayerCopyRequest, ResolverUpdate};
use prometeu_hal::sprite::Sprite;
use prometeu_hal::{Game2DFramePacket, Gfx2dCommand, GfxBridge};
use prometeu_hal::{Game2DFramePacket, Gfx2dCommand, GfxBridge, GfxUiCommand, ShellUiFramePacket};
use std::sync::Arc;
/// Blending modes inspired by classic 16-bit hardware.
@ -714,6 +714,12 @@ impl Gfx {
}
}
pub fn render_shell_ui_frame_packet(&mut self, packet: &ShellUiFramePacket) {
for command in &packet.commands {
self.apply_gfxui_command(command);
}
}
fn apply_gfx2d_command(&mut self, command: &Gfx2dCommand) {
match command {
Gfx2dCommand::Clear { color } => self.clear(*color),
@ -738,6 +744,30 @@ impl Gfx {
}
}
fn apply_gfxui_command(&mut self, command: &GfxUiCommand) {
match command {
GfxUiCommand::Clear { color } => self.clear(*color),
GfxUiCommand::FillRect { rect, color } => {
self.fill_rect(rect.x, rect.y, rect.w, rect.h, *color);
}
GfxUiCommand::DrawLine { x0, y0, x1, y1, color } => {
self.draw_line(*x0, *y0, *x1, *y1, *color);
}
GfxUiCommand::DrawCircle { x, y, radius, color } => {
self.draw_circle(*x, *y, *radius, *color);
}
GfxUiCommand::DrawDisc { x, y, radius, border_color, fill_color } => {
self.draw_disc(*x, *y, *radius, *border_color, *fill_color);
}
GfxUiCommand::DrawSquare { rect, border_color, fill_color } => {
self.draw_square(rect.x, rect.y, rect.w, rect.h, *border_color, *fill_color);
}
GfxUiCommand::DrawText { x, y, text, color } => {
self.draw_text(*x, *y, text, *color);
}
}
}
fn populate_layer_buckets(&mut self) {
for bucket in self.layer_buckets.iter_mut() {
bucket.clear();

View File

@ -8,10 +8,10 @@ use crate::memory_banks::{
};
use crate::pad::Pad;
use crate::touch::Touch;
use prometeu_hal::Game2DFramePacket;
use prometeu_hal::cartridge::AssetsPayloadSource;
use prometeu_hal::sprite::Sprite;
use prometeu_hal::{AssetBridge, AudioBridge, GfxBridge, HardwareBridge, PadBridge, TouchBridge};
use prometeu_hal::{Game2DFramePacket, ShellUiFramePacket};
use std::sync::Arc;
/// Aggregate structure for all virtual hardware peripherals.
@ -72,6 +72,10 @@ impl HardwareBridge for Hardware {
self.frame_composer.close_game2d_packet()
}
fn render_shell_ui_packet(&mut self, packet: &ShellUiFramePacket) {
self.gfx.render_shell_ui_frame_packet(packet);
}
fn render_frame(&mut self) {
if self.frame_composer.active_scene_id().is_none() {
let packet = self.frame_composer.close_game2d_packet();
@ -81,6 +85,10 @@ impl HardwareBridge for Hardware {
}
}
fn present(&mut self) {
self.gfx.present();
}
fn has_glyph_bank(&self, bank_id: usize) -> bool {
self.gfx.glyph_banks.glyph_bank_slot(bank_id).is_some()
}

View File

@ -2,7 +2,7 @@ use crate::asset_bridge::AssetBridge;
use crate::audio_bridge::AudioBridge;
use crate::gfx_bridge::GfxBridge;
use crate::pad_bridge::PadBridge;
use crate::render_submission::Game2DFramePacket;
use crate::render_submission::{Game2DFramePacket, ShellUiFramePacket};
use crate::sprite::Sprite;
use crate::touch_bridge::TouchBridge;
@ -13,7 +13,9 @@ pub trait HardwareBridge {
fn set_camera(&mut self, x: i32, y: i32);
fn emit_sprite(&mut self, sprite: Sprite) -> bool;
fn close_game2d_packet(&self) -> Game2DFramePacket;
fn render_shell_ui_packet(&mut self, packet: &ShellUiFramePacket);
fn render_frame(&mut self);
fn present(&mut self);
fn has_glyph_bank(&self, bank_id: usize) -> bool;
fn gfx(&self) -> &dyn GfxBridge;

View File

@ -1,8 +1,7 @@
use crate::{CrashReport, SystemOS};
use prometeu_hal::color::Color;
use prometeu_hal::gfx_bridge::GfxBridge;
use prometeu_hal::primitives::Rect;
use prometeu_hal::{HardwareBridge, InputSignals};
use prometeu_hal::{GfxUiCommand, HardwareBridge, InputSignals, ShellUiFramePacket};
use prometeu_vm::VirtualMachine;
const SHELL_A_BUTTON: Rect = Rect { x: 112, y: 108, w: 112, h: 48 };
@ -101,8 +100,6 @@ impl PrometeuHub {
os: &mut SystemOS,
hw: &mut dyn HardwareBridge,
) -> Option<SystemProfileAction> {
hw.gfx_mut().clear(Color::INDIGO);
let in_shell = os.windows().focused_window().is_some();
if !in_shell {
@ -127,21 +124,23 @@ impl PrometeuHub {
let pointer_x = hw.touch().x();
let pointer_y = hw.touch().y();
if os.windows().window_count() == 0 {
render_home(hw.gfx_mut(), pointer_x, pointer_y);
return;
}
for window in os.windows().windows() {
render_shell_window(
hw.gfx_mut(),
window.viewport,
window.color,
&window.title,
pointer_x,
pointer_y,
);
}
let packet = if os.windows().window_count() == 0 {
render_home_packet(pointer_x, pointer_y)
} else {
let mut commands = Vec::new();
for window in os.windows().windows() {
append_shell_window_commands(
&mut commands,
window.viewport,
window.color,
&window.title,
pointer_x,
pointer_y,
);
}
ShellUiFramePacket::new(commands)
};
hw.render_shell_ui_packet(&packet);
}
pub fn update_shell_profile(
@ -163,7 +162,7 @@ impl PrometeuHub {
}
self.render(os, hw);
hw.gfx_mut().present();
hw.present();
SystemProfileUpdate { crash, action }
}
@ -192,15 +191,29 @@ fn activation_input_down(hw: &dyn HardwareBridge) -> bool {
hw.touch().f().down || hw.pad().a().down || hw.pad().b().down || hw.pad().start().down
}
fn render_home(gfx: &mut dyn GfxBridge, pointer_x: i32, pointer_y: i32) {
gfx.fill_rect(VIEWPORT.x, VIEWPORT.y, VIEWPORT.w, VIEWPORT.h, COLOR_BG);
draw_panel(gfx, TITLE_PANEL, COLOR_PANEL_DARK, COLOR_BORDER);
draw_buffer_text(gfx, TITLE_PANEL.x + 58, TITLE_PANEL.y + 9, "PROMETEU HUB", COLOR_TEXT);
draw_panel(gfx, HOME_PANEL, COLOR_PANEL, COLOR_BORDER);
draw_buffer_text(gfx, HOME_PANEL.x + 26, HOME_PANEL.y + 22, "Native Shell Apps", COLOR_TEXT);
fn render_home_packet(pointer_x: i32, pointer_y: i32) -> ShellUiFramePacket {
let mut commands = Vec::new();
commands.push(GfxUiCommand::Clear { color: COLOR_BG });
fill_rect(&mut commands, VIEWPORT, COLOR_BG);
draw_panel(&mut commands, TITLE_PANEL, COLOR_PANEL_DARK, COLOR_BORDER);
draw_buffer_text(
gfx,
&mut commands,
TITLE_PANEL.x + 58,
TITLE_PANEL.y + 9,
"PROMETEU HUB",
COLOR_TEXT,
);
draw_panel(&mut commands, HOME_PANEL, COLOR_PANEL, COLOR_BORDER);
draw_buffer_text(
&mut commands,
HOME_PANEL.x + 26,
HOME_PANEL.y + 22,
"Native Shell Apps",
COLOR_TEXT,
);
draw_buffer_text(
&mut commands,
HOME_PANEL.x + 26,
HOME_PANEL.y + 40,
"first retro ui slice",
@ -209,50 +222,105 @@ fn render_home(gfx: &mut dyn GfxBridge, pointer_x: i32, pointer_y: i32) {
for button in HOME_BUTTONS {
let hovered = rect_contains(button.rect, pointer_x, pointer_y);
draw_button(gfx, button.rect, button.label, hovered);
draw_button(&mut commands, button.rect, button.label, hovered);
}
ShellUiFramePacket::new(commands)
}
fn render_shell_window(
gfx: &mut dyn GfxBridge,
fn append_shell_window_commands(
commands: &mut Vec<GfxUiCommand>,
viewport: Rect,
color: Color,
title: &str,
pointer_x: i32,
pointer_y: i32,
) {
gfx.fill_rect(VIEWPORT.x, VIEWPORT.y, VIEWPORT.w, VIEWPORT.h, COLOR_BG);
draw_panel(gfx, viewport, COLOR_PANEL_DARK, COLOR_BORDER);
gfx.fill_rect(viewport.x + 4, viewport.y + 24, viewport.w - 8, viewport.h - 28, color);
draw_buffer_text(gfx, viewport.x + 10, viewport.y + 8, title, COLOR_TEXT);
draw_buffer_text(gfx, viewport.x + 18, viewport.y + 44, "native fake shell", COLOR_PANEL_DARK);
fill_rect(commands, VIEWPORT, COLOR_BG);
draw_panel(commands, viewport, COLOR_PANEL_DARK, COLOR_BORDER);
fill_rect(
commands,
Rect { x: viewport.x + 4, y: viewport.y + 24, w: viewport.w - 8, h: viewport.h - 28 },
color,
);
draw_buffer_text(commands, viewport.x + 10, viewport.y + 8, title, COLOR_TEXT);
draw_buffer_text(
commands,
viewport.x + 18,
viewport.y + 44,
"native fake shell",
COLOR_PANEL_DARK,
);
let close_hovered = rect_contains(CLOSE_BUTTON, pointer_x, pointer_y);
let close_fill = if close_hovered { COLOR_HILITE } else { COLOR_BUTTON };
gfx.fill_rect(CLOSE_BUTTON.x, CLOSE_BUTTON.y, CLOSE_BUTTON.w, CLOSE_BUTTON.h, close_fill);
gfx.draw_rect(CLOSE_BUTTON.x, CLOSE_BUTTON.y, CLOSE_BUTTON.w, CLOSE_BUTTON.h, COLOR_BORDER);
draw_buffer_text(gfx, CLOSE_BUTTON.x + 5, CLOSE_BUTTON.y + 4, "x", COLOR_TEXT);
fill_rect(commands, CLOSE_BUTTON, close_fill);
draw_rect(commands, CLOSE_BUTTON, COLOR_BORDER);
draw_buffer_text(commands, CLOSE_BUTTON.x + 5, CLOSE_BUTTON.y + 4, "x", COLOR_TEXT);
}
fn draw_panel(gfx: &mut dyn GfxBridge, rect: Rect, fill: Color, border: Color) {
gfx.fill_rect(rect.x, rect.y, rect.w, rect.h, fill);
gfx.draw_rect(rect.x, rect.y, rect.w, rect.h, border);
gfx.draw_rect(rect.x + 2, rect.y + 2, rect.w - 4, rect.h - 4, COLOR_MUTED);
fn fill_rect(commands: &mut Vec<GfxUiCommand>, rect: Rect, color: Color) {
commands.push(GfxUiCommand::FillRect { rect, color });
}
fn draw_button(gfx: &mut dyn GfxBridge, rect: Rect, label: &str, hovered: bool) {
fn draw_rect(commands: &mut Vec<GfxUiCommand>, rect: Rect, color: Color) {
commands.push(GfxUiCommand::DrawLine {
x0: rect.x,
y0: rect.y,
x1: rect.x + rect.w - 1,
y1: rect.y,
color,
});
commands.push(GfxUiCommand::DrawLine {
x0: rect.x,
y0: rect.y + rect.h - 1,
x1: rect.x + rect.w - 1,
y1: rect.y + rect.h - 1,
color,
});
commands.push(GfxUiCommand::DrawLine {
x0: rect.x,
y0: rect.y,
x1: rect.x,
y1: rect.y + rect.h - 1,
color,
});
commands.push(GfxUiCommand::DrawLine {
x0: rect.x + rect.w - 1,
y0: rect.y,
x1: rect.x + rect.w - 1,
y1: rect.y + rect.h - 1,
color,
});
}
fn draw_panel(commands: &mut Vec<GfxUiCommand>, rect: Rect, fill: Color, border: Color) {
fill_rect(commands, rect, fill);
draw_rect(commands, rect, border);
draw_rect(
commands,
Rect { x: rect.x + 2, y: rect.y + 2, w: rect.w - 4, h: rect.h - 4 },
COLOR_MUTED,
);
}
fn draw_button(commands: &mut Vec<GfxUiCommand>, rect: Rect, label: &str, hovered: bool) {
let fill = if hovered { COLOR_BUTTON_ACTIVE } else { COLOR_BUTTON };
let border = if hovered { COLOR_HILITE } else { COLOR_BORDER };
gfx.fill_rect(rect.x, rect.y, rect.w, rect.h, fill);
gfx.draw_rect(rect.x, rect.y, rect.w, rect.h, border);
gfx.draw_rect(rect.x + 3, rect.y + 3, rect.w - 6, rect.h - 6, COLOR_MUTED);
gfx.fill_rect(rect.x + 12, rect.y + 12, 16, 24, border);
gfx.draw_rect(rect.x + 34, rect.y + 12, 62, 24, COLOR_PANEL_DARK);
draw_buffer_text(gfx, rect.x + 40, rect.y + 21, label, COLOR_TEXT);
fill_rect(commands, rect, fill);
draw_rect(commands, rect, border);
draw_rect(
commands,
Rect { x: rect.x + 3, y: rect.y + 3, w: rect.w - 6, h: rect.h - 6 },
COLOR_MUTED,
);
fill_rect(commands, Rect { x: rect.x + 12, y: rect.y + 12, w: 16, h: 24 }, border);
draw_rect(commands, Rect { x: rect.x + 34, y: rect.y + 12, w: 62, h: 24 }, COLOR_PANEL_DARK);
draw_buffer_text(commands, rect.x + 40, rect.y + 21, label, COLOR_TEXT);
}
fn draw_buffer_text(gfx: &mut dyn GfxBridge, x: i32, y: i32, text: &str, color: Color) {
gfx.draw_text(x, y, text, color);
fn draw_buffer_text(commands: &mut Vec<GfxUiCommand>, x: i32, y: i32, text: &str, color: Color) {
commands.push(GfxUiCommand::DrawText { x, y, text: text.to_string(), color });
}
#[cfg(test)]
@ -321,6 +389,16 @@ mod tests {
assert_eq!(HOME_BUTTONS[1].app, NativeShellApp::ShellB);
}
#[test]
fn home_render_produces_shell_ui_packet_commands() {
let packet = render_home_packet(SHELL_A_BUTTON.x, SHELL_A_BUTTON.y);
assert!(matches!(packet.commands.first(), Some(GfxUiCommand::Clear { .. })));
assert!(packet.commands.iter().any(|command| {
matches!(command, GfxUiCommand::DrawText { text, .. } if text == "PROMETEU HUB")
}));
}
#[test]
fn shell_close_button_sits_inside_shell_frame() {
assert!(rect_contains(SHELL_FRAME, CLOSE_BUTTON.x, CLOSE_BUTTON.y));

View File

@ -1,5 +1,5 @@
{"type":"meta","next_id":{"DSC":39,"AGD":39,"DEC":31,"PLN":87,"LSN":47,"CLSN":1}}
{"type":"discussion","id":"DSC-0038","status":"in_progress","ticket":"render-frame-packet-boundary","title":"Logical Render Pipelines and Command Packets","created_at":"2026-05-25","updated_at":"2026-05-25","tags":["gfx","renderer","runtime","frame-composer","architecture","ui","pipeline"],"agendas":[{"id":"AGD-0038","file":"AGD-0038-renderframepacket-boundary-for-classic-2d-renderer.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25"}],"decisions":[{"id":"DEC-0030","file":"DEC-0030-logical-render-pipeline-command-boundary.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25","ref_agenda":"AGD-0038"}],"plans":[{"id":"PLN-0073","file":"PLN-0073-render-contract-specs.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0074","file":"PLN-0074-hal-render-submission-types.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0075","file":"PLN-0075-rendermanager-core.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0076","file":"PLN-0076-capabilities-and-abi-domain-split.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0077","file":"PLN-0077-composer-buffer-and-game2d-packet.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0078","file":"PLN-0078-classic2d-game-renderer-consumer.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0079","file":"PLN-0079-gfx2d-primitive-domain.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0080","file":"PLN-0080-shell-ui-packet-and-gfxui-domain.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0081","file":"PLN-0081-shell-hub-migration.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0082","file":"PLN-0082-frame-publication-and-present-boundary.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0083","file":"PLN-0083-fade-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0084","file":"PLN-0084-host-debug-overlay-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0085","file":"PLN-0085-pbs-stdlib-and-syscall-declarations.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0086","file":"PLN-0086-end-to-end-render-boundary-validation.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0038","status":"in_progress","ticket":"render-frame-packet-boundary","title":"Logical Render Pipelines and Command Packets","created_at":"2026-05-25","updated_at":"2026-05-25","tags":["gfx","renderer","runtime","frame-composer","architecture","ui","pipeline"],"agendas":[{"id":"AGD-0038","file":"AGD-0038-renderframepacket-boundary-for-classic-2d-renderer.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25"}],"decisions":[{"id":"DEC-0030","file":"DEC-0030-logical-render-pipeline-command-boundary.md","status":"accepted","created_at":"2026-05-25","updated_at":"2026-05-25","ref_agenda":"AGD-0038"}],"plans":[{"id":"PLN-0073","file":"PLN-0073-render-contract-specs.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0074","file":"PLN-0074-hal-render-submission-types.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0075","file":"PLN-0075-rendermanager-core.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0076","file":"PLN-0076-capabilities-and-abi-domain-split.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0077","file":"PLN-0077-composer-buffer-and-game2d-packet.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0078","file":"PLN-0078-classic2d-game-renderer-consumer.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0079","file":"PLN-0079-gfx2d-primitive-domain.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0080","file":"PLN-0080-shell-ui-packet-and-gfxui-domain.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0081","file":"PLN-0081-shell-hub-migration.md","status":"done","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0082","file":"PLN-0082-frame-publication-and-present-boundary.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0083","file":"PLN-0083-fade-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0084","file":"PLN-0084-host-debug-overlay-removal.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0085","file":"PLN-0085-pbs-stdlib-and-syscall-declarations.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]},{"id":"PLN-0086","file":"PLN-0086-end-to-end-render-boundary-validation.md","status":"open","created_at":"2026-05-25","updated_at":"2026-05-25","ref_decisions":["DEC-0030"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0035","status":"done","ticket":"task-owned-shell-windows","title":"Agenda - Task-Owned Shell Windows","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","task","window-manager","shell","lifecycle"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0044","file":"discussion/lessons/DSC-0035-task-owned-shell-windows/LSN-0044-task-window-liveness-belongs-to-the-task.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
{"type":"discussion","id":"DSC-0034","status":"done","ticket":"system-os-domain-facades","title":"Agenda - SystemOS Domain Facades","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","services","api-surface","lifecycle","fs"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0043","file":"discussion/lessons/DSC-0034-system-os-domain-facades/LSN-0043-systemos-domain-facades.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
{"type":"discussion","id":"DSC-0023","status":"done","ticket":"perf-full-migration-to-atomic-telemetry","title":"Agenda - [PERF] Full Migration to Atomic Telemetry","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["perf","runtime","telemetry"],"agendas":[{"id":"AGD-0021","file":"AGD-0021-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0008","file":"DEC-0008-full-migration-to-atomic-telemetry.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0007","file":"PLN-0007-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0028","file":"discussion/lessons/DSC-0023-perf-full-migration-to-atomic-telemetry/LSN-0028-converging-to-single-atomic-telemetry-source.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}

View File

@ -2,7 +2,7 @@
id: PLN-0081
ticket: render-frame-packet-boundary
title: Shell Hub Migration
status: open
status: done
created: 2026-05-25
ref_decisions: [DEC-0030]
tags: [gfx, renderer, runtime, frame-composer, architecture, ui, pipeline]