A pull request page where the checks turn green one by one, a review approves it and the merge button lands it, branch deleted.
Add star milestone piece with custom repo and count #412 ╭──────────╮ │ ◆ Merged │ kail merged 3 commits into main from feat/star-milestone ╰──────────╯ ──────────────────────────────────────────────────────────────────────────────────────── ● reviewer approved these changes Looks great. The bold digits read well in the dots look. ╭──────────────────────────────────────────────────────────────────────────────────╮ │ ✓ All checks have passed 5 of 5 done │ │──────────────────────────────────────────────────────────────────────────────────│ │ ✓ Build and test (node 20) 20s │ │ ✓ Lint and typecheck 37s │ │ ✓ Visual snapshots, 734 tiles 54s │ │ ✓ End to end, chrome 11s │ │ ✓ Bundle size, +1.2 kB 28s │ ╰──────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────╮ │ ◆ Pull request successfully merged and closed ╭───────────────╮│ │ The feat/star-milestone branch can be safely deleted. │ Delete branch ││ │ ╰───────────────╯│ ╰──────────────────────────────────────────────────────────────────────────────────╯
Paste two lines into any page, use it from React, play it in a terminal, put a GIF in a README, or hand the Agent prompt to your coding agent. Every tab follows the look you pick above.
<script type="module" src="https://www.ascii-magic.com/ascii/ascii.js"></script>
<ascii-art piece="pr-merged"></ascii-art>// npm install ascii-magic-art
import { useEffect, useRef } from "react";
import { play } from "ascii-magic-art/runtime/player.js";
import * as piece from "ascii-magic-art/pieces/pr-merged.js";
export function PrMerged() {
const ref = useRef(null);
// play() draws the piece on a canvas in your look and returns stop(), which React runs on unmount
useEffect(() => play(ref.current, piece), []);
return <pre ref={ref} style={{ fontSize: 10, fontFamily: "Menlo, Consolas, monospace" }} />;
}npx ascii-magic-art pr-merged<!-- Export the GIF below in the look you picked, commit it, then: -->
<p align="center">
<img src="assets/pr-merged.gif" alt="Pull Request Merged, animated ASCII art" width="720">
</p>Add the animated ASCII art piece "pr-merged" (Pull Request Merged) from ASCII Magic to this project.
1. Load the script once, in the browser only (in SSR frameworks such as Next.js, load it on the client):
<script type="module" src="https://www.ascii-magic.com/ascii/ascii.js"></script>
2. Put the piece where it fits best, such as the hero, a loading state, an empty state or the 404 page:
<ascii-art piece="pr-merged"></ascii-art>
3. Keep a real heading or text next to it (the art is decoration), and size it with the size attribute or CSS.
Preview and options: https://www.ascii-magic.com/ascii/pr-merged
Rules for coding agents: https://www.ascii-magic.com/ascii/use/ai-coding-agentsPause on the frame you like, pick a look, then download it at an exact size.
MIT licensed and open source on GitHub. It imports one small helper file, kit.js. This is the animation itself: what gets drawn in every frame. The look you pick is applied on top by the player, like a filter, so this file stays the same in every look while the snippets above change with it. Edit it to change the animation; see the docs to make your own.
/* pr-merged: a pull request goes green check by check, gets approved and merges. */
import { Grid, palette, clamp } from "../lib/kit.js";
export const meta = {
slug: "pr-merged",
name: "Pull Request Merged",
category: "screens",
note: "A pull request page where the checks turn green one by one, a review approves it and the merge button lands it, branch deleted.",
tags: ["github", "pull-request", "merge", "ci", "code-review", "open-source", "readme", "ui"],
cols: 88, rows: 30, fps: 24,
loop: 13,
palette: palette(["#e6edf3", "#8b949e", "#30363d", "#7ee787", "#238636", "#d2a8ff", "#8957e5", "#e3b341", "#79c0ff", "#f85149", "#161b22"]),
};
const LOOP = 13;
const CHECKS = [
["build", "Build and test (node 20)", 1.4],
["lint", "Lint and typecheck", 2.1],
["visual", "Visual snapshots, 734 tiles", 3.2],
["e2e", "End to end, chrome", 4.4],
["size", "Bundle size, +1.2 kB", 5.0],
];
const SPIN = "↑↗→↘↓↙←↖";
export default function create() {
const g = new Grid(meta.cols, meta.rows), W = meta.cols;
return (t) => {
g.clear();
const ph = ((t % LOOP) + LOOP) % LOOP;
const approved = ph > 6.0, merged = ph > 8.2;
// title and state pill
g.text(2, 1, "Add star milestone piece with custom repo and count", "0");
g.text(2 + 52, 1, "#412", "1");
const pill = merged ? " ◆ Merged " : " ○ Open ", pc = merged ? "6" : "4";
g.box(2, 3, pill.length + 2, 3, "round", pc); g.text(3, 4, pill, merged ? "5" : "3");
const by = merged ? "merged 3 commits into main from feat/star-milestone" : "wants to merge 3 commits into main from feat/star-milestone";
g.text(pill.length + 6, 4, "kail", "0"); g.text(pill.length + 11, 4, by, "1");
g.hline(0, W - 1, 6, "─", "2");
// conversation: a review
g.text(2, 8, "●", "8"); g.text(4, 8, "reviewer", "0");
g.text(13, 8, approved ? "approved these changes" : "requested a review", approved ? "3" : "1");
g.text(4, 9, approved ? "Looks great. The bold digits read well in the dots look." : "...", "1");
// checks box
const bx = 2, bw = W - 4, top = 11;
const allGreen = ph > CHECKS[CHECKS.length - 1][2];
g.box(bx, top, bw, CHECKS.length + 4, "round", allGreen ? "4" : "2");
const head = allGreen ? "All checks have passed" : "Some checks haven't completed yet";
g.text(bx + 2, top + 1, allGreen ? "✓" : SPIN[Math.floor(t * 8) % 8], allGreen ? "3" : "7");
g.text(bx + 4, top + 1, head, "0");
const done = CHECKS.filter((c) => ph > c[2]).length;
const sum = `${done} of ${CHECKS.length} done`;
g.text(bx + bw - 2 - sum.length, top + 1, sum, "1");
g.hline(bx + 1, bx + bw - 2, top + 2, "─", "2");
CHECKS.forEach(([id, label, at], i) => {
const y = top + 3 + i, ok = ph > at, started = ph > at - 1.2;
g.text(bx + 2, y, ok ? "✓" : started ? SPIN[Math.floor(t * 8 + i) % 8] : "○", ok ? "3" : started ? "7" : "1");
g.text(bx + 4, y, label, ok ? "0" : "1");
const st = ok ? `${(12 + i * 17) % 60 + 8}s` : started ? "running" : "queued";
g.text(bx + bw - 2 - st.length, y, st, ok ? "1" : started ? "7" : "1");
});
// the merge box
const my = top + CHECKS.length + 5;
g.box(bx, my, bw, 5, "round", merged ? "6" : allGreen && approved ? "4" : "2");
if (merged) {
g.text(bx + 2, my + 1, "◆", "5"); g.text(bx + 4, my + 1, "Pull request successfully merged and closed", "0");
g.text(bx + 4, my + 2, "The feat/star-milestone branch can be safely deleted.", "1");
const del = ph > 9.6, label = del ? " Branch deleted " : " Delete branch ";
g.box(bx + bw - 3 - label.length, my + 1, label.length + 2, 3, "round", "2"); g.text(bx + bw - 2 - label.length, my + 2, label, del ? "1" : "0");
} else {
const ready = allGreen && approved, press = ph > 7.6 && ph < 8.2;
g.text(bx + 2, my + 1, ready ? "✓" : "○", ready ? "3" : "1");
g.text(bx + 4, my + 1, ready ? "This branch has no conflicts with the base branch" : "Waiting on checks and review", ready ? "0" : "1");
const lab = press ? " Merging... " : " Merge pull request ";
g.box(bx + 2, my + 2, lab.length + 2, 3, "round", ready ? "3" : "2");
g.text(bx + 3, my + 3, lab, ready ? "3" : "1");
// the bottom edge of the button sits on the merge box's bottom edge
g.set(bx + 2, my + 4, "├", ready ? "3" : "2"); g.set(bx + 3 + lab.length, my + 4, "┤", ready ? "3" : "2");
}
return g.frame();
};
}
/YOUR OWN
The pieces here are hand-built animations. To turn your own photo, logo or video into animated ASCII, use the ASCII Magic editor.