napkin-sketchdocs 1.0.0 GitHub

Working with other programs#

On this page

API hub · Reference · Quickstart · Cheatsheet

napkin-sketch trades drawings with Illustrator, Inkscape and other vector editors through SVG, which all of them read and write, writes an Illustrator script that rebuilds a drawing in Illustrator's own objects, and places files made elsewhere by reference with link. This page is the reference for what an export writes for another editor, what an import makes of another editor's file, what the Illustrator script builds, what survives the trip each way, and how a linked file differs from an imported or an embedded one.

Contents

What this is#

SVG is the common ground. An SVG napkin-sketch writes opens in Illustrator and Inkscape with its layer tree and its layer names, its curves as the same Bezier anchors, and its gradients and dashes as the SVG paint those editors show. An SVG either of them writes opens in napkin-sketch the same way round: named groups become named layers, curves stay curves, and gradients keep their stops. What only napkin-sketch knows about a mark - a brush's width profile, a Copic nib, the width of a text box - rides along in data-* attributes that other editors ignore, so napkin's own files come back as they left.

For Illustrator there is a second way across. --to jsx writes an ExtendScript file that, run in Illustrator, builds the drawing there out of Illustrator's own objects - layers, named groups, paths on the drawing's own anchors, text frames, an embedded image, and a linked file placed by link - rather than handing Illustrator an SVG to interpret.

A linked file is the other half. link places a file by reference: the drawing holds the file's path, one item on one layer stands for it, and the file is read only when an output has to draw it. That is what Illustrator calls a linked file, as opposed to an embedded one, and it is not an import, which breaks a file's contents into layers of the drawing.

The mental model#

 napkin-sketch --SVG: layer names three ways, data-* for napkin's own marks--> Illustrator, Inkscape
 napkin-sketch <--SVG: named groups become layers, curves stay curves--------- Illustrator, Inkscape
 napkin-sketch --.jsx: layers, named groups, paths on their anchors, links placed--> Illustrator
 napkin-sketch --link "assets/logo.svg"--> <image href="assets/logo.svg" data-link="true">
                                           the file is read only to draw it in a PNG
DirectionThroughWhat arrives
napkin-sketch to another editoran SVG export, or a copyThe visible layer tree under its names; every mark as a path; gradients, dashes, text and images
Another editor to napkin-sketchan SVG import, or a pasteNamed groups as layer groups, named objects as layers, curves as Bezier anchors, gradients by their stops
napkin-sketch to Illustratoran Illustrator script, --to jsxEvery layer, hidden and locked ones too, as layers and named groups; marks as paths on their anchors; text frames; images embedded and links placed
napkin-sketch to napkin-sketchan SVG export, then an importEvery visible layer and mark as it was, through the data-* attributes
A file made elsewhere into a drawinglinkOne item that stands for the file; the SVG keeps the reference

Reference#

Exporting SVG for another editor#

The app's File > Export > SVG, renderSketch(sketch, { format: 'svg' }) in code, and napkin-sketch draw card.napkin --to svg from a shell all run one writer, so they write the same file.

Importing SVG from another editor#

In the app, File > Import (Ctrl + I) or a paste; from a shell, napkin-sketch --import art.svg opens the app with the file imported. In code, importSvg from @isocialpractice/napkin-sketch does the same in a browser, where it measures the document with the DOM:

import { importSvg } from '@isocialpractice/napkin-sketch';

const imported = importSvg(svgText, { unnamedRootName: 'logo' });
// { width, height, background?, layers: [{ name, opacity, strokes, children? }] }
OptionDefaultMeaning
unnamedRootNameImportedThe name of the group a document with no groups arrives in. The app passes the file's name.
unnamedElementsmergesplit gives napkin's own exported marks a layer each, instead of merging them back onto their layer.

importSvg throws Not a valid SVG document. for text that is not SVG, and No importable content found in the SVG. for a file with nothing to draw.

What survives a round trip#

Whatnapkin-sketch, out and back inInto Illustrator or InkscapeInto Illustrator by its script
Layer namesYes, from data-nameYes, from id and inkscape:labelYes
Layer treeYesYes, as nested groups or sublayersYes, as layers and named groups
Layer opacityYesYesYes
Hidden layersNo: they are not writtenNoYes, hidden
Layer lockNoNoYes
CurvesYes, anchor for anchor at two decimalsYes, as the same BeziersYes, anchor for anchor, smooth points marked smooth
Width profiles and Copic nibsYes, from data-d, data-profile, data-nibAs the filled outline they drawAs the filled outline they draw
GradientsYes, from data-gradientYes, as SVG gradientsYes, as gradients with the same stops
DashesYes, from data-dashYes, as stroke-dasharrayYes, as strokeDashes
TextYes, with its runs, paragraphs, frame or path, and the Text Configurations its runs follow, from data-typesetAs text, a <tspan> a stretch in one style and a <textPath> for type on a path, in the reader's copy of the fontAs text frames: point, area and path type, each run's characters and each paragraph set
Markdown Flow textYes, its Markdown and its flow, from data-text and data-typesetAs it renders: the rendered text in its styles, with a quote's bars, a rule and a code block's shade as shapes under itAs it renders: the rendered text and its styles, plain text, since Illustrator has no Markdown
Code colored by a Clean Language AccentYes, live: each paragraph's accent, from data-typesetEach stretch of code in its color, a fill on its <tspan>Each stretch of code in its color, as the run's fill
Placed imagesYes, embeddedYes, embeddedYes, embedded
Linked filesYes, as linksAs a linked image, drawn when the editor can reach the fileYes, as placed items linked to the file
Erased areasYes, as eraser marks on their layerAs a maskAs strokes in the paper's color
EffectsYes, from data-effectsAs SVG filtersNo: drawn plain
A SplatterYes, live, from data-effects and the mark it stands forAs the lines it drawsAs the lines it draws
A WarpYes, live, from data-effects and the mark it stands forAs the bent shapeAs the bent paths
3DYes, live, from data-effects and the mark it stands forAs its facesAs a group of its faces

The SVG writer's reductions - shortest path spellings, shared paint on the root, defaults left unwritten - change no coordinate: a napkin export read back gives the same anchors and handles.

Rebuilding a drawing in Illustrator#

napkin-sketch draw card.napkin --to jsx - or --to jsx on render, or renderSketch(page, { format: 'jsx' }) and sketchesToJsx(pages) in code - writes an ExtendScript file. Run it in Illustrator with File > Scripts > Other Script, and it builds the drawing out of the objects Illustrator would have made of it:

napkin-sketchIllustrator
A pageA document of its own, its artboard the page, or the box the page is cut to, named after the page, a page pixel a point
The paperA locked Background layer holding one rectangle the artboard's size; none for a transparent page
A top-level layerA Layer under its name, with its opacity, hidden or locked when it is
A layer inside a groupA named GroupItem, nested as the tree nests: what Illustrator itself makes of napkin's SVG
A markA PathItem on the mark's own anchors: leftDirection is an anchor's incoming handle and rightDirection its outgoing one, and a point is SMOOTH when its handles are in line, CORNER otherwise. A freehand line is its samples, pruned as the SVG export prunes them
A mark of several contoursA CompoundPathItem, filled nonzero, so a hole stays a hole
A dotA filled circle its width across
A profiled or Copic markThe outline it fills, as the SVG export writes it
PaintRGBColors, round caps and joins, strokeDashes, and opacity, with a color's own alpha folded in; a fill and an outline of different alphas are a group of two paths
A gradientA GradientColor over a gradient with the same stops, a stop's alpha its opacity, laid on the axis the SVG draws it on
TextPoint text on its first baseline, area text in a box or a shape, or path text along a path, set in the first family of the item's font list that Illustrator has; each run's characters and each paragraph's attributes are set on their ranges, and a run that follows a Text Configuration takes the document's Character Style of its name, made once, and then its own attributes. A Markdown Flow text is written as it renders: its rendered text, its headings', code's and links' Character Styles
An imageEmbedded: its bytes ride in the script, which writes them to a scratch file, places it, embeds it as a RasterItem and deletes the file
A linkA PlacedItem whose file is the linked file: a linked file, in Illustrator's own sense

Linking files made elsewhere#

A linked file is placed, not read. In a napkin script:

link "assets/logo.svg" at 20 20 size 160 80 name "Logo"

In a composition, an image element with link: true, whose src is then a path rather than data:

design.image({ x: 20, y: 20, width: 160, height: 80, src: 'assets/logo.svg', link: true, name: 'Logo' });
OutputWhat it draws for a link
The app's canvasA placeholder: a dashed box with the file's name
SVGThe reference, <image href="assets/logo.svg" data-link="true">, which a viewer that can reach the file draws
PNGThe file, when the render is given resolveLink; the placeholder and a warning when it is not, or the file cannot be read
PDFThe placeholder, since writing the file into the PDF would import it
Illustrator scriptThe file, placed by link and found from the script's folder; the placeholder when it is not there or Illustrator will not place it
.skbkThe reference, with the placeholder beside it
LinkImportEmbed
What the drawing holdsThe file's pathThe file's contents, as layers and marksThe file's bytes, as a data URL
Rows in the Layers panelOneOne for each group and named objectOne
Editable in napkin-sketchMoved and sized, as one itemMark by markMoved and sized, as one item
A change to the fileShows up the next time an output reads itDoes not reach the drawingDoes not reach the drawing
Made withlink, or { link: true }File > Import, a paste, importSvgimage with an asset, File > Import of a PNG, JPEG, GIF or WebP

PDF#

The clipboard#

A copy in the app also goes to the system clipboard as SVG text, so it pastes into Illustrator or Inkscape, and a graphic copied in either of those pastes into the app as layers, through the same importer as File > Import. An in-app copy wins over its own SVG echo; a newer copy from outside wins over the in-app one.

Worked examples#

A layer tree that opens named everywhere. Two groups, a layer name with a space and an ampersand in it, and a layer name used twice:

napkin 1
page 320 200
name "sign"
group "Front" {
  layer "Board"
  color #1f2328 width 3 fill #ffe08a
  rect 20 20 280 120 r 12
  layer "Sun & Moon"
  fill #ff8a65
  circle 80 80 30
}
group "Back" {
  layer "Board"
  fill #326478
  rect 20 150 280 40 r 8
}

napkin-sketch draw sign.napkin --to svg writes sign.svg, whose groups read:

<g id="Front" data-name="Front" inkscape:label="Front" inkscape:groupmode="layer">
<g id="Board" data-name="Board" inkscape:label="Board" inkscape:groupmode="layer">
<g id="Sun_x20__x26__x20_Moon" data-name="Sun &amp; Moon" inkscape:label="Sun &amp; Moon" inkscape:groupmode="layer">
<g id="Back" data-name="Back" inkscape:label="Back" inkscape:groupmode="layer">
<g id="Board-2" data-name="Board" inkscape:label="Board" inkscape:groupmode="layer">

Inkscape's Layers panel reads the labels, and napkin's importer reads data-name, so the file comes back to napkin-sketch with the same five rows: Front holding Board and Sun & Moon, and Back holding Board. An editor that reads only the id gets the same names once it undoes the escapes and the suffix, as napkin's importer does for a file with no data-name.

The sign in Illustrator. The same script, drawn as an Illustrator script:

napkin-sketch draw sign.napkin --to jsx

sign.jsx builds the page one call a layer and a mark, in paint order, each nested layer inside its group. The circle's four points are smooth, each with its two handles:

    page("sign", 0, 0, 320, 200);
    paper([252, 250, 245], 100);
    open("Front", 100);
      open("Board", 100);
        path([[[32, 20, 25.37, 20, 32, 20, 0], ... ]], true, {stroke: [31, 35, 40], width: 3, fill: [255, 224, 138]});
      close(true, false);
      open("Sun & Moon", 100);
        path([[[110, 80, 110, 63.43, 110, 96.57, 1], [80, 110, 96.57, 110, 63.43, 110, 1], [50, 80, 50, 96.57, 50, 63.43, 1], [80, 50, 63.43, 50, 96.57, 50, 1]]], true, {stroke: [31, 35, 40], width: 3, fill: [255, 138, 101]});
      close(true, false);
    close(true, false);
    open("Back", 100);

The document it builds has one 320 by 200 point artboard named sign, and its layers, top first as Illustrator's Layers panel lists them, are Back holding a group Board, Front holding the groups Sun & Moon and Board, and the locked Background. The names are the names as typed, with no escapes, since a layer's name in Illustrator is free text.

A logo linked, not imported. A letterhead that places assets/logo.svg by reference and draws a rule under it:

napkin 1
page 400 240
name "letterhead"
background #ffffff
link "assets/logo.svg" at 20 20 size 160 80 name "Logo"
layer "Rule"
color #326478 width 2
line 20 120 380 120
napkin-sketch draw letterhead.napkin --to svg,png

The SVG holds the reference and nothing of the logo:

<image x="20" y="20" width="160" height="80" preserveAspectRatio="none" href="assets/logo.svg" data-link="true" data-name="logo.svg" data-tool="image" data-i="0"/>

The PNG has the logo drawn in it, read from assets/logo.svg beside the script, because the command line hands the render a resolver for the script's folder. Edit the logo and draw again, and both files carry the new one. Move the logo away, and draw still writes both, with the placeholder in the PNG, warns that assets/logo.svg could not be read, and exits with code 3.

Limits#

For agents#

See also#