Reference for every ai / ai_agents function-call plugin this module ships,
grouped the way varbase_ai_figma_base's recipe wires them onto the
canvas_ai_orchestrator agent: understand the design, understand the site and
decide, build what the decision chose, connect it to the rest of the site,
then check and improve it. Each entry documents what its execute() method
actually does (inputs, permission checks and return shape), not the
LLM-facing marketing copy in its description.
All plugins live in src/Plugin/AiFunctionCall/ and share the varbase_ai_figma:
id prefix. Machine permission names are the exact strings checked in code; a
user needs any one of the listed permissions, not all of them.
1. Understand the design¶
Before anything is built, the agent reads the Figma file itself.
Figma: List Design Pages (ai_figma:list_design_pages) is not part of this
module: it ships with the AI Figma
dependency and lists a file's top-level frames so the agent can plan one
Canvas page per design frame. See
AI Figma's own reference
for it. This page documents this module's own 29 tools, starting with the one
that reads the design itself.
Read the design¶
| Plugin id | varbase_ai_figma:get_design_context |
| Function name | varbase_figma_get_design_context |
| Group | information_tools |
| Permission | use ai figma design context, or administer ai agents / use Drupal Canvas AI |
Class: FigmaGetDesignContext.
Inputs¶
All optional; a pasted figma_url overrides file_key/node_id when both are
given, and an empty file_key falls back to the default file key configured
on ai_figma.
| Input | Required | Description |
|---|---|---|
figma_url |
No | A figma.com link, or the whole user message containing an @-prefixed one. File key and node id are extracted from it. |
file_key |
No | A Figma file key. Ignored if figma_url resolves one. |
node_id |
No | Node id (1283:979 or 1283-979) to scope the read. Leave empty to read the top of the file. |
Output¶
A YAML document combining the Figma read with what the active theme can already build:
figma_file_key: RJkuWNHla1P8VYHa5z6dnL
figma_node_id: '1:2'
colors: { ... }
typography: { ... }
node_outline: [ ... ]
content_texts:
- { text: 'Build faster with Varbase', layer: Heading, size: 52 }
available_components:
sections: [ ... ]
cards: [ ... ]
heroes: [ ... ]
content: [ ... ]
building_blocks:
read_context: 'BUILD ON THE EXISTING SITE. ...'
webforms: { 'webform:contact': Contact }
views_listings: { ... }
content_types: { ... }
instruction: '...'
accessibility: '...'
available_components comes from FigmaToCanvasBuilder::componentsByFamily()
(the same live theme registry component_match scores against).
building_blocks lists visitor-usable Webforms (open, not archived, not a
template_* sample), placeable Views listing blocks (admin/a11y views
excluded), and content types, so the agent reuses real Drupal building blocks
instead of hand-written markup. instruction and accessibility are read
from the "Figma Build Rules" / "Figma Accessibility Rules" AI Context items
when published, else from ai_figma.settings config, never hard-coded.
Use it with the Canvas AI assistant¶
Add Read the design to the assistant's tool list and paste (or @-mention)
a Figma link. The assistant reads colours, typography, real copy and the
site's existing components in one call, then builds from what already exists
instead of inventing new markup.
2. Understand the site, then decide¶
Nothing is placed before the site's own inventory is scanned and each design region is scored against it. This is what makes "reuse before create" a real decision rather than a hope.
See what we already have¶
| Plugin id | varbase_ai_figma:scan_inventory |
| Function name | varbase_figma_scan_inventory |
| Group | information_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: ScanInventory, backed by the varbase_ai_figma.inventory
(InventoryScanner) service.
Inputs¶
| Input | Required | Description |
|---|---|---|
kinds |
No | Comma-separated subset of component, pattern, block, view. Empty = all four. |
roles |
No | Comma-separated content roles (e.g. heading,image,button). Only candidates that can hold all of them are returned. |
limit |
No | Max entries per kind. Defaults to 40. |
Output¶
YAML grouped by kind, each entry keyed id, label, holds (its content
roles), plus kind-specific detail: component entries add props (with enum
values truncated to 8 + …) and slots; pattern entries add a structure
summary (components x N, depth, repeat) and made_of; view entries add
block_displays and lists (base table); block entries add category.
component (12):
- id: sdc.vartheme_bs5.card-hero
label: Card Hero
holds: 'heading, body, button, image'
props:
heading_level: 'string [h2|h3|h4]'
background_color: 'string [bg-primary|bg-dark|bg-light]'
slots: media
pattern (3):
- id: vaf_feature_grid
label: Feature Grid
holds: 'heading, body, icon'
section: '4 components, depth 2, repeats 3'
made_of: 'card-icon x3, heading x1'
Excludes machinery per varbase_ai_figma.settings:resolver.exclude (layout
wrappers, theme chrome, admin Views, system blocks); see
Configuration.
Use it with the Canvas AI assistant¶
Always call this before resolve_design. The assistant reads the real
props/enums/slots each component accepts, so it never invents a prop name or
writes free text into an enum.
Decide what to reuse and what to build¶
| Plugin id | varbase_ai_figma:resolve_design |
| Function name | varbase_figma_resolve_design |
| Group | information_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: ResolveDesign, backed by the varbase_ai_figma.resolver
(DesignResolver) service, tuned entirely by varbase_ai_figma.settings:resolver
(role hints, scoring weights, penalties, thresholds; see
Configuration).
Inputs¶
| Input | Required | Description |
|---|---|---|
regions |
Yes | A JSON array (a single region object is also tolerated). Each: {"name","roles":[...],"repeat":1,"dynamic":false,"section":true,"content":{...},"values":{...}}. Roles: heading, body, image, video, button, link, badge, list, icon, quote, stat, form, logo, author, date, price. |
kinds |
No | Restrict the palette scored against: comma-separated component, pattern, block, view. |
Empty/invalid regions returns a usage hint rather than throwing.
Output¶
Plain-language prose (not YAML): deliberately no machine names, ids or scores, per the tool's own instruction to the calling agent. One paragraph per region ("Hero - use what we already have. Use \"Card Hero\", a component already on this site."), followed by a one-line tally ("In short: 2 parts we already have, 1 part that needs adjusting.").
Internally each region resolves to a verdict:
- REUSE (score ≥
thresholds.reuse_at, default 85): place the named thing with the props it hands back. - ADAPT (≥
thresholds.adapt_at, default 60): use the closest thing, filling only the named gaps. - CREATE (below both): build only what is listed as missing; the closest existing thing is still named so the new component is scoped to the gap.
Scoring sums role_coverage (45), structural_fit (20), kind_fit (15),
value_fit (10) and name_affinity (10), minus penalties for
missing_required (15), dynamic_mismatch (20) and subject_mismatch (35).
Use it with the Canvas AI assistant¶
Call it after scan_inventory, one entry per design region. Repeat its answer
to the user verbatim: it is already written for a site builder to read, not
for a machine to parse further.
Find the closest component¶
| Plugin id | varbase_ai_figma:component_match |
| Function name | varbase_figma_component_match |
| Group | information_tools |
| Permission | use ai figma design context, or administer ai agents / use Drupal Canvas AI |
Class: FigmaComponentMatch. A deterministic (no LLM call) alternative to
resolve_design, scoped to a single Figma node against the theme's component
library alone (not patterns/blocks/views).
Inputs¶
| Input | Required | Description |
|---|---|---|
figma_url |
No | A Figma link (or @-prefixed mention); overrides file_key/node_id. |
file_key |
No | Figma file key. Falls back to the configured default. |
node_id |
No | Node id to scope the match. |
Output¶
YAML with a fingerprint of the node (guessed kind: hero, card, cta,
banner, …; family bucket; heading/paragraph/label counts; has_button /
has_image; needs; dominant_color), up to 3 candidates each with a
0-100 score, why (the signals that fired) and differences (missing
roles), and an overall recommendation:
reuse: top score ≥ 80.extend: top score 50-79;rationalenames what to add.create_new: nothing ≥ 50, or the library is empty.
Scoring is transparent and documented in scoreCandidate(): name/keyword
overlap with the guessed kind (up to 55), family-bucket affinity (up to 25),
and prop affinity approximated from the component's bare name (up to 20,
since the builder's real prop readers are protected and not available to this
tool).
fingerprint:
kind: hero
family: heroes
headings: 1
paragraphs: 1
has_button: true
candidates:
- component: card-hero
score: 82
family: heroes
why: ['name matches the "hero" kind', 'same "heroes" family as the node']
recommendation: reuse
rationale: 'Component "card-hero" is a strong match (82/100) ...'
Use it with the Canvas AI assistant¶
Use this for a single pasted component/node when a full region-by-region
resolve_design call is more than is needed (e.g. "does this Figma button
already exist as a component?".
3. Build what the decision chose¶
Once the decision is made, these tools place, edit and export the actual Canvas content.
Build the page¶
| Plugin id | varbase_ai_figma:create_canvas_page |
| Function name | varbase_figma_create_canvas_page |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: CreateCanvasPage.
Inputs¶
| Input | Required | Description |
|---|---|---|
title |
Yes | The Canvas page title. If a page with this title exists, its components are replaced. |
components |
Yes | Comma-separated list, placed in order. Mixes: a code component machine name; a theme SDC (sdc.vartheme_bs5.card-hero, or the bare leaf card-hero); webform:<id>; a block/Views block (views_block.blog-all, block.<id>, system_*). |
Output¶
Each name is classified (classify()) into webform / sdc / block / js
in that priority order (an author's own code component always wins over a
same-named system block); unknown names return the error message plus the
list of existing code components. Draft code components are enabled and
exposed to the Canvas component library (ComponentSourceManager::generateComponents())
before placement, the same step the editor's "Add to components" button
performs. Instance inputs are seeded: SDC props from prop_field_definitions
defaults, JS props from each prop's first examples[0], and block/Views/Webform
settings from the block's own default_settings (with webform_id filled in
for a Webform).
On success: Created Canvas page 12 ("About Varbase") at /page/12 with component(s): hero, stats, cta.
Use it with the Canvas AI assistant¶
The multi-page build primitive. Prefer passing a resolved Views/Webform/system
block reference over a hand-coded component whenever resolve_design named
one, so listings and forms stay live instead of frozen into markup.
Change a page that already exists¶
| Plugin id | varbase_ai_figma:page_edit |
| Function name | varbase_figma_page_edit |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: CanvasPageEdit, backed by varbase_ai_figma.page_analyzer and
varbase_ai_figma.page_editor.
Inputs¶
| Input | Required | Description |
|---|---|---|
page |
Yes | canvas_page numeric id or exact title. |
action |
Yes | One of move, add, remove, swap, set_columns, set_prop. |
target |
For all but add |
Component uuid, exact label, or machine name. |
position |
For move/add |
before \| after \| start \| end (default end). |
anchor |
For before/after |
The reference component. |
component |
For add/swap |
What to place: same forms create_canvas_page accepts. |
columns |
For set_columns |
A Canvas columns value, e.g. 50-50, 33-33-33, 100. |
prop / value |
For set_prop |
The instance prop to set and its new value. |
Output¶
Each action reports what changed and then the full resulting component order
(1. Hero [uuid]; 2. Stats [uuid]; ...) so the caller can confirm without a
second read. When target/anchor is empty, not found, or ambiguous, the
message lists every component on the page (label (component_id=..., uuid=...))
instead of failing silently, the disambiguation path the PRD calls for.
add/swap reuse the same component classification and default-inputs logic
as create_canvas_page; swap keeps only the inputs the new component
declares (falling back to keeping everything when that can't be discovered).
Use it with the Canvas AI assistant¶
Use for a single, surgical change after a page exists (move a section,
swap a block, widen a column) instead of calling create_canvas_page again
and losing everything else on the page.
Fix the details of one thing on a page¶
| Plugin id | varbase_ai_figma:update_component_inputs |
| Function name | varbase_figma_update_component_inputs |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: UpdateComponentInputs, backed by varbase_ai_figma.page_editor.
Adapted from ai_agents_experimental_collection's
ai_agents_canvas:update_component_inputs.
Inputs¶
| Input | Required | Description |
|---|---|---|
page_id |
Yes | The numeric canvas_page id. |
component_uuid |
Yes | The instance uuid (from the page's component tree). |
inputs |
Yes | A JSON object of prop => value to merge in: only the props sent are changed. |
Output¶
Updated 2 prop(s) on component <uuid> in page "About Varbase" (id 12): heading_text, cta_label.
Each prop is merged one at a time via setProp(), which preserves whether the
row stores inputs as an array or a JSON string.
Use it with the Canvas AI assistant¶
The fine-grained half of a build-then-verify loop: after previewing a page, fix one heading or swap one label without touching the rest of the tree.
Put it in the header or footer¶
| Plugin id | varbase_ai_figma:place_in_region |
| Function name | varbase_figma_place_in_region |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: PlaceInRegion.
Inputs¶
| Input | Required | Description |
|---|---|---|
components |
Yes | Comma-separated, placed in order: system blocks (system_branding_block, system_menu_block.main) preferred; a custom code component name as fallback. |
region |
Yes | header or footer. |
mode |
No | replace (default) or append. |
Output¶
Resolves js.<name> then block.<name> (tolerating :/. derivative
spellings). Creates the theme's PageRegion config entity from the block
layout if it doesn't exist yet, enables it, and writes the resolved
components into its component_tree (fresh uuids, block default settings
minus id/provider). Done: placed system_branding_block, system_menu_block.main into the global header region of vartheme_bs5 (replaced).
Unmatched names are listed separately, not silently dropped.
Use it with the Canvas AI assistant¶
Use once per region to build the site-wide header/footer the Drupal way, so individual Canvas pages stay content-only.
Save a section so it can be reused¶
| Plugin id | varbase_ai_figma:create_pattern |
| Function name | varbase_figma_create_pattern |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: CreatePattern, backed by varbase_ai_figma.pattern_builder
(PatternBuilder). Builds a Canvas Pattern directly from a Figma design
(contrast with save_as_pattern, which saves work already on a page).
Inputs¶
| Input | Required | Description |
|---|---|---|
label |
Yes | Human name; a machine id is generated from it. |
figma_url / file_key / node_id |
No | Identify the design region; a link overrides the explicit fields. |
layout |
No | Section shape hint: auto \| hero \| cards \| feature \| cta \| media \| pricing \| testimonials \| logos \| faq. Defaults to auto (inferred). |
Output¶
The builder reuses the closest existing theme component per region and only
scaffolds a new one where nothing fits, then the tool persists a
canvas.pattern config entity from the resulting rows:
Created Canvas pattern "Feature Grid" (id: feature_grid) with 5 component instance(s), layout "feature". Reused components: card-icon, heading. New components created: (none). It now appears in the Canvas editor Patterns tab.
A build or validation failure returns the error message instead of throwing.
Use it with the Canvas AI assistant¶
Use when the user wants a reusable section, not a whole page and not a single component ("save this pricing row as a pattern I can drop on other pages".
Save a section already on a page for reuse¶
| Plugin id | varbase_ai_figma:save_as_pattern |
| Function name | varbase_figma_save_as_pattern |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: SaveAsPattern.
Inputs¶
| Input | Required | Description |
|---|---|---|
page_id |
Yes | The canvas_page whose components to save. |
label |
Yes | Human name for the new pattern. |
section_uuid |
No | Save only this component and its descendants; omit to save the whole page. |
Output¶
Rows are re-keyed with fresh uuids (so the same page can be saved again
without id collisions), the section root is detached from its
parent_uuid/slot, and inputs are normalized to arrays. The generated
pattern id is vaf_<slugified label>, deduplicated with a random suffix on
collision. Saved "Homepage CTA" as pattern id "vaf_homepage_cta" (3 components). Add it to any page later with "Add a saved section to a page" (insert_pattern).
Use it with the Canvas AI assistant¶
Use after building something good on one page, to make it reusable elsewhere
the counterpart to create_pattern for work that already exists.
Add a saved section to a page¶
| Plugin id | varbase_ai_figma:insert_pattern |
| Function name | varbase_figma_insert_pattern |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: InsertPattern.
Inputs¶
| Input | Required | Description |
|---|---|---|
pattern_id |
Yes | The canvas.pattern id (from scan_inventory kinds=pattern). |
page_id |
Yes | The target canvas_page id. |
Output¶
Every row in the pattern's component_tree gets a fresh uuid (parent
references remapped), so the same pattern can be placed on many pages, or
the same page twice, without collisions. Rows are appended to the page's
existing components and saved once. Malformed rows (no resolvable uuid) are
skipped rather than duplicating stale references.
Inserted pattern "Feature Grid" (5 components) onto page "Homepage" (id 1).
Use it with the Canvas AI assistant¶
This is the "place it" half of a reuse decision: scan_inventory lists the
saved sections, resolve_design says which to reuse, insert_pattern places
it.
Bring the images across¶
| Plugin id | varbase_ai_figma:export_figma_images |
| Function name | varbase_figma_export_images |
| Group | modification_tools |
| Permission | use ai figma design context, or administer ai agents / use Drupal Canvas AI |
Class: ExportFigmaImages. Renders whole nodes (illustrations, composed
frames) via the Figma Images API (for the design's real, uploaded image
fills, use fetch_media_assets instead.
Inputs¶
| Input | Required | Description |
|---|---|---|
figma_url |
No | A Figma link; file key extracted from it. Falls back to the configured default. |
node_ids |
Yes | Comma-separated node ids to render, e.g. 9652:1031,9652:1067. |
format |
No | png (default), jpg or svg. |
Output¶
Each node is rendered, downloaded into public://figma/figma-<node>.<format>,
saved as a managed file entity, and, when format is not svg and the
Image media type exists, wrapped in an Image media entity. Per-node
failures (Figma couldn't render it, the download failed) are reported inline
rather than aborting the batch:
exported:
'9652:1031': { url: 'https://.../figma/figma-9652-1031.png', file_id: 42, media_id: 17 }
'9652:1067': { error: 'Download failed: ...' }
hint: 'Reference each url in component markup (src="...") instead of stock photos.'
Use it with the Canvas AI assistant¶
Call before writing component markup that needs the design's own imagery, so the agent references the returned URL instead of a stock-photo placeholder.
Collect the design files (logos, icons, photos)¶
| Plugin id | varbase_ai_figma:fetch_media_assets |
| Function name | varbase_figma_fetch_media_assets |
| Group | modification_tools |
| Permission | use ai figma design context, or administer ai agents / use Drupal Canvas AI |
Class: FetchMediaAssets. Refuses immediately if the Media module is not
enabled.
Inputs¶
| Input | Required | Description |
|---|---|---|
figma_url |
No | A Figma link; file key (and node id) extracted from it. |
file_key |
No | Figma file key, if no link is given. |
node_id |
No | Scope to one section (e.g. 9740-5207); omit to scan the whole file. |
Output¶
Walks the design (or node), collects its real image fills (logos, photos,
illustrations, via collectImageRefs() + fetchImageFills()), and for each:
skips it if a file at the stable, ref-keyed filename already exists (creating
the missing media entity if needed); otherwise checks a content-hash index
of every image already under public://figma/ so the exact same bytes are
never stored twice under a different Figma ref; otherwise downloads and
creates both the file and (when the Image media type exists) its media
entity.
summary: { total: 4, created: 1, already_existed: 3 }
fetched:
- { name: Logo, ref: 'abc123...', file: figma-asset-abc123.png, status: existing, media_id: 9, url: '...' }
Use it with the Canvas AI assistant¶
Call before building so components reference the design's own logos/photos from the first draft, rather than being patched with real imagery afterward.
Edit the theme files¶
| Plugin id | varbase_ai_figma:theme_file |
| Function name | varbase_figma_theme_file |
| Group | modification_tools |
| Permission | administer themes, or administer ai agents / use Drupal Canvas AI |
Class: ThemeFileEditor. Scoped strictly to the site's active default
theme directory (read from system.theme:default, not hard-coded), with the
target path resolved and jailed via realpath() against that base.
Inputs¶
| Input | Required | Description |
|---|---|---|
action |
Yes | list, read or write. |
path |
No | Relative to the theme directory, e.g. css/style.css; a sub-path for list. |
content |
For write |
The full replacement file content. |
Output¶
list returns every file path under the theme (or sub-path) recursively.
read/list accept css, js, yml, twig, md, svg; write refuses .twig
unconditionally (template-injection risk) and is further restricted to
css, js, yml, md, svg. A successful write calls
drupal_flush_all_caches() and reports the byte count written. Any path that
resolves outside the theme directory is refused with "Path ... is outside the <theme> theme. Refused.".
Use it with the Canvas AI assistant¶
Use for a Bootstrap variable override or a small CSS/JS tweak a Figma build needs, not for template changes, which this tool cannot make.
Set the site logo¶
| Plugin id | varbase_ai_figma:set_theme_logo |
| Function name | varbase_figma_set_theme_logo |
| Group | modification_tools |
| Permission | administer themes or administer ai agents (note: use Drupal Canvas AI alone is not sufficient here) |
Class: SetThemeLogo.
Inputs¶
| Input | Required | Description |
|---|---|---|
figma_url |
No | A link to the logo node; file key + node id extracted from it. |
file_key / node_id |
Conditionally | Required (one of link or these): a logo node id must be resolvable. |
format |
No | svg (default, recommended for logos) or png. |
apply_to_theme |
No | Theme machine name; defaults to the site default theme. |
Output¶
Logos in Figma are usually vector groups with no downloadable image fill, so
this renders the node via the Images API (not fetchImageFills()),
downloads it to public://figma/logo-<node>.<format>, saves it as a managed
file, and sets <theme>.settings:logo.use_default = false /
logo.path = <uri>.
logo_set: true
theme: vartheme_bs5
node_id: '7989-1361'
format: svg
file: logo-7989-1361.svg
url: 'https://.../figma/logo-7989-1361.svg'
note: 'The default theme now uses this logo. Reload the site to see it; clear caches if it does not appear.'
Use it with the Canvas AI assistant¶
Use for "change the logo to this Figma logo": the author no longer exports and uploads it by hand.
Suggest what to ask for next¶
| Plugin id | varbase_ai_figma:prompt_template |
| Function name | varbase_figma_prompt_template |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: PromptTemplate. Stores templates in a single config object,
varbase_ai_figma.prompt_templates.
Inputs¶
| Input | Required | Description |
|---|---|---|
action |
Yes | save, list, apply or delete. |
name |
For save/apply/delete | The template name (a machine name is derived by lower-casing and collapsing non-alphanumerics to _). |
instructions |
For save |
The reusable improvement-prompt text to store. |
description |
For save, optional |
A short human label; defaults to name. |
Output¶
list returns every saved template with a single-line preview (truncated at
117 chars + ...). apply returns the stored instructions verbatim, framed
as "Apply these improvement instructions to the current page: ...", for the
calling agent to execute; this tool never touches a page itself. save
overwrites any existing template of the same machine name. A missing template
name returns a message listing the templates that do exist.
Use it with the Canvas AI assistant¶
Save a quality checklist once ("fix headings, generate missing alt text,
tighten CTAs, add a meta description"), then apply it against any page
instead of retyping the same instructions.
Suggest alternative wording to test¶
| Plugin id | varbase_ai_figma:ab_variants |
| Function name | varbase_figma_ab_variants |
| Group | information_tools |
| Permission | use Drupal Canvas AI, administer ai agents, or use ai figma design context |
Class: AbVariants. Read-only: never edits the page, and does not push
variants to an experimentation module (out of scope, noted in the output).
Inputs¶
| Input | Required | Description |
|---|---|---|
page |
Yes | canvas_page numeric id or exact title. |
element |
No | Focus on one of hero \| cta \| headline; omit to auto-pick all high-impact elements. |
Output¶
Identifies up to three candidates from the page summary: the hero
headline (the first heading, preferring a larger one among the first three),
the primary CTA (a short, non-sentence text on a component whose name
hints cta/button/hero/call/action), and above-the-fold copy (the
first paragraph ≥ 60 chars), the last only when no single element was
requested. Requires a configured default AI chat provider (ai.settings); asks
it for 1-2 variants per element, each with a hypothesis and a metric from
CTR | scroll depth | form submissions.
page: '1 (Homepage)'
high_impact_elements:
- { element: 'hero headline', original: 'Build faster with Varbase' }
variants:
- { element: 'hero headline', original: '...', variant: 'Ship Drupal faster.', hypothesis: '...', metric: CTR }
note: 'Read-only suggestions. To actually run the test, the agent should push these variants to a connected A/B / experimentation module - that wiring is out of scope here and was not done.'
Use it with the Canvas AI assistant¶
Use to get testable copy alternatives for a page's highest-impact elements before wiring them into whatever A/B tool the site actually runs.
Check many pages at once¶
| Plugin id | varbase_ai_figma:batch_improve |
| Function name | varbase_figma_batch_improve |
| Group | information_tools |
| Permission | use Drupal Canvas AI or administer ai agents |
Class: BatchImprove. Read-only and fully deterministic: no AI/LLM call.
Inputs¶
| Input | Required | Description |
|---|---|---|
pages |
No | Comma-separated canvas_page ids/exact titles. Empty = all canvas_page entities, capped at 50 (noted in the output). |
checks |
No | Comma-separated subset of accessibility, seo, links. Defaults to all three. |
Output¶
One row per page: images_missing_alt, heading_issues (missing/multiple
H1, skipped levels), generic_links (anchor text like "click here"/"read
more"/empty), and a needs_attention flag, sorted with flagged pages first,
then by descending issue count. Site-wide totals are aggregated across all
audited pages.
pages_audited: 12
checks_run: [accessibility, seo, links]
totals: { images_missing_alt: 3, heading_issues: 1, generic_links: 2, pages_needing_attention: 2 }
pages:
- { page_id: 4, title: About, images_missing_alt: 2, heading_issues: 1, generic_links: 0, needs_attention: true }
note: 'Read-only batch audit (deterministic). Run ai_figma:audit_page on a specific page for full per-finding detail, then apply low-risk fixes (alt text, meta, spacing) with the targeted tools after review.'
Use it with the Canvas AI assistant¶
Use for a site-wide sweep, then drill into any flagged page with audit_page
for the full per-finding detail.
4. Connect it to the rest of the site¶
Once content exists, these tools wire it into navigation, the front page and site configuration.
Connect the design to the real site¶
| Plugin id | varbase_ai_figma:site_wiring |
| Function name | varbase_figma_site_wiring |
| Group | modification_tools |
| Permission | administer site configuration, or administer ai agents / use Drupal Canvas AI |
Class: FigmaSiteWiring.
Inputs¶
| Input | Required | Description |
|---|---|---|
action |
Yes | set_front_page, add_to_menu or set_path_alias. |
page |
Yes | A canvas_page numeric id, exact title, or any internal path starting with /. |
alias |
For set_path_alias, optional |
The wanted alias; auto-generated from the title (slugified) when empty. |
menu |
For add_to_menu, optional |
main, secondary or footer. Defaults to main. |
link_title |
For add_to_menu, optional |
Defaults to the page title. |
weight |
For add_to_menu, optional |
Integer menu weight. |
Output¶
set_front_page writes system.site:page.front. add_to_menu creates a
menu_link_content pointing at internal:/page/<id> (or the given path),
refusing a duplicate. set_path_alias replaces any existing alias for that
path with a path_alias entity. Every action returns a plain confirmation
sentence, e.g. Done: "Homepage" is now the Drupal front page (system.site:page.front = /page/1).
Use it with the Canvas AI assistant¶
Use right after create_canvas_page to finish the build the Drupal way: make
the new Homepage the front page, give every created page a clean alias, and
add it to navigation when the design shows it there.
Manage the menus¶
| Plugin id | varbase_ai_figma:menu_link |
| Function name | varbase_figma_menu_link |
| Group | modification_tools |
| Permission | administer menu, or administer ai agents / use Drupal Canvas AI |
Class: ManageMenu. Overlaps site_wiring's add_to_menu action but adds
list and remove.
Inputs¶
| Input | Required | Description |
|---|---|---|
action |
Yes | list, add or remove. |
menu |
No | main, secondary or footer. Defaults to main. |
page |
For add/remove | canvas_page id/title, or an internal path. |
link_title |
Optional (add); alternative match key (remove) | The link label, or (for remove without page) the exact title to match. |
weight |
For add, optional |
Integer order weight. |
Output¶
list returns every link in the menu as "Title" → /path (weight N).
remove matches by resolved path first, falling back to an exact
link_title match, and deletes every match (reporting how many). add
refuses a duplicate (same menu + same internal: uri).
Use it with the Canvas AI assistant¶
Use when a design adds or drops a page from the main/secondary/footer navigation, independent of building the page itself.
Install a set of features (recipe)¶
| Plugin id | varbase_ai_figma:apply_recipe |
| Function name | varbase_figma_apply_recipe |
| Group | modification_tools |
| Permission | administer site configuration or administer ai agents (deliberately not use Drupal Canvas AI: recipes can install modules/themes) |
Class: ApplyTempRecipe. Modelled on
\Drupal\varbase_recipes\Recipe\RecipeHelper.
Inputs¶
| Input | Required | Description |
|---|---|---|
recipe_yaml |
Yes | Complete recipe.yml content: name (required), optional type, install, config.actions. |
Output¶
Validates the YAML and requires at least a name; defaults type to Site.
Materialises the recipe via RecipeHelper::createRecipe() when
varbase_recipes is available, else writes it to a temp directory and loads
it with \Drupal\Core\Recipe\Recipe::createFromDirectory(), then runs it
through core's RecipeRunner::processRecipe(), the same machinery
drush recipe uses. Caches are flushed on success. Changes are
immediate and permanent.
Use it with the Canvas AI assistant¶
Use for a site configuration change a Figma build needs (enabling a module,
a config action) that doesn't fit config's single-object scalpel. Keep
recipes small and targeted.
Change a site setting¶
| Plugin id | varbase_ai_figma:config |
| Function name | varbase_figma_config |
| Group | modification_tools |
| Permission | administer site configuration, or administer ai agents / use Drupal Canvas AI |
Class: ManageConfig.
Inputs¶
| Input | Required | Description |
|---|---|---|
action |
Yes | list, get or set. |
name |
For get/set; optional prefix filter for list |
The config object name, e.g. system.site. |
values |
For set |
A YAML mapping of key paths to new values, e.g. page.front: /page/1. |
Output¶
list is unrestricted (names only, no values) and returns
\Drupal::config()->listAll($name). get/set are gated by an allow-list
(allowedConfig()): ai_figma., ai_agents.ai_agent., canvas,
system.site, node.type., field., core.entity_view_display.,
views.view., webform.webform., block.block., menu_link_content.,
pathauto., metatag.; anything else is refused. Even inside that
allow-list, set additionally refuses any name matching
/(\.|^)(settings|key|password|secret|smtp|mail|oauth|consumer)/i (a hard
regex check, not just the prefix list), so credentials and mail/SMTP
configuration can never be written through this tool. get returns the
config's raw data as YAML; set reports the keys written.
Use it with the Canvas AI assistant¶
Use for a single quick setting; for module installs or multi-object changes,
use apply_recipe instead.
5. Check and improve¶
Every build ends with verification and, where the site allows it, an AI-assisted improvement pass: all reversible, all reviewed before applying.
Look at the page in a real browser¶
| Plugin id | varbase_ai_figma:preview_token_url |
| Function name | varbase_figma_preview_token_url |
| Group | information_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: PreviewTokenUrl.
Inputs¶
| Input | Required | Description |
|---|---|---|
page_id |
Yes | The numeric canvas_page id. |
Output¶
Mints a random token (Crypt::randomBytesBase64(32)) and stores it in an
expirable key-value collection (varbase_ai_figma.preview_tokens) bound to
the page id with a 300-second TTL, then returns an absolute URL to the
varbase_ai_figma.token_preview route carrying that token. The route
consumes the token on first open, so the URL renders the page, including an
unpublished draft, with no login required, exactly once. A fresh call is
needed for a second look.
Use it with the Canvas AI assistant¶
Use right after building a page so an unauthenticated headless browser tool can actually see (and screenshot) the result, rather than trusting the build succeeded.
Check the page loads (quick)¶
| Plugin id | varbase_ai_figma:check_page_render |
| Function name | varbase_figma_check_page_render |
| Group | information_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: CheckPageRender. Adapted from
ai_agents_experimental_collection's ai_agents_sdc:check_component_render.
Inputs¶
| Input | Required | Description |
|---|---|---|
path |
No | A path on this site, e.g. /page/12. Empty = front page. |
Output¶
A plain unauthenticated HTTP GET against the site's own base URL
(http_errors disabled, 15s timeout, redirects followed). 401/403 are
reported as an access/publish issue from an anonymous probe, not necessarily a
render bug. 404 reports the path doesn't exist. Any other 4xx/5xx
returns the status plus up to 800 chars of stripped error output. 200 (or
any <400) reports renders OK.
Use it with the Canvas AI assistant¶
Run this first, right after building a page (much cheaper than a headless
browser preview), and only escalate to preview_token_url when this comes
back clean but the result still needs to be seen.
Check a page for problems¶
| Plugin id | varbase_ai_figma:audit_page |
| Function name | varbase_figma_audit_page |
| Group | information_tools |
| Permission | use Drupal Canvas AI, administer ai agents, or use ai figma design context |
Class: AuditPage. Read-only and fully deterministic (no AI/LLM call):
every check runs over the page's structured summary from
CanvasPageAnalyzer.
Inputs¶
| Input | Required | Description |
|---|---|---|
page |
Yes | canvas_page numeric id or exact title. |
checks |
No | Comma-separated subset of accessibility, headings, contrast, seo, spacing, images, links, sections. Defaults to all eight (a consolidated review). |
Output¶
Findings grouped by category, each with severity (critical \| warning \|
suggestion), a WCAG success-criterion tag where relevant, a plain-language
message and a fix. Notable implementation details:
- headings: flags a missing H1, more than one H1, and any level skip (e.g. H2→H4), and proposes a corrected level sequence.
- contrast: parses only concrete inline
#rgb/#rrggbb/rgb()pairs (real WCAG relative-luminance math,4.5:1minimum); CSS variables, keywords, gradients andhsl()cannot be resolved server-side and are skipped, not guessed at. - seo: a 0-100 score from five pass/fail checks (single H1, title set,
heading order, has body text, images have alt); always reported even when
seoisn't explicitly requested. - spacing, images, sections: explicitly labelled heuristic:
spacing scans component inputs for
p*-/m*-/padding/marginutility strings; images flags demo/stock sources and non-derivative/files/...paths (byte size isn't available from rendered HTML); sections guesses a page "kind" (contact/blog/landing/generic) from component names and suggests commonly-missing sections (CTA, testimonials, hero, FAQ, …).
page: { id: 4, title: About }
checks_run: [accessibility, headings, ...]
score: { seo: 80 }
summary: { critical: 1, warning: 2, suggestion: 4, total: 7 }
findings:
accessibility:
- { severity: critical, wcag: 'WCAG 1.1.1', message: 'Image is missing alt text (.../team.jpg).', fix: 'Add a concise, descriptive alt attribute...' }
note: 'Read-only audit. Apply fixes with the targeted edit/improve tools...'
Use it with the Canvas AI assistant¶
Use checks=all (the default) as the consolidated review panel after a
build; apply what it finds with page_edit, alt_text and
meta_description rather than editing by hand.
Improve the wording¶
| Plugin id | varbase_ai_figma:improve_text |
| Function name | varbase_figma_improve_text |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: ImproveText, backed by varbase_ai_figma.assistant (AiAssistant,
the site's default AI chat provider).
Inputs¶
| Input | Required | Description |
|---|---|---|
page |
Yes | canvas_page numeric id or exact title. |
target |
Yes | Component uuid, exact label, machine name, or the exact current copy to locate. |
prop |
No | The prop holding the text; auto-detected when omitted. |
kind |
No | headline \| body \| cta. Defaults to body. |
instruction |
No | Extra guidance, e.g. "for a technical audience". |
apply |
No | "true" to write back. Defaults to preview only. |
choice |
No | 1-based variant index to apply. Defaults to 1. |
Output¶
Resolves target first as a component reference, then (if that fails) as
exact/near-exact current text via the page's text summary; an ambiguous or
unresolvable target returns the full uuid/prop/snippet list rather than
failing blindly. Requires a configured AI chat provider. Returns 2-3 variants,
each with a one-line rationale; kind tunes the system prompt (headline:
sharper/scannable and no longer than the original; cta: 1-4 words,
action-oriented; body: clearer and more concise, links/formatting preserved).
When apply=true, the chosen variant is written to the resolved prop and the
page saved.
page: '4 (About)'
component: Hero
prop: heading_text
kind: headline
original: 'We build websites for organisations'
variants:
- { n: 1, text: 'Websites built for how you work', why: 'Leads with the benefit, active voice.' }
applied: 'No change written (apply was not set). Re-run with apply="true" and choice=<n> to apply one.'
Use it with the Canvas AI assistant¶
Use for "shorten this headline" / "make this CTA punchier" / "clarify this paragraph" on a page that already exists.
Describe the images for screen readers¶
| Plugin id | varbase_ai_figma:alt_text |
| Function name | varbase_figma_alt_text |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: GenerateAltText. Not true vision: alt is drafted from the image
filename plus page context, so suggestions need review.
Inputs¶
| Input | Required | Description |
|---|---|---|
page |
Yes | canvas_page numeric id or exact title. |
apply |
No | "true" to write the suggestion back. Defaults to preview only. |
Output¶
Finds every image missing (or with empty) alt text, builds a page-context
block (title + up to 8 headings + first substantial paragraph), and for each
image: if the filename matches icon|divider|spacer|separator|bg|background|
decoration|ornament|pattern|texture|bullet|dot, marks it decorative with
alt="" and skips the model call entirely; otherwise asks the model for one
concise alt (≤ 125 chars, no "image of" prefix) or the literal answer
DECORATIVE. When apply=true, write-back is best-effort in this order: (1)
resolve a managed file by mapping the src back to its public:// URI and set
alt on the first content entity's image-field item referencing it; (2)
failing that, find a page component whose serialised inputs mention the image
and carry an alt/image_alt/alt_text/imageAlt prop, and set that. If
neither resolves, the image is reported review-only.
Use it with the Canvas AI assistant¶
Run after a build (or as part of audit_page's accessibility findings) to
clear WCAG 1.1.1 violations; always treat the drafted alt as a starting point
to review, not a final answer.
Write the search-engine summary¶
| Plugin id | varbase_ai_figma:meta_description |
| Function name | varbase_figma_meta_description |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: MetaDescription.
Inputs¶
| Input | Required | Description |
|---|---|---|
page |
Yes | canvas_page numeric id or exact title. |
apply |
No | "true" to write the chosen variant. Defaults to preview only. |
choice |
No | 1-based variant index (1, 2 or 3). Defaults to 1. |
Output¶
Collects headings + on-page copy (capped at 2000 chars as the model's source
material), reads any existing description first (findMetaField() probes, in
order, a metatag-typed field, then field_metatags/metatag/
field_meta_tags, then a plain description/meta_description/
field_description property (canvas_page doesn't necessarily carry a
Metatag field), then asks the model for 2-3 variants (≤ 155 chars each,
character counts recomputed server-side, not trusted from the model). When
apply=true and a field was found, writes the chosen variant into it
(serialising the Metatag array's description key, or setting the plain
property directly) and saves; when no writable field exists, the variants are
still returned with a note to set it via the Metatag UI.
Use it with the Canvas AI assistant¶
Use per page after a build, or as the fix for audit_page's "confirm the
page has a meta description" reminder.
Translate the page¶
| Plugin id | varbase_ai_figma:translate_page |
| Function name | varbase_figma_translate_page |
| Group | modification_tools |
| Permission | administer ai agents or use Drupal Canvas AI |
Class: TranslatePage.
Inputs¶
| Input | Required | Description |
|---|---|---|
page |
Yes | canvas_page numeric id or exact title. |
language |
Yes | Target language, e.g. French, fr, Arabic. |
localize |
No | "true" (default) adapts idioms/dates/currency/culture, not just a literal translation. |
apply |
No | "true" to write translations back in place. Defaults to preview only. |
Output¶
Collects every text prop from the page summary and translates in batches of
40 strings per model call (translateAll()/translateBatch()), each batch
sent as an index-keyed JSON object so the response stays aligned with the
originals even when the model drops or reorders entries. Returns a
field-by-field change set (component_uuid, prop, original,
translated, changed). When apply=true, only the rows that actually
changed are written back (via component_uuid lookup + setProp()), and the
page is saved once. The report always warns that applying overwrites the
source language in place: to keep the original too, translate a
duplicate/language-translation of the page instead.
page_id: 4
target_language: French
localized: true
text_prop_count: 12
translated_count: 11
applied: false
fields:
- { component_uuid: '...', prop: heading_text, original: 'Build faster', translated: 'Construisez plus vite' }
note: 'Preview only - nothing was written. Call again with apply=true to write the translations back. ...'
Use it with the Canvas AI assistant¶
Duplicate the page first if the original language must survive, then run this
against the copy with apply=true.