CtrlK
BlogDocsLog inGet started
Tessl Logo

jbaruch/speaker-toolkit

Eight-skill presentation system: ingest talks into a rhetoric vault, run interactive clarification, generate a speaker profile, create presentations that match your documented patterns, produce the deck illustrations + thumbnail visual layer, create and publish talk-content Agent Skills with talk pages to a Jekyll shownotes site, verify a recorded screencast against its storyboard, and edit a Camtasia screencast into a speaker-first video with corrected captions and chapters, all informed by a 113-entry Presentation Patterns taxonomy (83 observable: 64 patterns + 19 antipatterns; 30 unobservable: 21 patterns + 9 antipatterns) for scoring, brainstorming, and go-live preparation.

75

Quality

94%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

trec-pointer.pyskills/screencast-editor/scripts/

#!/usr/bin/env python3
"""Extract the recorded pointer path from a Camtasia .trec.

The pointer is not in the screen pixels: Camtasia records it separately, in the
TSCM atom at the end of the file. Stills can never show where the presenter was
pointing; this can.

Usage:
    trec-pointer.py <recording.trec> [--out pointer.json]

Output: {"capture": {"x","y","width","height"}, "samples": [[seconds, nx, ny], ...]}
where nx, ny are normalized to the captured display, top-left origin.
Exit 0 on success, 1 when the file carries no pointer data, 2 on usage error.
"""

from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))
# The sibling module resolves only after the sys.path insert above.
import camtasia_model as model  # noqa: E402


def extract(recording: Path) -> dict:
    records = model.tscm_records(model.read_top_level_atom(recording, b"TSCM"))
    x, y, width, height = model.capture_rect(records)
    path = model.pointer_path(records)
    if not path:
        raise ValueError(f"{recording} recorded no pointer movement")
    samples = [
        [round(t, 4), round((px - x) / width, 5), round((py - y) / height, 5)]
        for t, px, py in path
    ]
    return {
        "capture": {"x": x, "y": y, "width": width, "height": height},
        "samples": samples,
    }


def main(argv: list[str] | None = None) -> int:
    parser = argparse.ArgumentParser(description=(__doc__ or "").split("\n")[0])
    parser.add_argument("recording", type=Path)
    parser.add_argument("--out", type=Path)
    args = parser.parse_args(argv)
    try:
        result = extract(args.recording)
    except ValueError as e:
        print(f"trec-pointer: {e}", file=sys.stderr)
        return 1
    text = json.dumps(result)
    if args.out:
        try:
            args.out.write_text(text + "\n", encoding="utf-8")
        except OSError as e:
            print(
                f"trec-pointer: cannot write {args.out}: {e}; choose a writable --out",
                file=sys.stderr,
            )
            return 1
        print(
            f"{len(result['samples'])} pointer samples -> {args.out}", file=sys.stderr
        )
    else:
        print(text)
    return 0


if __name__ == "__main__":
    sys.exit(main())

skills

README.md

tile.json