Seed UNS hierarchy across 6 sites; rebrand outputs to SCADA IT/OT with ZB template
Lands per-site UNS subtree files (Warsaw West/North, Shannon, Galway, TMT, Ponce) seeded from OpenText facility docs — Warsaw split confirmed as numbered = legacy Zimmer = West, lettered = legacy Biomet = North. Renames project framing from "Shopfloor IT/OT" to "SCADA IT/OT" for accuracy. Extracts a ZB-branded PowerPoint template from example_powerpoint.pptx and wires it into the outputs pipeline. Trims deck from 18 to 16 slides (BOBJ->Power BI transferred to another team, Non-Goals and Asks dropped); goal-state BOBJ analysis pruned to a stub.
This commit is contained in:
54
templates/README.md
Normal file
54
templates/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Zimmer Biomet PowerPoint Template
|
||||
|
||||
Clean reusable template extracted from `example_powerpoint.pptx` (a representative ZB-branded staff-meeting deck). Captures the two-layout pattern observed there:
|
||||
|
||||
- **Cover slide** — full-bleed branded background image with the deck title overlaid in white in the upper-left.
|
||||
- **Content slide** — title at top in Zimmer blue, content area, blue branded strip across the bottom, slide number in the lower-right, "CONFIDENTIAL – FOR ZIMMER BIOMET INTERNAL USE ONLY" in the lower-left margin above the strip.
|
||||
|
||||
## Files
|
||||
|
||||
```
|
||||
templates/
|
||||
├── README.md # this file
|
||||
├── build_template.py # regenerates zb-template.pptx from the assets
|
||||
├── zb-template.pptx # the template (3 slides: 1 cover + 2 content examples)
|
||||
└── assets/
|
||||
├── cover-background.jpeg # 2667×1500, full-bleed cover image (Zimmer Biomet branded)
|
||||
└── bottom-border.jpg # 2664×147, narrow horizontal strip for content slides
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
1. **Pick the deck up by `zb-template.pptx`** and replace the title text on slide 1, then duplicate slide 2 for each content slide you need.
|
||||
2. **Or write a slide-generator** that places the assets in the same positions (see `build_template.py` for the canonical positions in inches).
|
||||
3. **To update the template** (e.g., new ZB branding lands), drop replacement files into `assets/` with the same filenames and re-run `python3 build_template.py`.
|
||||
|
||||
## Design specifications
|
||||
|
||||
| Property | Value |
|
||||
|---|---|
|
||||
| Slide size | 13.33" × 7.5" (16:9) |
|
||||
| Title font | Arial Bold |
|
||||
| Cover title | 28pt, color `#F4F4F4` (near-white), positioned at (0.92", 1.38") size 6.0"×1.89" |
|
||||
| Cover subtitle | 14pt, color `#F4F4F4`, positioned at (0.92", 3.30") |
|
||||
| Content title | 28pt, color `#0066B3` (Zimmer blue), positioned at (0.92", 0.40") size 11.5"×0.85" |
|
||||
| Content body | 18pt, color `#333333`, positioned at (0.92", 1.50") size 11.5"×4.80" |
|
||||
| Bottom border | image, positioned at (0.01", 6.76") size 13.32"×0.74" |
|
||||
| Confidentiality text | 8pt, color `#404040`, "CONFIDENTIAL – FOR ZIMMER BIOMET INTERNAL USE ONLY", positioned at (0.29", 6.55") |
|
||||
| Slide number | 10pt, color `#2B2A80` (dark navy), positioned in the lower-right at (12.85", 6.55") |
|
||||
|
||||
Brand colors picked up from the example deck's slide layout XML:
|
||||
|
||||
- Zimmer blue: `#0066B3`
|
||||
- Dark navy / Z-purple: `#2B2A80`
|
||||
- Cover-text near-white: `#F4F4F4`
|
||||
|
||||
## What's intentionally left out
|
||||
|
||||
The example deck contained 14 slide masters and 12+ layouts accumulated over many years (multiple legacy decks merged together). This template captures **only the two patterns the user identified as universal** (cover + content-with-bottom-border) and discards the rest. If a specific historical layout is needed (e.g., the "Living Our Mission and Guiding Principles" branded chart on slide 3, or the "Title Slide" layout used on slide 13), copy the relevant slide out of `example_powerpoint.pptx` separately — that one-off content shouldn't pollute the reusable template.
|
||||
|
||||
## Relationship to `outputs/`
|
||||
|
||||
The `outputs/` auto-generation pipeline **uses this template** (as of 2026-04-30): `outputs/workspace/generate.js` references `templates/assets/cover-background.jpeg` for slide 1 and `templates/assets/bottom-border.jpg` as the bottom-border strip on slides 2–18, plus reskins content-slide HTMLs to the ZB color palette. See the `2026-04-30` entry in `outputs/run-log.md` for the integration details.
|
||||
|
||||
**Coordinate note:** the template's canonical coordinates are at 13.33"×7.5". The current pipeline runs at 10"×5.625" (pptxgen's `LAYOUT_16x9`, matching the existing 720×405pt HTML CSS). `generate.js` scales the template coordinates by 0.75× to fit. If the pipeline ever moves to native 13.33"×7.5", drop the scaling and use template coords as published in the table above.
|
||||
BIN
templates/assets/bottom-border.jpg
Normal file
BIN
templates/assets/bottom-border.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
templates/assets/cover-background.jpeg
Normal file
BIN
templates/assets/cover-background.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
133
templates/build_template.py
Normal file
133
templates/build_template.py
Normal file
@@ -0,0 +1,133 @@
|
||||
"""Build the Zimmer Biomet PowerPoint template from extracted assets.
|
||||
|
||||
Reads `assets/cover-background.jpeg` and `assets/bottom-border.jpg`,
|
||||
emits `zb-template.pptx` with two slides demonstrating the cover and
|
||||
content layouts. Re-run this script whenever assets change.
|
||||
"""
|
||||
from pptx import Presentation
|
||||
from pptx.util import Inches, Pt, Emu
|
||||
from pptx.dml.color import RGBColor
|
||||
from pptx.enum.text import PP_ALIGN
|
||||
import os
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
ASSET = os.path.join(HERE, "assets")
|
||||
OUT = os.path.join(HERE, "zb-template.pptx")
|
||||
|
||||
# Slide-size constants in EMU (English Metric Units; 914400 EMU = 1 inch)
|
||||
SLIDE_W = Inches(13.33)
|
||||
SLIDE_H = Inches(7.5)
|
||||
|
||||
# Brand colors from the example deck's slideLayout22 / slideLayout33 XML
|
||||
COVER_TITLE_COLOR = RGBColor(0xF4, 0xF4, 0xF4) # near-white for cover title over dark bg
|
||||
CONTENT_TITLE_COLOR = RGBColor(0x00, 0x66, 0xB3) # Zimmer blue
|
||||
SLIDE_NUMBER_COLOR = RGBColor(0x2B, 0x2A, 0x80) # dark navy/purple
|
||||
CONFIDENTIAL_COLOR = RGBColor(0x40, 0x40, 0x40) # dark gray on the white margin above the border
|
||||
|
||||
CONFIDENTIAL_TEXT = "CONFIDENTIAL – FOR ZIMMER BIOMET INTERNAL USE ONLY"
|
||||
|
||||
|
||||
def add_textbox(slide, left, top, width, height, text, *, font_size=12,
|
||||
color=None, bold=False, align=None, font_name="Arial"):
|
||||
tx = slide.shapes.add_textbox(left, top, width, height)
|
||||
tf = tx.text_frame
|
||||
tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = 0
|
||||
p = tf.paragraphs[0]
|
||||
if align is not None:
|
||||
p.alignment = align
|
||||
r = p.add_run()
|
||||
r.text = text
|
||||
r.font.name = font_name
|
||||
r.font.size = Pt(font_size)
|
||||
r.font.bold = bold
|
||||
if color is not None:
|
||||
r.font.color.rgb = color
|
||||
return tx
|
||||
|
||||
|
||||
def build_cover(slide):
|
||||
"""Cover slide: full-bleed background image + title in upper-left, white text."""
|
||||
slide.shapes.add_picture(
|
||||
os.path.join(ASSET, "cover-background.jpeg"),
|
||||
left=0, top=0, width=SLIDE_W, height=SLIDE_H,
|
||||
)
|
||||
add_textbox(
|
||||
slide,
|
||||
left=Inches(0.92), top=Inches(1.38),
|
||||
width=Inches(6.0), height=Inches(1.89),
|
||||
text="Deck Title",
|
||||
font_size=28, bold=True, color=COVER_TITLE_COLOR,
|
||||
)
|
||||
add_textbox(
|
||||
slide,
|
||||
left=Inches(0.92), top=Inches(3.30),
|
||||
width=Inches(6.0), height=Inches(0.5),
|
||||
text="Subtitle / date / author",
|
||||
font_size=14, color=COVER_TITLE_COLOR,
|
||||
)
|
||||
|
||||
|
||||
def build_content(slide, *, title="Section title", page_number="2"):
|
||||
"""Content slide: title at top, content area, bottom border + slide number + confidentiality text."""
|
||||
add_textbox(
|
||||
slide,
|
||||
left=Inches(0.92), top=Inches(0.40),
|
||||
width=Inches(11.5), height=Inches(0.85),
|
||||
text=title,
|
||||
font_size=28, bold=True, color=CONTENT_TITLE_COLOR,
|
||||
)
|
||||
placeholder = add_textbox(
|
||||
slide,
|
||||
left=Inches(0.92), top=Inches(1.50),
|
||||
width=Inches(11.5), height=Inches(4.80),
|
||||
text=("Body content goes here.\n"
|
||||
"• Bullet one\n"
|
||||
"• Bullet two\n"
|
||||
"• Bullet three"),
|
||||
font_size=18, color=RGBColor(0x33, 0x33, 0x33),
|
||||
)
|
||||
placeholder.text_frame.word_wrap = True
|
||||
|
||||
slide.shapes.add_picture(
|
||||
os.path.join(ASSET, "bottom-border.jpg"),
|
||||
left=Inches(0.01), top=Inches(6.76),
|
||||
width=Inches(13.32), height=Inches(0.74),
|
||||
)
|
||||
add_textbox(
|
||||
slide,
|
||||
left=Inches(0.29), top=Inches(6.55),
|
||||
width=Inches(8.0), height=Inches(0.20),
|
||||
text=CONFIDENTIAL_TEXT,
|
||||
font_size=8, color=CONFIDENTIAL_COLOR,
|
||||
)
|
||||
add_textbox(
|
||||
slide,
|
||||
left=Inches(12.85), top=Inches(6.55),
|
||||
width=Inches(0.40), height=Inches(0.20),
|
||||
text=page_number,
|
||||
font_size=10, color=SLIDE_NUMBER_COLOR, align=PP_ALIGN.RIGHT,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
prs = Presentation()
|
||||
prs.slide_width = SLIDE_W
|
||||
prs.slide_height = SLIDE_H
|
||||
|
||||
blank = prs.slide_layouts[6]
|
||||
|
||||
cover = prs.slides.add_slide(blank)
|
||||
build_cover(cover)
|
||||
|
||||
content = prs.slides.add_slide(blank)
|
||||
build_content(content, title="Content slide example", page_number="2")
|
||||
|
||||
second_content = prs.slides.add_slide(blank)
|
||||
build_content(second_content, title="Another content slide", page_number="3")
|
||||
|
||||
prs.save(OUT)
|
||||
print(f"Wrote {OUT}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
templates/zb-template.pptx
Normal file
BIN
templates/zb-template.pptx
Normal file
Binary file not shown.
Reference in New Issue
Block a user