Skip to content

Instantly share code, notes, and snippets.

@scturtle
Created April 1, 2026 03:44
Show Gist options
  • Select an option

  • Save scturtle/4e3325c1dc2149d9e4f5e37c56466c3b to your computer and use it in GitHub Desktop.

Select an option

Save scturtle/4e3325c1dc2149d9e4f5e37c56466c3b to your computer and use it in GitHub Desktop.
kitty graphics protocol
/* gcc -O2 -march=native -o kgp kgp.c -lm */
#define _POSIX_C_SOURCE 200809L
#include <math.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define WIDTH 320
#define HEIGHT 200
/* ════════════════════════════════════════════════════════════════════════
* Math & Plasma Animation
* ════════════════════════════════════════════════════════════════════════ */
static float sin_lut[4096];
void init_sin_lut() {
for (int i = 0; i < 4096; i++)
sin_lut[i] = sinf((float)i * (2.f * (float)M_PI / 4096.f));
}
static inline float fsin(float x) {
return sin_lut[(int)(x * (4096.f / (2.f * (float)M_PI))) & 4095];
}
static void plasma_frame(uint8_t *rgb, float t) {
for (int y = 0; y < HEIGHT; y++) {
float fy = (float)y / HEIGHT, cy = fy - 0.5f;
for (int x = 0; x < WIDTH; x++) {
float fx = (float)x / WIDTH, cx = fx - 0.5f;
float v = fsin(fx * 10.f + t) + fsin(fy * 8.f + t * 0.7f) +
fsin((fx + fy) * 7.f + t * 1.1f) +
fsin(sqrtf(cx * cx + cy * cy) * 18.f - t * 1.8f);
float a = v * (float)M_PI * 0.25f;
*rgb++ = (uint8_t)(128.f + 127.f * fsin(a));
*rgb++ = (uint8_t)(128.f + 127.f * fsin(a + 2.094f));
*rgb++ = (uint8_t)(128.f + 127.f * fsin(a + 4.189f));
}
}
}
/* ════════════════════════════════════════════════════════════════════════
* Base64 & Kitty Graphics Protocol
* ════════════════════════════════════════════════════════════════════════ */
static size_t base64_encode(const uint8_t *in, size_t len, char *out) {
static const char b64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *p = out;
for (size_t i = 0; i < len; i += 3) {
uint32_t w = (in[i] << 16) | ((i + 1 < len ? in[i + 1] : 0) << 8) |
((i + 2 < len ? in[i + 2] : 0));
*p++ = b64[(w >> 18) & 0x3f];
*p++ = b64[(w >> 12) & 0x3f];
*p++ = (i + 1 < len) ? b64[(w >> 6) & 0x3f] : '=';
*p++ = (i + 2 < len) ? b64[w & 0x3f] : '=';
}
return p - out;
}
static struct {
long id;
int frame;
char b64[256005]; /* 320*200*3/3*4 ≈ 256000 */
char proto[300000];
} ctx;
static void render_frame(const uint8_t *rgb) {
size_t b64_len = base64_encode(rgb, WIDTH * HEIGHT * 3, ctx.b64);
char *buf = ctx.proto;
size_t off = 0;
for (size_t i = 0; i < b64_len; i += 4096) {
int more = (i + 4096 < b64_len) ? 1 : 0;
size_t chunk = more ? 4096 : (b64_len - i);
if (i == 0) {
if (ctx.frame == 0)
off +=
sprintf(buf + off, "\033_Ga=T,i=%ld,f=24,s=%d,v=%d,q=2,c=60,m=%d;",
ctx.id, WIDTH, HEIGHT, more);
else
off +=
sprintf(buf + off, "\033_Ga=f,r=1,i=%ld,f=24,q=2,s=%d,v=%d,m=%d;",
ctx.id, WIDTH, HEIGHT, more);
} else {
if (ctx.frame == 0)
off += sprintf(buf + off, "\033_Gm=%d;", more);
else
off += sprintf(buf + off, "\033_Ga=f,r=1,q=2,m=%d;", more);
}
memcpy(buf + off, ctx.b64 + i, chunk);
off += chunk;
memcpy(buf + off, "\033\\", 2);
off += 2;
}
if (ctx.frame > 0)
off += sprintf(buf + off, "\033_Ga=a,q=2,c=1,i=%ld;\033\\", ctx.id);
else {
memcpy(buf + off, "\r\n", 2);
off += 2;
}
fwrite(ctx.proto, 1, off, stdout);
fflush(stdout);
ctx.frame++;
}
static void render_init() { printf("\033[?25l\033[2J\033[H"); }
static void render_done(long id) {
printf("\033_Ga=d,q=2,i=%ld;\033\\\033[H\033[2J\033[?25h", id);
fflush(stdout);
}
/* ════════════════════════════════════════════════════════════════════════
* Main Loop
* ════════════════════════════════════════════════════════════════════════ */
static volatile sig_atomic_t g_quit = 0;
static void on_signal(int s) {
(void)s;
g_quit = 1;
}
int main(void) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = on_signal;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
srand((unsigned)time(NULL));
ctx.id = (long)rand() | 1;
struct timespec last_time;
clock_gettime(CLOCK_MONOTONIC, &last_time);
float t = 0.f;
int frames = 0;
static uint8_t rgb24[WIDTH * HEIGHT * 3];
init_sin_lut();
render_init();
while (!g_quit) {
plasma_frame(rgb24, t);
render_frame(rgb24);
t += 0.01f;
frames++;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
long ms = (now.tv_sec - last_time.tv_sec) * 1000L +
(now.tv_nsec - last_time.tv_nsec) / 1000000L;
if (ms >= 1000) {
fprintf(stderr, "FPS: %d\r", frames);
frames = 0;
last_time = now;
}
}
render_done(ctx.id);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment