# Architecture ## Responsibilities ```text apps//index.jsx application, state, components ↓ runtime/js (@ps5-react/core) focus navigation, controller API, native modules, primitives ↓ React reconciler / NativeUI / QuickJS Embedded React C tree, layout, text, rasterization ↓ opaque ARGB8888 framebuffer native/shared/GlPresenter changed rows into a framebuffer texture, layers, presentation ↓ native/desktop | native/ps5 window/EGL, input, clock, lifecycle, native modules via native/shared/host_api ``` Applications do not access scePad, EGL, libkernel, or the SDK directly. They reach platform services only through the `@ps5-react/core` native modules (`runtime/js/native.js`), which wrap `globalThis.__ps5ReactNative`. Its shape is fixed by `native/shared/host_api.hpp`: `native/shared/host_api.cpp` installs it and implements the filesystem with POSIX, while `native/ps5/` and `native/desktop/` implement the platform functions. Calls are synchronous on the render thread. Networking calls submit/cancel/poll bounded native tasks; two workers perform network and disk I/O without touching QuickJS or the engine. Remote images have two more workers (fetch and decode) that hand finished pixels to the render thread, which registers them with the engine ([IMAGES.md](IMAGES.md)). Hosts cancel and join all workers before runtime shutdown. See [NETWORKING.md](NETWORKING.md) for the buffer, heap, stack and queue contract, and [NATIVE-API.md](NATIVE-API.md) for the bridge. The presenter keeps a copy of the framebuffer in a 2D texture on the GPU. Each frame it replays the engine's moved rects there as framebuffer blits, then uploads the damaged rows, merged into bands, through small buffer textures that a shader draws into that texture with `texelFetch`: on the PS5 `glTexSubImage2D` of 3840×270 takes about 15 ms of CPU, and every draw costs about 25 µs plus 15 µs per MiB of the buffer textures it reads, so only the rows being uploaded live in buffer textures. One draw then puts that texture on screen, scaled and letterboxed when the surface differs from the render size. When the engine lists layers (``, see [IMAGES.md](IMAGES.md)), that draw samples up to four of those images first (one more draw per four more), each uploaded once to its own texture, and the framebuffer over them with premultiplied blending; the engine leaves their rects transparent and keeps what it draws over them in the alpha channel. A frame that changed nothing is neither drawn nor swapped: the host sleeps to the next vertical sync. Every other pixel is still rasterized on the CPU. The presenter has no knowledge of React state, fonts, or widgets. The engine and JavaScript run on the same render thread. The PS5 host keeps the heap, shims, CRT, SDK pair, and FSELF path used by the hardware-tested proof of concept. Video decoding is the other work off the render thread: each `