Commit Graph
2797 Commits
Author SHA1 Message Date
dotCooCoo a8a1c82a43 PDF export: warn when a PDF/X file leaves out the document's bleed
Choosing a PDF/X standard without a PDF/X preset writes a file with no bleed
(BleedBox = TrimBox) even when Document Setup sets one, and the export gave no
warning about it. The export now warns when a PDF/X file has no bleed on a side
where the document's bleed has one. The warning comes ahead of the flattening
note, because the status bar shows only the first warning. The code adds a
warning and does not change what is written.

These cases do not warn: the PDF/X presets, Use document bleed settings, a
nonzero bleed on every side the document sets, a document with no bleed, files
that aren't PDF/X files, and Export for Screens rows whose artboards Include
Bleed grows.

The warning has a row in every catalog. The Summary's warning and error rows in
the Save PDF and Print dialogs now go through the catalog, so they show its
translations.
2026-11-08 11:42:47 +07:00
dotCooCoo 003f709eb2 Docs: give the open's kept-layout timings in CPU cycles on current main 2026-11-08 11:42:46 +07:00
dotCooCoo dbcdbf2466 Open: the first frame uses the layouts the open made for type objects
Opening a document laid out every type object for its bounds and
baselines and threw the layouts away, and the first frame laid the same
objects out again. The open now keeps them, up to 128 MiB, and a frame
takes each one once.

A frame takes a layout only for a text object equal to the one laid out,
and only while the fonts, the system fallback setting and the hyphenation
exceptions are unchanged. When the last frame being drawn ends, the rest
are dropped if a frame took one, and all of them are dropped after eight
frames that take none. A layout with bitmap or color glyphs and a text
object with a gradient are not kept.
2026-11-08 11:42:45 +07:00
dotCooCoo f4ccca02d0 Docs: the stroke outline reuse line is listed once
The progress doc listed the moved-path stroke outline reuse twice, once
with the timings first measured and once with the timings measured
against current main. The line with the earlier timings is removed.
2026-11-08 11:42:45 +07:00
dotCooCoo e89f917f5e Panels: long swatch, preset and Add Effect popups scroll inside a short window
The gradient swatches menu, the Image Trace button's list of presets, the
Appearance panel's swatch picker and the top level of the Add New Effect
popup (Appearance panel, Properties) had no length limit, so rows past the
bottom of a short window could not be reached. Each now uses menu_scroll.
Items, order and commands do not change, and a list that fits does not
scroll.
2026-11-08 11:42:44 +07:00
dotCooCoo 0b43158fbb Fix #5813: floating panels hide while a tool group's flyout is open
A tool group's flyout and the All Tools drawer draw in the main window,
so a floating panel's OS window covered them. On the desktop, except on
Wayland, floating panels now hide while either one is open, as they do
for a menu or a dialog, and show again when it closes. A flyout or
drawer left set under a hidden toolbar does not draw and does not hide
them.
2026-11-08 11:42:44 +07:00
dotCooCoo d2d6f6fa04 Merge main into feat/js-builtins-text 2026-11-07 20:36:50 -08:00
dotCooCoo a18fbee3c9 Docs: the paste timing line gives CPU time per paste and undo 2026-11-08 11:22:41 +07:00
dotCooCoo 2f09d9998e Menus: Delete Empty Artboards' enabled check does not walk the document every frame
The Artboards panel menu asks whether Delete Empty Artboards can run on
every frame while it is open, and each ask measured the document. With
an open path of 200,000 anchors across two artboards, that took 70.4 ms
a frame in a release build.

The answer is now kept per open document with the version of the
document it was measured on, and is measured again when the document
changes. A later frame takes under 0.001 ms. The first frame after an
edit measures once. A change of the selection or the view keeps the
answer.
2026-11-08 11:22:40 +07:00
dotCooCoo 7d8f2a315a Paste: skips relinking when nothing changes and finds pasted type in one walk
A paste relinked every copy to the document's resources even when no
resource had another name or color and the objects linked no graphic
style. It now leaves those copies as they are.

Finding the pasted type looked each id up and compared every text object
with the ones already found. Text commands and the bounds refresh after
a paste now look all ids up in one walk and keep the found ids in a set.
Giving a pasted group new ids builds its map of old to new ids only for
an Objects on Path group, which is the only kind that reads it.

A pasted solid paint with no swatch link and a tint other than 1 now
keeps that tint when no relinking runs. Saved art carries a tint of 1 on
such a paint.
2026-11-08 11:22:40 +07:00
dotCooCoo b17a744a9c Panels: floating panels reopen on the monitor where they were left
Squashed from #6038 onto main.
2026-11-08 11:22:40 +07:00
dotCooCoo c952b8d298 Fix #5347: a floating panel's menu scrolls inside its window
The main window's menu floor was stored once for the whole egui context,
so a menu in a panel's OS window stopped at the main window's bottom bars
instead of its own edge. The floor is now kept per window, and a window
with no recorded floor uses its bottom edge. A menu list is also never
taller than the window, so the last items of a menu stay reachable in a
100 pt window, below the 120 pt minimum.

The Digits, Stylistic Sets, Save Selection and Move to Group submenus,
the libraries menu, the Color Guide's Limit to Library menu and the Layers
panel's Filter popup now scroll the same way.
2026-11-08 11:22:39 +07:00
dotCooCoo 09aa816394 Docs: dimensions state when the menus dim Expand and when a dimension stays live 2026-11-08 11:22:38 +07:00
dotCooCoo bc9ea516f5 Dimension tool: Expand keeps a dimension as plain art after it moves
Object > Expand left a dimension's recipe on its group, so the next move
redrew the live dimension and discarded the expanded art. Expand now ends
the live link of a dimension whose art it changes, in the same undo step.
Moving or scaling the group leaves its art as it is, the art no longer
follows what it measured, and undo gives the live dimension back.

Expand Appearance, Create Outlines and Outline Stroke had the same fault
and now do the same, also when they reach only a part of a dimension. A
dimension whose art a command leaves as it was stays live. A dimension
selected with the art it measures becomes a plain group when Expand,
Expand Appearance or Outline Stroke replaces only that art.
2026-11-08 11:22:38 +07:00
dotCooCoo bbf4834f12 .ai import: a hidden clipping path's fill leaves with it
The fill read apart from a clipping path that was read on %_ lines, and
the copies of its subpaths, are recorded as read on those lines too, so
the copy of a look's art that is removed takes them along. The file
format notes list a compound clipping path whose subpaths paint
differently among the exceptions to a clipping path keeping its fill.
2026-11-08 11:22:37 +07:00
dotCooCoo 72959e6e80 .ai import: a multi-layer mask's fill paints once
Each layer a multi-layer mask covers gets a copy of the mask's path, so
a fill kept on that path painted in every layer, over the art the mask
covers in the layers before. The mask's fill is read as a path of its
own again, where the mask's path is, and the copies have no fill. A
fill read apart from a compound clipping path is a compound path whose
subpaths do not clip and have ids of their own. A fill read apart, its
subpaths and their points count toward the importer's object limit.

Docs: docs/file-format-parity.md.
2026-11-08 11:22:36 +07:00
dotCooCoo 6ab82ca71e .ai import: a filled clipping path keeps its fill
The reader took the fill off a clipping path in a file's editing data and
added a copy of the path, holding only that fill, under the art it clips.
A clipping path paints its own fill under the clipped art and its stroke
over it, so the reader now keeps the fill on the clipping path. A filled
clipping path opens as one path instead of two, in a clipping group, a
clipping layer and each level of nested clipping paths. Its note, tags and
gradient stroke (`1 BB`) are on that path as before.

A compound clipping path whose subpaths all paint alike keeps their fill.
When its subpaths paint differently, the fills of the filled subpaths are
still a compound path of their own under the clipped art, so a subpath
the file does not fill stays unfilled. Clipping paths in a compound path
that holds its drawn look still have their fills read as paths of their
own under the art, each with its clipping path's opacity mask.

Docs: docs/file-format-parity.md.
2026-11-08 11:22:36 +07:00
dotCooCoo a386b3e955 Color fields: a pasted hex code replaces the field's digits
A click put the caret among the six digits and the text box holds seven
characters, so only the first character of a pasted code went in. The
field then held no new color, and Enter closed the dialog with the old
color. A press on a field drawn before the hex field also dropped what
was typed, while Tab and Enter applied it.

The hex fields of the Color Picker, Swatch Options, Recolor Artwork, the
Color panel, Document Setup, Duotone, Color Themes and Perspective Grid
now share one set of rules:

- A click or keyboard focus selects the digits.
- A code of six digits, with or without #, replaces the digits wherever
  the caret is.
- A code of three digits also replaces them, unless the paste holds only
  those digits and exactly three digits stay. Those digits then edit the
  text in place.
- A paste of only one, two, four or five digits edits the text in place
  when it does not cover all of the text and the result has at most six
  digits.
- Any other paste leaves the field as it was.
- A press elsewhere commits the text in the frame of the press.
- A commit returns the digits without # and writes a three-digit code out
  as six, so Duotone reads a typed # and Perspective Grid, whose parser
  reads six digits only, takes a three-digit code.

Part of #5013
2026-11-08 11:22:35 +07:00
dotCooCoo 7d1f2062e3 Actions: Insert Stop pauses playback and shows a message
Squashed from #6028 onto main.
2026-11-08 11:22:34 +07:00
dotCooCoo fe0f3d919c .ai save: the editing copy keeps variables, data sets and bindings
Squashed from #6024 onto main.
2026-11-08 11:22:34 +07:00
dotCooCoo 57dbbbb41b Docs: .ai brush art spot color limits
The file-format entry states the 20,000-name limit across brush art and per section, the first-definition rule, and that colors past the limit still count toward the color mode.
2026-11-08 11:22:33 +07:00
dotCooCoo 8a34c89d7c .ai import: remove the duplicated editing-copy paragraph 2026-11-08 11:22:33 +07:00
dotCooCoo cbfca36c85 .ai import: spot colors in a kept brush's art become swatches
The reader kept a brush's art but dropped the colors it read from it, so
a spot color that only a Scatter or Art brush's art used made no swatch,
and the art's process colors did not count toward the document's color
mode.

The reader now keeps each brush art section's colors with its art. When
the document is finished, the colors of the art that a kept brush uses
are added after the rest of the file's, in the order the art was read:
its spot colors make swatches and its colors count toward the color
mode. Art that no kept brush uses (a pattern brush's tiles, a section
that a later one of the same name replaced, a section inside a symbol's
definition) brings none of its colors, and a spot color that the page's
art, a pattern or a symbol also defines keeps the value defined there.

Part of #637.
2026-11-08 11:22:32 +07:00
dotCooCoo 2faec2fa11 .ai import: Skew, Stair Step and Gravity measure the path's turn square to it
The spacing fitted from a type-on-a-path layout measured each turn against
the glyph's own foot. Skew's feet stay upright, so on a tilted or leftward
path the turn picked up a false angle and the fitted spacing was wrong (a
straight path at 30 degrees gave -9.7 instead of 0). Effects other than
Rainbow and 3D Ribbon now measure the turn against the baseline turned a
right angle.

The file-format doc states that a frame whose options set key 6 to true
keeps the default effect, alignment and Flip.
2026-11-08 11:22:31 +07:00
dotCooCoo bc5eb7aa47 Docs: state the limits of .ai type on a path import
Align to Path takes its distance from the path from VectorCraft's font metrics, and the fit under Gravity does not reproduce the file's layout.
2026-11-08 11:22:31 +07:00
dotCooCoo 53f6aafe87 .ai import: type on a path keeps its effect, alignment and flip
Type on a path from a file's text document opened as Rainbow on its
baseline, not flipped, whatever Type on a Path Options the frame kept.
Each frame now keeps its effect (Rainbow, Skew, 3D Ribbon, Stair Step,
Gravity), Align to Path (Ascender, Descender, Center, Baseline) and Flip.
A code or flag that can't be read leaves that option at its default.

Flipped type opens with the frame's path reversed once, after a copied
object takes its own art path, and an open path's end bracket stays so
the type starts where the file's range ends.

Spacing is still fitted from the file's layout. The fit now measures along
the path when Align to Path moves the baselines off it, and it follows the
glyphs' feet under 3D Ribbon, whose baselines stay level.
2026-11-08 11:22:30 +07:00
dotCooCoo 199c4c3467 Simplify: fitted curves stay within the tolerance of the path, and serpentines simplify faster
The curve fitter split a piece over the tolerance at its worst point and
accepted any piece at depth 41 whatever its error. A worst point near the
end of a piece peels off a few points, so a long path refitted nearly all
of its points at every level. A serpentine of 200,000 anchors kept pieces
with a fitted error of up to about 1,598 pt at a tolerance of 1 pt.

Simplify also took at most 256 samples per segment, so the lines between
the samples on a long arc could be farther from it than the tolerance.

- `fit_rec` moves a split that is near an end of its piece to two fifths
  of the piece from that end, so the depth is logarithmic, and it keeps no
  piece over the tolerance. A piece of 32 points or more is first fitted
  to about 16 of them, and it is split when that fit is over the tolerance.
- A curve is also rejected when it is over the tolerance from the lines
  between the points it fits, with samples close enough that it stays
  within 1% of the tolerance of the chord between them. A pair of points
  that would need more than 1,024 samples counts as too far.
- `join_pieces` joins neighboring pieces when one curve fits them, up to
  33 pieces per curve.
- `sample_steps` takes enough samples of a curved segment to keep it within
  0.5% of the tolerance of the lines between them. A segment that would
  need more than 65,536 samples stays as it is, and so does a segment
  after a run's first 16,777,216 samples or 2,097,152 result segments. With
  Convert to Straight Lines such a segment becomes evenly spaced lines, up
  to 65,536. A fit holds at most 1,048,576 samples, so a longer run is
  fitted in parts.
- Simplify fits at 98% of the tolerance, since turning a nearly straight
  curve into a line moves it by up to 1.5%.
- Above slider level 0, Object > Path > Smooth fits a whole closed path
  with no corner along one direction across its start, when no segment
  stays as it is and the path is fitted as one part. A direct-selected
  section does not get this. The start can still have a kink: a first or
  last fitted curve that is nearly straight becomes a line, which leaves
  along its chord, and a refit with more anchors than the path is
  discarded, so the path stays as it is.

A closed subpath that refits to one curve is still dropped, as on main, so
it can end up farther than the tolerance from the result. docs/mcp.md
states this.

The anchors of every simplified path can differ from before, and so can
the results of the Pencil, Blob Brush and Smooth, which use the same fit.
2026-11-08 11:22:29 +07:00
dotCooCoo a0bd9bbbad Artboards: duplicate, copy, cut, move and rearrange journal whether locked and hidden art goes
Squashed from #5994 onto main.
2026-11-08 11:22:29 +07:00
dotCooCoo b8233f7c19 .ai save: a reopened file opens on the artboard active when it was saved
Squashed from #5975 onto main.
2026-11-08 11:22:28 +07:00
dotCooCoo 74863fa778 Engine: execute refuses keys a command doesn't name, in every build
Session::execute ran check_params only in the engine's own tests, so a
direct execute in a release build ran a misspelled key with the
command's default. It now checks every call, the commands a command runs
included, as MCP and the control port already did. A command.batch or
an action.batch is checked before its first step runs, and each step is
checked again as it runs, so an effect.setParams step is checked
against the effects the steps before it added.

Saved steps play through Session::replay, which takes keys a command no
longer reads, so an action recorded by an older version still plays and
Session::replay still plays an older journal. The Actions panel's Play
(Accelerated, Step by Step and Pause For, its function keys and
ui.action.play) and the Batch dialog use it.

Docs: the cmd/params.rs module doc, the Parameter keys section of
docs/mcp.md and a line in docs/target-app-parity.md describe both
paths.
2026-11-08 11:22:28 +07:00
dotCooCoo fab3425f54 Merge main into feat/js-builtins-text 2026-11-07 20:18:06 -08:00
dotCooCoo 52e94d4f8a JavaScript: compiling a pattern charges the room its lists reserve
- The compiler charges each working list's added capacity before it
  grows (capacity doubles), the code that joins alternatives, and the
  flattened code with its stack, instead of an estimate from
  instruction and fragment counts.
- The scan for capturing groups and the syntax check before compiling
  each take one unit of fuel per unit of the pattern.
- Bytes a dropped HeldBytes released leave the heap's total at the
  next limit check, not at the next collection.
- The progress line lists the deletable RegExp.prototype flag
  properties among the test262 failures.
2026-11-07 20:12:42 -08:00
dotCooCoo d503688e16 3D (Classic): effect.lightingPreset refuses Extrude & Bevel (Classic)
Extrude & Bevel (Classic) has no lighting presets; its lights are set in
its own options. effect.lightingPreset now refuses a target whose effect
at the index is Extrude & Bevel (Classic) with an error that names it,
before any object changes. Before, every preset failed on it with an
unknown-parameter error for lightColor. The params text and docs/mcp.md
state the rule.
2026-11-07 20:10:52 -08:00
dotCooCoo 3d1ce948bc Docs: the JavaScript text built-ins line matches the radix output and matcher memory 2026-11-07 19:45:57 -08:00
dotCooCoo f916d981d3 Plug-ins: a live effect's commands may change the document
A live effect that declares commands may list `doc.write` and `state`, and
gets them when its manifest leaves `permissions` out, as a filter does. Only
its commands use them: drawing the effect changes no object and keeps no
data. Before, every output of such a command that changed an object was
refused, since a live effect could never hold `doc.write`.
2026-11-07 19:42:38 -08:00
dotCooCoo c4aa5cec8a Merge feat/js-interpreter into feat/js-builtins-text 2026-11-07 19:34:34 -08:00
dotCooCoo 9d528621f7 Docs: built-in test262 counts after the array length order change 2026-11-07 19:24:49 -08:00
dotCooCoo 813fe78a8c Merge feat/js-interpreter into feat/js-builtins-core
Takes #6178's rooting of every native call's arguments, the fuel per argument apply reads and the Error objects as NativeError prototypes. The bound-function and apply arm that rooted arguments only for those calls is removed, since every native call now roots them; the parsing line in docs/target-app-parity.md takes #6178's wording.
2026-11-07 19:12:18 -08:00
dotCooCoo 14ea556e92 Plug-ins: a malformed ids is refused, and a command out of budget changes nothing
plugin.run and plug-in commands read `ids` strictly: a value that is not
a list, or an entry that is not a non-negative integer, is an error
naming `ids` ("ids must be an array of non-negative integer object
ids"). Left out or null, `ids` is still the selection.

A new test shows that a plug-in command that runs out of its
instruction budget leaves the document and the undo history unchanged,
and that the error names the plug-in and the command.

docs/plugins.md and docs/mcp.md name MCP's `command_list` and
`list_commands` as the listings that show plug-in commands, and the
params text, docs and progress line describe the `ids` rule.
2026-11-07 18:47:22 -08:00
dotCooCoo 02fffcd00c JavaScript: String, Number, RegExp and Date built-ins
A realm now has String, Number, RegExp and Date as ECMAScript 5.1
sections 15.5, 15.7, 15.9 and 15.10 define them, with Annex B's substr,
getYear, setYear and toGMTString.

- String: every ES5 prototype method; split, replace, match and search
  take strings and RegExps. Each new string's length is checked against
  the heap limit before it is built, and scans take fuel.
- Number: toString(radix), toFixed, toExponential and toPrecision
  format from the number's exact decimal value.
- RegExp: a backtracking matcher keeps its choice points and capture
  state on the heap, within the heap room left, and takes fuel for every
  step, so a catastrophic pattern stops at the fuel limit. Patterns
  nested past Options::max_depth give a SyntaxError. Flags g, i and m,
  lastIndex, exec, test and toString.
- Date: chrono converts days to calendar dates, shifting by whole
  400-year cycles past its years. Realm::set_clock and
  Realm::set_time_zone set the clock and local time (UTC by default).
  Without a hint, a Date converts to a primitive as a string.

cargo xtask test262 also runs the suite's built-ins tests for the four
and prints their counts.
2026-11-07 18:24:27 -08:00
dotCooCoo 906fd4cfad Merge main into feat/plugin-menu-commands 2026-11-07 17:34:08 -08:00
dotCooCoo ed5de5edcb Plug-ins: a plug-in adds menu commands of its own under Object › Plug-ins
A filter or live effect may declare up to 32 `commands` in its manifest,
each `{id, label, params?}`. While the plug-in is installed each one is the
command `plugin.<id>.<command>`: listed by `command.list` and in the
plug-in's `plugin.list` entry, run through `run`, MCP and `command.batch`
with its parameters checked before the plug-in runs, and recorded in
actions. A run goes through `vc_run` on the selection with
`_context.mode` "command" and `_context.command`, under the plug-in's
permissions, as one undo step named after the command. A failing run
leaves the document as it was, and its error starts with the plug-in's
name and the command's label. Removing or replacing the plug-in removes
its commands.

In the app, a plug-in with commands is a submenu named after it under
Object › Plug-ins (Effect › Plug-ins for a live effect), holding its own
item and then its commands; a `menu` key in a manifest is ignored. A
command with parameters opens a dialog for them from its menu item or a
shortcut. Edit › Keyboard Shortcuts lists the commands for the user to
give a shortcut; a manifest cannot set one. Labels and names are shown
with control and bidirectional characters escaped, and a malformed entry
is refused by name when the module is installed.

Docs: docs/plugins.md, docs/mcp.md, docs/target-app-parity.md.
2026-11-07 17:32:54 -08:00
dotCooCoo 263c7cb926 JavaScript: arguments from apply stay alive while a native function runs
A native function called through apply could run JavaScript that started a
collection, which freed the arguments apply had read from the array-like
object. The native call now roots its receiver and arguments.

The parsing entry in docs/target-app-parity.md no longer says that nothing
runs scripts.
2026-11-07 17:10:48 -08:00
dotCooCoo bdf6db8d19 Merge main into feat/js-builtins-core 2026-11-07 17:10:42 -08:00
Luis 21249399c6 Release: refresh contributor credits for each release (#5997) (#5998)
About > Contributors still showed an old snapshot, because nothing
regenerated contributors/contributors.json before a release. Opt in to
the shared refresh from craft-common-actions: a read-only credits job
regenerates the snapshot for the release commit, and the shared release
workflow installs it before every source build. The snapshot is not
committed back.
2026-11-08 02:07:42 +01:00
dotCooCoo 7436a38f44 JavaScript: Object, Function, Array, Error, Math and JSON built-ins
vectorcraft-js now provides the ECMAScript 5.1 built-ins: the Object
property-descriptor functions, create, keys, seal and freeze (15.2),
Function.prototype.bind (15.3.4.5), Array with every ES5 method (15.4),
the error types (15.11), Math (15.8), JSON with revivers, replacers and
indentation (15.12), and the global functions with Annex B's escape and
unescape (15.1, B.2). Prototype methods are writable and configurable.

The array methods work on array-like objects and visit only the indices
that exist, so a sparse array of length 2^32-1 costs as much as its
elements, and they see indices a callback adds. join writes a cycle back
to an array as an empty string; JSON.stringify throws a TypeError on a
cycle. JSON parsing, writing and the reviver walk use no native
recursion. Every loop takes fuel and every result is checked against
the heap limit, so new Array(4294967295).join("x") ends with the heap
limit and a huge sort or stringify ends with a limit.

cargo xtask test262 also runs the suite's ES5 built-in tests and fetches
json2.js at a pinned commit, checked against its SHA-256, to compare its
output with the built-in JSON once Date, String.prototype.replace and
RegExp exist.
2026-11-07 16:49:38 -08:00
dotCooCoo decb3321d1 Docs: the 3D effects summary counts Extrude & Bevel (Classic) 2026-11-07 16:27:43 -08:00
dotCooCoo 20accc5943 Docs: 3D remaining-work lists name what 3D (Classic) still lacks
Extrude & Bevel (Classic) ships, so the remaining-work lists in
effects-parity.md, gaps.md (G3), target-app-parity.md and three-d.md
name Revolve (Classic), Rotate (Classic) and Map Art instead of all of
3D Classic.
2026-11-07 16:00:09 -08:00
dotCooCoo 1f352bc7c1 Plug-ins: manifests list permissions, the user grants them at install, and the host enforces the grant
A manifest may list `permissions` (doc.read, doc.write, state,
effect.render, export.write) and an `api` level. doc.read, doc.write
and state follow the capability model proposed in
storytold/photocraft#662; the other names are VectorCraft's own. An
unknown, reserved, duplicate or wrong-kind name is refused by name. A
manifest without the key gets the permissions its kind implies and
installs as before.

- Install Plug-in... and File > Open show the name, id, version, file
  SHA-256 and each permission in plain words, with control and
  bidirectional characters escaped and each string cut to 64
  characters. OK installs the module only if it still has the SHA-256
  shown; Cancel installs nothing. The heavy-budget prompt and the
  status line show the escaped name too, and OK keeps the `replace` it
  was given.
- `plugin.install` needs `grant` listing every permission, and
  `plugin.inspect` reports `needsApproval`. `hash` pins the module:
  one with another SHA-256 is refused. The grant is kept with the
  module's hash in the store's `grants.json`, and only that store's
  grants count while it is attached; the same set does not ask again,
  more permissions do, and `plugin.remove` forgets it.
- The Additional Plug-ins Folder and `plugin.reload` install only
  plug-ins the attached store has granted and report the others as
  needing approval. At startup the store skips an ungranted plug-in.
- A filter run without doc.read is given no objects; without state it
  neither reads nor writes `documentData`; without doc.write an output
  that changes the document is refused and the document is unchanged.

Docs: docs/plugins.md, docs/mcp.md, docs/target-app-parity.md.
2026-11-07 15:20:07 -08:00
dotCooCoo 5a4c3e12a5 3D (Classic): Extrude & Bevel (Classic) extrudes art with Wireframe, No Shading, Diffuse and Plastic surfaces
Effect > 3D and Materials > 3D (Classic) > Extrude & Bevel (Classic)... applies
`threeD.classicExtrude`, a live effect built on the Extrude & Bevel solid. It
takes Extrude Depth, Cap, a bevel with Height and Bevel Extent In or Out, the
Position presets, rotation and Perspective, and draws the faces with the
Wireframe, No Shading, Diffuse or Plastic surface: one to ten lights, Ambient
Light, Highlight Intensity and Size, Blend Steps, a Black, Custom or no Shading
Color, and Draw Hidden Faces. Invalid parameters are refused with an error.
2026-11-07 15:02:39 -08:00