- L_table: Inches(0.5×rows) → min(0.5×rows, 5.3) 상한 적용 (footer y=7.05, table top y=1.7 → max 5.3" + 0.05" gap) - 영향 슬라이드: 행 수 11+인 표 전체 (DI/DO 14행, TactTime 13행, PLC신호 12행) - SKILL.md Notes에 table 높이 상한 규칙 문서화 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
138 lines
6.5 KiB
Markdown
138 lines
6.5 KiB
Markdown
---
|
||
name: ubisam-ppt-make
|
||
description: Build a .pptx deck in the Ubisam SW 설계서 design system (extracted from P-PRJ_BFHB_UBISAM). UbiSam logo on every page, fixed fonts (한글=굴림, 영문=Arial), blue #4A8DCB accent. Use when the user wants a Ubisam-style design document deck or runs /ubisam-ppt-make.
|
||
---
|
||
|
||
# ubisam-ppt-make — Ubisam SW 설계서 deck builder
|
||
|
||
Deterministic PPT builder following the design system extracted from
|
||
`P-PRJ_BFHB_UBISAM_Ver1.4.pptx` and the user's edited layout showcase
|
||
(UbiSam logo placed on every page). Takes a JSON spec and emits a `.pptx`
|
||
via python-pptx.
|
||
|
||
## When to use
|
||
|
||
- The user types `/ubisam-ppt-make`
|
||
- Requests like "Ubisam 설계서 PPT 만들어줘" / "유비삼 스타일 덱" / "this format으로"
|
||
- New design-document presentations that must keep Ubisam branding
|
||
|
||
## Design system (fixed)
|
||
|
||
- Slide: 16:9 (13.333 × 7.5 in)
|
||
- **슬라이드 마스터 배경** (모든 pptx 자동 적용):
|
||
- 캔버스: `BG_SOFT` `#F4F7FA` (연회색) — `_apply_master_background()` 에서 마스터+레이아웃 전체 설정
|
||
- 하단 accent 바: `#4A8DCB` h=0.15in @ y=7.35in (마스터 공통)
|
||
- cover·divider·closing은 자체 full rect로 덮음; 나머지 레이아웃은 상속
|
||
- spec JSON에서 `"background_color": "RRGGBB"` 로 재정의 가능
|
||
- Accent: `#4A8DCB` (blue), dark `#2F5E8C`; warn `#E53E3E`
|
||
- Ink `#262A2E`, sub-gray `#6B7278`, soft panel `#F4F7FA`
|
||
- **Font rule (do not change): 한글=굴림, 영문=Arial** — applied to every run
|
||
- **UbiSam logo on every page**: cover = bottom-right, all others = top-right
|
||
- Header pattern: `0X.` badge + title + KO subtitle + split accent bar
|
||
- Footer: `Ubisam | <doc_title>` + page number (content pages only)
|
||
|
||
## 12 layout types (`slide.type`)
|
||
|
||
Document layouts:
|
||
|
||
| type | purpose | key fields |
|
||
|------|---------|-----------|
|
||
| `cover` | 표지 | `tag, title, subtitles[], team, contacts[]` |
|
||
| `history` | 변경 이력 표 | `rows[] = [No,Version,날짜,변경자,내용]` |
|
||
| `agenda` | 목차 그리드(≤6) | `items[] = {no,title,sub}` |
|
||
| `divider` | 섹션 간지(큰 숫자) | `no, title, subtitle` |
|
||
| `content` | 4분할 패널 | `no, title, subtitle, panels[] = {title,body}` |
|
||
| `flow` | 시퀀스 플로우차트 | `no, title, subtitle, steps[]={title,code,kind}, branch{title,sub}` |
|
||
| `table` | 스펙/IO 표 | `no, title, headers[], widths[], center_cols[], rows[][]` |
|
||
| `closing` | 마무리 | `title, message, team, contacts[]` |
|
||
|
||
Manual layouts (HMI Manual / 27번):
|
||
|
||
| type | purpose | key fields |
|
||
|------|---------|-----------|
|
||
| `screen_guide` | 화면 설명(캡처+번호 콜아웃) | `no, title, caption, image(PNG경로), items[]={title,desc,pos:[x,y]}` |
|
||
| `procedure` | 조작 절차(번호 단계) | `no, title, steps[]={title,desc}` |
|
||
| `icon_ref` | 버튼/아이콘 설명(3열 카드, ≤6) | `no, title, items[]={icon,name,func}` |
|
||
| `alarm` | 알람·조치(주의 배너+표) | `no, title, notice, rows[]=[코드,알람명,원인,조치]` |
|
||
|
||
`kind` for flow steps: `"proc"` (process box) or `"dec"` (decision, blue outline).
|
||
`pos` in `screen_guide` items = callout marker offset (inch) inside the capture box.
|
||
Page numbers auto-increment over content/manual pages; cover/divider/closing excluded.
|
||
`divider`/`closing` use a white background with a `#0070C0` / `#2F5E8C` block.
|
||
|
||
## Choosing a layout for each piece of data
|
||
|
||
Match every chunk of source/analysis data to the layout whose intent fits it —
|
||
do not force everything into `table`. Full rules + disambiguation in
|
||
[`reference/layout_selection.md`](reference/layout_selection.md). Cheat sheet:
|
||
|
||
- ordered **human** steps → `procedure` · machine sequence **with branches** → `flow`
|
||
- 2–4 facets, one line each → `content` · repeating rows/cols → `table`
|
||
- annotate ONE screenshot → `screen_guide` · button/icon legend → `icon_ref`
|
||
- fault → cause → action (+safety) → `alarm` · revision log → `history`
|
||
|
||
## Workflow
|
||
|
||
1. **Gather info** — topic, doc title, sections, slide contents, contacts.
|
||
If the user gives no content, build the sample showcase (all layouts).
|
||
2. **Classify each data chunk → layout** using the guide above, then
|
||
**write the spec JSON** — see `examples/showcase.json` and the type tables.
|
||
Reuse the original BFHB sample text only when the user wants the showcase.
|
||
3. **Run the builder**:
|
||
```bash
|
||
cd <skill-dir>
|
||
python build_deck.py --input spec.json --output "생성파일/<name>.pptx"
|
||
# or, sample showcase:
|
||
python build_deck.py --output "생성파일/Ubisam_layout_showcase.pptx"
|
||
```
|
||
4. **Verify** — render to PNG and eyeball every slide (see Verification).
|
||
5. **Report** — output path + slide summary.
|
||
|
||
## Spec schema (minimal)
|
||
|
||
```json
|
||
{
|
||
"doc_title": "P-PRJ BFHB SW 설계서",
|
||
"slides": [
|
||
{ "type": "cover", "title": "...", "subtitles": ["..."],
|
||
"team": "시스템 사업팀", "contacts": ["이름 직급 email"] },
|
||
{ "type": "divider", "no": "01", "title": "...", "subtitle": "..." },
|
||
{ "type": "content", "no": "02.", "title": "...", "subtitle": "...",
|
||
"panels": [ {"title": "...", "body": "..."} ] }
|
||
]
|
||
}
|
||
```
|
||
|
||
A full working spec is in [`examples/showcase.json`](examples/showcase.json).
|
||
|
||
## Verification (required, project rule 13)
|
||
|
||
Export every slide to PNG and inspect; check no overflow/overlap, logo on
|
||
every page, and 한글=굴림 / 영문=Arial on all runs.
|
||
|
||
```powershell
|
||
# PowerPoint COM export (Windows, PowerPoint installed)
|
||
$ppt = New-Object -ComObject PowerPoint.Application
|
||
$pres = $ppt.Presentations.Open($pptx, $true, $false, $false)
|
||
$i=1; foreach ($s in $pres.Slides) { $s.Export("$dir/slide$i.png","PNG",1280,720); $i++ }
|
||
$pres.Close(); $ppt.Quit()
|
||
```
|
||
|
||
Font audit (every `rPr` must show `ea=굴림`, `latin=Arial`):
|
||
```bash
|
||
python -c "import zipfile,re;from collections import Counter;z=zipfile.ZipFile('deck.pptx');\
|
||
[print(Counter(re.findall(r'<a:ea typeface=\"([^\"]*)\"',z.read(n).decode('utf-8','ignore')))) \
|
||
for n in z.namelist() if re.match(r'ppt/slides/slide\\d+',n)]"
|
||
```
|
||
|
||
## Notes
|
||
|
||
- python-pptx sets only the latin font via `run.font.name`; `_set_font()` also
|
||
writes `<a:ea>`/`<a:cs>` so Korean renders in 굴림. Always go through it.
|
||
- Logo asset: `assets/Ubisam_logo_transparent.png`. On dark divider/closing the
|
||
colored logo has lower contrast but matches the user's original placement.
|
||
- Keep `.md` files under 200 lines (project rule 4); split if it grows.
|
||
- **`table` 높이 상한**: 표는 `_TABLE_MAX_H = 5.3"` (y 1.7" ~ 7.0")로 자동 제한.
|
||
행이 많아도 푸터(`Ubisam | <doc_title>`, y=7.05")를 절대 침범하지 않는다.
|
||
행 높이는 `min(0.5×rows, 5.3) / rows`로 균등 압축된다.
|