support z-index + dual canvas for DOM. Doesnt work for webgl

This commit is contained in:
Anthony Kim
2026-02-11 14:19:27 -08:00
parent 2c4997f529
commit 1d0cf32b28
7 changed files with 235 additions and 50 deletions
@@ -3,7 +3,7 @@
* @license MIT
*/
import { IApcHandler, IImageAddonOptions, IResetHandler, ITerminalExt } from '../Types';
import { IApcHandler, IImageAddonOptions, IResetHandler, ITerminalExt, ImageLayer } from '../Types';
import { ImageRenderer } from '../ImageRenderer';
import { ImageStorage, CELL_SIZE_DEFAULT } from '../ImageStorage';
import Base64Decoder, { type DecodeStatus } from 'xterm-wasm-parts/lib/base64/Base64Decoder.wasm';
@@ -504,12 +504,18 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler {
const savedY = buffer.y;
const savedYbase = buffer.ybase;
// Determine layer based on z-index: negative = behind text, 0+ = on top.
// Bottom layer only works when allowTransparency is enabled (otherwise text
// canvas background is opaque and hides the bottom canvas). Fall back to top.
const wantsBottom = cmd.zIndex !== undefined && cmd.zIndex < 0;
const layer: ImageLayer = (wantsBottom && this._coreTerminal.options.allowTransparency) ? 'bottom' : 'top';
let storageId: number;
if (w !== bitmap.width || h !== bitmap.height) {
const resized = await createImageBitmap(bitmap, { resizeWidth: w, resizeHeight: h });
storageId = this._storage.addImage(resized);
storageId = this._storage.addImage(resized, layer);
} else {
storageId = this._storage.addImage(bitmap);
storageId = this._storage.addImage(bitmap, layer);
}
this._kittyIdToStorageId.set(image.id, storageId);
@@ -86,5 +86,25 @@ describe('KittyGraphicsTypes', () => {
assert.ok(isNaN(cmd.format!));
assert.strictEqual(cmd.id, 5);
});
it('should parse z-index key with positive value', () => {
const cmd = parseKittyCommand('a=T,f=100,z=10');
assert.strictEqual(cmd.zIndex, 10);
});
it('should parse z-index key with zero', () => {
const cmd = parseKittyCommand('a=T,f=100,z=0');
assert.strictEqual(cmd.zIndex, 0);
});
it('should parse z-index key with negative value', () => {
const cmd = parseKittyCommand('a=T,f=100,z=-1');
assert.strictEqual(cmd.zIndex, -1);
});
it('should leave zIndex undefined when not specified', () => {
const cmd = parseKittyCommand('a=T,f=100');
assert.strictEqual(cmd.zIndex, undefined);
});
});
});
@@ -70,7 +70,9 @@ export const enum KittyKey {
// Quiet mode (1=suppress OK responses, 2=suppress error responses)
QUIET = 'q',
// Cursor movement policy (0=move cursor after image, 1=don't move cursor)
CURSOR_MOVEMENT = 'C'
CURSOR_MOVEMENT = 'C',
// Z-index for image layering (negative = behind text, 0+ = on top)
Z_INDEX = 'z'
}
// Pixel format constants
@@ -95,6 +97,7 @@ export interface IKittyCommand {
more?: number;
quiet?: number;
cursorMovement?: number;
zIndex?: number;
compression?: string;
payload?: string;
}
@@ -164,6 +167,7 @@ export function parseKittyCommand(data: string): IKittyCommand {
case KittyKey.MORE: cmd.more = numValue; break;
case KittyKey.QUIET: cmd.quiet = numValue; break;
case KittyKey.CURSOR_MOVEMENT: cmd.cursorMovement = numValue; break;
case KittyKey.Z_INDEX: cmd.zIndex = numValue; break;
}
}