Review: one point-index parser for freeform lines; i18n; ROADMAP (#1056)
parse_freeform and paint.freeform.addLine share point_indices, which also keeps addLine from wrapping a huge index round on 32-bit targets (wasm). The new messages are in the catalogs that translate every message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f5111045a9
commit
adfe6e3820
|
|
@ -123,7 +123,7 @@ Ranked; detail in [docs/roadmap.md](docs/roadmap.md) and [docs/gaps.md](docs/gap
|
|||
|
||||
| Date | What landed |
|
||||
|---|---|
|
||||
| 2026-10-11 | Effect › Brush Strokes: Accented Edges, Angled Strokes, Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes, Sumi-e (G2). Command parameters from agents and files checked before anything changes (paint, place, cuts, dashes, crop, asset ids, anchors, paths, distort; #984–#999); command dialogs keep whole numbers whole, so Create Object Mosaic takes the tiles typed (#1000); stepper arrows take Shift (×10) and Ctrl/Cmd (÷10) like the arrow keys (#991). Exports and Rasterize supersample Art Optimized edges, so shapes meeting edge to edge leave no seam (#983). Character and paragraph styles take leading, kerning, mojikumi and the other attributes left out at their defaults (#1001). Drawing, typing and pasting with no layer shown and unlocked is refused instead of adding art to a hidden or locked layer (#1002). MCP `add_text` gives type on or in a path the colour asked for (#1003). MCP `screenshot` of a connected app renders the artboard asked for (#1004). `vectorcraft-cli run` ends quietly when its reader closes early (#1005). Select › All on Active Artboard selects on the artboard made active, not always the first (#1006). Reverse Gradient keeps off-centre midpoints, mirrored (#1007). A polar grid with no radial dividers draws none (#1008). Use Precise Cursors also covers the Pen's join pointer (#1009). SVGs with one absolute and one unitless root side import at their size, unstretched (#1010). DXF US survey inches, yards and miles open at their size and name (#1011). A file placed into a document with no other links follows its first change even while the app sits idle (#1031). PDF import keeps the style a font name says when the file doesn't embed the font (#1023). Shift selects ruler guides and art together, and Delete removes both (#1022). Open filled paths are hit by their fill on every side, the rotate cursor bows around the corner it is at, the flip icons match their flips, the Color Picker previews on the selection, and Properties › Transform reaches Scale Corners and Scale Strokes & Effects (#1036). Offset Path and the other booleans finish on outlines where the sweep used to loop until memory ran out (linesweeper 0.5, #1028). Floating panel groups stack into sets that move together, collapse to their tabs and dock as extra dock columns that scroll (#1020). Ruler guides live on layers: listed in the Layers panel, shown, hidden, locked, duplicated, merged and deleted with their layer, and moved between layers (#1021). A `.ai` whose editing data uses global process colours (`Xk`/`XK`) or pattern fills keeps its sublayers: the colours come in as global swatches at their tint, the patterns as pattern swatches (#1025). A `.ai` in PostScript form opens through its layers, read from the program itself, also when it names the prolog defining its operators without including it, as Rhino and other CAD apps write it (#1027). A fill or stroke chosen while the Type tool has characters selected colours just those characters (#1063). Scaled type shows its scaled font size, leading, baseline shift and horizontal scale in the Character panel, and a size typed there is the size you get (#1034). Character panel menu › Proportional Metrics sets Japanese and Chinese full-width glyphs on the font's proportional widths in horizontal type (#966). Align, Distribute, Move, Arrange, Lock, Hide, Ungroup and other Object commands that would change nothing no longer record an undo step or mark the document changed (#1060). Spot colours defined in Lab open with their Lab values from `.ai` and PDF files, instead of as wrong RGB colours or their CMYK equivalents (#1032). Build scripts leave a generated source they wouldn't change untouched, so the next build doesn't compile most of the workspace again where file times lose their sub-second part (#1051). A fill colour recolours the gradient mesh point last clicked with the Mesh tool or Direct Selection, and a Mesh tool click on a mesh's point selects that mesh (#1052). The All Tools drawer stays two tools wide instead of filling a wide window (#1054). Text Wrap's Make, Release and Options refuse a list of object ids with a malformed or unknown id instead of skipping it (#1055). |
|
||||
| 2026-10-11 | Effect › Brush Strokes: Accented Edges, Angled Strokes, Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes, Sumi-e (G2). Command parameters from agents and files checked before anything changes (paint, place, cuts, dashes, crop, asset ids, anchors, paths, distort; #984–#999); command dialogs keep whole numbers whole, so Create Object Mosaic takes the tiles typed (#1000); stepper arrows take Shift (×10) and Ctrl/Cmd (÷10) like the arrow keys (#991). Exports and Rasterize supersample Art Optimized edges, so shapes meeting edge to edge leave no seam (#983). Character and paragraph styles take leading, kerning, mojikumi and the other attributes left out at their defaults (#1001). Drawing, typing and pasting with no layer shown and unlocked is refused instead of adding art to a hidden or locked layer (#1002). MCP `add_text` gives type on or in a path the colour asked for (#1003). MCP `screenshot` of a connected app renders the artboard asked for (#1004). `vectorcraft-cli run` ends quietly when its reader closes early (#1005). Select › All on Active Artboard selects on the artboard made active, not always the first (#1006). Reverse Gradient keeps off-centre midpoints, mirrored (#1007). A polar grid with no radial dividers draws none (#1008). Use Precise Cursors also covers the Pen's join pointer (#1009). SVGs with one absolute and one unitless root side import at their size, unstretched (#1010). DXF US survey inches, yards and miles open at their size and name (#1011). A file placed into a document with no other links follows its first change even while the app sits idle (#1031). PDF import keeps the style a font name says when the file doesn't embed the font (#1023). Shift selects ruler guides and art together, and Delete removes both (#1022). Open filled paths are hit by their fill on every side, the rotate cursor bows around the corner it is at, the flip icons match their flips, the Color Picker previews on the selection, and Properties › Transform reaches Scale Corners and Scale Strokes & Effects (#1036). Offset Path and the other booleans finish on outlines where the sweep used to loop until memory ran out (linesweeper 0.5, #1028). Floating panel groups stack into sets that move together, collapse to their tabs and dock as extra dock columns that scroll (#1020). Ruler guides live on layers: listed in the Layers panel, shown, hidden, locked, duplicated, merged and deleted with their layer, and moved between layers (#1021). A `.ai` whose editing data uses global process colours (`Xk`/`XK`) or pattern fills keeps its sublayers: the colours come in as global swatches at their tint, the patterns as pattern swatches (#1025). A `.ai` in PostScript form opens through its layers, read from the program itself, also when it names the prolog defining its operators without including it, as Rhino and other CAD apps write it (#1027). A fill or stroke chosen while the Type tool has characters selected colours just those characters (#1063). Scaled type shows its scaled font size, leading, baseline shift and horizontal scale in the Character panel, and a size typed there is the size you get (#1034). Character panel menu › Proportional Metrics sets Japanese and Chinese full-width glyphs on the font's proportional widths in horizontal type (#966). Align, Distribute, Move, Arrange, Lock, Hide, Ungroup and other Object commands that would change nothing no longer record an undo step or mark the document changed (#1060). Spot colours defined in Lab open with their Lab values from `.ai` and PDF files, instead of as wrong RGB colours or their CMYK equivalents (#1032). Build scripts leave a generated source they wouldn't change untouched, so the next build doesn't compile most of the workspace again where file times lose their sub-second part (#1051). A fill colour recolours the gradient mesh point last clicked with the Mesh tool or Direct Selection, and a Mesh tool click on a mesh's point selects that mesh (#1052). The All Tools drawer stays two tools wide instead of filling a wide window (#1054). Text Wrap's Make, Release and Options refuse a list of object ids with a malformed or unknown id instead of skipping it (#1055). A freeform gradient line with a malformed point index is refused instead of being shortened to the indices that are valid (#1056). |
|
||||
| 2026-10-10 | Initial live Revolve (Effect › 3D and Materials, #846, #605), in its own `three-d` crate. Progress docs re-measured and restructured to the craftrules standard (this page, `docs/target-app-parity.md`, `gaps.md`, `ui-parity.md`, the format, hardware, localization, effects and type checklists). Same day: v0.8.0; Effect › Distort, Pixelate and Texture filters (13); German interface; Variables (data merge); Graph Type value axes and tick marks; restart when the first frame never reaches the screen (#964) |
|
||||
| 2026-10-09 | Radial Blur, Smart Blur, Unsharp Mask (gap 2 begins); 340 commits, the busiest day |
|
||||
| 2026-10-08 | v0.5.0–v0.7.0; community contributions: Pen and shape-tool modifiers, Layers, Artboards, Japanese composition, Hebrew/Arabic type, interface languages, saved selections |
|
||||
|
|
|
|||
|
|
@ -150,16 +150,9 @@ pub(crate) fn parse_freeform(v: &Value) -> std::result::Result<Freeform, String>
|
|||
}
|
||||
if let Some(lines) = v.get("lines") {
|
||||
let lines = lines.as_array().ok_or("`freeform.lines` must be an array")?;
|
||||
for (line, values) in lines.iter().enumerate() {
|
||||
let values = values.as_array().ok_or_else(|| format!("freeform line {line} must be an array of point indices"))?;
|
||||
let indices: Vec<usize> = values
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let id = v.as_u64().ok_or_else(|| format!("freeform line {line} has a non-integer point index: {v}"))?;
|
||||
usize::try_from(id).map_err(|_| format!("freeform line {line} has an out-of-range point index: {id}"))
|
||||
})
|
||||
.collect::<std::result::Result<_, _>>()?;
|
||||
f.add_line(indices).map_err(|e| format!("freeform line {line}: {e}"))?;
|
||||
for (i, l) in lines.iter().enumerate() {
|
||||
let ix = point_indices(l).ok_or_else(|| format!("freeform line {i} must be an array of point indices"))?;
|
||||
f.add_line(ix).map_err(|e| format!("freeform line {i}: {e}"))?;
|
||||
}
|
||||
}
|
||||
if let Some(m) = str_param(v, "mode") {
|
||||
|
|
@ -168,6 +161,12 @@ pub(crate) fn parse_freeform(v: &Value) -> std::result::Result<Freeform, String>
|
|||
Ok(f)
|
||||
}
|
||||
|
||||
/// `v` as a list of point indices: `None` unless it is an array of non-negative integers, so no
|
||||
/// malformed index is dropped or wrapped round.
|
||||
fn point_indices(v: &Value) -> Option<Vec<usize>> {
|
||||
v.as_array()?.iter().map(|i| usize::try_from(i.as_u64()?).ok()).collect()
|
||||
}
|
||||
|
||||
pub(crate) fn parse_mode(m: &str) -> std::result::Result<FreeformMode, String> {
|
||||
FreeformMode::parse(m).ok_or_else(|| format!("unknown freeform mode `{m}` (points, lines)"))
|
||||
}
|
||||
|
|
@ -289,11 +288,7 @@ fn delete_point(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
|
||||
fn add_line(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "paint.freeform.addLine";
|
||||
let points: Vec<usize> = p
|
||||
.get("points")
|
||||
.and_then(Value::as_array)
|
||||
.and_then(|a| a.iter().map(|v| v.as_u64().map(|i| i as usize)).collect())
|
||||
.ok_or_else(|| bad(C, "`points` must be an array of point indices"))?;
|
||||
let points = p.get("points").and_then(point_indices).ok_or_else(|| bad(C, "`points` must be an array of point indices"))?;
|
||||
let line = edit(s, p, C, |f, _| f.add_line(points.clone()))?;
|
||||
Ok(json!({ "line": line }))
|
||||
}
|
||||
|
|
@ -334,11 +329,11 @@ fn get(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
Ok(v)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod parse_tests {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// A line with an index that isn't a point's is refused, not shortened to the indices that are.
|
||||
#[test]
|
||||
fn malformed_freeform_lines_are_not_silently_shortened() {
|
||||
let points = json!([
|
||||
|
|
@ -346,13 +341,7 @@ mod parse_tests {
|
|||
{"at": [50, 0], "color": "#00ff00"},
|
||||
{"at": [100, 0], "color": "#0000ff"}
|
||||
]);
|
||||
for lines in [
|
||||
json!([[0, "broken", 2]]),
|
||||
json!([[0, -1, 2]]),
|
||||
json!([[0, 1.5, 2]]),
|
||||
json!([{"points": [0, 1]}]),
|
||||
json!("not an array"),
|
||||
] {
|
||||
for lines in [json!([[0, "broken", 2]]), json!([[0, -1, 2]]), json!([[0, 1.5, 2]]), json!([{"points": [0, 1]}]), json!("not an array")] {
|
||||
let value = json!({"points": points, "lines": lines, "mode": "lines"});
|
||||
assert!(parse_freeform(&value).is_err(), "invalid lines accepted: {value}");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3321,6 +3321,7 @@ theme Appearance Erscheinungsbild
|
|||
@msg `color` must be a colour `color` muss eine Farbe sein
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` muss ein Befehl sein, dessen Menüeintrag ein Dialogfeld öffnet (siehe ui.menuDialog)
|
||||
@msg `freeform.points` must be an array `freeform.points` muss ein Array sein
|
||||
@msg `freeform.lines` must be an array `freeform.lines` muss ein Array sein
|
||||
@msg `gradient` must be an object `gradient` muss ein Objekt sein
|
||||
@msg `library` is a library id or name (see {list}) `library` ist die ID oder der Name einer Bibliothek (siehe {list})
|
||||
@msg `mode` applies to freeform gradients `mode` gilt für Freiformverläufe
|
||||
|
|
@ -3422,6 +3423,7 @@ theme Appearance Erscheinungsbild
|
|||
@msg empty path leerer Pfad
|
||||
@msg file version {0} is newer than this VectorCraft supports ({VERSION}) die Dateiversion {0} ist neuer, als dieses VectorCraft unterstützt ({VERSION})
|
||||
@msg freeform point {i} needs `at` [x, y] and a valid `color` Freiformpunkt {i} braucht `at` [x, y] und eine gültige `color`
|
||||
@msg freeform line {i} must be an array of point indices Freiformlinie {i} muss ein Array von Punktindizes sein
|
||||
@msg give both `start` and `end` [x, y] (or neither) geben Sie sowohl `start` als auch `end` [x, y] an (oder keines von beiden)
|
||||
@msg give corners of the path: anchors between two straight sides geben Sie Ecken des Pfads an: Ankerpunkte zwischen zwei geraden Seiten
|
||||
@msg give the path `id` and the width point `index` geben Sie die `id` des Pfads und den `index` des Breitenpunkts an
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3422,6 +3422,7 @@ axis Both Ambos
|
|||
@msg `color` must be a colour `color` debe ser un color
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` debe ser un comando cuyo elemento de menú abra un cuadro de diálogo (consulta ui.menuDialog)
|
||||
@msg `freeform.points` must be an array `freeform.points` debe ser una lista
|
||||
@msg `freeform.lines` must be an array `freeform.lines` debe ser una lista
|
||||
@msg `gradient` must be an object `gradient` debe ser un objeto
|
||||
@msg `library` is a library id or name (see {list}) `library` es el id o el nombre de una biblioteca (consulta {list})
|
||||
@msg `mode` applies to freeform gradients `mode` se aplica a los degradados de forma libre
|
||||
|
|
@ -3523,6 +3524,7 @@ axis Both Ambos
|
|||
@msg empty path trazado vacío
|
||||
@msg file version {0} is newer than this VectorCraft supports ({VERSION}) la versión de archivo {0} es más reciente de lo que admite este VectorCraft ({VERSION})
|
||||
@msg freeform point {i} needs `at` [x, y] and a valid `color` el punto de forma libre {i} necesita `at` [x, y] y un `color` válido
|
||||
@msg freeform line {i} must be an array of point indices la línea de forma libre {i} debe ser una lista de índices de puntos
|
||||
@msg give both `start` and `end` [x, y] (or neither) indica `start` y `end` [x, y] (o ninguno de los dos)
|
||||
@msg give corners of the path: anchors between two straight sides indica esquinas del trazado: puntos de ancla entre dos lados rectos
|
||||
@msg give the path `id` and the width point `index` indica el `id` del trazado y el `index` del punto de anchura
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3419,6 +3419,7 @@ axis Both Les deux
|
|||
@msg `color` must be a colour `color` doit être une couleur
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` doit être une commande dont l’élément de menu ouvre une boîte de dialogue (voir ui.menuDialog)
|
||||
@msg `freeform.points` must be an array `freeform.points` doit être un tableau
|
||||
@msg `freeform.lines` must be an array `freeform.lines` doit être un tableau
|
||||
@msg `gradient` must be an object `gradient` doit être un objet
|
||||
@msg `library` is a library id or name (see {list}) `library` est l’identifiant ou le nom d’une bibliothèque (voir {list})
|
||||
@msg `mode` applies to freeform gradients `mode` s’applique aux dégradés de forme libre
|
||||
|
|
@ -3520,6 +3521,7 @@ axis Both Les deux
|
|||
@msg empty path tracé vide
|
||||
@msg file version {0} is newer than this VectorCraft supports ({VERSION}) la version de fichier {0} est plus récente que celles que prend en charge cette version de VectorCraft ({VERSION})
|
||||
@msg freeform point {i} needs `at` [x, y] and a valid `color` le point de forme libre {i} nécessite `at` [x, y] et une `color` valide
|
||||
@msg freeform line {i} must be an array of point indices la ligne de forme libre {i} doit être un tableau d’indices de points
|
||||
@msg give both `start` and `end` [x, y] (or neither) indiquez à la fois `start` et `end` [x, y] (ou aucun des deux)
|
||||
@msg give corners of the path: anchors between two straight sides indiquez des angles du tracé : des points d’ancrage entre deux côtés droits
|
||||
@msg give the path `id` and the width point `index` indiquez l’`id` du tracé et l’`index` du point de largeur
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3422,6 +3422,7 @@ axis Both Entrambi
|
|||
@msg `color` must be a colour `color` deve essere un colore
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` deve essere un comando la cui voce di menu apre una finestra di dialogo (vedi ui.menuDialog)
|
||||
@msg `freeform.points` must be an array `freeform.points` deve essere un array
|
||||
@msg `freeform.lines` must be an array `freeform.lines` deve essere un array
|
||||
@msg `gradient` must be an object `gradient` deve essere un oggetto
|
||||
@msg `library` is a library id or name (see {list}) `library` è l'id o il nome di una libreria (vedi {list})
|
||||
@msg `mode` applies to freeform gradients `mode` si applica alle sfumature a forma libera
|
||||
|
|
@ -3523,6 +3524,7 @@ axis Both Entrambi
|
|||
@msg empty path tracciato vuoto
|
||||
@msg file version {0} is newer than this VectorCraft supports ({VERSION}) la versione del file {0} è più recente di quelle supportate da questo VectorCraft ({VERSION})
|
||||
@msg freeform point {i} needs `at` [x, y] and a valid `color` il punto a forma libera {i} richiede `at` [x, y] e un `color` valido
|
||||
@msg freeform line {i} must be an array of point indices la linea a forma libera {i} deve essere un array di indici di punti
|
||||
@msg give both `start` and `end` [x, y] (or neither) specifica sia `start` sia `end` [x, y] (o nessuno dei due)
|
||||
@msg give corners of the path: anchors between two straight sides specifica angoli del tracciato: punti di ancoraggio tra due lati diritti
|
||||
@msg give the path `id` and the width point `index` specifica l'`id` del tracciato e l'`index` del punto di larghezza
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3471,9 +3471,11 @@ theme Appearance 外観
|
|||
@msg `at` must be [x, y] `at` は [x, y] の形式で指定してください
|
||||
@msg `color` must be a colour `color` にはカラーを指定してください
|
||||
@msg `freeform.points` must be an array `freeform.points` には配列を指定してください
|
||||
@msg `freeform.lines` must be an array `freeform.lines` には配列を指定してください
|
||||
@msg `{key}` must be a number `{key}` には数値を指定してください
|
||||
@msg a freeform gradient keeps at least one point フリーフォームグラデーションには少なくとも 1 つのポイントが必要です
|
||||
@msg freeform point {i} needs `at` [x, y] and a valid `color` フリーフォームのポイント {i} には `at` [x, y] と有効な `color` が必要です
|
||||
@msg freeform line {i} must be an array of point indices フリーフォームのライン {i} にはポイントのインデックスの配列を指定してください
|
||||
@msg no point {i} (the gradient has {_1}) ポイント {i} はありません (このグラデーションのポイントは {_1} 個です)
|
||||
@msg no segment {segment} on line {line} ライン {line} にセグメント {segment} はありません
|
||||
@msg unknown freeform mode `{m}` (points, lines) `{m}` は不明なフリーフォームのモードです (points、lines)
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3418,6 +3418,7 @@ axis Both Оба
|
|||
@msg `color` must be a colour `color` должно быть цветом
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` должно быть командой, пункт меню которой открывает диалоговое окно (см. ui.menuDialog)
|
||||
@msg `freeform.points` must be an array `freeform.points` должно быть массивом
|
||||
@msg `freeform.lines` must be an array `freeform.lines` должно быть массивом
|
||||
@msg `gradient` must be an object `gradient` должно быть объектом
|
||||
@msg `library` is a library id or name (see {list}) `library` — это идентификатор или имя библиотеки (см. {list})
|
||||
@msg `mode` applies to freeform gradients `mode` применяется к произвольным градиентам
|
||||
|
|
@ -3519,6 +3520,7 @@ axis Both Оба
|
|||
@msg empty path пустой контур
|
||||
@msg file version {0} is newer than this VectorCraft supports ({VERSION}) версия файла {0} новее, чем поддерживает этот VectorCraft ({VERSION})
|
||||
@msg freeform point {i} needs `at` [x, y] and a valid `color` произвольной точке {i} нужны `at` [x, y] и допустимый `color`
|
||||
@msg freeform line {i} must be an array of point indices произвольная линия {i} должна быть массивом индексов точек
|
||||
@msg give both `start` and `end` [x, y] (or neither) укажите и `start`, и `end` [x, y] (или ни одного)
|
||||
@msg give corners of the path: anchors between two straight sides укажите углы контура: опорные точки между двумя прямыми сторонами
|
||||
@msg give the path `id` and the width point `index` укажите `id` контура и `index` точки ширины
|
||||
|
|
|
|||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
|
|
@ -3405,6 +3405,7 @@ axis Both Обидві
|
|||
@msg `color` must be a colour `color` має бути кольором
|
||||
@msg `command` must be a command whose menu item opens a dialog (see ui.menuDialog) `command` має бути командою, пункт меню якої відкриває діалогове вікно (див. ui.menuDialog)
|
||||
@msg `freeform.points` must be an array `freeform.points` має бути масивом
|
||||
@msg `freeform.lines` must be an array `freeform.lines` має бути масивом
|
||||
@msg `gradient` must be an object `gradient` має бути об’єктом
|
||||
@msg `library` is a library id or name (see {list}) `library` — це ідентифікатор або ім’я бібліотеки (див. {list})
|
||||
@msg `mode` applies to freeform gradients `mode` застосовується до довільних градієнтів
|
||||
|
|
@ -3506,6 +3507,7 @@ axis Both Обидві
|
|||
@msg empty path порожній контур
|
||||
@msg file version {0} is newer than this VectorCraft supports ({VERSION}) версія файлу {0} новіша, ніж підтримує цей VectorCraft ({VERSION})
|
||||
@msg freeform point {i} needs `at` [x, y] and a valid `color` довільній точці {i} потрібні `at` [x, y] та допустимий `color`
|
||||
@msg freeform line {i} must be an array of point indices довільна лінія {i} має бути масивом індексів точок
|
||||
@msg give both `start` and `end` [x, y] (or neither) вкажіть `start`, `end` [x, y] (або жодного)
|
||||
@msg give corners of the path: anchors between two straight sides вкажіть кути контуру: опорні точки між двома прямими сторонами
|
||||
@msg give the path `id` and the width point `index` вкажіть `id` контуру та `index` точки ширини
|
||||
|
|
|
|||
|
Can't render this file because it has a wrong number of fields in line 13.
|
Loading…
Reference in New Issue