Release v0.11.4
This commit is contained in:
parent
7e7036b422
commit
26a7d2d454
|
|
@ -2,6 +2,14 @@
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
## 0.11.4 — 2026-04-08
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- Fix `@open-pencil/core` published package containing stale import paths from before the domain module restructuring — CLI and MCP installs from npm now resolve correctly
|
||||||
|
- Add `save_file` MCP tool for saving the current document to disk
|
||||||
|
- Clipboard text export now writes richer v4 `derivedTextData` payloads with glyph outlines for better paste fidelity
|
||||||
|
|
||||||
## 0.11.3 — 2026-04-08
|
## 0.11.3 — 2026-04-08
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "OpenPencil",
|
"productName": "OpenPencil",
|
||||||
"version": "0.11.3",
|
"version": "0.11.4",
|
||||||
"identifier": "net.dannote.open-pencil",
|
"identifier": "net.dannote.open-pencil",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "bun run dev",
|
"beforeDevCommand": "bun run dev",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "open-pencil-app",
|
"name": "open-pencil-app",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.11.3",
|
"version": "0.11.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@open-pencil/cli",
|
"name": "@open-pencil/cli",
|
||||||
"version": "0.11.3",
|
"version": "0.11.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@open-pencil/core",
|
"name": "@open-pencil/core",
|
||||||
"version": "0.11.3",
|
"version": "0.11.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { resolveRGBAForPreview } from '../color/management'
|
|
||||||
import { getCanvasKit } from '../canvaskit'
|
import { getCanvasKit } from '../canvaskit'
|
||||||
|
import { resolveRGBAForPreview } from '../color/management'
|
||||||
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from '../constants'
|
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from '../constants'
|
||||||
import { resolveNodeTextDirection } from '../text/direction'
|
import { resolveNodeTextDirection } from '../text/direction'
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ import {
|
||||||
makeCanvasNodeChange,
|
makeCanvasNodeChange,
|
||||||
buildFontDigestMap
|
buildFontDigestMap
|
||||||
} from './kiwi/serialize'
|
} from './kiwi/serialize'
|
||||||
import { buildDerivedTextDataV4 } from './text/clipboard-derived-text'
|
|
||||||
import { randomInt } from './random'
|
import { randomInt } from './random'
|
||||||
|
import { buildDerivedTextDataV4 } from './text/clipboard-derived-text'
|
||||||
|
|
||||||
import type { NodeChange as KiwiNodeChange } from './kiwi/codec'
|
import type { NodeChange as KiwiNodeChange } from './kiwi/codec'
|
||||||
import type { InstanceNodeChange } from './kiwi/instance-overrides'
|
import type { InstanceNodeChange } from './kiwi/instance-overrides'
|
||||||
|
|
@ -317,7 +317,16 @@ export async function buildFigmaClipboardHTML(
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
collectTextNodes(nodes[i])
|
collectTextNodes(nodes[i])
|
||||||
nodeChanges.push(
|
nodeChanges.push(
|
||||||
...sceneNodeToKiwi(nodes[i], canvasGuid, i, localIdCounter, graph, blobs, undefined, fontDigestMap)
|
...sceneNodeToKiwi(
|
||||||
|
nodes[i],
|
||||||
|
canvasGuid,
|
||||||
|
i,
|
||||||
|
localIdCounter,
|
||||||
|
graph,
|
||||||
|
blobs,
|
||||||
|
undefined,
|
||||||
|
fontDigestMap
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ export const FIG_KIWI_DEFAULT_VERSION = 101
|
||||||
|
|
||||||
import { deflateSync, inflateSync } from 'fflate'
|
import { deflateSync, inflateSync } from 'fflate'
|
||||||
|
|
||||||
import { getGlyphOutlineCommandsSync } from '../text/opentype'
|
|
||||||
import { getLoadedFontData, normalizeFontFamily, weightToStyle } from '../text/fonts'
|
import { getLoadedFontData, normalizeFontFamily, weightToStyle } from '../text/fonts'
|
||||||
|
import { getGlyphOutlineCommandsSync } from '../text/opentype'
|
||||||
import { encodeVectorNetworkBlob, buildStyleOverrideTable } from '../vector'
|
import { encodeVectorNetworkBlob, buildStyleOverrideTable } from '../vector'
|
||||||
import { stringToGuid, VARIABLE_BINDING_FIELDS } from './convert'
|
import { stringToGuid, VARIABLE_BINDING_FIELDS } from './convert'
|
||||||
import { sceneNodeToKiwiWithContext, type KiwiNodeChange } from './node-export'
|
import { sceneNodeToKiwiWithContext, type KiwiNodeChange } from './node-export'
|
||||||
|
|
@ -208,7 +208,8 @@ function buildDerivedTextData(
|
||||||
}
|
}
|
||||||
|
|
||||||
const style = weightToStyle(node.fontWeight, node.italic)
|
const style = weightToStyle(node.fontWeight, node.italic)
|
||||||
const glyphCommandLists = getGlyphOutlineCommandsSync(node.fontFamily, style, node.text, node.fontSize) ?? []
|
const glyphCommandLists =
|
||||||
|
getGlyphOutlineCommandsSync(node.fontFamily, style, node.text, node.fontSize) ?? []
|
||||||
const lineHeight = node.lineHeight ?? Math.ceil(node.fontSize * 1.2)
|
const lineHeight = node.lineHeight ?? Math.ceil(node.fontSize * 1.2)
|
||||||
const glyphAdvance = node.text.length > 0 ? node.width / Math.max(node.text.length, 1) : 0
|
const glyphAdvance = node.text.length > 0 ? node.width / Math.max(node.text.length, 1) : 0
|
||||||
|
|
||||||
|
|
@ -221,8 +222,9 @@ function buildDerivedTextData(
|
||||||
rotation: 0
|
rotation: 0
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const logicalIndexToCharacterOffsetMap = Array.from({ length: node.text.length + 1 }, (_, index) =>
|
const logicalIndexToCharacterOffsetMap = Array.from(
|
||||||
index * glyphAdvance
|
{ length: node.text.length + 1 },
|
||||||
|
(_, index) => index * glyphAdvance
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -234,7 +236,7 @@ function buildDerivedTextData(
|
||||||
position: { x: 0, y: lineHeight },
|
position: { x: 0, y: lineHeight },
|
||||||
width: node.width,
|
width: node.width,
|
||||||
lineHeight,
|
lineHeight,
|
||||||
lineAscent: Math.max(lineHeight - (node.fontSize * 0.2), 0)
|
lineAscent: Math.max(lineHeight - node.fontSize * 0.2, 0)
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
glyphs,
|
glyphs,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { normalizeFontFamily, weightToStyle } from './fonts'
|
import { normalizeFontFamily, weightToStyle } from './fonts'
|
||||||
import { getGlyphOutlineCommandsSync } from './opentype'
|
import { getGlyphOutlineCommandsSync } from './opentype'
|
||||||
|
|
||||||
import type { SceneNode } from '../scene-graph'
|
|
||||||
import type { NodeChange } from '../kiwi/codec'
|
import type { NodeChange } from '../kiwi/codec'
|
||||||
|
import type { SceneNode } from '../scene-graph'
|
||||||
|
|
||||||
export interface ShapedClipboardText {
|
export interface ShapedClipboardText {
|
||||||
lineHeight: number
|
lineHeight: number
|
||||||
|
|
@ -27,7 +27,8 @@ export async function buildDerivedTextDataV4(
|
||||||
const normalizedFamily = normalizeFontFamily(node.fontFamily)
|
const normalizedFamily = normalizeFontFamily(node.fontFamily)
|
||||||
const key = `${normalizedFamily}|${style}`
|
const key = `${normalizedFamily}|${style}`
|
||||||
const lineHeightFallback = node.lineHeight ?? Math.ceil(node.fontSize * 1.2)
|
const lineHeightFallback = node.lineHeight ?? Math.ceil(node.fontSize * 1.2)
|
||||||
const glyphCommandLists = getGlyphOutlineCommandsSync(node.fontFamily, style, node.text, node.fontSize) ?? []
|
const glyphCommandLists =
|
||||||
|
getGlyphOutlineCommandsSync(node.fontFamily, style, node.text, node.fontSize) ?? []
|
||||||
|
|
||||||
const glyphs = glyphCommandLists.map((commands, index) => {
|
const glyphs = glyphCommandLists.map((commands, index) => {
|
||||||
const shapedGlyph = shaped?.glyphs[index]
|
const shapedGlyph = shaped?.glyphs[index]
|
||||||
|
|
@ -35,7 +36,7 @@ export async function buildDerivedTextDataV4(
|
||||||
commands,
|
commands,
|
||||||
position: {
|
position: {
|
||||||
x: shapedGlyph?.x ?? 0,
|
x: shapedGlyph?.x ?? 0,
|
||||||
y: shapedGlyph?.y ?? (shaped?.baseline ?? lineHeightFallback)
|
y: shapedGlyph?.y ?? shaped?.baseline ?? lineHeightFallback
|
||||||
},
|
},
|
||||||
fontSize: node.fontSize,
|
fontSize: node.fontSize,
|
||||||
firstCharacter: shapedGlyph?.firstCharacter ?? index,
|
firstCharacter: shapedGlyph?.firstCharacter ?? index,
|
||||||
|
|
@ -53,7 +54,7 @@ export async function buildDerivedTextDataV4(
|
||||||
position: { x: 0, y: shaped?.baseline ?? lineHeightFallback },
|
position: { x: 0, y: shaped?.baseline ?? lineHeightFallback },
|
||||||
width: shaped?.lineWidth ?? node.width,
|
width: shaped?.lineWidth ?? node.width,
|
||||||
lineHeight: shaped?.lineHeight ?? lineHeightFallback,
|
lineHeight: shaped?.lineHeight ?? lineHeightFallback,
|
||||||
lineAscent: shaped?.lineAscent ?? Math.max(lineHeightFallback - (node.fontSize * 0.2), 0)
|
lineAscent: shaped?.lineAscent ?? Math.max(lineHeightFallback - node.fontSize * 0.2, 0)
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
glyphs,
|
glyphs,
|
||||||
|
|
@ -67,7 +68,8 @@ export async function buildDerivedTextDataV4(
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
logicalIndexToCharacterOffsetMap:
|
logicalIndexToCharacterOffsetMap:
|
||||||
shaped?.logicalIndexToCharacterOffsetMap ?? Array.from({ length: node.text.length + 1 }, () => 0),
|
shaped?.logicalIndexToCharacterOffsetMap ??
|
||||||
|
Array.from({ length: node.text.length + 1 }, () => 0),
|
||||||
derivedLines: [{ directionality: 'LTR' }],
|
derivedLines: [{ directionality: 'LTR' }],
|
||||||
truncationStartIndex: -1,
|
truncationStartIndex: -1,
|
||||||
truncatedHeight: -1
|
truncatedHeight: -1
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@open-pencil/mcp",
|
"name": "@open-pencil/mcp",
|
||||||
"version": "0.11.3",
|
"version": "0.11.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/server.js",
|
"main": "./dist/server.js",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@open-pencil/vue",
|
"name": "@open-pencil/vue",
|
||||||
"version": "0.11.3",
|
"version": "0.11.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue