OpenTUI 0.7.0
Before 0.7.0, typing one character in a 10,000-line Textarea laid out all 10,000 lines before the key call returned, and the Yoga measure of the next frame walked them again. Typing and pasting slowed down with the size of the document, and word wrap paid the most. In 0.7.0, an edit only records that the view must scroll to the cursor. The layout runs once, at the next read of the viewport or the visual cursor, or at the next frame. It compares the text with the text of the last layout and lays out only the lines around the change. An insert, a delete, an undo, or a join lays out one line. Enter lays out two lines, and a 100-line paste lays out 101.
A read that needs the layout still pays for it. visualCursor lays out the text when an edit is pending. cursorOffset reads the logical cursor and does not lay out the text. To check after each key whether the cursor is at the start of the text, compare cursorOffset:
const atStart = input.cursorOffset === 0 // not input.visualCursor.offset === 0
Before 0.7.0, Renderable found the hooks of each node by reflection. It scanned the property descriptors of every new instance two times. For 10,000 rows of a Text subclass that overrides renderSelf, this took 20,000 scans and 160,000 descriptor reads. Now a node reads its hooks from its class once, at construction. Prototype methods with super, constructor options, and assignments to renderBefore, renderAfter, onLifecyclePass, and onSizeChange work as before.
Three kinds of code must change. First, a hook that you add by reflection does nothing until you call node.refreshHooks(). Examples are an instance class field, Object.defineProperty(), or an assignment to the renderSelf or onUpdate of one node. Second, a patch or spy on a prototype method after nodes exist does not reach those nodes, and untyped JSX props such as onUpdate and onResize have no effect. Third, renderBefore, renderAfter, and onLifecyclePass are now accessors. A class field that overrides one of them is a TypeScript error, so assign the hook in the constructor. An onLifecyclePass class field still runs, because attaching the node registers it.
import { BoxRenderable, RGBA, type BoxOptions, type RenderContext } from "@opentui/core"
class MarkedBox extends BoxRenderable {
constructor(ctx: RenderContext, options: BoxOptions) {
super(ctx, options)
this.renderAfter = (buffer) => {
buffer.drawText("*", this.screenX, this.screenY, RGBA.fromInts(255, 0, 0))
}
}
}
A class that used defineNativeIntegration() must now declare the description directly. Without the type annotation, kind does not keep its literal type:
import { Renderable, type NativeRenderableIntegration } from "@opentui/core"
class Marker extends Renderable {
static override readonly nativeIntegration: NativeRenderableIntegration = {
kind: "custom",
body: "host",
}
}
The nativeSceneWorkBudget renderer option let a frame yield to the event loop during native preparation. OpenTUI, its SSH package, and OpenCode did not set it. On a 10,000-line log, it cut the longest native slice by about 0.15 ms but used 27% more native time. With one mutation per event-loop turn, each yield started preparation again, until the frame failed with LayoutLimit. A renderer that scrolled or streamed under a budget showed no frames. Now preparation and paint finish in one call. A C binding built against the old header passes every argument after the removed max_work_items one slot off, so the ABI version changes. To update a binding, generate it again from the new opentui.h. Then remove the max_work_items argument and any OT_SCENE_FRAME_YIELD case, and use the 224-byte ot_scene_stats record. The work_budget of ot_session_pump is a different budget and does not change.
0.7.0 also adds a native input parser. The TypeScript parser parses each framed unit again with regular expressions, and its structure caused bugs that are hard to fix in place. These bugs include lost Escape-prefixed events, empty Alt key names, wrong Alt keys for non-ASCII characters, wheel releases that ended drags, and negative X10 coordinates. The native parser is a bounded state machine that does not allocate, and it handles all of these cases. It is off by default while timing and buffering edge cases are tested. To try it, set OTUI_NATIVE_INPUT_PARSER=1 or create the renderer with the option:
const renderer = await createCliRenderer({ experimental_nativeInput: true })
With OTUI_NATIVE_INPUT_SHADOW=1, the renderer also runs the other parser. It writes a [stdin-shadow] warning for each event that the two parsers report differently. The warnings contain your input, so protect them as you would a stdin log. To report a parser bug, include a log from OTUI_STDIN_LOG. The native parser is bounded, so it ignores stdinParserMaxBufferBytes.
Known issue: when the terminal hangs up, as when an SSH connection closes, the renderer prints Error disabling raw mode and Native scene shutdown failed errors with stack traces to stderr. The process still exits with code 0.
Breaking changes
- core: A renderer created with
nativeSceneWorkBudgetthrows at construction, so remove the option.NativeSceneFrame.Yieldand themaxWorkItemsargument ofFFIRenderLib.sceneFrameStep()are removed. See How Core uses native. (#1719) - core:
NativeSceneFrameRequest.geometryRevisionis removed. See How Core uses native. (#1760) - native:
ot_scene_frame_step_with_geometryno longer has itsmax_work_itemsparameter,OT_SCENE_FRAME_YIELDis removed, andOT_CONTEXT_ABI_VERSIONis 2. Build bindings again from the newopentui.h, because records with version 1 fail withOT_UNSUPPORTED_VERSION. See C. (#1719) - native:
ot_scene_statschanges from 64 to 224 bytes, andot_scene_get_statsreturnsOT_INVALID_ARGUMENTfor the 64-byte record. Generate the record again from the new header. See Frames and output. (#1722) - native: In the Zig module,
Context.sceneFrameStepWorkBudgetedis removed,sceneFrameStepWithRecordingno longer takesmax_work_items, andreplaceOwnedStyledTextno longer takes aSyntaxStyle.OwnedStyledChunknow holds a style value, and the module no longer exports 12 extra span-feed symbols. See Zig. (#1719, #1768, #1784) - core:
Renderable.defineNativeIntegration()andNativeRenderableIntegration.constructionare removed. Declarestatic override readonly nativeIntegration: NativeRenderableIntegration = { ... }withoutconstruction. See Custom renderables. (#1754) - core: A node reads its hooks from its class at construction, so a hook added by reflection runs only after
refreshHooks(). A class field that overridesrenderBefore,renderAfter, oronLifecyclePassis a TypeScript error (TS2610), so assign it in the constructor. See Custom renderables. (#1754) - core: The protected
TextBufferRenderable._textBufferSyntaxStylefield is removed. Styled text keeps its styles in the text buffer, so remove code that reads the field. See Code. (#1775) - core:
translateXandtranslateYthrowRangeErrorfor values outside the 32-bit float range of the layout setters. Before, such values did not paint. See Layout. (#1682)
Added
- core: The
experimental_nativeInputrenderer option, orOTUI_NATIVE_INPUT_PARSER, parses stdin with a new native parser.OTUI_NATIVE_INPUT_SHADOWruns both parsers and logs each event that they report differently. See Environment variables. (#1592, #1787) - native:
ot_session_input_feed()parses terminal input into caller-ownedot_input_eventrecords, a payload buffer, and anot_input_drainsummary, and it does not allocate.ot_session_input_expect()sets the replies that the parser expects, andot_session_input_reset()clears the parser state.FFIRenderLib.sessionInputFeed(),sessionInputExpect(), andsessionInputReset()wrap them. See Host I/O and time. (#1592) - core:
getNativeStats().frameWork, also ingetStats(), counts the work of the last presented scene frame, such as Yoga solves, view preparations, and painted cells. The test renderer optionnativeSceneFullFramemakes each frame rebuild its work lists, so tests can compare the counts. See Rendering diagnostics. (#1722) - native:
ot_scene_statsreports the work of the last presented scene frame.ot_scene_set_debug_flags()withOT_SCENE_DEBUG_FULL_FRAMEforces the full frame path, andfull_path_reasonsuses theOT_SCENE_FULL_PATH_*bits. See Frames and output. (#1722) - core: The protected
_paintWidthand_paintHeightofRenderablegive the size that arenderSelf()paints, clamped to the cell range that drawing accepts. See Custom renderables. (#1682)
Changed
- core: An edit in a text view or editor lays out only the lines that it changed, once, at the next read or frame. Typing one character in a 10,000-line Textarea lays out 1 line, not 10,000. Typing or pasting over a selection scrolls once instead of twice. See Editing buffers and views. (#1758, #1751, #1747)
- core: A Yoga measure of text at the render width reads the render layout, and at a different width it measures again only the edited lines. One edit in a 10,000-line word-wrapped editor measures 0 lines, not 10,000. See Layout. (#1772)
- core: Text writes that cannot change the size no longer cause a Yoga solve. Examples are the same bytes, colors, styles, viewport changes, scrolls,
textAlign,truncate,tabIndicator,tabIndicatorColor, and the editor scroll margin. See Rendering pipeline. (#1755, #1767, #1774) - core: A ScrollBox with viewport culling refreshes its rows only after a layout change or a row change, and an idle ScrollBox requests no update hook. A 10,000-row list does 0 row refreshes on idle and scroll frames, not 10,000. See ScrollBox. (#1756, #1761)
- core: A frame records one hit rectangle per member and no longer writes a screen-sized hit grid. A hit test walks the members of the presented frame from the top. See Interaction, focus, and selection. (#1771)
- core: With
wrapMode: "none", a line that is scrolled right skips the text to the left of the viewport by chunk and cluster. An idle editor with one 256 KiB line no longer walks the line on each frame. See Textarea. (#1777) - core: After style and paint writes, reads of
x,y,width, andheightuse the cached layout without a native call or a flush.getLayout()andgetComputedLayout()call native code on every call, and a rejected staged write shows at the next flushing call. See Layout. (#1760) - core: Only native code checks staged style writes. On Node, a
box.widthwrite with a flush takes 111 ns instead of 149 ns. A paint value that only native code rejects, such as an opacity above 1 passed tosetNativeScenePaint, fails at the next flush. See Rendering pipeline. (#1770) - core: A text buffer keeps its styled-text styles by value, and a
Codecreates two native objects instead of three. A highlight update no longer copies the style table or scans the object table. See Code. (#1768, #1775) - core: A wheel step scrolls only the innermost scroller under the pointer that can still move in its direction. A scroller at its edge, or one that cannot scroll that axis, gives the step to the next scroller out, as browsers do. Before, one step moved every scroller on its path, so the text of a Textarea inside a ScrollBox moved twice as far, and the Textarea moved away from the pointer. The event still bubbles, so the split-pane sync of a Diff and the
onMouseScrollhandler of an ancestor still receive it. Text, Code, and Textarea treat Shift+wheel as sideways, and an editor’s sideways step stops at its widest line. See ScrollBox. (#1761) - core: 896 symbols that terminals draw in one cell take one cell in every width method, also with VS15. Examples are ‼, ⁉, ☢, ⚛, 🖥, 🗑, and the Mahjong, domino, and playing-card tiles. Every measured terminal advances one cell for at least 892 of the 896. Before, they took two cells, so text after them moved one column right, the cursor landed past the text, and old cells stayed on screen. With VS16, as in ❤️, they take two cells in the grapheme methods and one cell in
wcwidth, so under tmux and screen ❤️ is still one cell too narrow, until OpenTUI selects the width method correctly. In classic Windows conhost, which gives VS15 its own cell, 53 of these symbols followed by VS15 are now one cell off. Some terminals draw a glyph wider than the one cell that they advance, so it covers the next character, extends into a blank cell, or is cut off; this comes from the terminal, not from the layout. See Text and terminal cells. (#1762) - core:
detectLinks()styles bare URLs withmarkup.link.labelfrom the newsyntaxStylecontext field and keeps their other attributes. Bare URLs in Markdown prose now look like link labels. See Markdown. (#1765) - core: An audio stream whose decoder reads past
maxProbeBytesrejects with the decoder error. Before, it could play a truncated prefix and end without an error. See Streaming audio. (#1759) - core: The embedded terminal uses a newer Ghostty and no longer answers Kitty graphics or glyph protocol queries, and it ignores OSC 72 drag-and-drop commands. DECSTR,
CSI g, DECRQM, and other controls now behave as in xterm. XTGETTCAP answers from Ghostty’s terminfo, which claims some features that the embedded terminal does not draw. See Embedded terminal. (#1714) - native: Highlight reads mark styled-text styles with the new
OT_STYLE_RUN_FLAGbit, and user highlights reject such style ids. Styled text no longer registerschunkNstyles in the attachedSyntaxStyle, andot_text_buffer_clearwithout reset keeps styled highlights but drops their links. The styled-text batch accepts buffers that have an attached style. See Editing buffers and views. (#1768) - native:
ot_editor_view_get_viewport,ot_editor_view_set_scroll_margin, and a localot_editor_view_selectcan lay out text and returnOT_OUT_OF_MEMORY. This occurs only while a scroll to the cursor is pending. See C. (#1751) - native:
ot_scene_set_paintrejects a translation that is not finite or exceedsFLT_MAX,ot_scene_set_stylestores finite margin, padding, position, and gap values beyond ±1e30 as ±1e30, andOT_LAYOUT_PAINTclamps an axis outside the 32-bit cell range. See C. (#1682)
Fixed
- core: Text with a fractional flex size rounds like a box and stays inside the rounded box of its parent. Before, Yoga rounded the right edge of text up but rounded containers to the nearest cell, so the last glyph of each wrapped line could draw under the next column or under a ScrollBox scrollbar. Some layouts move by one cell. Text at a half-cell offset, such as centered text with an odd leftover, moves right or down to the position of a box of the same size. A box centered inside another centered box, with odd leftovers at both levels, can move left or up. Update snapshots of such layouts. The public
yoga.tsAPI keeps the upstream rounding. See Layout. (#1728) - core: A node with layout outside 32-bit cell coordinates, such as
left = 2 ** 31 - 1ormargin = 1e15, no longer makes every later frame fail withInvalidArgument. Native code clamps only the geometry that it paints, clips, and hit-tests. See Layout. (#1682) - core: With the
wcwidthwidth method,drawTextandencodeUnicodegive a multi-code-point cluster, such as 👩💻, the same width as the layout. Before, text after the cluster landed two cells to the left. Clusters wider than four cells, such as 👨👩👧, are still drawn too narrow. See Text and terminal cells. (#1773) - core: A
ScrollBarposition is never negative. Before, a ScrollBox with content that fit the viewport could report ascrollToporscrollLeftsuch as -7 while its content did not move. A ScrollBar’sonChangevalue andscrollPositionnow agree, and with sticky bottom over short content, a sideways scroll no longer stops the box from following new content. See ScrollBar. (#1769) - core:
destroy()leaves raw mode after the Session restores the terminal, andresume()enters raw mode before mouse reporting starts again. Before, mouse reports could show as text such as^[[<35;30;5Mat the shell prompt.suspend()still leaves raw mode at once, so mouse reports can still echo there. See Lifecycle and cleanup. (#1720) - core:
Audio.playStream()with an MP3 whose first chunk is larger than the decoder probe limit always rejects with{ action: "decoder", errorCode: -3 }. Before, it sometimes rejected with{ action: "write", status: -1 }, depending on thread timing. See Streaming audio. (#1759) - core: An Input with wrap off limits its horizontal scroll by the widest line, not the widest text piece, so it no longer jumps sideways on resize. A typed character lands on the same side of zero-width text as in the same text loaded in one piece. See Input. (#1747)
- core: Undo and redo in a Textarea scroll to the cursor in the restored text. Before, they used the layout from before the undo and could leave blank rows below the text. See Textarea. (#1751)
- core: Undo and redo in a Textarea or Input emit content-changed, so
onContentChangeandline-info-changerun. Before, an app that synced on content changes kept the text from before the undo, and the line-number gutter kept its old width. See Textarea. (#1790) - core: A node that is resized and then given an
onLifecyclePassbefore its first frame gets its firstonResize. Before, a buffered node kept its old buffer size and clipped its drawing. See Custom renderables. (#1754) - core: Two text buffers that share a
SyntaxStylekeep their own styled-text colors. Before, each update of one buffer changed the colors of the other. See Editing buffers and views. (#1768) - core: In an
EmbeddedTerminalRenderable, RIS (ESC c) and DECSTR (CSI ! p) reset the palette that a program set with OSC 4, and keep the OSC 10, 11, and 12 colors. Tools such askitten icatnow use their text fallback and do not show blank cells. See Embedded terminal. (#1714)
API changes#
@opentui/core#
Added
method FFIRenderLib.sessionInputExpect(context: NativeContextHandle, session: SessionHandle, flags: number): voidmethod FFIRenderLib.sessionInputFeed(context: NativeContextHandle, session: SessionHandle, bytes: Uint8Array, nowNs: bigint, records: Uint8Array, payload: Uint8Array): NativeInputDrainmethod FFIRenderLib.sessionInputReset(context: NativeContextHandle, session: SessionHandle, flags: number): voidproperty CliRendererConfig.experimental_nativeInput?: booleanprotected readonly property Renderable._paintHeight: numberprotected readonly property Renderable._paintWidth: number
Changed
function detectLinks(chunks: TextChunk[], context: { content: string; highlights: SimpleHighlight[]; sourceRanges?: Array<{ start: number; end: number; }>; }): TextChunk[]function detectLinks(chunks: TextChunk[], context: { content: string; highlights: SimpleHighlight[]; sourceRanges?: Array<{ start: number; end: number; }>; syntaxStyle?: SyntaxStyle; }): TextChunk[]method FFIRenderLib.sceneFrameStep(context: NativeContextHandle, session: SessionHandle, previous: NativeSceneFrameRequest | null, options: NativeSceneFrameOptions, maxWorkItems?: number, recording?: Uint8Array | null): NativeSceneFrameRequestmethod FFIRenderLib.sceneFrameStep(context: NativeContextHandle, session: SessionHandle, previous: NativeSceneFrameRequest | null, options: NativeSceneFrameOptions, recording?: Uint8Array | null): NativeSceneFrameRequestproperty Renderable.renderAfter?: (this: Renderable, buffer: OptimizedBuffer, deltaTime: number) => voidproperty Renderable.renderAfter: PaintHook | undefinedproperty Renderable.renderBefore?: (this: Renderable, buffer: OptimizedBuffer, deltaTime: number) => voidproperty Renderable.renderBefore: PaintHook | undefinedtype NativeRenderStats = { nativeLastFrameTime: number; nativeAverageFrameTime: number; nativeFrameCount: number; cellsUpdated: number; averageCellsUpdated: number; nativeRenderTime?: number; nativeStdoutWriteTime?: number; }type NativeRenderStats = { nativeLastFrameTime: number; nativeAverageFrameTime: number; nativeFrameCount: number; cellsUpdated: number; averageCellsUpdated: number; nativeRenderTime?: number; nativeStdoutWriteTime?: number; frameWork: NativeFrameWork; }
Removed
enum-member NativeSceneFrame.Yieldstatic protected method Renderable.defineNativeIntegration(integration: NativeRenderableIntegration): NativeRenderableIntegrationproperty CliRendererConfig.nativeSceneWorkBudget?: numberreadonly property NativeRenderableIntegration.construction?: "prototype" | "fields"property NativeSceneFrameRequest.geometryRevision?: numberprotected property TextBufferRenderable._textBufferSyntaxStyle: SyntaxStyle
@opentui/core/testing#
Added
property TestRendererOptions.nativeSceneFullFrame?: boolean
opentui.h#
Added
const OT_INPUT_EVENTS_MIN = 4const OT_INPUT_EXPECT_CURSOR_POSITION = 4const OT_INPUT_EXPECT_KITTY_KEYBOARD = 2const OT_INPUT_EXPECT_REPLIES = 1const OT_INPUT_FOCUS = 4const OT_INPUT_FOCUS_IN = 1const OT_INPUT_FOCUS_OUT = 0const OT_INPUT_KEY = 1const OT_INPUT_KEY_BACKSPACE = 127const OT_INPUT_KEY_CAPS_LOCK = 57358const OT_INPUT_KEY_DELETE = 57349const OT_INPUT_KEY_DOWN = 57353const OT_INPUT_KEY_END = 57357const OT_INPUT_KEY_ENTER = 13const OT_INPUT_KEY_ESCAPE = 27const OT_INPUT_KEY_F1 = 57364const OT_INPUT_KEY_F35 = 57398const OT_INPUT_KEY_HOME = 57356const OT_INPUT_KEY_INSERT = 57348const OT_INPUT_KEY_ISO_LEVEL3_SHIFT = 57453const OT_INPUT_KEY_ISO_LEVEL5_SHIFT = 57454const OT_INPUT_KEY_KITTY = 1const OT_INPUT_KEY_KP_0 = 57399const OT_INPUT_KEY_KP_9 = 57408const OT_INPUT_KEY_KP_ADD = 57413const OT_INPUT_KEY_KP_BEGIN = 57427const OT_INPUT_KEY_KP_DECIMAL = 57409const OT_INPUT_KEY_KP_DELETE = 57426const OT_INPUT_KEY_KP_DIVIDE = 57410const OT_INPUT_KEY_KP_DOWN = 57420const OT_INPUT_KEY_KP_END = 57424const OT_INPUT_KEY_KP_ENTER = 57414const OT_INPUT_KEY_KP_EQUAL = 57415const OT_INPUT_KEY_KP_HOME = 57423const OT_INPUT_KEY_KP_INSERT = 57425const OT_INPUT_KEY_KP_LEFT = 57417const OT_INPUT_KEY_KP_MULTIPLY = 57411const OT_INPUT_KEY_KP_PAGE_DOWN = 57422const OT_INPUT_KEY_KP_PAGE_UP = 57421const OT_INPUT_KEY_KP_RIGHT = 57418const OT_INPUT_KEY_KP_SEPARATOR = 57416const OT_INPUT_KEY_KP_SUBTRACT = 57412const OT_INPUT_KEY_KP_UP = 57419const OT_INPUT_KEY_LEFT = 57350const OT_INPUT_KEY_LEFT_ALT = 57443const OT_INPUT_KEY_LEFT_CONTROL = 57442const OT_INPUT_KEY_LEFT_HYPER = 57445const OT_INPUT_KEY_LEFT_META = 57446const OT_INPUT_KEY_LEFT_SHIFT = 57441const OT_INPUT_KEY_LEFT_SUPER = 57444const OT_INPUT_KEY_LOWER_VOLUME = 57438const OT_INPUT_KEY_MEDIA_FAST_FORWARD = 57433const OT_INPUT_KEY_MEDIA_PAUSE = 57429const OT_INPUT_KEY_MEDIA_PLAY = 57428const OT_INPUT_KEY_MEDIA_PLAY_PAUSE = 57430const OT_INPUT_KEY_MEDIA_RECORD = 57437const OT_INPUT_KEY_MEDIA_REVERSE = 57431const OT_INPUT_KEY_MEDIA_REWIND = 57434const OT_INPUT_KEY_MEDIA_STOP = 57432const OT_INPUT_KEY_MEDIA_TRACK_NEXT = 57435const OT_INPUT_KEY_MEDIA_TRACK_PREVIOUS = 57436const OT_INPUT_KEY_MENU = 57363const OT_INPUT_KEY_MUTE_VOLUME = 57440const OT_INPUT_KEY_NUM_LOCK = 57360const OT_INPUT_KEY_PAGE_DOWN = 57355const OT_INPUT_KEY_PAGE_UP = 57354const OT_INPUT_KEY_PAUSE = 57362const OT_INPUT_KEY_PRESS = 1const OT_INPUT_KEY_PRINT_SCREEN = 57361const OT_INPUT_KEY_RAISE_VOLUME = 57439const OT_INPUT_KEY_RELEASE = 3const OT_INPUT_KEY_REPEAT = 2const OT_INPUT_KEY_RIGHT = 57351const OT_INPUT_KEY_RIGHT_ALT = 57449const OT_INPUT_KEY_RIGHT_CONTROL = 57448const OT_INPUT_KEY_RIGHT_HYPER = 57451const OT_INPUT_KEY_RIGHT_META = 57452const OT_INPUT_KEY_RIGHT_SHIFT = 57447const OT_INPUT_KEY_RIGHT_SUPER = 57450const OT_INPUT_KEY_SCROLL_LOCK = 57359const OT_INPUT_KEY_TAB = 9const OT_INPUT_KEY_TEXT_TRUNCATED = 2const OT_INPUT_KEY_UP = 57352const OT_INPUT_MOD_ALT = 2const OT_INPUT_MOD_CAPS_LOCK = 64const OT_INPUT_MOD_CTRL = 4const OT_INPUT_MOD_HYPER = 16const OT_INPUT_MOD_META = 32const OT_INPUT_MOD_NUM_LOCK = 128const OT_INPUT_MOD_SHIFT = 1const OT_INPUT_MOD_SUPER = 8const OT_INPUT_MOUSE = 2const OT_INPUT_MOUSE_BUTTON_NONE = 255const OT_INPUT_MOUSE_DOWN = 1const OT_INPUT_MOUSE_DRAG = 4const OT_INPUT_MOUSE_MOVE = 3const OT_INPUT_MOUSE_SCROLL = 5const OT_INPUT_MOUSE_UP = 2const OT_INPUT_PASTE = 3const OT_INPUT_PASTE_END = 2const OT_INPUT_PASTE_START = 1const OT_INPUT_PAYLOAD_BYTES_MIN = 4384const OT_INPUT_REPLY = 5const OT_INPUT_REPLY_APC = 5const OT_INPUT_REPLY_CSI = 1const OT_INPUT_REPLY_CURSOR_POSITION = 2const OT_INPUT_REPLY_DCS = 4const OT_INPUT_REPLY_FRAGMENT = 1const OT_INPUT_REPLY_OSC = 3const OT_INPUT_REPLY_SS3 = 2const OT_INPUT_RESET_KEEP_REPLY = 1const OT_INPUT_TIMEOUT_NS = 20000000const OT_SCENE_DEBUG_FULL_FRAME = 1const OT_SCENE_FULL_PATH_FORCED = 1const OT_SCENE_FULL_PATH_IMAGES = 4const OT_SCENE_FULL_PATH_SCREEN = 2const OT_STYLE_RUN_FLAG = 2147483648field ot_scene_stats.candidate_visits: uint64_t, offset 72field ot_scene_stats.cells_cleared: uint64_t, offset 160field ot_scene_stats.feedback_operations: uint64_t, offset 112field ot_scene_stats.full_path_reasons: uint32_t, offset 208field ot_scene_stats.geometry_reads: uint64_t, offset 96field ot_scene_stats.hit_cells_cleared: uint64_t, offset 176field ot_scene_stats.hit_cells_compared: uint64_t, offset 184field ot_scene_stats.hit_cells_written: uint64_t, offset 168field ot_scene_stats.host_requests: uint32_t, offset 212field ot_scene_stats.layout_rounds: uint32_t, offset 216field ot_scene_stats.member_cells: uint64_t, offset 152field ot_scene_stats.members_painted: uint64_t, offset 144field ot_scene_stats.overlap_tests: uint64_t, offset 136field ot_scene_stats.paint_visits: uint64_t, offset 80field ot_scene_stats.reserved: uint32_t, offset 220field ot_scene_stats.rows_compared: uint64_t, offset 192field ot_scene_stats.rows_diffed: uint64_t, offset 200field ot_scene_stats.view_preparations: uint64_t, offset 88field ot_scene_stats.viewport_child_refreshes: uint64_t, offset 128field ot_scene_stats.visibility_steps: uint64_t, offset 120field ot_scene_stats.work_frame_id: uint64_t, offset 64field ot_scene_stats.yoga_solves: uint64_t, offset 104function ot_scene_set_debug_flags(ot_context *, const ot_handle *session, uint32_t flags): ot_statusfunction ot_session_input_expect(ot_context *context, const ot_handle *session, uint32_t flags): ot_statusfunction ot_session_input_feed(ot_context *context, const ot_handle *session, const uint8_t *bytes, uint32_t byte_count, uint64_t now_ns, ot_input_event *records, uint32_t capacity, uint8_t *payload, uint32_t payload_capacity, ot_input_drain *out_drain): ot_statusfunction ot_session_input_reset(ot_context *context, const ot_handle *session, uint32_t flags): ot_statusstruct ot_input_drainstruct ot_input_event
Changed
const OT_CONTEXT_ABI_VERSION = 1const OT_CONTEXT_ABI_VERSION = 2function ot_scene_frame_step_with_geometry(ot_context *, const ot_handle *session, const ot_scene_frame_request *previous, const ot_scene_frame_options *, uint32_t max_work_items, const uint8_t *recording, uint32_t recording_length, ot_scene_frame_request *out_request, ot_scene_frame_geometry *out_geometry): ot_statusfunction ot_scene_frame_step_with_geometry(ot_context *, const ot_handle *session, const ot_scene_frame_request *previous, const ot_scene_frame_options *, const uint8_t *recording, uint32_t recording_length, ot_scene_frame_request *out_request, ot_scene_frame_geometry *out_geometry): ot_status
Removed
const OT_SCENE_FRAME_YIELD = 5