CtrlK
BlogDocsLog inGet started
Tessl Logo

metis-strategy/metis-pptx

Create or edit PowerPoint presentations. Dual-mode skill: (1) Editing mode preserves existing templates via Open XML unpack/edit/repack when an existing .pptx is provided. (2) Generation mode creates new Metis-branded decks from a design system with 36 composable components and 5 layout grids. Includes brand extraction for client decks and visual QA via PowerPoint COM. Triggers on deck, slides, presentation, PPT, or any .pptx request.

84

Quality

84%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Advisory

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

render_timesaver_library.pyscripts/

"""
Admin tool — re-render the Metis Timesaver PNG library on the shared drive.

The skill itself does NOT call this script during normal use. The shared-drive
PNG library at the path below is the single source of truth for `metis-pptx`'s
Path B (Timesaver) workflow; the skill reads those PNGs directly and never
renders them on the fly.

Run this only when:
  - The source Timesaver pptx has been updated (slides added, edited, reordered).
  - An admin needs to rebuild the shared library after a brand refresh.

Default source:
    G:\\Shared drives\\Knowledge Management\\New Brand Assets\\PPT Assets\\
    Metis_Timesaver Slides.pptx

Default destination (the canonical shared library that the skill reads):
    G:\\Shared drives\\Knowledge Management\\New Brand Assets\\PPT Assets\\
    timesaver_pngs\\

Override with --output-dir, or set METIS_TIMESAVER_PNG_DIR.

Requires Windows + Microsoft PowerPoint + pywin32 + write access to the
target folder. Running this overwrites every slide-N.png in --output-dir.
"""
import argparse
import os
import sys

DEFAULT_SOURCE = (
    r"G:\Shared drives\Knowledge Management\New Brand Assets\PPT Assets"
    r"\Metis_Timesaver Slides.pptx"
)
DEFAULT_OUTPUT = (
    r"G:\Shared drives\Knowledge Management\New Brand Assets\PPT Assets"
    r"\timesaver_pngs"
)


def render(source_path: str, output_dir: str, width: int = 1600, height: int = 900):
    """Render every slide of the source deck to <output_dir>/slide-N.png via PowerPoint COM."""
    import win32com.client  # imported lazily so this script can be inspected without pywin32

    os.makedirs(output_dir, exist_ok=True)

    if not os.path.exists(source_path):
        sys.exit(f"Source not found: {source_path}")

    # PowerPoint COM Export requires native Windows backslash paths
    output_dir = os.path.abspath(output_dir).replace("/", "\\")
    source_path = os.path.abspath(source_path).replace("/", "\\")

    ppt = win32com.client.Dispatch("PowerPoint.Application")
    ppt.Visible = 1
    try:
        pres = ppt.Presentations.Open(source_path, WithWindow=False, ReadOnly=True)
        n = pres.Slides.Count
        print(f"Source: {source_path}")
        print(f"Slides: {n}")
        print(f"Output: {output_dir}")
        for idx in range(1, n + 1):
            out = os.path.join(output_dir, f"slide-{idx}.png")
            pres.Slides(idx).Export(out, "PNG", width, height)
            if idx % 20 == 0 or idx == n:
                print(f"  rendered {idx}/{n}")
        pres.Close()
    finally:
        ppt.Quit()


def main() -> None:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("--source", default=DEFAULT_SOURCE,
                    help="Path to Metis_Timesaver Slides.pptx (default: shared G:\\ drive)")
    ap.add_argument("--output-dir",
                    default=os.environ.get("METIS_TIMESAVER_PNG_DIR", DEFAULT_OUTPUT),
                    help=f"Folder to write slide-N.png into (default: shared library at {DEFAULT_OUTPUT})")
    ap.add_argument("--width", type=int, default=1600)
    ap.add_argument("--height", type=int, default=900)
    args = ap.parse_args()

    render(args.source, args.output_dir, args.width, args.height)
    print(f"\nDone. {len(os.listdir(args.output_dir))} previews available at:\n  {args.output_dir}")


if __name__ == "__main__":
    main()

SKILL.md

tile.json