Releases: frontsail-ai/aspicio
Release list
v0.13.0
The release that makes PDFs look like PDFs. A page is drawn on paper now, embedded images render, and there's a light theme to view it all in.
Pages are drawn on paper
A PDF page renders on a bounded white sheet, the way Acrobat and Preview show it.
Before, page content sat directly on the dark canvas. A typical print file only looked right because its artwork carried its own white background — a vector-only or transparent-background file, like a dieline, rendered against near-black, and soft-mask fades dissolved into the viewer chrome instead of fading into paper.
The sheet follows the page's CropBox, which is the finished page a file declares when it's been imposed on oversized media. Zoom-to-fit frames the page rather than the ink on it, so a logo in the corner of an A4 sheet now opens showing the sheet instead of the corner.
Trim and bleed guides
The two boxes a print operator actually works to — where the knife falls, and how far artwork must run past it — now draw as dashed guides on the sheet.
They stay one pixel wide at every zoom level. A guide that thickened as you zoomed in would compete with the linework it exists to measure.
A light theme
The whole viewer switches between dark and light: a toggle in the demo, a theme-mode attribute on the embeddable components.
It's a real second palette rather than an inverted one. Every text pairing clears WCAG AA on all three surfaces text can land on — panel, canvas, and paper.
CAD colours don't survive a light background on their own. The default AutoCAD palette was designed for a black screen, and its yellow sits at 1.3:1 against a light canvas — effectively invisible. Pen colours are now darkened just enough to stay readable while keeping their hue, and the default pen resolves to ink black, the way every CAD tool renders it.
PDF colours are never touched. A dieline authored in 100% cyan renders as 100% cyan in either theme. A DXF pen colour is a display convention; PDF colour is ink, and the two are treated differently on purpose.
Images inside PDFs
PDFs with embedded raster images — scanned drawings, photographic artwork under a dieline — now render them, decoding Flate and baseline JPEG.
Spot colours resolve to their real ink values instead of washing out to white, and images sit correctly beneath the vector linework drawn over them. Hover highlights and selection outlines draw above artwork rather than disappearing behind it.
Content is also clipped to the clipping paths a file declares, so artwork no longer spills past where the file says it should stop.
Multi-page drawings
Entity counts and the layer list now describe the page or sheet you're looking at, rather than the whole document — page 3 no longer shows page 1's figures. A page that draws nothing explains itself instead of leaving a silent blank canvas.
Demo
- A drawing URL in the query string (
?src=…) raises a confirmation prompt naming the file and the site it would come from, instead of being silently ignored. - Popovers and panels dismiss consistently on Escape.
- Analytics run behind a consent banner.
For developers
All additions — nothing was removed from any published export, so upgrading from 0.12.0 needs no code changes.
@aspicio/core
PageGeometryon spaces, withspacePage(doc, name)to read it — a space either declares paper or it doesn't.- Viewer options:
sheet,sheetEdge,select,selectOnSheet,legibleOn,ink. setCanvasColors()re-colours a live viewer without recreating it, for theme switching.- Colour helpers:
contrastRatio,relativeLuminance,darkenForLegibility. IMAGEentities carrying decoded raster images, on every surface.
@aspicio/elements, @aspicio/react, @aspicio/vue, @aspicio/svelte
theme-mode/themeMode:"dark"(default) or"light".aspicioLightTokensandaspicioCanvasColorsalongside the existingaspicioTokens.
Canvas colours that the renderer needs as numbers (paper, sheet edge, selection) live in aspicioCanvasColors; CSS custom properties cover the chrome. They can't be interchanged — the sheet is WebGL geometry, not a DOM surface.
What's Changed
- Fix the Dependabot config that has never run by @korya in #154
- Move CI actions off the deprecated Node 20 runtime by @korya in #155
- Add GA4 to the demo behind a Consent Mode v2 banner by @korya in #159
- chore(deps): Bump the minor-and-patch group with 11 updates by @dependabot[bot] in #156
- chore(deps-dev): Bump bumpp from 11.1.0 to 12.1.1 by @dependabot[bot] in #157
- chore(deps-dev): Bump typescript from 6.0.3 to 7.0.2 by @dependabot[bot] in #158
- fix(core): Resolve PDF colour spaces so spot colours keep their ink colours by @korya in #160
- Draw PDF raster images: IMAGE entities on every surface (PDF-9) by @korya in #167
- feat(demo): Explain a load that draws nothing (DEMO-20) by @korya in #168
- chore(ci): Bump actions/checkout from 5 to 7 by @dependabot[bot] in #179
- chore(ci): Bump actions/setup-node from 5 to 7 by @dependabot[bot] in #180
- chore(ci): Bump actions/cache from 5 to 6 by @dependabot[bot] in #182
- fix(demo): Dismiss transient surfaces on Escape and when modals open by @korya in #183
- Draw hover and selection overlays above raster images by @korya in #184
- Scope entity counts to a space, not a document by @korya in #186
- chore(deps): Bump the minor-and-patch group across 1 directory with 5 updates by @dependabot[bot] in #185
- Draw PDF pages on paper, with a light theme and page guides by @korya in #195
- Crop PDF content to clipping paths and form /BBox by @korya in #196
- Make light-canvas linework and selection actually legible by @korya in #197
- Confirm a query-string source instead of ignoring it by @korya in #200
- chore(release): 0.13.0 by @korya in #202
New Contributors
- @dependabot[bot] made their first contribution in #156
Full Changelog: v0.12.0...v0.13.0
v0.12.0
Aspicio reads PDFs. This is the release where a DXF viewer became a drawing viewer — and the one release with a breaking change, because making room for a second format meant nothing could be named after the first.
PDF support
Vector PDFs open everywhere Aspicio works: the demo, the embeddable components, the HTTP API, the MCP server, and the in-chat widget.
Aspicio reads them itself — no external PDF engine — which is why the parser is described in terms of what it does and does not claim. It reads page geometry, vector paths and fills, text through ToUnicode and font encodings, and colour spaces including spot inks. It measures in points and invents no scale: a drawing whose real-world size lives only in its artwork is not second-guessed.
Multi-page files are fully viewable. Page 1 opens, and every later page is a named space you can switch to without reloading.
Optional-content groups become layers. A PDF's OCG layers — how packaging files separate a dieline from the artwork it cuts — appear in the layer panel and toggle like DXF layers do. Two groups that share a name stay two rows rather than silently merging, and a group the file declares but never draws on still gets a row, because the panel reports what the file says.
Damage is contained and counted, never fatal. A page that fails to decode costs that page, not the document; a truncated stream draws what it has and says so. A file that isn't structurally a PDF fails with a readable message instead of a stack trace.
For agents
The HTTP API and the MCP server both grew a six-tool matrix: describe and render, in DXF-specific, PDF-specific, and format-agnostic flavours — the last detecting the format from the bytes.
Both surfaces now generate their tool definitions from one shared table, so the two can't drift apart in what they claim to accept.
Demo
- Open a drawing from a URL. One dialog gathers both paths — a dropzone and a URL field, no tabs — with streaming progress, a cancel control, and a remembered list of recent URLs. Fetch failures explain themselves rather than dropping you on a generic error.
- Remote drawings are shareable. The link carries both the source and the exact view, so a colleague opens the same drawing at the same zoom.
Upgrading from 0.11.x
This release has a breaking change. Two things moved.
1. Import a format explicitly. The root entry points no longer include a parser, so an app pulls in only the format it uses:
import { DrawingViewer } from "@aspicio/core";
import { dxfParser } from "@aspicio/core/dxf"; // and/or "@aspicio/core/pdf"
new DrawingViewer(el, { parsers: [dxfParser] });The same applies to the component packages: @aspicio/elements/formats/dxf, and the matching subpath on react, vue and svelte.
This is what keeps a PDF-only app free of DXF code and vice versa — guaranteed by module boundaries rather than bundler cleverness, and checked by a build gate.
2. Format-neutral names dropped their Dxf prefix, since they were never DXF-specific:
| Before | After |
|---|---|
DxfViewer |
DrawingViewer |
DxfDocument |
DrawingDocument |
DxfSource |
DrawingSource |
DxfViewerOptions |
DrawingViewerOptions |
DxfParseError |
DrawingParseError |
DxfTheme |
AspicioTheme |
<DxfEmbed> <DxfPreview> <DxfLayerPanel> |
<AspicioEmbed> <AspicioPreview> <AspicioLayerPanel> |
DXF rendering behaviour is unchanged.
What's Changed
- Spell out the gated release workflow in the runbook by @korya in #122
- Open DXF from a remote URL by @korya in #123
- Fix clipped focus ring on the zoom-cluster buttons by @korya in #124
- docs: Correct stale package count, Cloudflare refs, and MCP tools by @korya in #126
- feat(demo): Merge the Open-DXF dialog into one tabless view by @korya in #127
- feat(core)!: Put format parsers behind their own entry points by @korya in #128
- feat(core): Add the PDF object layer by @korya in #133
- feat(core): Add the PDF strict gate by @korya in #134
- feat(core): Add the PDF content interpreter by @korya in #135
- feat(core): Extract PDF text through ToUnicode and font encodings by @korya in #136
- feat(core): Assemble PDF pages into a drawing document by @korya in #137
- feat(core): Add the PDF entry points and prove format separation by @korya in #138
- feat(demo): Open PDFs in the demo by @korya in #139
- Expose PDF to agents: six MCP tools and four HTTP endpoints by @korya in #140
- Open PDFs in the in-chat viewer by @korya in #142
- Stop calling Aspicio DXF-only in the in-repo docs by @korya in #141
- Name PDF on the demo's secondary SEO surfaces by @korya in #143
- Describe both formats in the OpenAPI document and embed skill by @korya in #144
- Stop advertising layers next to dielines by @korya in #145
- Tell the registries Aspicio reads PDF by @korya in #146
- Assert on rendered UI, not the inlined bundle by @korya in #147
- Make INV-12's exemption a test rather than a judgement by @korya in #148
- Specify OCG layers, from what real files actually contain by @korya in #149
- Add the optional-content model for PDF layers by @korya in #150
- Put marked content on its optional-content layer by @korya in #151
- Finish OCG layers — panels, corpus tests, cross-page proof by @korya in #152
- chore(release): 0.12.0 by @korya in #153
Full Changelog: v0.11.1...v0.12.0
v0.11.1
Patch release. Published packages get one core fix; the rest is demo-app polish that ships on the website, not npm.
Core (@aspicio/core)
- Animated zoom compounds correctly (#118, closes #39). Clicking the zoom button twice quickly now lands at the full factor (~156%) instead of ~125%. Each click reads the animation's destination rather than the mid-flight camera, so rapid clicks accumulate; interrupting a zoom to reset rotation no longer abandons the pending zoom.
Demo (deployed app only)
- "Show all" layers control (#119). Hide a rendered layer and a one-click "Show all" appears in the panel header to restore every layer — no more re-checking each one or reaching for the
Ashortcut. - Empty-state, export, and focus polish (#117). Dropped the orphan divider on the empty screen, unwrapped the export caption, and added a themed keyboard-focus ring.
All six packages (core, elements, react, vue, svelte, mcp) publish together at 0.11.1.
Install: npx -y @aspicio/mcp · hosted MCP at https://aspicio-api.frontsail.app/mcp · demo at https://aspicio.frontsail.app
v0.11.0
Reliability and polish across the DXF engine and its two viewers, plus the metadata that gets the server listed cleanly in the directories. If you consume @aspicio/* from npm, the headline is two new core exports; if you use the hosted MCP, everything below is already live.
@aspicio/core
- Honest parse errors (#28) — an invalid drawing no longer leaks the parser's internals.
parseDxf/parseDxfBytesnow throw aDxfParseErrorphrased for a person: "The file is empty" for empty input, "Not a valid DXF file" otherwise. The exception type is exported so surfaces can branch on it. - Shared empty-layer classification (#34) — new
isEmptyLayer/partitionLayershelpers, so every surface groups geometry-less layers by one definition.
Viewers (demo + in-chat widget)
- Info panel keeps out of your way (#35) — the selection panel docks in the corner opposite your click, so it never covers the entity you just selected.
- Measurements carry units (#29, #36) — the info panel shows
8 mm,201.1 mm², and labels a circle's length as CIRCUMFERENCE (perimeter for closed polylines), matching the measure readout and the copied summary. - Empty layers collapse away (#34) — layers with no rendered geometry (
0,Defpoints, xref scaffolding) tuck into a collapsible group, collapsed by default and omitted when there are none — in both the demo sidebar and the in-chat viewer. - Empty-state now names the full engine (#30) — the "supports" list includes TEXT, MTEXT, DIMENSION, HATCH, SOLID, SPLINE, and POINT, not just the primitives.
Distribution
- Domain-verification routes for the OpenAI and Glama directories, and Smithery listing metadata (description + homepage) so the server scores and lists cleanly.
Install
- Any framework or none:
npm i @aspicio/elements three - React:
npm i @aspicio/react react three· Vue:npm i @aspicio/vue vue three· Svelte:npm i @aspicio/svelte svelte three - Remote MCP (no install):
https://aspicio-api.frontsail.app/mcp· Local stdio:npx -y @aspicio/mcp - npm:
@aspicio/core·@aspicio/elements·@aspicio/react·@aspicio/vue·@aspicio/svelte·@aspicio/mcp— all 0.11.0
🤖 Generated with Claude Code
v0.10.0
Structured MCP output and a demo you can actually find: describe_dxf (and the remote view_dxf) now declare output schemas so agents consume results reliably, and the hosted demo went from an empty JavaScript shell to a fully crawlable, shareable site. Package APIs are otherwise unchanged — updating @aspicio/* is safe and boring.
Packages
- MCP output schemas — the structured tools declare their result shape in the MCP handshake, so models parse
describe_dxffacts (units, bounds, layers, counts) without guessing (#95) - READMEs link the live demo — every npm page now points straight at https://aspicio.frontsail.app (#104)
Hosted demo
- Crawlable everywhere — real title/description/Open Graph card, JSON-LD, robots.txt + sitemap, and a static rendition of the empty screen served to non-JS crawlers and unfurlers (DEMO-15/16) (#100, #101)
- New pages — /docs/ (packages, bindings, HTTP API at a glance) and /mcp/ (tools, hosted endpoint, install commands) (AGT-15) (#102)
- Mobile fix — the toolbar wraps on narrow phones instead of pushing "Open DXF" off-screen; 44px touch targets (#101)
- Faster first paint — self-hosted fonts kill the render-blocking Google Fonts chain; hashed assets cache immutably; trailing-slash and security headers via Vercel config (#100, #103)
Under the hood
- Widget polish: honest copy-button feedback under blocked clipboards (#96) and keylined layer swatches for light themes (#97)
- OpenAI app-directory domain verification served by the API, plus Search Console verification on the demo (#98, #99)
- Dev ergonomics: mprocs + just runbook (#94); Cloudflare leftovers removed and hosting docs refreshed (#92, #93)
Install
- Any framework or none:
npm i @aspicio/elements three - React:
npm i @aspicio/react react three· Vue:npm i @aspicio/vue vue three· Svelte:npm i @aspicio/svelte svelte three - Remote MCP (no install):
https://aspicio-api.frontsail.app/mcp· Local stdio:npx -y @aspicio/mcp - npm:
@aspicio/core·@aspicio/elements·@aspicio/react·@aspicio/vue·@aspicio/svelte·@aspicio/mcp— all 0.10.0
🤖 Generated with Claude Code
v0.9.0
Aspicio moves into its permanent home: every hosted surface now lives on branded frontsail.app domains, served from Vercel, with the DNS zone staying right where it was. No package API changes — if you consume @aspicio/* from npm, this release is a version-number ride-along.
New addresses
- Demo — https://aspicio.frontsail.app (privacy, terms, and
llms.txtincluded) - Hosted MCP —
https://aspicio-api.frontsail.app/mcp(#89) — the MCP registry listing now points here, published automatically by the tag-driven OIDC workflow's first live run - HTTP API —
https://aspicio-api.frontsail.app·/openapi.jsonnow advertises whichever origin served it (#88), so the doc stays truthful on every domain - The old workers.dev endpoints continue to serve during the transition — nothing breaks today.
Under the hood
- The API runs as a Vercel Node function built from the same platform-free handler as the Worker — native resvg instead of WASM, one prebuilt self-contained bundle, deployed from CI with post-deploy smoke tests (#88, #90)
- Rate limiting on the new host is enforced by a platform WAF rule; AGT-4/AGT-5 amended accordingly
- Directory-submission groundwork: explicit
destructiveHinton every tool, 256/48 px icons, and a generatedchatgpt-app-submission.json(#83)
Install
- Any framework or none:
npm i @aspicio/elements three - React:
npm i @aspicio/react react three· Vue:npm i @aspicio/vue vue three· Svelte:npm i @aspicio/svelte svelte three - Remote MCP (no install):
https://aspicio-api.frontsail.app/mcp· Local stdio:npx -y @aspicio/mcp - npm:
@aspicio/core·@aspicio/elements·@aspicio/react·@aspicio/vue·@aspicio/svelte·@aspicio/mcp— all 0.9.0
🤖 Generated with Claude Code
v0.8.0 — every framework, one look
Embed the viewer from React, Vue, Svelte, plain HTML, or nothing at all — and get the same pixels everywhere. This release rebuilds the embed UI as one implementation with thin framework veneers, verified pixel-identical in production builds.
The bindings family
@aspicio/elements(#84) —<aspicio-embed>,<aspicio-preview>,<aspicio-layer-panel>as Lit web components: the single implementation of the embed UI, shadow-DOM-isolated from host CSS, themable via--aspicio-*custom properties and::part()hooks. Works from plain HTML with one tag.@aspicio/react(#84) — now a thin veneer over the elements with its published API intact; existing users upgrade without code changes.@aspicio/vue(#85) — the same three components with typed props and emits, unwrapped payloads, and reactive-proxy safety (Fileuploads throughref()state just work).@aspicio/svelte(#86) — shipped as raw Svelte 5 source via thesvelteexport condition; your bundler compiles it, so it always matches your Svelte version.- Identity is measured, not promised: production-build embed screenshots across all four consumption paths differ by zero pixels, and every binding's example app runs the same e2e scenarios in dev and production modes in CI.
Examples for every path
apps/vue-example,apps/svelte-example— real integrations mirroring the React example.apps/vanilla-example— hand-rolled chrome on the rawDxfViewerAPI.apps/widget-example(#86) — the in-chat MCP Apps viewer driven by a fake host across seven configurations (sizes, light/dark, inline/fullscreen, empty, too-large, chunked pull): the widget's first end-to-end protocol coverage.
In-chat viewer polish
- Layer swatches survive strict host CSPs (#82); empty drawings get a proper state card and xref layer names dedupe (#81); README shows the widget in action (#79); directory submission prep (#80, #83).
Install
- Any framework or none:
npm i @aspicio/elements three - React:
npm i @aspicio/react react three· Vue:npm i @aspicio/vue vue three· Svelte:npm i @aspicio/svelte svelte three - Remote MCP (no install):
https://aspicio-api.dmitri-66a.workers.dev/mcp· Local stdio:npx -y @aspicio/mcp - npm:
@aspicio/core·@aspicio/elements·@aspicio/react·@aspicio/vue·@aspicio/svelte·@aspicio/mcp— all 0.8.0
🤖 Generated with Claude Code
v0.7.0 — parsing hardening, proven on a corpus
Messy real-world DXF got first-class treatment. This release hardens the parse layer against the files people actually have, pins that behavior to a public corpus, and finishes automating the MCP registry listing.
Parsing
- DXF text control codes decode properly (PARSE-9):
%%d/%%c/%%psymbols,%%nnnchar codes,\U+XXXXunicode, and caret encoding now render as the symbols drafters intended — degrees, diameters, ± — instead of literal escapes. - Out-of-range boolean header flags no longer trip parsing (PARSE-11): files written by lenient CAD exporters load instead of failing on a technicality.
- SVG export survives degenerate drawings: the viewBox is padded so zero-area content (a single point, a horizontal line) still rasterizes to a visible PNG instead of an empty image.
Proven, not promised
- The jscad/sample-files DXF corpus is pinned end to end in the test suite — parse, tessellate, and describe every file, so future parser changes regress loudly.
- The text module sits at 100% coverage on all metrics.
Release automation
- The MCP registry listing publishes automatically via GitHub OIDC on every release — no tokens, no manual
mcp-publisherstep.
Install
- Remote MCP (no install):
https://aspicio-api.dmitri-66a.workers.dev/mcp - Local stdio:
npx -y @aspicio/mcp - Claude Code:
/plugin marketplace add frontsail-ai/aspicio→/plugin install aspicio@aspicio - npm:
@aspicio/core·@aspicio/react·@aspicio/mcp— all 0.7.0
🤖 Generated with Claude Code
v0.6.1 — registry ownership proof
Patch release for official MCP registry publishing: @aspicio/mcp now embeds "mcpName": "io.github.frontsail-ai/aspicio" — the registry's proof that the npm package and the listing belong together — and server.json pins 0.6.1. A drift guard keeps the pair coherent.
No functional changes; see v0.6.0 for the in-chat viewer release.
🤖 Generated with Claude Code
v0.6.0 — the in-chat viewer release
The drawing now opens inside the conversation. This release ships the MCP Apps interactive viewer and the host-compatibility hardening that five rounds of live testing in ChatGPT and Claude demanded.
For people in chats
view_dxf— an interactive in-chat DXF viewer (#64): pan, zoom, layer toggles with the colors actually drawn, fullscreen, light/dark host theming. Works in ChatGPT, Claude, and any MCP Apps host from the same widget. The viewer shows exactly the drawing the assistant delivered — file-open controls stay off unless explicitly enabled (AGT-14).- Big drawings work everywhere (#68): small files embed in the result; larger ones are pulled by the widget itself (with chunked fallback), sidestepping host result caps (claude.ai diverts results beyond ~150K chars).
- The viewer reports its real status to the model — loaded (layers/size) or the exact failure reason — so the assistant narrates facts, not guesses.
- "Render this" shows something: for URL sources,
render_dxfincludes a direct image link chat UIs can display even where MCP image blocks are hidden (#65).
Hardening from live host testing
- Shadow-DOM isolation against host stylesheet injection; self-healing layer panels; fail-fast on silent hosts; result-generation guards against pull races (#69).
- The "empty layer panel" root cause — a focus-scroll displacement of the overflow-hidden panel via absolutely-positioned hidden checkboxes — found via live DevTools capture and fixed at the mechanism (#71).
- Server instructions steer host models to prefer (or offer) the interactive viewer over static renders (#69).
Registry-ready
serverInfonow reports the real version on every surface — stdio, remote, and core'sVERSIONexport (#63, #72).
Install
- Remote MCP (no install):
https://aspicio-api.dmitri-66a.workers.dev/mcp - Local stdio:
npx -y @aspicio/mcp - Claude Code:
/plugin marketplace add frontsail-ai/aspicio→/plugin install aspicio@aspicio - npm:
@aspicio/core·@aspicio/react·@aspicio/mcp— all 0.6.0
🤖 Generated with Claude Code