Skip to content

feat(scene): add SVG file import#33

Open
willytop8 wants to merge 2 commits into
akinloluwami:mainfrom
willytop8:wr/svg-import
Open

feat(scene): add SVG file import#33
willytop8 wants to merge 2 commits into
akinloluwami:mainfrom
willytop8:wr/svg-import

Conversation

@willytop8
Copy link
Copy Markdown

@willytop8 willytop8 commented May 10, 2026

Summary

  • Adds a new SceneSvg scene object type that stores raw SVG markup and renders it via a data:image/svg+xml <img> tag (browser-sandboxed — scripts and event handlers do not execute)
  • Wires up the uploads panel (previously a "Coming soon" stub) with a working SVG file picker
  • Export pipeline works without changes — the existing canvas renderer picks up the new case 'svg' branch in drawSceneObject

Changes

File What changed
avnac-scene.ts New SceneSvg type; 'svg' added to SceneObjectType and SceneObject union; parse, clone, and display-name cases
avnac-document.ts Re-exports SceneSvg
avnac-scene-render.ts svgMarkupToDataUrl helper; case 'svg' in drawSceneObject
object-view.tsx Live editor renders SVG objects via <img> data URL
editor-uploads-panel.tsx SVG file picker with DOMParser-based size detection, parseerror guard, and sanitizer

Safety

SVGs are rendered exclusively via <img> with a data URL — the browser sandboxes the SVG document so scripts and event handlers are inert. A regex sanitizer runs before storage as defense-in-depth: strips <script>, <foreignObject>, on* event attributes, and external <use href="https://..."> references.

Out of scope

  • SVG color/stroke editing (the markup is self-contained)
  • Drag-from-external-URL SVG import
  • AI controller add_svg tool

View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

Summary by cubic

Adds SVG import as a first-class scene object so users can upload SVGs, place them on the artboard, and export without changing the pipeline. Renders SVGs safely via a data-URL .

  • New Features

    • Introduced SceneSvg and svg handling across parse/clone/display-name and canvas renderer; export works as-is.
    • Uploads panel supports multi-file SVG selection, detects natural size via DOMParser, centers on the artboard, and scales to a max 800px edge.
    • Safe rendering: stores markup and renders via data-URL <img>; sanitizer strips <script>, <foreignObject>, on* attributes, and external <use href>.
  • Bug Fixes

    • Reject non-SVG XML by verifying the root tag before size detection.
    • Handle per-file read errors so one bad file doesn’t block others.
    • Clamp display width/height to at least 1px to prevent zero-sized objects.

Written for commit 67650d8. Summary will update on new commits.

Introduces a first-class `svg` scene object that stores raw SVG markup
and renders it via a data-URL `<img>` tag (browser-sandboxed, no script
execution). Adds an SVG file picker to the uploads panel that was
previously a "Coming soon" stub.

- `avnac-scene.ts`: new `SceneSvg` type, `'svg'` in `SceneObjectType`
  and `SceneObject` union, parse / clone / displayName cases
- `avnac-document.ts`: re-exports `SceneSvg`
- `avnac-scene-render.ts`: `svgMarkupToDataUrl` helper + `case 'svg'`
  in `drawSceneObject` — export pipeline works without further changes
- `object-view.tsx`: live editor renders SVG objects via `<img>` data URL
- `editor-uploads-panel.tsx`: SVG file picker with DOMParser-based size
  detection, parseerror guard, and regex sanitizer (strips `<script>`,
  `<foreignObject>`, `on*` attrs, external `<use href>`)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 10, 2026

@willytop8 is attempting to deploy a commit to the Akinkunmi Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/src/components/editor-uploads-panel.tsx">

<violation number="1" location="frontend/src/components/editor-uploads-panel.tsx:33">
P2: `parseSvgNaturalSize` accepts any well-formed XML as SVG because it never checks that the parsed root element is `<svg>`, so non-SVG XML can be imported and stored as an SVG object.</violation>

<violation number="2" location="frontend/src/components/editor-uploads-panel.tsx:76">
P1: File read errors are not handled, causing unhandled promise rejections and aborting processing of remaining files</violation>

<violation number="3" location="frontend/src/components/editor-uploads-panel.tsx:90">
P2: Imported SVG dimensions should be clamped to at least 1; rounding can otherwise create zero-sized objects for tiny SVGs.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread frontend/src/components/editor-uploads-panel.tsx Outdated
Comment thread frontend/src/components/editor-uploads-panel.tsx Outdated
Comment thread frontend/src/components/editor-uploads-panel.tsx
- parseSvgNaturalSize: reject non-SVG XML by checking root tag name
- handleSvgFiles: catch FileReader errors per-file so one failure
  does not abort remaining files in a multi-file upload
- clamp display dimensions to at least 1px to prevent zero-sized
  objects when rounding tiny SVG natural dimensions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/src/components/editor-uploads-panel.tsx">

<violation number="1" location="frontend/src/components/editor-uploads-panel.tsx:36">
P3: Strictly comparing `tagName` to `'svg'` rejects valid namespace-prefixed SVG roots (e.g. `svg:svg`), causing imported SVGs to be silently skipped.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

if (doc.querySelector('parsererror')) return null

const root = doc.documentElement
if (root.tagName.toLowerCase() !== 'svg') return null
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Strictly comparing tagName to 'svg' rejects valid namespace-prefixed SVG roots (e.g. svg:svg), causing imported SVGs to be silently skipped.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/components/editor-uploads-panel.tsx, line 36:

<comment>Strictly comparing `tagName` to `'svg'` rejects valid namespace-prefixed SVG roots (e.g. `svg:svg`), causing imported SVGs to be silently skipped.</comment>

<file context>
@@ -33,6 +33,7 @@ function parseSvgNaturalSize(markup: string): { width: number; height: number }
   if (doc.querySelector('parsererror')) return null
 
   const root = doc.documentElement
+  if (root.tagName.toLowerCase() !== 'svg') return null
   const wAttr = root.getAttribute('width')
   const hAttr = root.getAttribute('height')
</file context>
Suggested change
if (root.tagName.toLowerCase() !== 'svg') return null
if (root.localName.toLowerCase() !== 'svg' || root.namespaceURI !== 'http://www.w3.org/2000/svg') return null

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant