ink-sdl 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/dist/{chunk-YE6CUIKT.js → chunk-LP5C65TH.js} +81 -34
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +81 -1
- package/dist/index.js +1 -1
- package/fonts/CozetteVector.ttf +0 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -168,6 +168,7 @@ Creates stdin/stdout streams and a window for use with Ink.
|
|
|
168
168
|
| `borderless` | `boolean` | `false` | Remove window decorations (title bar, borders) |
|
|
169
169
|
| `minWidth` | `number` | `undefined` | Minimum window width in pixels |
|
|
170
170
|
| `minHeight` | `number` | `undefined` | Minimum window height in pixels |
|
|
171
|
+
| `existing` | `ExistingSdlResources` | `undefined` | Use existing SDL window/renderer (see Advanced Usage) |
|
|
171
172
|
|
|
172
173
|
#### Returns
|
|
173
174
|
|
|
@@ -213,6 +214,49 @@ if (isSdlAvailable()) {
|
|
|
213
214
|
|
|
214
215
|
## Advanced Usage
|
|
215
216
|
|
|
217
|
+
### Using Existing SDL Window/Renderer
|
|
218
|
+
|
|
219
|
+
For applications that need to share a single SDL window between ink-sdl and custom rendering (e.g., an emulator with a menu UI), you can pass existing SDL resources:
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import { render, Text, Box } from "ink";
|
|
223
|
+
import { createSdlStreams, getSdl2, type ExistingSdlResources } from "ink-sdl";
|
|
224
|
+
|
|
225
|
+
// Create your own SDL window and renderer
|
|
226
|
+
const sdl = getSdl2();
|
|
227
|
+
sdl.init(0x20 | 0x4000); // SDL_INIT_VIDEO | SDL_INIT_EVENTS
|
|
228
|
+
|
|
229
|
+
const myWindow = sdl.createWindow("My App", 100, 100, 800, 600, 0x4);
|
|
230
|
+
const myRenderer = sdl.createRenderer(myWindow, -1, 0x2);
|
|
231
|
+
|
|
232
|
+
// Use them with ink-sdl
|
|
233
|
+
const streams = createSdlStreams({
|
|
234
|
+
existing: { window: myWindow, renderer: myRenderer },
|
|
235
|
+
fontSize: 16,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
render(<MenuApp />, { stdin: streams.stdin, stdout: streams.stdout });
|
|
239
|
+
|
|
240
|
+
// When done with ink-sdl UI, close() cleans up ink-sdl resources
|
|
241
|
+
// but does NOT destroy your window/renderer
|
|
242
|
+
streams.window.close();
|
|
243
|
+
|
|
244
|
+
// You can now render directly to the same window, or create new streams later
|
|
245
|
+
// When completely done, destroy the window/renderer yourself
|
|
246
|
+
sdl.destroyRenderer(myRenderer);
|
|
247
|
+
sdl.destroyWindow(myWindow);
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Ownership rules:**
|
|
251
|
+
|
|
252
|
+
- When `existing` is provided, ink-sdl does NOT own the window/renderer
|
|
253
|
+
- `close()` will NOT destroy the provided window/renderer
|
|
254
|
+
- The caller retains ownership and must destroy them when fully done
|
|
255
|
+
- Window options (`width`, `height`, `title`, `fullscreen`, `borderless`) are ignored
|
|
256
|
+
- Rendering options (`fontSize`, `scaleFactor`, `fontPath`, etc.) still apply
|
|
257
|
+
|
|
258
|
+
### Low-Level Components
|
|
259
|
+
|
|
216
260
|
For more control, you can use the lower-level components directly:
|
|
217
261
|
|
|
218
262
|
```typescript
|
|
@@ -223,6 +267,8 @@ import {
|
|
|
223
267
|
InputBridge,
|
|
224
268
|
getSdl2,
|
|
225
269
|
getSdlTtf,
|
|
270
|
+
type ExistingSdlResources,
|
|
271
|
+
type SDLPointer,
|
|
226
272
|
} from "ink-sdl";
|
|
227
273
|
```
|
|
228
274
|
|
|
@@ -1886,6 +1886,10 @@ var SdlUiRenderer = class {
|
|
|
1886
1886
|
renderer = null;
|
|
1887
1887
|
textRenderer = null;
|
|
1888
1888
|
renderTarget = null;
|
|
1889
|
+
/** Whether we own the window (should destroy it on cleanup) */
|
|
1890
|
+
ownsWindow = true;
|
|
1891
|
+
/** Whether we own the renderer (should destroy it on cleanup) */
|
|
1892
|
+
ownsRenderer = true;
|
|
1889
1893
|
ansiParser;
|
|
1890
1894
|
inputBridge;
|
|
1891
1895
|
windowWidth;
|
|
@@ -1920,38 +1924,13 @@ var SdlUiRenderer = class {
|
|
|
1920
1924
|
* Initialize SDL window and renderer
|
|
1921
1925
|
*/
|
|
1922
1926
|
initSDL(options) {
|
|
1923
|
-
if (!this.sdl.init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
|
|
1924
|
-
throw new Error("Failed to initialize SDL2 for UI rendering");
|
|
1925
|
-
}
|
|
1926
1927
|
this.defaultBgColor = parseBackgroundColor(options.backgroundColor);
|
|
1927
1928
|
this.bgColor = { ...this.defaultBgColor };
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
if (options.fullscreen === "desktop") {
|
|
1933
|
-
windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
|
1934
|
-
} else if (options.fullscreen === true) {
|
|
1935
|
-
windowFlags |= SDL_WINDOW_FULLSCREEN;
|
|
1936
|
-
}
|
|
1937
|
-
if (options.borderless && !options.fullscreen) {
|
|
1938
|
-
windowFlags |= SDL_WINDOW_BORDERLESS;
|
|
1939
|
-
}
|
|
1940
|
-
this.window = this.sdl.createWindow(
|
|
1941
|
-
options.title ?? "ink-sdl",
|
|
1942
|
-
SDL_WINDOWPOS_CENTERED,
|
|
1943
|
-
SDL_WINDOWPOS_CENTERED,
|
|
1944
|
-
this.windowWidth,
|
|
1945
|
-
this.windowHeight,
|
|
1946
|
-
windowFlags
|
|
1947
|
-
);
|
|
1948
|
-
if (options.minWidth !== void 0 || options.minHeight !== void 0) {
|
|
1949
|
-
const minW = options.minWidth ?? 1;
|
|
1950
|
-
const minH = options.minHeight ?? 1;
|
|
1951
|
-
this.sdl.setWindowMinimumSize(this.window, minW, minH);
|
|
1929
|
+
if (options.existing) {
|
|
1930
|
+
this.initWithExistingResources(options);
|
|
1931
|
+
} else {
|
|
1932
|
+
this.initNewResources(options);
|
|
1952
1933
|
}
|
|
1953
|
-
const rendererFlags = options.vsync !== false ? SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC : SDL_RENDERER_ACCELERATED;
|
|
1954
|
-
this.renderer = this.sdl.createRenderer(this.window, -1, rendererFlags);
|
|
1955
1934
|
this.userScaleFactor = options.scaleFactor === void 0 ? null : options.scaleFactor;
|
|
1956
1935
|
if (this.userScaleFactor !== null) {
|
|
1957
1936
|
this.scaleFactor = this.userScaleFactor;
|
|
@@ -1979,7 +1958,62 @@ var SdlUiRenderer = class {
|
|
|
1979
1958
|
this.sdl.setRenderTarget(this.renderer, null);
|
|
1980
1959
|
this.sdl.renderClear(this.renderer);
|
|
1981
1960
|
this.sdl.renderPresent(this.renderer);
|
|
1982
|
-
|
|
1961
|
+
if (this.ownsWindow) {
|
|
1962
|
+
this.sdl.raiseWindow(this.window);
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
/**
|
|
1966
|
+
* Initialize with existing SDL window and renderer
|
|
1967
|
+
*/
|
|
1968
|
+
initWithExistingResources(options) {
|
|
1969
|
+
const existing = options.existing;
|
|
1970
|
+
this.window = existing.window;
|
|
1971
|
+
this.renderer = existing.renderer;
|
|
1972
|
+
this.ownsWindow = false;
|
|
1973
|
+
this.ownsRenderer = false;
|
|
1974
|
+
if (!this.sdl.init(SDL_INIT_EVENTS)) {
|
|
1975
|
+
throw new Error("Failed to initialize SDL2 events");
|
|
1976
|
+
}
|
|
1977
|
+
const size = this.sdl.getWindowSize(this.window);
|
|
1978
|
+
this.windowWidth = size.width;
|
|
1979
|
+
this.windowHeight = size.height;
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* Initialize by creating new SDL window and renderer
|
|
1983
|
+
*/
|
|
1984
|
+
initNewResources(options) {
|
|
1985
|
+
if (!this.sdl.init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
|
|
1986
|
+
throw new Error("Failed to initialize SDL2 for UI rendering");
|
|
1987
|
+
}
|
|
1988
|
+
this.ownsWindow = true;
|
|
1989
|
+
this.ownsRenderer = true;
|
|
1990
|
+
let windowFlags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
|
|
1991
|
+
if (!options.fullscreen) {
|
|
1992
|
+
windowFlags |= SDL_WINDOW_RESIZABLE;
|
|
1993
|
+
}
|
|
1994
|
+
if (options.fullscreen === "desktop") {
|
|
1995
|
+
windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
|
1996
|
+
} else if (options.fullscreen === true) {
|
|
1997
|
+
windowFlags |= SDL_WINDOW_FULLSCREEN;
|
|
1998
|
+
}
|
|
1999
|
+
if (options.borderless && !options.fullscreen) {
|
|
2000
|
+
windowFlags |= SDL_WINDOW_BORDERLESS;
|
|
2001
|
+
}
|
|
2002
|
+
this.window = this.sdl.createWindow(
|
|
2003
|
+
options.title ?? "ink-sdl",
|
|
2004
|
+
SDL_WINDOWPOS_CENTERED,
|
|
2005
|
+
SDL_WINDOWPOS_CENTERED,
|
|
2006
|
+
this.windowWidth,
|
|
2007
|
+
this.windowHeight,
|
|
2008
|
+
windowFlags
|
|
2009
|
+
);
|
|
2010
|
+
if (options.minWidth !== void 0 || options.minHeight !== void 0) {
|
|
2011
|
+
const minW = options.minWidth ?? 1;
|
|
2012
|
+
const minH = options.minHeight ?? 1;
|
|
2013
|
+
this.sdl.setWindowMinimumSize(this.window, minW, minH);
|
|
2014
|
+
}
|
|
2015
|
+
const rendererFlags = options.vsync !== false ? SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC : SDL_RENDERER_ACCELERATED;
|
|
2016
|
+
this.renderer = this.sdl.createRenderer(this.window, -1, rendererFlags);
|
|
1983
2017
|
}
|
|
1984
2018
|
/**
|
|
1985
2019
|
* Update terminal dimensions based on window size
|
|
@@ -2344,6 +2378,11 @@ var SdlUiRenderer = class {
|
|
|
2344
2378
|
}
|
|
2345
2379
|
/**
|
|
2346
2380
|
* Clean up resources
|
|
2381
|
+
*
|
|
2382
|
+
* When using existing window/renderer (via `existing` option), this method
|
|
2383
|
+
* will NOT destroy the window or renderer - only the resources created by
|
|
2384
|
+
* ink-sdl (TextRenderer, render target texture). The caller is responsible
|
|
2385
|
+
* for destroying the window/renderer they provided.
|
|
2347
2386
|
*/
|
|
2348
2387
|
destroy() {
|
|
2349
2388
|
if (this.textRenderer) {
|
|
@@ -2354,14 +2393,22 @@ var SdlUiRenderer = class {
|
|
|
2354
2393
|
this.sdl.destroyTexture(this.renderTarget);
|
|
2355
2394
|
this.renderTarget = null;
|
|
2356
2395
|
}
|
|
2357
|
-
if (this.renderer) {
|
|
2396
|
+
if (this.ownsRenderer && this.renderer) {
|
|
2358
2397
|
this.sdl.destroyRenderer(this.renderer);
|
|
2359
|
-
this.renderer = null;
|
|
2360
2398
|
}
|
|
2361
|
-
|
|
2399
|
+
this.renderer = null;
|
|
2400
|
+
if (this.ownsWindow && this.window) {
|
|
2362
2401
|
this.sdl.destroyWindow(this.window);
|
|
2363
|
-
this.window = null;
|
|
2364
2402
|
}
|
|
2403
|
+
this.window = null;
|
|
2404
|
+
}
|
|
2405
|
+
/**
|
|
2406
|
+
* Check if this renderer owns the SDL window
|
|
2407
|
+
*
|
|
2408
|
+
* Returns false when using an existing window via the `existing` option.
|
|
2409
|
+
*/
|
|
2410
|
+
ownsResources() {
|
|
2411
|
+
return this.ownsWindow && this.ownsRenderer;
|
|
2365
2412
|
}
|
|
2366
2413
|
/**
|
|
2367
2414
|
* Reset state for reuse
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -220,6 +220,19 @@ declare const createSDLRect: (x: number, y: number, w: number, h: number) => Buf
|
|
|
220
220
|
* from Ink and renders it to an SDL window using text rendering.
|
|
221
221
|
*/
|
|
222
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Existing SDL resources to use instead of creating new ones.
|
|
225
|
+
*
|
|
226
|
+
* When provided, ink-sdl will use these resources instead of creating its own.
|
|
227
|
+
* The caller retains ownership and is responsible for destroying them after
|
|
228
|
+
* ink-sdl is done.
|
|
229
|
+
*/
|
|
230
|
+
interface ExistingSdlResources {
|
|
231
|
+
/** Existing SDL window pointer */
|
|
232
|
+
window: SDLPointer;
|
|
233
|
+
/** Existing SDL renderer pointer */
|
|
234
|
+
renderer: SDLPointer;
|
|
235
|
+
}
|
|
223
236
|
interface SdlUiRendererOptions {
|
|
224
237
|
width?: number;
|
|
225
238
|
height?: number;
|
|
@@ -243,6 +256,19 @@ interface SdlUiRendererOptions {
|
|
|
243
256
|
minWidth?: number | undefined;
|
|
244
257
|
/** Minimum window height in pixels */
|
|
245
258
|
minHeight?: number | undefined;
|
|
259
|
+
/**
|
|
260
|
+
* Use existing SDL window and renderer instead of creating new ones.
|
|
261
|
+
*
|
|
262
|
+
* When provided, ink-sdl will:
|
|
263
|
+
* - Use the existing window/renderer for all rendering
|
|
264
|
+
* - NOT destroy them when destroy() is called (caller retains ownership)
|
|
265
|
+
* - Read dimensions from the existing window
|
|
266
|
+
* - Ignore width/height/title/fullscreen/borderless options (window already exists)
|
|
267
|
+
*
|
|
268
|
+
* This enables sharing a single SDL window between ink-sdl and other renderers,
|
|
269
|
+
* such as an emulator that switches between menu UI and game rendering.
|
|
270
|
+
*/
|
|
271
|
+
existing?: ExistingSdlResources | undefined;
|
|
246
272
|
}
|
|
247
273
|
/** Result from processing SDL events */
|
|
248
274
|
interface ProcessEventsResult {
|
|
@@ -265,6 +291,10 @@ declare class SdlUiRenderer {
|
|
|
265
291
|
private renderer;
|
|
266
292
|
private textRenderer;
|
|
267
293
|
private renderTarget;
|
|
294
|
+
/** Whether we own the window (should destroy it on cleanup) */
|
|
295
|
+
private ownsWindow;
|
|
296
|
+
/** Whether we own the renderer (should destroy it on cleanup) */
|
|
297
|
+
private ownsRenderer;
|
|
268
298
|
private ansiParser;
|
|
269
299
|
private inputBridge;
|
|
270
300
|
private windowWidth;
|
|
@@ -291,6 +321,14 @@ declare class SdlUiRenderer {
|
|
|
291
321
|
* Initialize SDL window and renderer
|
|
292
322
|
*/
|
|
293
323
|
private initSDL;
|
|
324
|
+
/**
|
|
325
|
+
* Initialize with existing SDL window and renderer
|
|
326
|
+
*/
|
|
327
|
+
private initWithExistingResources;
|
|
328
|
+
/**
|
|
329
|
+
* Initialize by creating new SDL window and renderer
|
|
330
|
+
*/
|
|
331
|
+
private initNewResources;
|
|
294
332
|
/**
|
|
295
333
|
* Update terminal dimensions based on window size
|
|
296
334
|
*/
|
|
@@ -383,8 +421,19 @@ declare class SdlUiRenderer {
|
|
|
383
421
|
getScaleFactor(): number;
|
|
384
422
|
/**
|
|
385
423
|
* Clean up resources
|
|
424
|
+
*
|
|
425
|
+
* When using existing window/renderer (via `existing` option), this method
|
|
426
|
+
* will NOT destroy the window or renderer - only the resources created by
|
|
427
|
+
* ink-sdl (TextRenderer, render target texture). The caller is responsible
|
|
428
|
+
* for destroying the window/renderer they provided.
|
|
386
429
|
*/
|
|
387
430
|
destroy(): void;
|
|
431
|
+
/**
|
|
432
|
+
* Check if this renderer owns the SDL window
|
|
433
|
+
*
|
|
434
|
+
* Returns false when using an existing window via the `existing` option.
|
|
435
|
+
*/
|
|
436
|
+
ownsResources(): boolean;
|
|
388
437
|
/**
|
|
389
438
|
* Reset state for reuse
|
|
390
439
|
*/
|
|
@@ -553,6 +602,37 @@ interface SdlStreamsOptions {
|
|
|
553
602
|
minWidth?: number | undefined;
|
|
554
603
|
/** Minimum window height in pixels */
|
|
555
604
|
minHeight?: number | undefined;
|
|
605
|
+
/**
|
|
606
|
+
* Use existing SDL window and renderer instead of creating new ones.
|
|
607
|
+
*
|
|
608
|
+
* When provided, ink-sdl will:
|
|
609
|
+
* - Use the existing window/renderer for all rendering
|
|
610
|
+
* - NOT destroy them when the window is closed (caller retains ownership)
|
|
611
|
+
* - Read dimensions from the existing window
|
|
612
|
+
* - Ignore width/height/title/fullscreen/borderless options
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* ```typescript
|
|
616
|
+
* // Create your own SDL window and renderer
|
|
617
|
+
* const myWindow = SDL_CreateWindow(...);
|
|
618
|
+
* const myRenderer = SDL_CreateRenderer(myWindow, ...);
|
|
619
|
+
*
|
|
620
|
+
* // Use them with ink-sdl
|
|
621
|
+
* const streams = createSdlStreams({
|
|
622
|
+
* existing: { window: myWindow, renderer: myRenderer },
|
|
623
|
+
* fontSize: 16,
|
|
624
|
+
* });
|
|
625
|
+
*
|
|
626
|
+
* // When done with ink-sdl, clean up
|
|
627
|
+
* streams.window.close();
|
|
628
|
+
*
|
|
629
|
+
* // You can now use the window/renderer for other purposes
|
|
630
|
+
* // or destroy them yourself when fully done
|
|
631
|
+
* SDL_DestroyRenderer(myRenderer);
|
|
632
|
+
* SDL_DestroyWindow(myWindow);
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
existing?: ExistingSdlResources | undefined;
|
|
556
636
|
}
|
|
557
637
|
/**
|
|
558
638
|
* SDL Window wrapper that emits events
|
|
@@ -1059,4 +1139,4 @@ declare class InputBridge {
|
|
|
1059
1139
|
*/
|
|
1060
1140
|
declare const isSdlAvailable: () => boolean;
|
|
1061
1141
|
|
|
1062
|
-
export { AnsiParser, type Color, type DrawCommand, type InkKeyEvent, InputBridge, type SDLPointer, Sdl2, SdlInputStream, type SdlKeyEvent, SdlOutputStream, type SdlStreams, type SdlStreamsOptions, SdlTtf, SdlUiRenderer, type SdlUiRendererOptions, SdlWindow, TextRenderer, createSDLRect, createSdlStreams, getSdl2, getSdlTtf, isSdl2Available, isSdlAvailable, isSdlTtfAvailable };
|
|
1142
|
+
export { AnsiParser, type Color, type DrawCommand, type ExistingSdlResources, type InkKeyEvent, InputBridge, type SDLPointer, Sdl2, SdlInputStream, type SdlKeyEvent, SdlOutputStream, type SdlStreams, type SdlStreamsOptions, SdlTtf, SdlUiRenderer, type SdlUiRendererOptions, SdlWindow, TextRenderer, createSDLRect, createSdlStreams, getSdl2, getSdlTtf, isSdl2Available, isSdlAvailable, isSdlTtfAvailable };
|
package/dist/index.js
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ink-sdl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Render Ink terminal apps in native SDL windows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
-
"
|
|
19
|
+
"fonts"
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
22
|
"dev": "tsx src/index.ts",
|