Files
playbook/antigravity-awesome-skills/skills/pptx-deck-creation/references/visual-asset-adapters.md
T
2026-07-20 00:03:02 +00:00

7.4 KiB

Visual Asset Guidelines

This skill cannot bundle helper scripts, so these guidelines show how to perform each visual-asset ability inline using public APIs and short, self-contained snippets you run at request time (scratch cell or terminal).

How to use a guideline:

  1. Pick the ability you need below.
  2. Run the inline snippet (adjust inputs) in an ephemeral scratch file or terminal — do not save it into the skill, since the skill keeps only references/.
  3. Place the returned local asset path into layout_tree.objects with content.path, content.alt, bbox, z_index, and classification.

Shared rules:

  • Always return a local file path for any placed asset, plus content.alt.
  • Record provenance (source, license, provider, model) for audits.
  • On failure, write a failure manifest; never substitute a placeholder and call it generated.
  • Never request secrets in chat or a prompt dialog. For cloud auth use .env or az login.
  • Before a billable generation call or any request that sends user-provided or source material to a third party, disclose the provider/model, the material that will leave the machine, likely cost, and output path. Obtain explicit confirmation unless the user already authorized that exact operation.

Use the public Iconify API — no key required.

  • Search: https://api.iconify.design/search?query=<q>&limit=<n>
  • Download SVG: https://api.iconify.design/<prefix>/<name>.svg?color=%23<hex>
import json, urllib.parse, urllib.request
from pathlib import Path

def icon_search(query, limit=8, prefix=None, color=None, out_dir="assets/icons"):
    q = urllib.parse.quote(query)
    url = f"https://api.iconify.design/search?query={q}&limit={limit}"
    if prefix:
        url += f"&prefix={urllib.parse.quote(prefix)}"
    data = json.load(urllib.request.urlopen(url, timeout=15))
    Path(out_dir).mkdir(parents=True, exist_ok=True)
    results = []
    for icon_id in data.get("icons", []):
        pfx, name = icon_id.split(":", 1)
        svg_url = f"https://api.iconify.design/{pfx}/{name}.svg"
        if color:
            svg_url += f"?color=%23{color}"
        svg_path = Path(out_dir) / f"{pfx}_{name}.svg"
        svg_path.write_bytes(urllib.request.urlopen(svg_url, timeout=15).read())
        results.append({"id": icon_id, "svg_path": str(svg_path), "license": "per-set (see iconify.design)"})
    return {"query": query, "results": results}
  • Prefer simple, single-color icons matching the theme accent.
  • Use icons as supporting cues, not replacements for required text.

Prefer the VS Code fetch tools (fetch_webpage) or an MCP image-search tool you have available. When you already have a direct image URL (from search results or the user), download it locally:

import urllib.request
from pathlib import Path

def download_image(url, out_path="assets/images/img1.jpg"):
    Path(out_path).parent.mkdir(parents=True, exist_ok=True)
    req = urllib.request.Request(url, headers={"User-Agent": "pptx-builder/1.0"})
    Path(out_path).write_bytes(urllib.request.urlopen(req, timeout=20).read())
    return {"url": url, "local_path": out_path}
  • Capture source and license for attribution; verify usage rights before placing.
  • Reference the saved file via content.path; do not hotlink remote URLs into the deck.
  • Do not use image placeholders as fallback assets; select an approved asset or omit the object.

3. Vector Asset Decision

Use a true SVG only when it is already a clean vector asset or when the source contains no essential text or data that needs editing. Do not wrap a raster in an SVG and treat the result as editable.

  • Do not trace a raster merely to satisfy an editability requirement.
  • If an illustration contains essential text, recreate the text with native PowerPoint objects.
  • Keep the original raster or a non-compliant SVG only as a supporting visual or hidden reference.

4. Text → Infographic

Generate through a user-managed provider (OpenAI or Azure OpenAI). Read credentials from environment; never accept secrets via chat.

Before running the snippet, obtain the external-call confirmation described in the shared rules. If output_path or its manifest already exists, choose a new path or obtain separate explicit overwrite confirmation; do not silently replace either file.

import base64, json, os
from pathlib import Path
from openai import OpenAI, AzureOpenAI  # provided by the user's environment

def text_to_infographic(prompt, output_path, provider="openai",
                        model_or_deployment="gpt-image-1", size="1024x1024",
                        confirmed=False, allow_overwrite=False):
    output = Path(output_path)
    manifest_path = output.with_suffix(".manifest.json")
    existing = [path for path in (output, manifest_path) if path.exists()]
    if existing and not allow_overwrite:
        raise FileExistsError(f"Refusing to overwrite existing paths: {existing}")
    manifest_path.parent.mkdir(parents=True, exist_ok=True)
    manifest = {"provider": provider, "model_or_deployment": model_or_deployment,
                "output_path": output_path}
    if not confirmed:
        manifest.update(status="cancelled", error="External generation was not confirmed")
        manifest_path.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
        return manifest
    try:
        if provider == "azure-openai":
            client = AzureOpenAI(
                azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
                api_key=os.environ.get("AZURE_OPENAI_API_KEY"),
                api_version=os.environ.get("AZURE_OPENAI_API_VERSION", "2024-02-01"),
            )
        else:
            client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
        result = client.images.generate(model=model_or_deployment, prompt=prompt, size=size)
        output.write_bytes(base64.b64decode(result.data[0].b64_json))
        manifest["status"] = "ok"
    except Exception as exc:  # report, never fake-generate
        manifest.update(status="error", error=str(exc))
    manifest_path.write_text(json.dumps(manifest, indent=2), encoding="utf-8")
    return manifest
  • Collect missing values via vscode_askQuestions: provider, prompt, model/deployment, size, output path.
  • Before calling the function, disclose the provider/model, material leaving the machine, likely cost, and output path. Set confirmed=True only after the user explicitly authorizes that exact external request. Set allow_overwrite=True only after separate explicit approval to replace every existing output or manifest path.
  • Use .env or az login for auth; never ask for keys/tokens in chat or the dialog.
  • Use generated art as a supporting visual. Recreate essential text, labels, metrics, and steps with native PowerPoint objects. Add a vector asset only when it is a clean, editable source.

5. NotebookLM Infographic Bridge

NotebookLM has no public generation API, so treat this as an optional, user-configured bridge.

  • If the user has a NotebookLM/MCP bridge tool configured, call it with source_refs + prompt, then save the returned image locally and record provenance.
  • If no bridge is configured, fall back to Text → Infographic (section 4) or omit the asset.
  • Apply the same confirmation, overwrite, provenance, and failure-manifest rules as the other generation guidelines.