Commit Graph
40 Commits
Author SHA1 Message Date
dotCooCoo 08de741ca9 3D (Classic): Rotate (Classic) turns flat art in 3D with the No Shading and Diffuse surfaces
Effect › 3D and Materials › 3D (Classic) › Rotate (Classic)… turns every
fill and stroke as one flat plane, as Rotate does, and shades it with the
classic No Shading or Diffuse surface.

- `effect.apply` with `threeD.classicRotate`: the Position rotation and
  Perspective, `surface` (`none` or `diffuse`), the classic lights,
  Ambient Light, Blend Steps and Shading Color. It has no highlight, no
  Draw Hidden Faces and no shadow.
- The dialog shows Position on the Rotation tab and the surface and
  lights on the Lighting tab, with no Object tab.
- Groups and layers turn about one shared center, and the effect also
  goes on a fill or stroke, as Rotate's does.
- `effect.lightingPreset` refuses it, as it refuses the other classic
  3D effects.
- Unknown parameters, numbers out of range, bad flags, a surface other
  than No Shading or Diffuse and bad shading colors are refused with an
  error.
2026-11-11 23:44:11 -08:00
dotCooCoo 5d8065e929 3D (Classic): Revolve (Classic) sweeps a profile with Angle, Cap and Offset and the classic surfaces
Effect › 3D and Materials › 3D (Classic) › Revolve (Classic)… sweeps the
profile round a vertical axis, as Revolve does, and draws every face with
the Wireframe, No Shading, Diffuse and Plastic surfaces of Extrude & Bevel
(Classic).

- `effect.apply` with `threeD.classicRevolve`: Angle (0 to 360), Cap,
  Offset (0 to 1000 pt) from the left or right edge of the profile's
  bounds, the Position rotation and Perspective, and the classic lights,
  Ambient Light, highlight, Blend Steps and Shading Color.
- Groups and layers revolve about one shared axis, and the effect also
  goes on a fill or stroke, as Revolve's does.
- `effect.lightingPreset` refuses it, as it refuses Extrude & Bevel
  (Classic).
- Revolve faces carry their view-space normal, and
  `three_d::revolve_facets` hands them to the classic surface code.
- Unknown parameters, numbers out of range and bad flags, edges,
  surfaces and colors are refused with an error.
2026-11-11 23:04:22 -08:00
bflatastic c58bd01525 3D: the shadow passes read the six-field solid parts again
#6716 added the member index to each solid part after #6754's shadow
code was written against the five-field tuple, so main stopped compiling
once both landed. The Inflate, Extrude and shadow-drawing loops now
destructure all six fields.
2026-11-12 10:11:01 +07:00
BFlat bac3be03cb Merge pull request #6716 from dotCooCoo/fix/3d-fill-walls-behind-stroke
3D: a stroke's walls cover the fill's walls at concave corners
2026-11-12 10:03:08 +07:00
dotCooCoo 73c7c7511b 3D and Materials: shadows behind or below the object, with Distance and Bounds
Revolve, Extrude & Bevel, Inflate and Rotate take a Shadows switch on the
Lighting tab, with Position (Behind Object or Below Object), Distance from
Object (0 to 100%) and Shadow Bounds (10 to 400%), saved in the effect as
shadow, shadowPosition, shadowDistance and shadowBounds.

With shadows on, the first light casts a hard-edged vector shadow of the
solid: every face of every solid of the object projected along the light
onto a plane behind the object (square to the view) or below it (square to
its own vertical axis and turned with it), filled black with the nonzero
rule at 50% times the opacity of the art that casts it, in that art's
blending mode, and drawn behind the solids. Distance moves the plane away
by a share of the object's largest size; Bounds ends the plane at a square
about the foot of the object's center, four times that size across at
100%. No shadow is drawn while Shading is off, when the first light's
intensity is 0, or when it does not reach the plane. A member's opacity
mask and blending mode apply to the part of the shadow it casts. A shadow
is cast from at most 327,680 faces; past that, commands are refused and a
loaded file draws the source path. The canvas, SVG and PDF exports draw the
shadow, and Expand Appearance keeps it as a path. Values out of range are
refused before the document changes.

Docs: docs/three-d.md, docs/mcp.md, docs/effects-parity.md and the
docs/target-app-parity.md evidence list.
2026-11-11 17:50:33 -08:00
dotCooCoo 5e78aa6575 3D: a stroke's walls cover the fill's walls at concave corners
Extrude & Bevel (both kinds) and Inflate drew the faces of the fill's
solid and the stroke's solid in one order by each face's center depth.
At a concave corner a long fill wall could sort after a stroke wall in
front of it, so stripes of the fill showed through the stroke.

- Facets now record whether they are side faces (walls, bevels,
  Inflate's sides) and whether they are turned away from the viewer.
- With caps on, each fill side face turned toward the viewer is drawn
  before every face of the same shape's stroke whose bounds overlap
  it, for strokes whose solid hides the fill's whole edge: a closed
  shape, a width, no dashes, width profile or brush, and a solid color
  or a gradient without transparent stops. Caps, other shapes in a
  group, hollow effects and translucent or blended surfaces keep their
  order.

Docs: docs/three-d.md (Fills and strokes), docs/target-app-parity.md.
2026-11-11 15:32:33 -08:00
dotCooCoo 5ac7d97d85 Guides: ruler guides are document objects on their layers
Ruler guides were a list kept beside the layers. Each guide is now an
object of its layer or sublayer, always directly in it and above the
layer's art. These behave as on main:

- Guides draw on screen only. Exports (SVG, PDF, PNG, PSD), Fit All,
  Select All, the art bounds, clicks and marquees, and a layer's
  Pathfinder and Transform effects leave them out. The Layers panel
  lists them as guide rows of their layer, the highest guide.list
  index first.
- Deleting a layer deletes its guides, and merging layers keeps their
  guides in the merged layer.
- The guide commands number guides as guide.list does, in the order
  they were made.

New: each guide takes an id from the document's object ids. An object
command given a guide's id fails with an error, and node.move cannot
put a guide into a group or out of its layers. A guide made while an
opacity mask, a symbol or a pattern is edited moves to the top
visible, unlocked layer when editing ends.

File format: native files still save the guides in the document's
guides list, in every file version, so older builds read them. Each
entry may now also carry the guide's id, name, locked and hidden
flags; older builds ignore those fields. Opening a file puts each
saved guide on its layer (on the top visible, unlocked layer when the
file names none or a layer it does not have), and each saved guide
counts against the object limit for opening a file. A ruler guide node
that a file holds below a layer's art moves up to the layer's guides,
and one anywhere else (in a group or another object, beside the
layers, or in a symbol) is removed. Ruler guides read from an .ai file
become guide objects on the layer they were on, numbered in the order
the file lists them.
2026-11-11 09:52:28 -08:00
dotCooCoo 6ae93b1222 3D effects: Extrude & Bevel, Inflate and Rotate on a group keep each member's blending mode
On a group, these effects drew every member's solids in Normal mode: only
an opacity mask on a member or on a group inside the 3D group was applied
to the solids it holds. A member's blending mode, and that of a group
inside the 3D group, now apply the same way, to the solids of the members
it holds together. Group Revolve already did this.
2026-11-11 07:12:15 -08:00
Dylan M. Taylor a8f5549fd5 Merge branch 'main' into fix/sec-effects-paint-dash-budget 2026-11-11 12:55:22 +00:00
Dylan M. Taylor 18556f2a84 address review: one paint allowance across items, derived paints counted, bounded trap pair scan, dash error names both limits 2026-11-11 05:59:18 +00:00
Dylan M. Taylor adecf50ab9 address review: count freeform line headers, share paint budget across items, bound dash walk, report trap pair limit 2026-11-11 01:00:23 +00:00
dotCooCoo 24155e1f75 3D: an opacity mask on a group member masks its solids
A 3D effect on a group built its solids from the members' paths and
paint and left out each member's opacity mask, and the mask of a group
inside the 3D group. Clipping groups, blends and symbol instances
resolved for the effect lost their masks the same way.

A member, or a group inside the 3D group, with an opacity mask now
gets a scope like one with its own opacity or blending mode, and the
mask goes on the group that holds that member's surfaces. Revolve
applies it with the member's opacity and blending mode; Extrude &
Bevel, Extrude & Bevel (Classic), Inflate and Rotate draw each solid
on its own when a mask is present and put the masked members' solids
in a group with the mask. A resolved clipping group, blend or symbol
instance keeps its mask. A disabled mask is ignored.
2026-11-10 14:30:10 -08:00
dotCooCoo 6e3f04032d 3D: the group refusal lists groups and clipping groups among what it builds from
The message for a group member that can't become a solid now names groups
and clipping groups too. docs/three-d.md states that an image left out of a
clipping group also needs no visible fills or strokes of its own.
2026-11-10 11:48:39 -08:00
dotCooCoo d7845e7068 3D: Rotate keeps each clipped fill in its place among the strokes
Inside a clipping group, the fills of a shape were cut into one piece in
the top fill's place. Rotate turns every fill, so with a fill, a stroke
and a fill, the lower fill was drawn above the stroke. With Rotate, each
fill now becomes its own piece in its own place. Extrude & Bevel, Inflate
and Revolve build from the top fill and keep one piece there, also when
an object changes from Rotate to another 3D type.
2026-11-10 11:16:25 -08:00
dotCooCoo bad4b986f5 3D: resolving art for a 3D effect has a work limit and keeps geometry effects
- Resolving the symbol instances, blends and clipping groups a 3D effect
  builds from counts every object it visits or makes and stops past
  262,144 with an error. Nested symbol instances that end in hidden art
  are refused instead of being expanded at every level. Each object is
  visited once; a group is no longer walked again for each level above it.
- A symbol instance, blend or clipping group inside a 3D group keeps its
  appearance, so its geometry effects reshape the art it shows. A nested
  group's geometry effects now reshape its members inside a 3D group too,
  and inside a clipping group they apply before the clip cuts the art.
- Hidden members and guides of a group inside a clipping group build no
  solid.
- Tests cover an empty clipping group, a blend set to no steps, an
  instance of an empty symbol, a symbol holding a clipping group, the
  paint-copy budget across resolved art, and art past the limits drawing
  as it does without the effect.
2026-11-10 00:29:58 -08:00
dotCooCoo f0dad6010f 3D: effects build from clipping groups, blends and symbol instances
Extrude & Bevel, Extrude & Bevel (Classic), Inflate, Rotate and Revolve
now apply to a clipping group (or a layer with a clipping mask), a blend
or a symbol instance, alone or inside a group or layer. The solid is
built from the art the object shows: the art inside the clipping path
(fills cut to the clip, strokes as their outlines cut to the clip), the
blend's keys and steps, and the symbol's art where the instance places
it. Validation, the canvas, bounds, Expand Appearance, Rasterize and
assets.add3D read the same art from the document.

An image is refused, alone or in a group, with a message to trace it
first with Object > Image Trace > Make. A missing symbol, a symbol that
holds an instance of itself, art nested more than 64 levels deep and
more than 4,096 objects are refused. The refusal messages change, and
their rows change in every catalog.

Docs: docs/three-d.md, docs/revolve.md, docs/mcp.md,
docs/target-app-parity.md.
2026-11-09 23:22:20 -08:00
dotCooCoo 2e81086c38 Revolve: a nested group's opacity applies once to its members together
The opacity of a group inside a revolved group was multiplied into each member's surface, so where members overlap they drew darker than the group does without the effect. A member or group with opacity below 100% or a blending mode other than Normal now holds its members' surfaces in one group with that opacity and mode.
2026-11-09 18:30:41 -08:00
dotCooCoo d8d73495bb Revolve: a group member's blending mode applies to its surface
A member of a group with Revolve drew its surface in Normal mode whatever its own blending mode or that of a group it is in. Each mode now applies once, to the member's surface or to the surfaces of the group that has it, nested as the groups are. Expand Appearance keeps every face of a blended member.
2026-11-09 18:05:17 -08:00
dotCooCoo cddebdf7f6 3D: a group's fill or stroke takes no 3D effect
Revolve, Extrude & Bevel, Inflate and Rotate on a group or layer draw only as the group's own effect. On the group's fill or stroke they drew nothing, yet effect.apply and effect.setParams accepted them. Both now refuse that placement.
2026-11-09 17:51:22 -08:00
dotCooCoo bb142cc063 Revolve: the fills and strokes of one object share the paint-copy budget
Each fill or stroke with its own Revolve counted the copies of its paint from zero, so an object with several of them could draw past the 256 MiB budget. They now share one count, and past it the source path draws, as for the members of a group.

effect.apply and effect.setParams on a fill or stroke now check the Revolve in that item's paint, after the item's geometry effects before it, together with the object's other items that carry a Revolve. Before, they checked the object's top fill.

docs/revolve.md marks the axis position, type handling and member paint as VectorCraft's own rules, and docs/mcp.md says how the budget is counted.
2026-11-09 17:19:13 -08:00
dotCooCoo b07c808093 Revolve: type, groups and layers revolve, and the profile and face limits are higher
Type sweeps as its glyph outlines and stays editable. On a group or layer every visible member sweeps about one axis on the edge of the members' bounds together, each in its own paint.

A surface now takes up to 16,384 profile points and 163,840 faces. Curves take fewer samples, down to 4, when a surface passes those limits, and the command reports the failure below that, after the geometry effects before the Revolve and with the cumulative size of its paint copies counted. Mesh export turns the walls of holes toward them. Expand Appearance works on type with Extrude as well as Revolve.

Fixes #3617
2026-11-09 16:09:03 -08:00
dotCooCoo a7fc513a0c Merge main into feat/3d-classic-extrude-bevel 2026-11-08 15:34:06 -08:00
dotCooCoo b9d999fe26 Asset Export: the 3D mesh triangle limit bounds memory across objects
The 2,000,000-triangle limit on a 3D object's meshes is now checked as
each mesh is built, so an object past it is refused before the rest of
its meshes are built:

- Revolve counts each fill's and stroke's mesh as it builds it, instead
  of building every one first.
- Inflate still solves every shape's membrane at once (the eye depends
  on the highest puff), but builds each solid only when its mesh is
  reached (inflate_meshes), so a refused object leaves the later
  solids unbuilt.
- All the objects of one 3D asset share one budget
  (three_d_meshes_of), so assets.export3D refuses an asset whose
  objects pass the limit together.
2026-11-09 03:08:23 +07:00
dotCooCoo b568977af4 Asset Export: 3D objects export as USDA, USDZ, glTF or OBJ meshes
Squashed from #6168 onto main.
2026-11-09 00:29:05 +07:00
dotCooCoo 517e0b7ae8 Effects: hiding a 3D effect still checks the values given with it
effect.setParams with visible: false skipped every 3D parameter check,
so a hidden edit could store a Classic depth of 2001, an unknown
surface or bevel, an empty light list or a Revolve edge other than left
or right. The values given are now checked by validate_three_d_params
(the checks of validate_three_d that do not build the art); after a
change of 3D type the values the effect keeps are checked too. The
object still does not need to fit while the effect is hidden.
2026-11-08 06:35:39 -08:00
dotCooCoo 4a64208b82 Merge main into feat/3d-classic-extrude-bevel 2026-11-08 00:02:52 -08:00
dotCooCoo ba25415792 3D and Materials: Window › 3D and Materials edits the selection's 3D effect in place
The panel opens from Window › 3D and Materials (window.panel {panel:
"threeD"}). Its object types Plane, Extrude, Revolve and Inflate apply
Rotate, Extrude & Bevel, Revolve or Inflate to each selected object
without a 3D effect, and change the 3D effect of each other selected
object in place, all as one undo step. Below them are the effect
dialog's Object, Rotation and Lighting tabs with the same controls.
A changed setting goes to every selected 3D effect that takes it, as
one undo step; a drag previews and records one step on release, and a
change of selection during a drag commits it first, and so does closing
or hiding the panel. A setting the
selected effects hold with different values shows its default with its
reset dot filled. A light list edit reaches only the objects whose list
matches the first object's.

effect.setParams takes threeDType (plane, extrude, revolve, inflate):
the settings both effects take keep their values, rotation angles wrap
into -180..180 outside Revolve, and the rest start at the new effect's
defaults. Another value, or a non-3D effect at index, is refused; the
type an effect already has, with nothing else to change, records no
undo step.

Materials, shadows and ray-traced rendering are not part of this.

Docs: docs/three-d.md, docs/mcp.md, docs/effects-parity.md,
docs/target-app-parity.md.

Fixes #3672
2026-11-08 12:59:34 +07: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
Don Omondi 3f7f743ddb 3D effects: Extrude & Bevel, Inflate and Rotate apply to groups
A 3D effect on a group or layer builds a solid from every path,
compound path and type in it, all turned about one shared axis, as the
public docs describe for groups. Fixes #4506.
2026-11-07 00:17:14 +07:00
Dylan M. Taylor 34e6973b50 effects: count paint strings in 3D copies, charge dash restarts, cap trap pairs 2026-11-04 03:11:07 +00:00
bflatastic f4be2b9006 3D Extrude & Bevel, Inflate and Rotate apply to type, which stays editable (#4715) 2026-10-30 23:03:51 +07:00
aiongg 0d282bad01 refactor(effects): move solids.rs tests to solids/tests.rs 2026-10-26 18:33:15 +00:00
Louise FoxandClaude Opus 5.5 78105cc695 Plug-ins: filters read and set effects and stroke styles (G17)
A filter could reshape and repaint objects, but not set the stroke's
join, cap or miter limit, nor the effects an object's appearance holds.
A tool that prepares objects for a live effect (a sheet of samples,
each with the effect at its own settings) had to leave the user to
apply the effect to each object by hand.

- Each input stroke has its join, cap and miterLimit beside its paint
  and width (live effects get the same, through the shared encoder),
  and each object its own effect records, {id, params, visible}.
- An output stroke may set them (miter limit clamped to 1-500), and an
  output object's "effects" replaces its own effects.
- The host admits each record as effect.apply does: an effect that
  effect.list lists or an installed live-effect plug-in, parameters it
  takes (filled in to their defaults; a plug-in's checked against its
  manifest), one 3D effect that fits the object (its fills' and
  strokes' own effects counted), and the texture of an effect with
  Load Texture (Glass, Texturizer) as the effect stores it, never a
  file to read. A record the object already had stays as
  it is, so a filter that hands its input back changes nothing. One
  refused record refuses the whole output and the document stays as
  it was.

The plug-ins crate checks the records' form; which effects exist is the
engine's to say (objects::AdmitEffects, engine plugin::admit_effects).
effects::validate_three_d is the one check of whether a 3D effect fits
an object, for effect.apply, effect.setParams and the filters.

A path handed back as it was now stays the live shape it was: write()
dropped a live rectangle's or ellipse's parameters whenever the output
held a path, changed or not, so a filter that returned its input
turned a live rectangle into a plain path.

objects/tests.rs checks the round trip, stroke styles on existing and
new strokes, the host's refusal, the bad forms refused, and a live
rectangle handed back unchanged (a plain path before the fix);
tests_plugins.rs runs filters that set a built-in and a plug-in effect,
an echo that changes nothing, and six refused outputs.
CRAFT_PLUGIN_FRAME_WASM=<folder> saves a test filter to try in the app.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhvnnnD5fTFupK8WWq35un
2026-10-22 01:25:50 +07:00
dotCooCoo ac1b380b40 3D and Materials: Extrude & Bevel and Inflate build a solid from each stroke's outline
Extrude & Bevel and Inflate built one solid from the path, painted with
the object's top fill or, without a fill, its top stroke. A filled and
stroked object lost its stroke, and a stroked open path was extruded as
the area it would enclose if it were closed.

Each visible stroke now builds a solid from its outline in its own
paint, beside the solid the top fill builds from the path, as Rotate
already turns each stroke's outline. When the fill and the strokes are
opaque with normal blending, the faces of all the solids are drawn in
one back-to-front order; otherwise each solid is drawn on its own, in
the order of the appearance. Under a light that is not white, a surface
drawn as one composite or with an opacity mask is also drawn on its
own. In that one order a flat cap turned toward the viewer is drawn
after every other face, untwisted solids included, so the stroke's
front cap covers the fill's walls inside it. The solids share one set
of bounds, and with Perspective one eye sees every inflated solid. A
stroke whose outline is past the 2,048-point limit is left out.

Inflate's cells cut by a hole now pass only the nearby contours to the
boolean. An inflated, outlined 72 pt "VectorCraft" takes about 8 ms
instead of 34 ms, and 66 ms with a 3 pt stroke.

Docs: docs/three-d.md (Fills and strokes), docs/target-app-parity.md.
2026-10-19 21:51:26 +07:00
alpha-rock 039a467dcb M9: add multiple colored lights to 3D effects
Add opaque RGB light color and up to ten independently adjustable lights to
Revolve, Extrude & Bevel, Inflate and Rotate. Keep light selection, Add/Delete,
selected-light gizmos and preview transactions on the existing command path.

Preserve legacy white-light Inflate polygons, paint composition and seam joins,
including the 0.05 seam minimum. Use shared smooth normals for colored Inflate,
and batch solid-fill RGB channel paths behind one surface clip. Keep source
paths editable and SVG/PDF output vector artwork.

Rebase onto main f7de3d6a, retaining both sides of progress docs and all 22
catalogs. Shade freeform points once through the shared paint mapper. Document
release measurements and a reproducible CLI fixture, including the remaining
source-gradient cost and the one-light timing tradeoff.

Validation: full cargo xtask ci passed all 10 steps; 7,978 tests passed, zero
failed and 11 ignored. Four legacy white-light PNGs match unchanged main byte
for byte. Three paired release bench/perf repetitions completed without busy
warnings; all six standard perf runs passed every budget. Two-light solid
Inflate improved from 136.2 to 96.8 ms/frame at 1200x1200, default eight threads.
2026-10-18 01:11:39 +07:00
bflatastic a6d5c461a1 Fix #1724: 3D effects on a nonzero compound path keep the area its contours fill
Extrude & Bevel, Inflate and Rotate built their solid from the outline by
nesting alone: a contour inside an odd number of others was a hole. Under the
nonzero rule a contour inside another that runs the same way encloses filled
art, so the effect cut a hole the object doesn't have. The fill rule now
reaches the outline builder, which leaves out contours with filled art on
both sides before pairing outlines and holes.
2026-10-14 09:02:28 +07:00
Ayberk A. 043b446b94 3D and Materials: the light takes the documented settings
The public 3D and Materials panel options give the Light Settings as
Intensity (0–100 %), Rotation (-180° to 180°), Height (0° to 90°),
Softness (0–100 %) and Ambient Light (0–200 %), with the light moved to
the back or the front of the object. The 3D effects (Revolve included)
had Direction and Elevation (an azimuth and elevation), Intensity and
Ambient (0–100 %).

- Rotation turns the light round the object on the page (our reading:
  0° on its right, counterclockwise); Height raises it from beside the
  object (0°) to straight in front (90°); Light behind the object puts
  it at the back. The light gizmo's ring and line are Rotation and
  Height.
- Softness wraps the light round the object: at 0 % it falls off with
  the angle as before, at 100 % it reaches nothing only straight away.
- Ambient Light runs to 200 %; faces stay no brighter than the art.
- lightRotation, lightHeight, lightBehind and lightSoftness replace
  lightAzimuth and lightElevation. An earlier light is read as the same
  direction, so it shades exactly as before (old and new code give the
  same colours for the four effects and five lights); effect.setParams
  turns a stored one into the new form before applying new values, and
  the parameter description names lightAzimuth and lightElevation as the
  earlier form, so effect.apply and effect.setParams still take them. The
  default light is the earlier default's: Rotation 125.26°, Height 30°.
- The dialog's Lighting tab shows the settings in the documented order;
  Softness, Ambient Light and Light behind the object are in every
  catalog, and the unused Direction, Elevation and Ambient are gone.

Light colour, presets, several lights and shadows are not built.
2026-10-14 05:10:48 +07:00
Ayberk A. 39db6abfce 3D and Materials: Perspective runs 0° to 160°, as documented
The public 3D and Materials panel options give Perspective as 0° to 160°
("how close or far the object appears"); it was a 0–100 % strength, for
Revolve, Extrude & Bevel, Inflate and Rotate alike.

- The eye stands where a sphere about the object's centre, √3 times its
  half size (the box around it fits inside), fills that angle of the
  view: 0° is none, wider brings the eye nearer, and at 160° it is just
  outside the sphere, never inside the object. The documentation doesn't
  say how the angle places the eye; docs/three-d.md says this is our
  reading.
- `perspectiveAngle` (degrees) replaces `perspective` (%). A strength from
  an earlier file or script is read as the angle that shows exactly the
  same view: sin(angle / 2) = √3 × strength / 4, 100 % about 51.3°. An
  angle given too wins. effect.setParams turns a stored strength into the
  angle before applying new values. The parameter description names
  `perspective` as the earlier form, so effect.apply and effect.setParams
  still take it under the key check of #1592. Old and new code draw the four effects identically at 0, 25,
  60 and 100 % (bounds equal to 1e-9).
- The dialogs' Perspective fields run 0–160°.

# Conflicts:
#	docs/target-app-parity.md
2026-10-14 05:10:09 +07:00
Ayberk A. 15cef94ba6 3D and Materials: Inflate takes Twist, Taper and Cap
The public 3D and Materials panel options list Depth, Twist, Taper and Cap
for every 3D type; Inflate had only Depth.

- Twist (0° to 360°) and Taper (1–100 %) turn and scale the back about the
  shape's centre, as Extrude & Bevel's do: a puffed back is turned and
  lowered in proportion, and the sides follow in slices.
- Cap: Solid closes the back; Hollow leaves it off, so the inflated front is
  a shell open behind. The documentation doesn't say what Cap means for
  Inflate; this reading is stated in docs/three-d.md.
- The dialog's Object tab shows them in the documented order (Depth, Twist,
  Taper, Cap), then Volume and Both sides.

At 0 % volume a twisted, tapered Inflate has the extrusion's outline from
every side (tested).

A twisted, tapered, hollow Inflate draws on the canvas exactly as it
exports, and expands to faces with their own ids (tested). ROADMAP and the
parity pages list the new options; the 3D score stays at ~25 %.
2026-10-13 05:22:00 +07:00
Ayberk A. 8a3458a974 Effect › 3D and Materials: Extrude & Bevel, Inflate and Rotate
The three 3D types besides Revolve, as live effects in the three-d crate,
drawn as shaded vector faces by the canvas, SVG/PDF export and Expand
Appearance alike, from the public 3D and Materials documentation:

- Extrude & Bevel: depth (0-2000 pt), twist, taper, solid or hollow caps,
  and bevels in six original cross-sections (classic, rounded, cove, step,
  ogee) with width, height, repeat, spacing, inside and both sides.
- Inflate: the shape as a membrane under pressure (a Poisson solve held at
  zero along the outline and holes), so it rises vertically from the edge
  and rounds without creases; volume, depth and both sides. Steep cells
  near the outline are refined without cracks.
- Rotate: every fill and stroke turned in 3D and shaded as one plane.

All three share Revolve's view and lighting parameters, the rotation and
light gizmos (turning about the art's centre) and a dialog with Object,
Rotation and Lighting tabs, with Position presets (Front ... Isometric
Bottom, our own values). An object takes one 3D effect. Inflate cuts the
grid cells that straddle a hole's edge with pathops, hence the new
pathops -> three-d layer order.

Docs: docs/three-d.md, mcp.md, and the 3D rows of the parity docs.
2026-10-13 00:35:07 +07:00