Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Changed
- README `docs/media/intro.gif` sits on a photographed green forest desktop (not teal blobs): Terminal chrome, a pointer that walks titlebar → composer → slash / model → Shell, and the signed lock TUI. Local CLI only — no Cortex Cloud handoff in the banner story.

## 0.1.9

### Changed
Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
<a href="https://cortex.foundation">cortex.foundation</a>
</p>

![Animated green Cortex CLI in a complete Terminal window on a macOS-styled desktop, with a moving pointer](./docs/media/intro.gif)
![Cortex CLI in macOS Terminal on a green forest desktop: splash, prompt, slash commands, a Shell tool row, and a moving pointer](./docs/media/intro.gif)

*Generated macOS-styled demo, not a desktop recording. The green CLI frames
come from the offline `readme_hero` renderer; the desktop and pointer are
composited. No live coding request is performed.*
*Generated macOS desktop demo, not a screen recording. The TUI frames come
from the offline `readme_hero` lock boards; the forest wallpaper, Terminal
chrome and pointer are composited. No live coding request is performed.*
Regenerate with `./scripts/render-demo-gif.sh` (Cargo, Python with Pillow, and
FFmpeg required); terminal pixels are preserved 1:1 before GIF quantization.

Expand Down Expand Up @@ -184,8 +184,9 @@ The banner above is generated from this repository, not captured by hand:
./scripts/render-demo-gif.sh
```

That records the signed lock TUI (splash → typing → working) headlessly
through `generate_tui_demo` and rasterises the frames into `docs/media/intro.gif`.
That records the signed lock TUI (splash → type a prompt → working → slash
palette → `/model` → Shell → composer) headlessly through `generate_tui_demo`
and composites it onto the forest desktop in `docs/media/intro.gif`.

## Release and CI secrets

Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ servers, skills, agents, plugins, hooks, sessions and permissions.
New here? Start with **[Getting started](guides/getting-started.md)**, then keep
**[CLI reference](reference/cli.md)** open in another tab.

![Cortex Code running a change end to end](media/intro.gif)
![Cortex CLI in macOS Terminal on a green forest desktop, touring slash commands and a live tool row](media/intro.gif)

## Contents

Expand Down
Binary file added docs/media/intro-preview/composer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/intro-preview/model.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/intro-preview/palette.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/intro-preview/shell.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/intro-preview/splash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/intro-preview/working.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/media/intro.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/macos-wallpaper-green.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 44 additions & 2 deletions scripts/ansi-frames-to-gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,12 @@ def main() -> int:
default=None,
help="Write named PNGs from manifest labels to this directory and skip the GIF",
)
parser.add_argument(
"--preview-dir",
type=Path,
default=None,
help="Also write one composed still per storyboard label",
)
args = parser.parse_args()

manifest_path = args.frames / "manifest.json"
Expand Down Expand Up @@ -420,6 +426,23 @@ def main() -> int:
)
macos = importlib.util.module_from_spec(spec)
spec.loader.exec_module(macos)
storyboard = tuple(
label
for entry in manifest["frames"]
for label in [entry.get("label") or Path(entry["file"]).stem] * entry["hold"]
)
preview_dir = args.preview_dir
previewed: set[str] = set()
preview_labels = {
"splash",
"working",
"palette",
"model",
"shell",
"composer",
}
if preview_dir is not None:
preview_dir.mkdir(parents=True, exist_ok=True)
for entry in manifest["frames"]:
ansi = (args.frames / entry["file"]).read_text()
grid = parse_ansi(ansi, width, height)
Expand All @@ -432,10 +455,29 @@ def main() -> int:
output_index += 1
else:
desktop = macos.build_desktop(image, f"Cortex CLI — cortex — {width}×{height}")
label = entry.get("label") or Path(entry["file"]).stem
for _ in range(entry["hold"]):
macos.animate_mouse(desktop, output_index, total_frames).save(
png_root / f"{output_index:05d}.png"
frame = macos.animate_mouse(
desktop,
output_index,
total_frames,
label=label,
labels=storyboard,
content_size=image.size,
)
frame.save(png_root / f"{output_index:05d}.png")
if (
preview_dir is not None
and label in preview_labels
and label not in previewed
):
safe = "".join(ch if ch.isalnum() or ch in "-_" else "_" for ch in label)
preview = frame
if preview.width > 1000:
preview_height = round(preview.height * 1000 / preview.width)
preview = preview.resize((1000, preview_height), Image.LANCZOS)
preview.save(preview_dir / f"{safe}.png", optimize=True)
previewed.add(label)
output_index += 1

if named_dir is not None:
Expand Down
67 changes: 55 additions & 12 deletions scripts/check-macos-demo.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""Run with the renderer's Pillow environment: python3 scripts/check-macos-demo.py."""
import importlib.util
import hashlib
import importlib.util
from pathlib import Path

from PIL import Image, ImageChops
Expand All @@ -17,30 +17,73 @@
raw.putpixel((0, 0), (255, 255, 255))
desktop = macos.build_desktop(raw, "Cortex CLI — cortex — 120×40")
assert desktop.size == (1416, 1140), desktop.size
assert macos.WALLPAPER_PATH.is_file(), macos.WALLPAPER_PATH

x = macos.DESKTOP_MARGIN + macos.CONTENT_INSET
y = macos.WINDOW_TOP + macos.TITLEBAR_H + macos.CONTENT_INSET
box = (x, y, x+raw.width, y+raw.height)
box = (x, y, x + raw.width, y + raw.height)
assert desktop.crop(box).tobytes() == raw.tobytes(), "CLI pixels must stay 1:1 before the pointer"

# A photograph has far more unique colours than the retired teal ellipses.
forest = desktop.crop((8, macos.MENUBAR_H + 8, 72, 220))
assert len({pixel for pixel in forest.getdata()}) > 80, "desktop backdrop is not a forest photograph"

labels = (
("splash",) * 12
+ ("typing",) * 36
+ ("prompt-ready",) * 6
+ ("working",) * 12
+ ("palette",) * 12
+ ("model",) * 10
+ ("shell",) * 12
+ ("composer",) * 10
)
total = len(labels)
titlebar_hits = 0
terminal_hits = 0
previous = None
for frame in range(98):
image = macos.animate_mouse(desktop, frame, 98)
assert image.crop(box).tobytes() == raw.tobytes(), f"CLI pixels changed at {frame}"
for frame in range(total):
image = macos.animate_mouse(
desktop, frame, total, label=labels[frame], labels=labels, content_size=raw.size
)
px, py, _pressed = macos.pointer_pose(
frame,
total,
desktop_size=desktop.size,
content_size=raw.size,
label=labels[frame],
labels=labels,
)
if macos.WINDOW_TOP <= py <= macos.WINDOW_TOP + macos.TITLEBAR_H:
titlebar_hits += 1
if box[0] <= px <= box[2] and box[1] <= py <= box[3]:
terminal_hits += 1
if previous is not None:
assert ImageChops.difference(previous, image).getbbox(), f"Pointer stalled at {frame}"
previous = image
assert macos.animate_mouse(desktop, 0, 98).tobytes() == macos.animate_mouse(desktop, 98, 98).tobytes()

assert titlebar_hits >= 2, f"pointer never visited the titlebar ({titlebar_hits})"
assert terminal_hits >= 8, f"pointer never entered the terminal ({terminal_hits})"
assert macos.animate_mouse(desktop, 0, total, labels=labels).tobytes() == macos.animate_mouse(
desktop, total, total, labels=labels
).tobytes()

gif = Path(__file__).resolve().parents[1] / "docs/media/intro.gif"
assert gif.stat().st_size < 5 * 1024 * 1024
assert gif.stat().st_size < 5 * 1024 * 1024, gif.stat().st_size
with Image.open(gif) as image:
assert image.size == desktop.size
assert image.n_frames == 98, image.n_frames
assert image.size == desktop.size, image.size
n_frames = image.n_frames
assert 100 <= n_frames <= 160, n_frames
assert image.info["loop"] == 0
pixels = set()
duration = 0
for frame in range(image.n_frames):
for frame in range(n_frames):
image.seek(frame)
pixels.add(hashlib.sha256(image.convert("RGB").tobytes()).digest())
duration += image.info["duration"]
assert len(pixels) == 98, len(pixels)
assert len(pixels) >= 70, len(pixels)
assert 8000 <= duration <= 15000, duration
print("PASS: desktop dimensions, exact CLI pixels, moving looping pointer, 98 unique GIF frames, duration and <5 MiB")
print(
"PASS: photo wallpaper, exact CLI pixels, titlebar+terminal pointer, "
f"{n_frames} GIF frames, duration and <5 MiB"
)
Loading
Loading