Skip to content

SVG and animated SVG

The SVG generator writes a vector graphic with the chat model. It is static by default; with the Style option it can also be animated, and the Animated SVG component and the Inline SVG (animated) display make it move on the page.

A generated SVG ready to review: a flat paper plane icon in navy and white, with the name and alternative text prefilled from the description and Open full size in a new tab.

Styles

Style What the model writes What moves it
Static A drawing, no animation Nothing
Animated: draw the strokes Stroke-only parts (<g class="ai-media-part">), no animation in the file The component draws each stroke by its own length, part by part
Animated: CSS keyframes A <style> with @keyframes inside the file The component starts it when it scrolls into view
Animated: SMIL <animate>, <animateTransform>, <set> The component starts it when it scrolls into view

Editors see Style under Options only when Editor options > SVG > Show the style is on. Hidden by default, with Static as the default style (editor_options.svg.style: show, default).

Each animated style adds its own AI Prompt to the SVG drawing prompt, in the AI module's prompt library (prompt type ai_media_svg_motion):

Use Setting Default prompt
Draw the strokes prompts.svg_draw ai_media_svg_motion__draw
CSS keyframes prompts.svg_css ai_media_svg_motion__css
SMIL prompts.svg_smil ai_media_svg_motion__smil

Showing it so it moves

An SVG in an <img> gets no page CSS or script, so motion that starts on scroll cannot run there. Two ways print it inline instead:

  • Animated SVG (ai_media:animated-svg), a Single Directory Component that Canvas can place. Props: svg, label (empty means decorative), animation (auto, draw, rise, play, none), stagger, duration, replay. It has no AI dependency: hand-written SVG works too.
  • Inline SVG (animated), a display (field formatter) for image and file fields. Use it on the SVG media type's source field, and a generated SVG animates wherever the media item is shown. Files that are not SVG render as images.

auto draws a "draw the strokes" SVG, plays an SVG that carries its own animation, and shows any other SVG still. The motion starts when the drawing scrolls into view; with prefers-reduced-motion the finished drawing is shown at once, SMIL included. Without JavaScript, and in print, the drawing is shown as it is. The review step after Generate uses the same component, so the preview moves as the page will.

Safety

Inline SVG shares the page, so it is checked harder than a file. Every SVG goes through SvgSanitizer, on top of enshrined/svg-sanitize:

  • No <script>, <foreignObject>, <image>, <iframe>; a link is unwrapped and its drawing kept.
  • No event handlers, no href other than #id, no javascript: or data: value, no url() outside the file.
  • In <style> and style="": no @import, no javascript: (escaped or not), no expression().
  • Animation keeps what it needs: <style> with @keyframes, <animate>, <animateTransform>, <animateMotion>, <set>. The library drops <animate> and <set>, because either can rewrite a link; they are allowed back only when attributeName is not a link, a handler, a style, a class or an id.

Before an answer is kept

  • It must draw: at least 3 drawable elements, and every path d a complete command sequence (a moveto with a point, then another command).
  • A transform attribute on an element that CSS animates is moved onto a new wrapper <g>, because a CSS transform replaces the attribute.
  • A refused answer is asked for again, saying why, up to 3 tries, and only while the time spent is under the AI module's request timeout.
  • A provider error ends the press. A timeout says so: "The AI service (provider, model) did not answer within N seconds." No timeout of AI Media's own is added; the AI module's Request timeout applies to each call. A provider that needs longer per call takes the AI module's http_client_options (timeout) provider configuration.

SVG media that can be selected

Core's media thumbnail base field refuses svg, so an SVG media item saves but no field or media embed can select it. While the SVG generator is on, AI Media adds svg to that field. Core also renders nothing for an SVG through an image style (no toolkit can resize it); AI Media shows the original file instead, so the Media Library grid shows the drawing.

Example recipe

recipes/ai_media_svg_example shows it working right after install:

drush recipe modules/contrib/ai_media/recipes/ai_media_svg_example

It adds an "SVG Image" media type (or keeps the site's own svg_image), saves generated SVGs into it, shows it with Inline SVG (animated), adds an Animated SVG field on Basic page, adds the type to text formats whose media embed lists its types, shows the Style option, and creates an "Animated SVG example" page with a process flow that draws and a bar chart that plays its own keyframes. It is inside the module, like core's own core/recipes, so it ships with the module and needs no separate package. Generic example SVGs are in tests/fixtures/svg.

For media embeds in recipes, AI Media adds the allowMediaEmbedTypes config action: it adds types to a format's embed list and leaves alone a format that allows every type or has no embed filter.

filter.format.full_html:
  allowMediaEmbedTypes: [image, svg_image]

Not included: a CKEditor "Generate SVG" button

The AI module's CKEditor tools return text into the editor. CKEditor 5 has no model for SVG, so it strips or breaks inline <svg>, and a text format would need a filter that prints sanitized SVG. Generate the SVG as media instead and embed it; it renders through the media's display.

When an SVG does not show

What Symptom Where it is fixed
Media thumbnail refuses .svg The item saves and lists, but cannot be selected AI Media, for the SVG generator's media type while the generator is on
An image style cannot resize SVG An empty box in the Media Library grid or an image style display AI Media, while the SVG generator is on and has a media type
The media field does not allow the SVG type No SVG tab in that field's Media Library Site config: the field's Media types
The text format's Embed media lists types without the SVG type No SVG tab behind CKEditor's Insert Media Site config, or allowMediaEmbedTypes in a recipe
The theme's image template drops the <img> An empty <figure> where the image should be The theme
Limit allowed HTML runs after Embed media and has no <img> Every embedded image, SVG or not, is removed Site config: order the filters, or allow <img>