Agent skill

PPTX

by ginlix-ai in ginlix-ai/LangAlpha

PowerPoint decks built with pptxgenjs and native charts, existing decks edited in place with python-pptx, then rendered to images and audited for overflow, overlap, bounds and typography before…

Apache-2.0Auto-check passedDocuments & Office

Install PPTX

skills CLI
$ npx skills add ginlix-ai/LangAlpha --skill pptx -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install ginlix-ai/LangAlpha pptx --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/ginlix-ai/LangAlpha.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/langalpha_deliverables/skills/pptx .claude/skills/pptx && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
pptx
GitHub stars
1.8k
Token cost
~7.3k tokens
SKILL.md length
3,864 words
Files
4 (incl. scripts)
Skills in repo
37
Repo updated
First seen
Licence
Apache-2.0

At a glance

PowerPoint decks built with pptxgenjs and native charts, existing decks edited in place with python-pptx, then rendered to images and audited for overflow, overlap, bounds and typography before…

  • Works in 6 steps: Outline first, one message per slide.… → Write a build script, /build_.js, and… → Audit the file, not the script. python… → …
  • Tasks that involve PowerPoint presentations
  • SKILL.md covers Decide: Which Output?, Workflow, Design Rules and Build a New Deck, plus 4 more sections
  • Runs Python scripts from its folder; calls python, npm and python3

What it does

PPTX is an agent skill from ginlix-ai/LangAlpha. PowerPoint decks built with pptxgenjs and native charts, existing decks edited in place with python-pptx, then rendered to images and audited for overflow, overlap, bounds and typography before delivery

Its SKILL.md is about 7.3k tokens, which your agent loads only when the skill is triggered. The skill folder holds 4 other files, including scripts (for example `scripts/check.py`, `scripts/extract.py` and `scripts/render.py`).

It sits in Documents & Office, covering PowerPoint presentations. It works with Microsoft PowerPoint and python-pptx. The repository describes itself as: Claude Code for Financial Market. The licence is Apache-2.0.

When your agent uses it

  • Tasks that involve PowerPoint presentations

Example prompts

  • “/pptx”

Requirements

  • Python 3

Workflow steps

6 steps, taken from the first numbered list in SKILL.md.

  1. Outline first, one message per slide. Write the outline before any code, as ## Slide N headings each carrying one declarative sentence…
  2. Write a build script, /build_.js, and run it with NODE_PATH=$(npm root -g) node /build_.js. Never assemble a deck through ad-hoc calls…
  3. Audit the file, not the script. python .agents/skills/pptx/scripts/check.py /.pptx --strict reads what the file contains, including the…
  4. Render and look: python .agents/skills/pptx/scripts/render.py /.pptx --montage, then view montage.png. This is not optional. Clipped text…
  5. Fix in the build script, never in the .pptx, then rerun steps 2 to 4 until check.py passes and the render looks right.
  6. Deliver the .pptx and the .js beside it, and say in the reply what each slide claims.

What it can do on your machine

Read from SKILL.md and the folder at commit e05bd91. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships 3 files in scripts/ (Python), which the agent can run.

    Shell commands in SKILL.md call:

    • python
    • npm
    • python3
    • markitdown
    • soffice

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use npm, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

PPTX loads about 7.3k tokens when it runs. Until then it costs about 52 tokens; SKILL.md has 3,864 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~52
When it runs · the whole SKILL.md, loaded when a task matches
~7.3k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.

SKILL.md

The full file from ginlix-ai/LangAlpha at commit e05bd91, republished under its Apache-2.0 licence (© ginlix-ai). 3,864 words, ~7,284 tokens.

Download SKILL.mdSave it as .claude/skills/pptx/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.
name
pptx
description
PowerPoint decks built with pptxgenjs and native charts, existing decks edited in place with python-pptx, then rendered to images and audited for overflow, overlap, bounds and typography before delivery

PPTX

Build or edit a PowerPoint deck and write it into the task directory (e.g. acme_q4/acme_q4_review.pptx). Someone will stand in front of it, or forward it to a colleague who will. That is what the format is for: a deck is a sequence of single claims, each sized to be read from the back of a room. A slide that needs a paragraph is not a slide, it is a page, and it belongs in a report.

This is the right output when the deck itself is the deliverable: an investment committee pack, a diligence readout, a board update, an earnings walkthrough. It is the wrong output for anything the reader will study alone at their own pace (that is html-report) and for anything they will change numbers in (that is xlsx).

User preferences override these defaults. A house template, a brand palette, a required title slide, a fixed section order: those outrank every rule here. If the user hands you a deck to work in, work in it and match what is already there. The rules below are for when nothing has been specified.

Decide: Which Output?

WantUse
Something to present from, or hand to someone who will present it and edit slide by slidepptx (this skill)
A document to read alone, print, or export to PDFhtml-report
A model they will change inputs inxlsx
One chart or table inside the conversationinline-widget
A live app with a backendinteractive-dashboard

Workflow

  1. Outline first, one message per slide. Write the outline before any code, as ## Slide N headings each carrying one declarative sentence: the claim the slide makes, not its topic. "Revenue grew 21 percent on flat headcount" is a slide. "Revenue" is a filing cabinet. If you cannot write the sentence, you do not have the slide yet.
  2. Write a build script, <task>/build_<name>.js, and run it with NODE_PATH=$(npm root -g) node <task>/build_<name>.js. Never assemble a deck through ad-hoc calls. The script is the source of truth; when the user asks for a change, edit the script and rerun.
  3. Audit the file, not the script. python .agents/skills/pptx/scripts/check.py <task>/<name>.pptx --strict reads what the file contains, including the position a placeholder inherits from its layout, and reports shapes off the slide, boxes covering each other, overflowing text, fonts and placeholders. It compares the slide's own shapes, so branding that lives on the layout or the master is something only the render in step 4 will show you covered. Fix every fail; for every warn, either fix it or write the one line in the delivery that says why it stands.
  4. Render and look: python .agents/skills/pptx/scripts/render.py <task>/<name>.pptx --montage, then view montage.png. This is not optional. Clipped text, a legend over a bar, a title that jumps, one slide twice as dense as its neighbours: all of it is visible here and nowhere else.
  5. Fix in the build script, never in the .pptx, then rerun steps 2 to 4 until check.py passes and the render looks right.
  6. Deliver the .pptx and the .js beside it, and say in the reply what each slide claims.

Design Rules

Geometry. 16:9 (LAYOUT_WIDE, 13.333 x 7.5 in) unless the user's screen is not. The 0.6 in margin is the left and right content margin, so content spans 12.13 in; vertically each band sits at the y below, from the title at 0.45 to the footer band ending at 7.25. One geometry for every content slide:

BandyHeight
Title0.450.60
Kicker (units, period, scope)1.050.35
Rule1.420.02
Content1.75up to 4.85
Footer and page number6.950.30

Write that as one function in the build script and call it for every slide. A title that moves by a tenth of an inch between slides reads as a flicker when the deck is clicked through, and check.py reports it.

One idea per slide. The title states the finding. The body supports it. If the body supports two findings, that is two slides. Three bullets is a good slide, six is a document, and nine is a filing.

Type. Two families at most, and one is usually enough. Sizes:

RoleSizeWeight
Cover title40ptbold
Slide title28ptbold
Card or section heading18ptbold
Body and bullets16 to 18ptregular
Table text14ptheader bold
Chart axis and data labels12ptregular
Footer, source line, footnote10ptregular, secondary colour

Nothing below 10pt, ever, and nothing below 14pt in a table. A number small enough to need leaning in is a number nobody checks.

Budgets check.py holds you to. Its overflow estimate assumes an average glyph 0.50 em wide (0.54 bold) and 1.2 line spacing, so a box fits about width_in * 72 / (pt * 0.5) characters per line: a 28pt bold title across the 12.13 in content width is one line up to about 56 characters, and the 0.60 in title band holds exactly one. Write the finding in under 56 characters or drop to 24pt. The checker takes the largest text in the top 30 percent of the slide (2.25 in) as the title when there is no title placeholder, which is every pptxgenjs deck, so a 40pt number in that band is read as a wandering title: big numbers sit below 2.25 in. Page numbers are a 10pt addText box in the footer band, never slide.slideNumber, which ignores fontSize and renders at 18pt in a box too short for it.

Fonts. Arial, Calibri, Cambria, Times New Roman and Courier New each have a metric-compatible clone installed here (Liberation Sans, Carlito, Caladea, Liberation Serif, Liberation Mono), so the render you inspect breaks its lines exactly where PowerPoint will. Georgia, Verdana, Tahoma, Trebuchet MS and anything else do not: they render substituted, so the layout you checked is not the layout the reader gets. Set fontFace explicitly on every text element; a run with no font takes whatever the theme hands it.

Colour. One accent, used for one meaning. Everything else is ink, grey, and paper.

RoleHex
Slide groundFFFFFF
Title and body ink1A1A1A
Secondary text, labels, footers5A5A5A
Rules, borders, gridlinesD8D5D0
Panel and card fillF4F2EE
Accent, and chart series 11F4E79
Chart series 2, 34E86B8, 8FB4D4
Positive, gain1A7F4F
Negative, lossB42318

Green and red mean gain and loss and nothing else. Never encode a category in a colour that already means a direction.

Speaker notes when the user will present, or when they asked. One or two sentences per slide saying what to say, not a transcript of the slide. check.py --require-notes enforces the presence, not the quality.

Build a New Deck

pptxgenjs 4.0.1 is installed globally, so the script needs NODE_PATH=$(npm root -g).

js
const PptxGenJS = require("pptxgenjs");

const INK = "1A1A1A", MUTED = "5A5A5A", RULE = "D8D5D0", ACCENT = "1F4E79";
const FONT = "Arial", M = 0.6, W = 13.333, CONTENT_W = W - 2 * M;

const pptx = new PptxGenJS();
pptx.layout = "LAYOUT_WIDE";

// One geometry for every content slide, so the title never moves.
function contentSlide(title, kicker) {
  const slide = pptx.addSlide();
  slide.background = { color: "FFFFFF" };
  slide.addText(title, { x: M, y: 0.45, w: CONTENT_W, h: 0.6,
    fontFace: FONT, fontSize: 28, bold: true, color: INK, valign: "middle" });
  slide.addText(kicker, { x: M, y: 1.05, w: CONTENT_W, h: 0.35,
    fontFace: FONT, fontSize: 14, color: MUTED, valign: "top" });
  slide.addShape("rect", { x: M, y: 1.42, w: CONTENT_W, h: 0.02, fill: { color: RULE } });
  return slide;
}

const s = contentSlide("Revenue grew 21 percent on flat headcount", "Three findings drive the FY2026 view");
s.addText(
  [
    { text: "Q4 revenue of $1,240mm beat consensus by 3.4 percent.", options: { bullet: true } },
    { text: "Gross margin held at 64.2 percent on a heavier hardware mix.", options: { bullet: true } },
    { text: "Net retention of 118 percent carries half the FY2026 plan.", options: { bullet: true } },
  ],
  { x: M, y: 1.9, w: CONTENT_W, h: 2.6, fontFace: FONT, fontSize: 18, color: INK,
    lineSpacingMultiple: 1.4, valign: "top" }
);
s.addNotes("Do not read the bullets out; the room has already read them. Lead with the margin point.");

pptx.writeFile({ fileName: "acme_q4/acme_q4_review.pptx" })
  .then(() => console.log("written"));         // the check runs on the file: see step 3

Geometry is checked on the written file by check.py, which reads the real slide XML rather than the build script's intent. A shape crossing a slide edge, or two text boxes covering each other by more than 0.1 in in both directions, is a fail. Fix every one in the script and rebuild.

Charts stay native

addChart writes a real chart part that the reader can click into, retheme, and read numbers off. A picture of a chart is a dead end for them and blurs at any zoom.

js
slide.addChart(
  pptx.ChartType.bar,
  [{ name: "Revenue ($mm)", labels: ["Q1", "Q2", "Q3", "Q4"], values: [980, 1035, 1128, 1240] }],
  { x: 0.6, y: 1.75, w: 7.4, h: 4.6,
    barDir: "col", chartColors: [ACCENT], showLegend: false, showValue: true,
    dataLabelFontFace: FONT, dataLabelFontSize: 12, dataLabelColor: INK,
    catAxisLabelFontFace: FONT, catAxisLabelFontSize: 12, catAxisLabelColor: MUTED,
    valAxisLabelFontFace: FONT, valAxisLabelFontSize: 12, valAxisLabelColor: MUTED,
    valAxisMaxVal: 1400, valGridLine: { color: RULE, style: "solid", size: 1 },
    catGridLine: { style: "none" }, valAxisLineShow: false, catAxisLineShow: false }
);
  • Series data is [{ name, labels, values }], one object per series, labels identical across series.

  • One series: pass one colour. chartColors with several entries colours each bar separately, which looks like four categories where there is one.

  • Units go in the kicker or the axis title, not on every label. Turn the legend off when there is one series.

  • pptx.ChartType.bar with barDir: "col" is vertical, "bar" is horizontal. line, pie, doughnut, area, scatter are the rest of the useful set.

  • A combo chart (bars for one series, a line for another) is an array of { type, data, options } in place of the single type, with the shared geometry and axis options in the second argument:

    js
    slide.addChart(
      [{ type: pptx.ChartType.bar,  data: [{ name: "Revenue ($B)", labels, values: revenue }], options: { chartColors: [ACCENT], barDir: "col" } },
       { type: pptx.ChartType.line, data: [{ name: "FCF ($B)", labels, values: fcf }], options: { chartColors: [SERIES2], lineSize: 3, lineDataSymbol: "circle" } }],
      { x: 0.6, y: 1.75, w: 7.3, h: 4.7, showLegend: true, legendPos: "b", legendFontSize: 12,
        catAxisLabelFontSize: 12, valAxisLabelFontSize: 12, valGridLine: { color: RULE, style: "solid", size: 1 } }
    );
  • Reach for an image only when the chart type genuinely does not exist here (a waterfall, a slope chart, a small-multiple grid). Then say in the reply that it is an image.

Put the takeaway beside the chart in words. A chart with no sentence next to it makes the room do the work.

Tables
js
const head = { fill: { color: ACCENT }, color: "FFFFFF", bold: true };
slide.addTable(
  [[{ text: "Segment", options: head }, { text: "Q4 revenue", options: head }],
   ["Platform", "742"],
   [{ text: "Total", options: { bold: true } }, { text: "1,240", options: { bold: true } }]],
  { x: M, y: 1.9, w: CONTENT_W, colW: [4.6, 7.53], fontFace: FONT, fontSize: 14,
    color: INK, rowH: 0.42, valign: "middle", border: { type: "solid", pt: 1, color: RULE } }
);

A table is as tall as its rows: rowH times the row count, whatever h says, and that sum is what the geometry checks measure. Keep y plus the sum inside the content band.

Six rows and four columns is a slide. Twelve rows is a handout, so cut it to the rows that carry the argument and put the full table in an appendix slide or an xlsx. Right-align numbers, put units in the header, and state totals rather than implying them.

Editing an Existing Deck

Never rebuild a human's deck to change three words. Their master, layouts, theme, and every slide you are not touching are work you would be throwing away, and rebuilding loses the parts nobody documented. Open it with python-pptx and write into it.

python
from pptx import Presentation
from pptx.util import Inches, Pt

prs = Presentation("acme_q4/client_deck.pptx")

def set_text(shape, new_text):
    """Replace a shape's words and keep its formatting.

    The first run carries the font, size and colour, so writing into it and
    dropping the rest preserves the look without having to know what it is.
    `shape.text = "..."` throws all of that away.
    """
    frame = shape.text_frame
    paragraph = frame.paragraphs[0]
    if not paragraph.runs:
        paragraph.add_run()
    paragraph.runs[0].text = new_text
    for run in paragraph.runs[1:]:
        run._r.getparent().remove(run._r)
    for extra in frame.paragraphs[1:]:
        extra._p.getparent().remove(extra._p)

slide = prs.slides[3]
set_text(slide.shapes.title, "Segment detail, restated")

# A new slide comes from a layout the deck already has, so it inherits the design.
layout = next(l for l in prs.slide_layouts if l.name == "Title and Content")
new = prs.slides.add_slide(layout)
new.shapes.title.text = "FY2026 bridge"
new.placeholders[1].text_frame.text = "Volume carries 14 of the 21 points."

prs.save("acme_q4/client_deck_v2.pptx")

Read the deck first: python .agents/skills/pptx/scripts/extract.py deck.pptx gives every slide's text, notes, tables, charts, and the shape names and coordinates you will write into. markitdown deck.pptx is faster for prose alone but drops every position, so it answers "what does this say" and never "which box do I write into". A legacy .ppt opens with python -c "import anydoc,sys; print(anydoc.to_markdown(sys.argv[1]))" old.ppt for the same read-only view (never pass ocr="hosted", which uploads the file to an external service); to edit one, convert it with soffice --headless --convert-to pptx old.ppt and start from the .pptx.

What a python-pptx save preserved when it was measured, on one six-slide deck with a chart, a table and notes: the theme part came back byte for byte, the slide parts that were not edited came back with the same elements, attributes and order (differing only in the whitespace between tags), and the native chart kept its series values. Two parts were rewritten and both are harmless: [Content_Types].xml is rebuilt from the parts present, and a relationship target is normalised from an absolute to a relative path. That is a measurement of one deck, not a guarantee for yours, so prove it on your own edit:

bash
python3 -c "
import zipfile
a, b = zipfile.ZipFile('before.pptx'), zipfile.ZipFile('after.pptx')
print([n for n in sorted(set(a.namelist()) & set(b.namelist()))
       if not n.endswith('/') and a.read(n) != b.read(n)])"

Then render both with render.py and compare the slides you did not touch. That comparison is mandatory, not a formality: a part that survives the byte diff can still come out different once a renderer lays it out. Rules that follow:

  • Match what is there. Read a neighbouring slide's fonts, sizes and colours from extract.py and reuse them. Do not restyle a deck the user did not ask you to restyle.
  • Placeholders inherit their position from the layout. Reading shape.left gives the inherited value; writing to it pins the shape and ends the inheritance, so leave it alone unless moving it is the task.
  • A run's font.size of None means inherited, not 18pt. Do not "fix" it by setting a size.
  • There is no copy-a-slide. Add a slide from the same layout and re-add the content. There is no delete either; remove the sldId from prs.slides._sldIdLst when you must.
  • Chart data: chart.replace_data(CategoryChartData(...)) refreshes the numbers and keeps the formatting. Deleting and re-adding the chart loses it.
  • Rerun check.py and render.py on the edited file. An edit is a deck change like any other.
Show full SKILL.md (1,979 more words)Show less

Verification Scripts

All three live under .agents/skills/pptx/scripts/, take a .pptx path (or --help), and print JSON to stdout. They read the saved file, so they judge a deck the same way whoever built it: yours, or the one the user sent you.

render.py <deck.pptx> [--out DIR] [--dpi N] [--montage] [--cols N] [--keep-pdf]: LibreOffice to PDF, pdftoppm to PNG, one image per slide, plus a numbered contact sheet with --montage. A flag outside those five is an error, so a misspelt --montage stops the run instead of rendering the deck without the contact sheet and reporting success; --dpi and --cols take whole numbers, 1 to 600 and 1 to 12.

json
{"status": "success", "out": "...", "dpi": 110, "pages_rendered": 6, "slides_in_deck": 6,
 "pages": ["...slide-1.png"], "montage": "...montage.png"}

status is success or error (no PDF, no images, no contact sheet), and only error exits non-zero; an error carries previous_render_kept, since the whole set is drawn beside DIR and swapped in only once every part of it exists, the contact sheet included. A warning field appears when the page count does not match the slide count, and slide_of_page says which deck slide each image shows: hidden slides, which LibreOffice leaves out of the PDF, are listed in hidden_slides and the images and montage tiles are then numbered by deck slide rather than by page, while anything else it dropped or split leaves slide_of_page null, the mapping being unknown. Look at the montage. A script cannot tell you the deck is ugly.

check.py <deck.pptx> [--strict] [--require-notes] [--slide N]: the audit. --slide counts from 1 and errors when the deck has no such slide, rather than passing an audit of nothing. A flag outside those three is an error too, so a misspelt --strict stops the run instead of dropping the gate and exiting 0.

json
{"status": "fail", "stats": {"slides": 6, "chart_parts": 1, "images": 0, "tables": 1,
  "pictures": 0, "notes_slides": 6, "aspect": 1.778, "fonts_used": ["Arial"],
  "fonts_theme": {"major": "Calibri Light", "minor": "Calibri"}},
 "findings": [{"check": "bounds", "level": "fail", "count": 2,
   "message": "shape crosses a slide edge; part of it will never be seen",
   "examples": ["slide 2 (Shape 1: right 15.00 > 13.33)"]}]}

status is pass or fail. fail-level findings block delivery, warn is a judgement call, info is context. Only --strict makes a failing deck exit non-zero, so put --strict in the loop and let it stop you. fonts_theme is the first master's faces, and a deck carrying more than one master adds fonts_theme_by_master, since each slide resolves its fonts against the theme of its own master.

CheckLevelWhat it means
package, package_slides, package_mediafail / warncorrupt zip, slide parts that do not match the slide list, media nothing references
boundsfaila shape crosses a slide edge; a table is measured by the sum of its row heights
overlap, overlap_shapesfail / warntwo shapes cover 15 percent of the smaller one, at least 0.1 in in both directions; containment is exempt only when the outer shape holds no text and the slide paints it first (a card, a full-slide background), and is reported when it holds text
occludedfaila filled shape fully covers text that sits earlier in the shape tree, so the render shows the fill and none of the words; a shape with no fill of its own is exempt, so is one whose fill the author turned down to 100% transparency, and a group is judged by its members, since they are what paint
text_overflow, text_tightfail / warnestimated line count needs more height than the box has
placeholderfailClick to add, Lorem, TODO or [INSERT still in the deck
font_size, font_size_tablefailbody under 10pt, table text under 14pt; a run that states no size of its own is judged on the size it inherits, resolved through its paragraph, its shape's list style, its layout placeholder, its master placeholder and the master's text styles; a run in a body PowerPoint autofitted is then judged at the size it draws, the stated or inherited size times the fontScale recorded on a:normAutofit, which the finding names as 32pt scaled to 20pt by autofit
fonts, fonts_metricfail / warnmore than two families; a family with no metric-compatible clone
title_driftwarna title away from the position the rest of the deck uses; the title is the placeholder or, without one, the largest text in the top 30 percent of the slide; slide 1 is exempt as the cover, whether or not it carries a title of its own
aspectwarnnot 16:9
notesfailwith --require-notes, a content slide with none
charts_as_pictureswarna large bitmap, or one named like a chart, where a native chart belongs
font_size_inherited, geometry_unknown, hidden_shapesinfoa run whose size nothing in that chain states and a shape with no position of its own, so the rule could not be applied; and the shapes the file marks hidden, named once and left out of every pass since PowerPoint draws none of them, a hidden group taking its members with it

Overflow is an estimate from font size, box width, character count and the line breaks inside a paragraph, not a measurement: it is deliberately loose and it reports lines, so read a finding as "go look at that slide in the render". An autofitted body is estimated at the size it draws, with its leading tightened by the lnSpcReduction recorded alongside the fontScale, since PowerPoint shrinks that text rather than letting it spill. Geometry checks reach inside a group, measuring each member where the group's own scale puts it and giving it the group's place in the paint order, and they measure a rotated shape by the box its spun corners cover rather than the rectangle stored in the file, a rotated group included: its angle spins its members about the group's centre, so a member is measured in the group's unrotated space, turned about that centre, and swept through the angles it and its groups add up to, a group inside a group included. Text inside a group is still read for the content checks and measured for overflow in the box the group's scale gives it rather than the box stored on the child, since resizing a group rescales that box and leaves the point size alone, so an 18pt run inside a group at half scale still renders at 18pt.

extract.py <deck.pptx> [--slide N] [--text-only]: the deck as data, for reading before editing. Per slide: title and title_from (placeholder, or largest_in_top_band when the deck has no title placeholders, which is every pptxgenjs deck; that is the rule check.py uses too, and topmost_text is the last resort when nothing sits in the top band), layout, text (including table rows), notes, a shapes inventory with names, kinds, inches and font sizes (a table reports height as the extent the slide shows, with frame_height and rows_height beside it so you can see the two disagree), plus tables (cells) and charts (type, categories, series values; an XY or bubble series reports x_values, y_values and, for bubbles, bubble_sizes in place of values). A chart's cached points are optional in the format, and one that carries only its workbook references reports those instead, as values_ref on the series and categories_ref on the chart, rather than an empty list that reads as a chart with no numbers. A plot type python-pptx does not model, a 3-D pie or a stock chart, is named from the element in the part and carries series_unread: one such chart used to raise through the run and cost the inventory of every other slide in the deck. Both reach inside groups, in document order: a grouped chart is not in the slide's own shape list, so its numbers would otherwise reach neither the report nor check-deck. A member's left, top, width and height are slide inches like every other shape's, not the coordinate space its group stores them in, so they line up with the slide and with check.py's findings; moving or resizing a group rewrites the group alone and leaves the stored numbers on every child untouched. Rotation is reported as the angle and never folded into the frame: a rotated shape or group lists its unrotated box, the numbers an edit assigns back, and check.py is where the turned box is measured. A shape the file marks hidden is left out of text, tables and charts, the way check.py leaves it out of every pass, so the report reads as the slide shows: a stale figure parked behind the live one is not a second claim about it and a hidden Source: line cites nothing. The shapes inventory still lists it, carrying "hidden": true, a hidden group taking its members with it, since an edit may be what unhides it. --slide counts from 1 and errors when the deck has no such slide, rather than returning an empty slides. A flag outside those two is an error too, so a misspelt --slide stops the run instead of returning the whole deck as though it had never been typed.

Pitfalls

pptxgenjs

  • Units are inches, and pptxgenjs reads any number of 100 or more as EMUs instead. Keep coordinates in inches and never let a computed value cross 100.
  • Percentage strings (x: "50%") resolve against the slide at render time, so a mix of inches and percentages in one layout is a layout you cannot reason about. Pick inches.
  • autoPage is off by default, so a table taller than the slide runs off the bottom silently. check.py takes a table's bounds from the sum of its row heights, which is what PowerPoint draws rather than the frame height stored in the file, and report it out of bounds. Cut the table, or set autoPage: true and accept that pptxgenjs picks the break points and the extra slides skip your title helper.
  • Never use fit: "shrink" or autoFit. pptxgenjs writes <a:normAutofit/> with no fontScale, so LibreOffice shrinks the text to fit and PowerPoint does not: the render passes and the reader sees the overflow. Size the box to the text instead.
  • Text is vertically centred by default, so an overfull box spills equally above and below and can cover the title. Set valign: "top" on every content box.
  • Rich text is an array of runs: [{ text, options }]. breakLine: true ends a paragraph, bullet: true makes a bullet. A plain string is a single run and takes the box's options.
  • Bullets come from { bullet: true }, never a literal • character, which cannot be restyled and breaks indentation.
  • Images: sizing: { type: "contain" | "cover" | "crop", w, h } preserves the aspect ratio. Setting w and h alone stretches the picture.
  • Colours are RRGGBB with no #. "#1F4E79" is silently wrong.
  • writeFile returns a promise. Do the work that follows inside .then() or the process can exit before the file lands.
  • LAYOUT_WIDE is 13.333 x 7.5 in, LAYOUT_16x9 is 10 x 5.625 in. Same ratio, different coordinate system. Choose once, at the top.

python-pptx

  • shape.text = "..." and cell.text = "..." destroy every run's formatting. Use the set_text helper above.
  • shape.left and friends are EMUs. Inches(1.5) to write, shape.left.inches to read.
  • Table cells: cell.text_frame.paragraphs[0].runs[0], same rules as any other text frame.
  • Do not open a deck with python-pptx to build one from nothing. Its default template is 4:3 with placeholders you will fight; pptxgenjs is the build path.
  • Charts added by python-pptx need CategoryChartData; the pptxgenjs data shape is not the same.

Deliverable Checklist

  • Every slide's claim is stated in its title, and the outline sentence and the title still match.
  • check.py --strict passes.
  • The montage was rendered and looked at, and every slide was worth looking at twice.
  • 16:9, one geometry for titles, nothing outside the 0.6 in side margins or below the footer band.
  • At most two font families, all metric-safe; nothing under 10pt, nothing under 14pt in a table.
  • Numeric charts are native chart parts (stats.chart_parts is not zero when the deck has charts), one colour per series, units stated once.
  • Speaker notes where the user will present.
  • No Click to add, no TODO, no Lorem, no source line missing from a slide that quotes a number.
  • An edited deck was diffed against the original and only the parts you meant to change moved.
  • The build script sits next to the deck and reruns cleanly, and the reply names the file and what each slide claims.

© ginlix-ai, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 3 other files (scripts) in plugins/langalpha_deliverables/skills/pptx of ginlix-ai/LangAlpha.

  • SKILL.md
  • scripts/check.py
  • scripts/extract.py
  • scripts/render.py

Open the folder on GitHubat commit e05bd91

Compare with similar skills

PPTX next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

PPTX compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
PPTX this skillginlix-ai/LangAlpha1.8k—~7.3kAutomated safety check: PassApache-2.0
Slidesfcakyon/claude-codex-settings1.2k1 repos~1.1kAutomated safety check: PassMIT
Thesis Defense PPTX Builderzouchenzhen/thesis-defense-pptx-skill266—~2.4kAutomated safety check: PassApache-2.0
Powerpoint SlidesNoi1r/powerpoint-skill124—~12kAutomated safety check: NotesMIT
PPTX HTML Fidelity Auditsanqiufong/slides-from-anything1321 repos~3.5kAutomated safety check: PassApache-2.0
PPTX Chart Forensicsaiden0z/pptx-renderer127—~970Automated safety check: PassApache-2.0

Similar skills

  • Slides

    fcakyon/claude-codex-settings

    Create and edit presentation slide decks (.pptx) with PptxGenJS, bundled layout helpers, and render/validation utilities.

    1.2k GitHub starsUsed in 1 repo~1.1k tokens
    Documents & OfficeAuto-check passed
  • Thesis Defense PPTX Builder

    zouchenzhen/thesis-defense-pptx-skill

    Builds an editable thesis defense PowerPoint from a thesis PDF or LaTeX project while preserving a supplied university or lab template, then runs a visual quality check.

    266 GitHub stars~2.4k tokensUpdated 4 mo ago
    Documents & OfficeAuto-check passed
  • Powerpoint Slides

    Noi1r/powerpoint-skill

    Create visually rich PowerPoint (.pptx) presentations from academic papers, research notes, or any content the user wants in slide format.

    124 GitHub stars~12k tokensUpdated 6 mo ago
    Documents & OfficeAuto-check: notes
  • PPTX HTML Fidelity Audit

    sanqiufong/slides-from-anything

    Audit a python-pptx export against its source HTML deck, identify layout/content drift (footer overflow, cropped content, missing italic/em, lost styling, off-rhythm spacing), and re-export with…

    132 GitHub starsUsed in 1 repo~3.5k tokens
    Documents & OfficeAuto-check passed
  • PPTX Chart Forensics

    aiden0z/pptx-renderer

    A skill your agent uses when diagnosing or fixing PPTX renderer chart mismatches, chart oracle failures, ECharts option drift, OOXML chart XML parsing gaps, axis or legend discrepancies, plotArea…

    127 GitHub stars~970 tokensUpdated yesterday
    Documents & OfficeAuto-check passed
  • PPTX Oracle Eval

    aiden0z/pptx-renderer

    A skill your agent uses when running, refreshing, comparing, or summarizing PPTX renderer oracle evaluations, including shape, SmartArt, chart, table, connector, fillstroke, python-pptx, cases…

    127 GitHub stars~981 tokensUpdated yesterday
    Documents & OfficeAuto-check passed

More from ginlix-ai/LangAlpha

All 37 skills in this repo
  • Investment Deck Check

    ginlix-ai/LangAlpha

    Quality-checks an investment deck in .pptx form before it goes out: number consistency, chart and narrative alignment, source coverage, language and a circulation verdict.

    1.8k GitHub stars~3.7k tokensUpdated yesterday
    Auto-check passed
  • Equity Initiation Report

    ginlix-ai/LangAlpha

    Produces a first-time equity research initiation report in five tasks: company research, financial model, valuation, charts and a DOCX report.

    1.8k GitHub stars~3.8k tokensUpdated yesterday
    Auto-check passed
  • Builds or repairs an integrated income statement, balance sheet and cash flow model in Excel with live formulas, supporting schedules, scenarios and a Checks sheet.

    1.8k GitHub stars~5.4k tokensUpdated yesterday
    Auto-check passed
  • Financial Model Checker

    ginlix-ai/LangAlpha

    Audits an existing Excel financial model without editing it, checking structure, formulas, integrity identities and source tie-out, and ends in a prioritized issue log.

    1.8k GitHub stars~4.2k tokensUpdated yesterday
    Auto-check passed
  • DCF Model Builder

    ginlix-ai/LangAlpha

    Builds a live Excel DCF valuation workbook with free cash flow projections, WACC, terminal value, three scenarios, sensitivity grids and a reverse DCF.

    1.8k GitHub stars~7.7k tokensUpdated yesterday
    Auto-check passed
  • Builds Word files with python-docx, edits existing ones in place with tracked changes and comments, then renders and validates the result.

    1.8k GitHub stars~4.8k tokensUpdated yesterday
    Auto-check passed

Questions about PPTX

What does PPTX do?

PowerPoint decks built with pptxgenjs and native charts, existing decks edited in place with python-pptx, then rendered to images and audited for overflow, overlap, bounds and typography before…. PPTX is an agent skill from ginlix-ai/LangAlpha.

When should I use PPTX?

PPTX fits situations like: tasks that involve PowerPoint presentations.

How do I install PPTX in Claude Code?

Run `npx skills add ginlix-ai/LangAlpha --skill pptx -a claude-code`. Or copy the skill folder (plugins/langalpha_deliverables/skills/pptx in ginlix-ai/LangAlpha) into .claude/skills/pptx in your project. Claude Code loads it when a task matches its description.

How do I install PPTX in Codex?

Run `npx skills add ginlix-ai/LangAlpha --skill pptx -a codex`. Or copy the skill folder (plugins/langalpha_deliverables/skills/pptx in ginlix-ai/LangAlpha) into .agents/skills/pptx in your project. Codex loads it when a task matches its description.

Can I use PPTX in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ginlix-ai/LangAlpha --skill pptx -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/pptx, .gemini/skills/pptx, .github/skills/pptx and .opencode/skills/pptx in your project.

What does PPTX need to run?

Going by SKILL.md and its folder, PPTX needs Python for the scripts in its folder and the command-line tools its instructions call (python, npm, python3, markitdown and soffice). Our summary lists: Python 3.

Does PPTX access the network?

SKILL.md contains no URLs. Its commands use npm, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is PPTX safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.

What licence does PPTX use?

PPTX is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does PPTX use?

About 7.3k tokens (SKILL.md is roughly 29k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to PPTX?

Skills that share tags, products or a category with PPTX: Slides (fcakyon/claude-codex-settings, 1.2k stars), Thesis Defense PPTX Builder (zouchenzhen/thesis-defense-pptx-skill, 266 stars), Powerpoint Slides (Noi1r/powerpoint-skill, 124 stars) and PPTX HTML Fidelity Audit (sanqiufong/slides-from-anything, 132 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains PPTX?

ginlix-ai (a GitHub organization) maintains it in ginlix-ai/LangAlpha, which has 1,811 GitHub stars. The repository holds 37 skills in this directory. The repository was last updated on October 9, 2026.

Source: ginlix-ai/LangAlpha on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.