╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Title.zig ────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │http│ ssh │ │ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
344 "#....#", 345 ".#..#.", 346 ".#..#.", 347 "..##..", 348 "..##..", 349 "..##..", 350 ".#..#.", 351 ".#..#.", 352 "#....#", 353 }, 354 'Y' => .{ 355 "#....#", 356 ".#..#.", 357 ".#..#.", 358 "..##..", 359 "..##..", 360 "..##..", 361 "..##..", 362 "..##..", 363 "..##..", 364 }, 365 'Z' => .{ 366 "######", 367 "....#.", 368 "....#.", 369 "...#..", 370 "..##..", 371 "..#...", 372 ".#....", 373 ".#....", 374 "######", 375 }, 376 '0' => .{ 377 ".####.", 378 "#...##", 379 "#..#.#", 380 "#..#.#", 381 "#.#..#", 382 "#.#..#", 383 "##...#", 384 "#....#", 385 ".####.", 386 }, 387 '1' => .{ 388 "..##..", 389 ".###..", 390 "..##..", 391 "..##..", 392 "..##..", 393 "..##..", 394 "..##..", 395 "..##..", 396 "######", 397 }, 398 '2' => .{ 399 ".####.", 400 "#....#", 401 ".....#", 402 "....#.", 403 "...#..", 404 "..#...", 405 ".#....", 406 "#.....", 407 "######", 408 }, 409 '3' => .{ 410 ".####.", 411 "#....#", 412 ".....#", 413 ".....#", 414 ".####.", 415 ".....#", 416 ".....#", 417 "#....#", 418 ".####.", 419 }, 420 '4' => .{ 421 "....#.", 422 "...##.", 423 "..#.#.", 424 ".#..#.", 425 "#...#.", 426 "######", 427 "....#.", 428 "....#.", 429 "....#.", 430 }, 431 '5' => .{ 432 "######", 433 "#.....", 434 "#.....", 435 "#.....", 436 "#####.", 437 ".....#", 438 ".....#", 439 "#....#", 440 ".####.", 441 }, 442 '6' => .{ 443 ".####.", 444 "#....#", 445 "#.....", 446 "#.....", 447 "#####.", 448 "#....#", 449 "#....#", 450 "#....#", 451 ".####.", 452 }, 453 '7' => .{ 454 "######", 455 ".....#", 456 "....#.", 457 "....#.", 458 "...#..", 459 "...#..", 460 "..#...", 461 "..#...", 462 ".#....", 463 }, 464 '8' => .{ 465 ".####.", 466 "#....#", 467 "#....#", 468 "#....#", 469 ".####.", 470 "#....#", 471 "#....#", 472 "#....#", 473 ".####.", 474 }, 475 '9' => .{ 476 ".####.", 477 "#....#", 478 "#....#", 479 "#....#", 480 ".#####", 481 ".....#", 482 ".....#", 483 "#....#", 484 ".####.", 485 }, 486 '-' => .{ 487 "......", 488 "......", 489 "......", 490 "......", 491 ".####.", 492 "......", 493 "......", 494 "......", 495 "......", 496 }, 497 '.' => .{ 498 "......", 499 "......", 500 "......", 501 "......", 502 "......", 503 "......", 504 "......", 505 "..##..", 506 "..##..", 507 }, 508 else => null, 509 }; 510 } 511 512 // map a 2x3 sub-pixel pattern to its corresponding sextant codepoint 513 fn sextantCodepoint(pattern: u6) u21 { 514 return switch (pattern) { 515 0b000000 => ' ', 516 0b010101 => 0x258C, // ▌ left half block 517 0b101010 => 0x2590, // ▐ right half block 518 0b111111 => 0x2588, // █ full block 519 else => blk: { 520 var offset: u21 = @as(u21, pattern) - 1; 521 if (pattern > 0b010101) offset -= 1; 522 if (pattern > 0b101010) offset -= 1; 523 break :blk 0x1FB00 + offset; 524 }, 525 }; 526 } 527 528 fn renderTitle(allocator: std.mem.Allocator, input: []const u8) ![]const u8 { 529 var rows: [3]std.ArrayList(u8) = .{ .empty, .empty, .empty }; 530 defer for (&rows) |*r| r.deinit(allocator); 531 532 var first = true; 533 for (input) |c| { 534 const glyph = glyphFor(c) orelse continue; 535 536 // row-aligned dither: keep on-pixels only at even bitmap rows. 537 var kept: [9][6]bool = std.mem.zeroes([9][6]bool); 538 for (0..9) |r| { 539 if (r % 2 != 0) continue; 540 for (0..6) |col| { 541 kept[r][col] = glyph[r][col] == '#'; 542 } 543 } 544 545 if (!first) { 546 for (&rows) |*r| try r.append(allocator, ' '); 547 } 548 first = false; 549 550 for (0..3) |text_row| { 551 for (0..3) |text_col| { 552 var pattern: u6 = 0; 553 for (0..3) |sub_row| { 554 for (0..2) |sub_col| { 555 const row_idx = text_row * 3 + sub_row; 556 const col_idx = text_col * 2 + sub_col; 557 if (kept[row_idx][col_idx]) { 558 pattern |= @as(u6, 1) << @intCast(sub_row * 2 + sub_col); 559 } 560 } 561 } 562 const cp = sextantCodepoint(pattern); 563 var utf8_buf: [4]u8 = undefined; 564 const len = try std.unicode.utf8Encode(cp, &utf8_buf); 565 try rows[text_row].appendSlice(allocator, utf8_buf[0..len]); 566 } 567 } 568 } 569 570 var out: std.ArrayList(u8) = .empty; 571 errdefer out.deinit(allocator); 572 try out.appendSlice(allocator, rows[0].items); 573 try out.append(allocator, '\n'); 574 try out.appendSlice(allocator, rows[1].items); 575 try out.append(allocator, '\n'); 576 try out.appendSlice(allocator, rows[2].items); 577 return out.toOwnedSlice(allocator); 578 } 579