Advanced Content Editor

Created: 2026-05-27 · Updated: 2026-08-19

The Advanced Content Editor lets you create PowerPoint shapes directly with C# code, test them live, and save them as snippets in the library. Scripts are executed at runtime using Roslyn (Microsoft C# Scripting).

No Support

The Advanced Content Editor is intended for experienced users with C# knowledge.
PPPTools provides no support for custom scripts.
Faulty scripts can have unexpected effects on the open presentation.


How to Open

  • Ribbon → Tools → Advanced Content Editor
  • or: in the snippet or action management view via Edit code — opens the selected entry's script directly in the editor

Changed

The editor used to be reachable from the task pane's burger menu ≡ as well. That entry has been removed; use the ribbon button instead. The ribbon button itself has also moved: from the Content Manager group to the Tools group — icon and function are unchanged.

The task pane opens automatically in wide mode.


Interface

Area Description
Line numbers Narrow panel to the left of the code field — shows line numbers in sync while scrolling
Code field Enter or paste a C# script
Cursor position Shows current line and column (right side of toolbar: Ln 1 Col 1)
Error panel Shows compiler and runtime errors (appears automatically on error)

Toolbar

The toolbar is organized into button groups. Buttons with a small arrow open a dropdown with options.

Run & Save

Button Function
▶ Run Execute the script on the active slide
💾 Save ▾ Dropdown: save snippet locally or upload as draft to the public library

Dropdown «💾 Save»:

Option Description
Save as Snippet Run script, generate preview image, enter metadata and save locally
Upload as Draft Send snippet as draft to the public library (for admin review and approval)

Analyse & Code

Button Function
📂 Load Load the code of an existing snippet into the editor
🔍 Analyse ▾ Dropdown with analysis and code tools

Dropdown «🔍 Analyse»:

Option Description
Analyse Code Statically analyse the script: show recognized @param definitions, compiler warnings and errors in a dialog
Generate Code (replace) Generate ppptools.* code from the selected shape and replace the editor content (only if empty or showing the starter template)
Generate Code (append) Append the generated code to the existing editor content (with a separator comment)
Show Nodes Visualize the key points of the selected shape with colored markers on the slide
Reset Editor Reset code to the starter template and clear the error panel

Line Numbers & Cursor Position

The narrow panel to the left of the code field automatically shows line numbers — synchronized with vertical scrolling. The current cursor position is shown on the right side of the toolbar:

Ln 12  Col 5

The display updates on every cursor movement.


Available Variables

The following variables are available directly in the script:

Variable Type Description
ppptools AdvancedScriptHelper All PowerPoint operations (shape creation, selection, Boolean ops, styling …)
Params SnippetParamBag Parameter values from the @param dialog (for parameterized snippets)

No direct COM access

oSlide and aPowerPoint are not available in scripts — all operations go through ppptools.* methods. This prevents uncontrolled access to the PowerPoint application.

ppptools Methods (Overview)

→ Full reference with parameters and code examples: PPPTools Reference

Category Methods
Slide SlideWidth, SlideHeight
Create AddShape, AddRect, AddOval, BuildFreeform, AddPolygon, AddPolyline
Selection GetSelected, GetSelectedRange
Boolean ops Union, Intersect, Combine, Subtract
Grouping GroupSelected, Group
Duplicate Duplicate
Z-Order SendBackward, BringForward, SendToBack, BringToFront
Flip FlipH, FlipV
Position CenterOnSlide, Scale
Styling SetFill, SetGradient, SetLine, HideLine, SetText
Asking AskColor, AskRgb, AskFont, AskLine, AskFill
Applying the answer ApplyColor, ApplyFont, ApplyLine, ApplyFill, ToColor
Animations AddAnimation

Important Scripting Rules

Roslyn scripts run in a special context. The following rules must be followed to avoid compiler errors:

Use var / dynamic instead of Shape

The type Shape exists in two namespaces simultaneously (Microsoft.Office.Core and Microsoft.Office.Interop.PowerPoint) — this causes a compiler error.

// ❌ Error — ambiguous reference (when Shape types are used mixed)
Shape oRect = ppptools.AddRect(...);

// ✅ Correct
var oRect = ppptools.AddRect(...);

Enums without the PowerPoint. prefix

A script already has the namespaces Microsoft.Office.Core, Microsoft.Office.Interop.PowerPoint, System, System.Drawing and System.Collections.Generic imported. Enums are therefore written without a prefix — PowerPoint. is not an alias inside a script.

// ❌ Error CS0103: The name 'PowerPoint' does not exist in the current context
ppptools.SetText(sh, "Title", align: PowerPoint.PpParagraphAlignment.ppAlignCenter);

// ✅ Correct
ppptools.SetText(sh, "Title", align: PpParagraphAlignment.ppAlignCenter);

The same goes for MsoTriState, MsoLineDashStyle and every other Office enum. The PPPTools namespace, by contrast, is not imported: spelling out a type from it — FD_FillSpec, say — needs using PPPTools; at the top of the script, or simply var.

Use local functions instead of Action<T>

Action<Shape> fails on the ambiguous type Shape (see above), not on the System namespace — that one is imported. A local function taking dynamic sidesteps the ambiguity:

// ❌ Error
Action<Shape> style = sh => { sh.Fill.ForeColor.RGB = ...; };

// ✅ Correct — local void function
void ApplyStyle(dynamic sh)
{
    sh.Fill.ForeColor.RGB = ...;
}

Selection for Boolean operations

List<Shape> cannot be used directly due to the namespace conflict. Select shapes using .Select() instead:

// ✅ Correct
oShape1.Select(MsoTriState.msoTrue);   // first shape: Replace = true
oShape2.Select(MsoTriState.msoFalse);  // additional shape: Replace = false
ppptools.Union();
dynamic oResult = ppptools.GetSelected();   // retrieve result shape

Setting Colors With a Design Reference

A color sits in a PowerPoint file in one of two ways: as a fixed RGB value, or as a reference to a design color slot — “Accent 1, 40 % lighter”. Only the reference follows a template change. Setting it by hand is awkward, because two properties have to be set in the right order:

// The manual way — and the order is not arbitrary:
// ObjectThemeColor resets Brightness to 0.
sh.Fill.ForeColor.ObjectThemeColor = MsoThemeColorIndex.msoThemeColorAccent1;
sh.Fill.ForeColor.Brightness       = 0.4f;

PPPTools carries its own color model for exactly this — the same one behind the format dialogs. A script can use it directly: the script host references the PPPTools assembly.

The short way

using PPPTools;   // required for the .ApplyTo(...) notation

var color = FD_ColorValue.Parse("accent1+40");
color.ApplyTo(sh.Fill.ForeColor);
color.ApplyTo(sh.Line.ForeColor);

ApplyTo decides for itself: design reference → ObjectThemeColor + Brightness in the right order, fixed color → RGB, “automatic” → the target is left untouched. The return value tells you whether anything was set.

Without using

ApplyTo is an extension method — it only exists with using PPPTools; at the top of the script. To do without, call it in full: PPPTools.FD_ColorApply.ApplyTo(color, sh.Fill.ForeColor);

What fits in the text

Notation Meaning
accent1accent6 the six accent colors of the design
lt1 dk1 lt2 dk2 Light 1 · Dark 1 · Light 2 · Dark 2
hlink folHlink Link · followed link
accent1+40 40 % lighter
accent1-25 25 % darker
#8EAADB fixed RGB value — does not follow the template
auto not set; the target stays as it is

These are the same tokens as in the file format (schemeClr val) and the same ones PPPTools stores in presets and shape tags. Parse never throws — anything unreadable yields auto.

Building one directly instead of parsing

var a = FD_ColorValue.FromTheme(FD_ThemeSlot.Accent1, 0.4f, null);  // reference
var b = FD_ColorValue.FromHex("#8EAADB");                            // fixed
var c = FD_ColorValue.FromRgb(System.Drawing.Color.Firebrick);       // fixed
var d = FD_ColorValue.Auto;                                          // not set

The null in FromTheme is the design source. Setting needs none — the slot goes into the file as a reference and PowerPoint resolves it itself. It is only needed when the script has to know the color itself.

Resolving or reading a color back

var theme = FD_Theme.Snapshot();                    // fresh snapshot of the design colors
System.Drawing.Color rgb = color.Resolve(theme);    // what the reference yields in this deck

var current = FD_ColorApply.Read(sh.Fill.ForeColor, theme);
if (current.HasThemeRef) { /* the shape follows the template */ }

Inside loops

FD_Theme.Snapshot() reads fifteen colors over COM. If you need a color per iteration — puzzle pieces, Wordclouds, tile walls — use FD_Theme.Recent(): the same snapshot, reused for a quarter of a second.

The rule: store the reference, not the resolved value

Resolve exists for display and calculation, not for storage. Writing the resolved number into the shape freezes the color — the next template change passes it by. Fixed is still right where the color is not supposed to follow: brand colors, eyedropper colors, colors taken from an image.

@param color delivers a fixed value

A parameter of type color or themecolor hands the script a System.Drawing.Color — RGB without a reference. To get a design reference in a snippet, build it in code (FD_ColorValue.Parse("accent1")) or let the token be chosen through an @param enum.

Font, border and fill in one go

The same mechanism exists for whole formats. Every field is optional — whatever stays null is left untouched:

using PPPTools;
using System.Collections.Generic;

var theme = FD_Theme.Snapshot();

new FD_FontSpec { Family = "Segoe UI", Size = 18f, Bold = true,
                  Color = FD_ColorValue.Parse("accent2") }
    .ApplyToShape(sh, theme);

new FD_LineSpec { Visible = true, Weight = 1.5f, Dash = FD_LineDash.Dash,
                  Color = FD_ColorValue.Parse("dk1") }
    .ApplyToShape(sh, theme);

new FD_FillSpec
{
    Kind  = FD_FillKind.Gradient,
    Angle = 90f,
    Stops = new List<FD_GradientStop>
    {
        new FD_GradientStop(FD_ColorValue.Parse("accent1"),    0f),
        new FD_GradientStop(FD_ColorValue.Parse("accent1-30"), 1f)
    }
}.ApplyToShape(sh, theme);

Position and transparency of a gradient stop are 0…1, not percentages. ApplyToShape returns how many properties were actually set — 0 means “nothing requested” or “the target supports none of it”.


Opening Format Dialogs From a Snippet

So far this was about the model: colors, fonts, borders and fills written as values in the script. A snippet can also open the format dialogs itself and ask the user in the middle of a run — the very same windows the ribbon opens.

The difference to snippet parameters: those are collected before the run, so it must be clear up front what to ask for. Asking mid-run also works for whatever only emerges while computing — per shape found, per group, depending on an intermediate result.

Question Answer Dialog
ppptools.AskColor(title, start, autoCaption) FD_ColorValue color picker — with design reference
ppptools.AskRgb(title, start) Color? color picker — fixed color value
ppptools.AskFont(title, start, changeMode) FD_FontSpec font
ppptools.AskLine(title, start, changeMode) FD_LineSpec border
ppptools.AskFill(title, start, changeMode) FD_FillSpec fill, gradients included

All arguments are optional. The answer is applied with ApplyColor, ApplyFont, ApplyLine and ApplyFill — those need no using PPPTools;.

Try it: one shape, four dialogs

The snippet creates a rectangle and asks for fill, border, font and text color one after the other — paste, run, done:

var sh = ppptools.AddRect(120, 120, 320, 140);
ppptools.SetText(sh, "Formatted test shape",
    align: PpParagraphAlignment.ppAlignCenter);

var fill = ppptools.AskFill("Fill of the test shape", sh);   // start values from the shape
if (fill == null) return;                                    // null = canceled
ppptools.ApplyFill(sh, fill);

var line = ppptools.AskLine("Border of the test shape", sh);
if (line != null) ppptools.ApplyLine(sh, line);

var font = ppptools.AskFont("Font of the test shape", sh);
if (font != null) ppptools.ApplyFont(sh, font);

var textColor = ppptools.AskColor("Text color", "lt1");      // suggestion: Background 1
if (textColor != null) ppptools.ApplyColor(sh, textColor, "text");

ppptools.ShowResult("Done", "Test shape formatted.", "OK", "success");

Order matters

SetText sets font name and size itself (defaults Arial / 12 pt), so it has to come before ApplyFont — otherwise the text overwrites the font just chosen.

For comparison, the same thing with parameters, asked before the run:

// @param font  Schrift   "Font"       default="Segoe UI,20,Bold"
// @param fill  Fuellung  "Fill"       default="gradient:#0070C0,#00B0F0,90"
// @param line  Rahmen    "Border"     default="#003A66,1.5,solid"
// @param color Textfarbe "Text color" default="#FFFFFF"
// @button Create test shape

var sh = ppptools.AddRect(120, 120, 320, 140);
ppptools.SetText(sh, "Formatted test shape", color: Params.GetColor("Textfarbe"),
                 align: PpParagraphAlignment.ppAlignCenter);

ppptools.ApplyFill(sh, Params.GetFill("Fuellung"));   // FillSpec from @param fill
ppptools.SetLine (sh, Params.GetLine("Rahmen"));      // LineSpec from @param line
ppptools.SetFont (sh, Params.GetFont("Schrift"));     // Font from @param font

The difference is not the effort but the result: AskColor returns the color with its design reference, @param color only passes on a finished color value.

Which one when?

@parambefore the run Ask*during the run
When the question comes once, in the parameter dialog before the start as often as the snippet wants, anywhere
What can be asked whatever is known when writing the snippet also whatever only emerges while computing — per shape found, per group
Preset default="…" in the @param line a shape (its values) or the last answer (start)
Design reference of a color lost at the parameter boundary → fixed color value preserved → FD_ColorValue, and ApplyColor writes it onto the slide
Cancel the run never starts null — the snippet decides: stop, skip, use a default
Readability every setting sits in the snippet header the questions sit in the code, spread across the flow

The two do not exclude each other: a snippet may carry @param lines in its header and ask again later — the basic setting up front, the exception per shape mid-run.

Asking and applying

var color = ppptools.AskColor("Color for the header", "accent1+40");
if (color == null) return;                 // canceled

ppptools.ApplyColor(sh, color);            // fill (default)
ppptools.ApplyColor(sh, color, "line");    // border
ppptools.ApplyColor(sh, color, "text");    // text color
var font = ppptools.AskFont("Font", sh);   // start values read from the shape
if (font != null) ppptools.ApplyFont(sh, font);

var line = ppptools.AskLine("Border", sh);
if (line != null) ppptools.ApplyLine(sh, line);

var fill = ppptools.AskFill("Fill", sh);
if (fill != null) ppptools.ApplyFill(sh, fill);

ApplyFont, ApplyLine and ApplyFill return how many properties were actually set.

null means canceled

All five questions return null when the user closes the dialog without confirming. The Apply methods swallow null silently — they simply do nothing. What a cancel means is therefore up to the snippet: stop (return), skip this one shape (continue), or carry on with a default.

What the dialog opens with

For AskFont, AskLine and AskFill, start takes either a shape — then the dialog reads its current values as start values — or an earlier answer, in which case the dialog reopens where the user left it. For AskColor, start is a storage string ("accent1+40", "#1F4E79", "auto").

Together that gives the loop parameters could not express:

FD_FillSpec last = null;                    // needs using PPPTools; — or just use var
foreach (dynamic sh in ppptools.GetSelectedRange())
{
    string name  = sh.Name;
    object start = (object)last ?? (object)sh;

    last = ppptools.AskFill("Fill for " + name, start);
    if (last == null) break;                // cancel ends the loop
    ppptools.ApplyFill(sh, last);
}

Time limit

A script may compute for at most 5 minutes, after which PPPTools stops it. Only computing time counts: while one of these dialogs is open, the clock stands still. So a loop over many shapes may take as long as you need to answer. (The same applies in the snippet gallery, there with 30 seconds of computing time.)

Changing only what is ticked

The third switch on AskFont, AskLine and AskFill is change mode: every single property may then stay on “unchanged”. Only what the user actually ticks is written, the rest of the shape stays as it is. Without the switch the dialog returns a complete set of values.

var only = ppptools.AskFont("What should change?", sh, true);
if (only != null) ppptools.ApplyFont(sh, only);

Reference instead of value

AskColor returns an FD_ColorValue, and ApplyColor writes the design reference as such onto the shape — the color then follows a template change. Parameters cannot do this: @param color only passes on a finished color value across the parameter boundary.

For the methods that expect a fixed color (SetFill, SetLine, SetGradient), ToColor resolves the reference against the presentation design:

var c = ppptools.AskColor("Color", "accent1");
if (c == null) return;

ppptools.ApplyColor(sh, c);                                   // keeps “Accent 1”
ppptools.SetGradient(sh2, ppptools.ToColor(c), Color.White);  // fixed value

AskRgb is the same thing one step earlier: it asks for a fixed color value right away.

While the dialog is open

The dialogs open in the center of the screen, not at the mouse pointer — the snippet left the pointer somewhere arbitrary. If a progress indicator is running, it steps aside and returns afterwards with its state intact.


Examples

Each example has its own page with a visual preview, full code, and step-by-step explanation.

Foundation examples (Boolean operations):

# Example Topics
1 Rectangle ppptools.AddRect, fill color, removing the border
2 Circle ppptools.AddOval, center-point calculation, border color
3 Union Selection pattern, ppptools.Union(), ppptools.GetSelected()
4 Square with Hole ppptools.Combine(), true geometric holes
5 Gear Wheel Chaining 3 Boolean ops, Adjustments[1], all tooth counts

Full parameterized examples (all ppptools methods):

Example ppptools Methods
Gear Wheel (parameterized) AddShape, AddOval, GetSelected, GetSelectedRange, Union, Intersect, Combine, SlideWidth/Height
Post-it (parameterized) BuildFreeform, AddRect, GetSelected, Duplicate, Intersect, Subtract, FlipH, SendBackward, SetGradient, HideLine, Group
Persona (parameterized) BuildFreeform, AddOval, AddRect, Group, Scale, SlideWidth/Height

Workflow

Generate Code from a Selected Shape

The Generate Code (replace) and Generate Code (append) options read the currently selected shape in PowerPoint and produce immediately executable ppptools.* code.

Replace vs. Append:

Option Behavior
Generate Code (replace) Editor is empty or shows only the starter template → code is inserted directly, replacing the content
Generate Code (append) Existing code is preserved → new code is appended with a separator comment

What is generated:

Shape type Generated code
Rectangle ppptools.AddRect(...)
Oval / Circle ppptools.AddOval(...)
Other AutoShape ppptools.AddShape(MsoAutoShapeType.xxx, ...)
FreeForm (straight segments only) ppptools.AddPolygon(new float[]{...}, new float[]{...})
FreeForm (with curves) ppptools.BuildFreeform(...) + AddNodes(...)
Group Recursive code for all members + ppptools.Group(...)
Fill ppptools.SetFill(...) or ppptools.SetGradient(...)
Line ppptools.SetLine(...) or ppptools.HideLine(...)
Text ppptools.SetText(...)
Animations ppptools.AddAnimation(...) + timing

Ideal workflow

Draw a shape manually in PowerPoint → Generate Code (replace) → the editor shows the exact code
to recreate it → adjust parameters → ▶ Run to test → 💾 Save as Snippet.


Show Nodes

The Show Nodes option places colored markers directly on the slide for each key point of the selected shape.

FreeForm Shapes

For FreeForm shapes, each node is labeled with its coordinates, index, segment type (Line / Curve) and editing type (Corner / Auto).

Color coding:

Color Meaning
🟢 Green Start node (index 0)
🔴 Red Intermediate nodes
🔵 Blue Last node

Standard Shapes (Rectangle, Oval, AutoShape …)

For standard shapes, the 4 corner points (TL / TR / BR / BL) and the center point (C) are displayed:

Marker Position Shape
TL / TR / BR / BL Corners Small blue circle
C Center Small orange diamond

An info label above the shape shows name, type and dimensions.

Clean up

Delete the markers after analysis: select all shapes named Node_*, NodeLabel_* or NodeInfo_* and delete them, or use Ctrl+Z to undo.


Analyse Code

The Analyse Code option statically checks the current script and shows the result in a dialog:

  • Recognized @param definitions (name, type, default value)
  • Compiler warnings
  • Compiler errors

Useful to verify that all @param declarations are correct before running the script.

→ More about @param: Parameterized Snippets


Testing a Script

  1. Enter code in the code field or load an existing snippet via 📂 Load
  2. Click ▶ Run — the shape appears on the active slide
  3. If errors occur: read the error panel, fix the code, run again
  4. Delete test shapes manually (Delete key)

Note

A presentation must be open with an active slide.


Saving as a Snippet

  1. Click 💾 Save ▾ → Save as Snippet
  2. The script runs — newly created shapes are detected automatically
  3. A preview image is generated from the new shapes
  4. Shapes are deleted after the preview is exported
  5. Metadata dialog: enter Name*, Category, Tags, Description etc.
  6. Click Save — the snippet appears immediately in the gallery

Technical Name & Grouping

The metadata dialog also offers Technical Name (target object name on insertion) and Grouping (combine multiple created objects). Details: Save Snippet.


Editing an Existing Snippet

You open an already saved Code snippet not via 📂 Load, but directly from the manager:

  1. Content Manager → Snippets → Manage, select the snippet
  2. Click Edit code below the preview image

The editor opens in snippet edit mode with a reduced toolbar:

Button Function
▶ Run Run the script on the active slide (as usual)
Save Overwrites the code.cs of this snippet — same ID, metadata unchanged
Rebuild preview Creates the preview image again — from the current editor code, not from the saved file
Close Back to snippet management, with the snippet selected again

Snippet's own files

In edit mode ppptools.AssetPath() points to the folder of the edited snippet — bundled images or data lists therefore already work while testing in the editor.

Code snippets only

For fragment and picture snippets Edit code is disabled. Opening it requires a Pro license — just like the editor itself.


Uploading as a Draft to the Public Library

Finished snippets can be sent directly from the editor as a draft to the public library:

  1. Click 💾 Save ▾ → Upload as Draft
  2. The script runs and a preview image is generated
  3. Fill in the metadata dialog (Name*, Category, Tags, Description)
  4. The snippet is sent to the library server as a Draft
  5. An admin reviews and publishes the snippet

Draft status

After uploading, the snippet is not yet public — it must first be reviewed and approved by an admin.

Publish Flow


Microsoft Documentation

Topic Link
All shape types (MsoAutoShapeType) learn.microsoft.com
Shapes.AddShape method learn.microsoft.com
Shape object (all properties) learn.microsoft.com
FillFormat (fill) learn.microsoft.com
LineFormat (border) learn.microsoft.com