mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Merge pull request #3442 from alpha-rock/feature/3d-light-presets
Add lighting presets to 3D effects
This commit is contained in:
+3
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
**Stage: alpha** · next: beta, ~13 points (ready for real work ~62% → ~75%, and reliable `.ai` exchange) and ~170–270 h away
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-21 · **Change:** minor (Print: Japanese paper sizes in the Print dialog's Media list — JIS B4 257 × 364 mm, JIS B5 182 × 257 mm and JIS B6 128 × 182 mm beside the ISO B4/B5 (which keep their ISO 216 sizes), はがき, 往復はがき, 封筒 長形3号/長形4号/角形2号/角形3号 and 四六判; about 90 community PRs of 2026-10-19: Objects on Path, the Simplify slider, Pencil Edit Selected Paths in the middle of a path, Georgian, and more; Background Export progress dialog with Cancel, #2564; about 85 community PRs of 2026-10-18: Justification…, Word .docx placed as area type, CCITT Group 3 TIFF, Roman Hanging Punctuation, blend spines edited with the Anchor Point tool, shadows and glows in stack order, coloured 3D lights, a Dutch catalog completed; 3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; about 145 community PRs of 2026-10-17: image-decode overflow guards, opaque floating panels, MCP export cancel and progress, editable Illustrator EPS import, scoped `doc_inspect`, Dutch, Danish and Indonesian, Simplified Chinese messages, screen-reader names; headline numbers unchanged; about 160 community PRs of 2026-10-15/16: PDF import crash fixes, Dimension tool, legacy `.ai` save, Intertwine, web pen input, Image Trace fixes, `.ai`/EPS/PDF import fidelity, Bulgarian, Greek, Swedish and Finnish catalogs; headline numbers unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-21 · **Change:** minor (3D: original Standard, Diffuse, Top Left and Right lighting presets; command access, effective-setting recognition and preview/history; scores and estimates unchanged; Print: Japanese paper sizes in the Print dialog's Media list — JIS B4 257 × 364 mm, JIS B5 182 × 257 mm and JIS B6 128 × 182 mm beside the ISO B4/B5 (which keep their ISO 216 sizes), はがき, 往復はがき, 封筒 長形3号/長形4号/角形2号/角形3号 and 四六判; about 90 community PRs of 2026-10-19: Objects on Path, the Simplify slider, Pencil Edit Selected Paths in the middle of a path, Georgian, and more; Background Export progress dialog with Cancel, #2564; about 85 community PRs of 2026-10-18: Justification…, Word .docx placed as area type, CCITT Group 3 TIFF, Roman Hanging Punctuation, blend spines edited with the Anchor Point tool, shadows and glows in stack order, coloured 3D lights, a Dutch catalog completed; 3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; about 145 community PRs of 2026-10-17: image-decode overflow guards, opaque floating panels, MCP export cancel and progress, editable Illustrator EPS import, scoped `doc_inspect`, Dutch, Danish and Indonesian, Simplified Chinese messages, screen-reader names; headline numbers unchanged; about 160 community PRs of 2026-10-15/16: PDF import crash fixes, Dimension tool, legacy `.ai` save, Intertwine, web pen input, Image Trace fixes, `.ai`/EPS/PDF import fidelity, Bulgarian, Greek, Swedish and Finnish catalogs; headline numbers unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
VectorCraft is a clean-room, open-source, pure-Rust reimplementation of the Adobe Illustrator workflow. It runs
|
||||
on macOS, Windows, Linux, FreeBSD and the web (WASM), and agents can drive all of it over MCP, the CLI and a JSON
|
||||
@@ -134,6 +134,7 @@ Ranked; detail in [docs/roadmap.md](docs/roadmap.md) and [docs/gaps.md](docs/gap
|
||||
|
||||
| Date | What landed |
|
||||
|---|---|
|
||||
| 2026-10-21 | 3D lighting: four original lighting presets shared by Revolve, Extrude & Bevel, Inflate and Rotate, with command access and manual Custom settings; scores and estimates unchanged. |
|
||||
| 2026-10-21 | Print: the Print dialog's Media list has the Japanese papers — JIS B4 (257 × 364 mm), JIS B5 (182 × 257 mm) and JIS B6 next to the ISO B4/B5 (which keep their ISO 216 dimensions for settings saved before them), はがき 100 × 148 mm, 往復はがき 148 × 200 mm, 封筒 長形3号 120 × 235 mm / 長形4号 90 × 225 mm / 角形2号 240 × 332 mm / 角形3号 216 × 277 mm and 四六判 127 × 188 mm. A paper is named by its JSON id or its dialog label, any case and spacing (`B5 (JIS)` or `b5jis`), and every added size prints as its own PDF page size. Headline numbers unchanged. |
|
||||
| 2026-10-18 | Inch rulers divide the inch in half, not in ten. Zooming in stepped an inch ruler through 0.2, 0.1 and 0.05 of an inch, marks an inch ruler does not carry; below an inch the steps are binary fractions now, 1/2 down to 1/16, with the unlabelled ticks between them binary too (down to 1/128, so the 32nds, 64ths and 128ths appear as the report expects), while the metric units, points, pixels and picas keep their tenths. A label carries the decimals its step needs, so a sixteenth reads 0.0625 rather than the rounded 0.06, with trailing zeros dropped (#2827). Headline numbers unchanged. |
|
||||
| 2026-10-18 | Exported and saved files can repeat their bytes: PNG, PDF, EPS, legacy `.ai`, packaged zips and `.vectorcraft` saves recorded the wall-clock time they were made in, so the same commands run twice gave different bytes though the pixels matched. `SOURCE_DATE_EPOCH` now stands in for the clock in everything a file records, as the reproducible-builds specification defines it; a date a command is given still wins, and a malformed value is ignored rather than refusing the export. The recovery heartbeat and the seed PDF encryption draws on keep the real clock, so a password-protected PDF still differs between runs (#2880). Headline numbers unchanged. |
|
||||
@@ -186,6 +187,7 @@ The full pre-standard record of what landed is kept in [docs/roadmap.md](docs/ro
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-21 | minor | 3D: original Standard, Diffuse, Top Left and Right lighting presets; command access, effective-setting recognition and preview/history; scores and estimates unchanged |
|
||||
| 2026-10-21 | minor | Print: Japanese paper sizes in the Print dialog's Media list (JIS B4/B5/B6, はがき, 往復はがき, 封筒 長形3号/長形4号/角形2号/角形3号, 四六判); ISO B4/B5 keep their sizes, and a paper is named by id or label, any case and spacing. Headline numbers unchanged. |
|
||||
| 2026-10-17 | minor | Colored Inflate: shared membrane normals and smooth RGB vector ramps replace flat polygon bands; channel groups are batched per solid-fill surface. White-light Inflate retains its original polygons, paint composition and seam joins; the 0.05 seam minimum is restored. Scores and hour estimates unchanged. |
|
||||
| 2026-10-16 | minor | 3D lighting: one to ten directional lights, a selectable light list, Add Light and Delete Light, independent settings and artboard gestures; ambient applied once and smooth RGB vector export; scores and hour estimates unchanged |
|
||||
|
||||
@@ -147,3 +147,6 @@ sync_github_name = true
|
||||
|
||||
[people.addibble]
|
||||
sync_github_name = true
|
||||
|
||||
[people.alpha-rock]
|
||||
display_name = "Aditya Sisodiya"
|
||||
|
||||
@@ -40,6 +40,7 @@ mod clip;
|
||||
mod distort;
|
||||
mod group;
|
||||
mod lighting;
|
||||
mod lighting_presets;
|
||||
mod live;
|
||||
mod marks;
|
||||
pub mod pixel;
|
||||
@@ -72,6 +73,7 @@ pub use group::{
|
||||
OutlineHook, PATHFINDER_EFFECTS, evaluate_container, has_container_appearance, has_pathfinder, is_pathfinder, member_shapes, paints,
|
||||
pathfinder_children,
|
||||
};
|
||||
pub use lighting_presets::{LIGHTING_PRESETS, LightingPreset, lighting_preset_params, matching_lighting_preset};
|
||||
pub use live::{expand_live, expand_live_deep, expanded_live_group, text_outliner};
|
||||
pub use marks::{CROP_MARKS, crop_marks_art, has_crop_marks};
|
||||
pub use pixel::{PIXEL_EFFECTS, PixelFx, PixelSpace};
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
//! Original lighting rigs for the publicly documented 3D preset names.
|
||||
//! Adobe publishes the names, not numeric settings. These values are our own; Standard
|
||||
//! retains the existing default. A preset replaces the light rig and ambient only.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_three_d::{DEFAULT_LIGHT, Light};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LightingPreset {
|
||||
pub id: &'static str,
|
||||
pub label: &'static str,
|
||||
rotation: f64,
|
||||
height: f64,
|
||||
softness: f64,
|
||||
ambient: f64,
|
||||
}
|
||||
|
||||
pub const LIGHTING_PRESETS: [LightingPreset; 4] = [
|
||||
LightingPreset { id: "standard", label: "Standard", rotation: DEFAULT_LIGHT.0, height: DEFAULT_LIGHT.1, softness: 0.0, ambient: 25.0 },
|
||||
LightingPreset { id: "diffuse", label: "Diffuse", rotation: DEFAULT_LIGHT.0, height: DEFAULT_LIGHT.1, softness: 100.0, ambient: 35.0 },
|
||||
LightingPreset { id: "topLeft", label: "Top Left", rotation: 135.0, height: 45.0, softness: 0.0, ambient: 25.0 },
|
||||
LightingPreset { id: "right", label: "Right", rotation: 0.0, height: 30.0, softness: 0.0, ambient: 25.0 },
|
||||
];
|
||||
|
||||
impl LightingPreset {
|
||||
/// The same patch is used by commands and the dialog's preview transaction. Null
|
||||
/// `lights` replaces an explicit multi-light rig with this single white light.
|
||||
pub fn params(self) -> Value {
|
||||
json!({
|
||||
"lights": null, "lightColor": "#ffffff", "lightIntensity": 80.0,
|
||||
"lightRotation": self.rotation, "lightHeight": self.height,
|
||||
"lightSoftness": self.softness, "lightBehind": false, "ambient": self.ambient,
|
||||
})
|
||||
}
|
||||
|
||||
fn matches(self, light: Light, ambient: f64) -> bool {
|
||||
let close = |a: f64, b: f64| (a - b).abs() < 1e-6;
|
||||
!light.behind
|
||||
&& light.color.iter().all(|c| close(*c, 1.0))
|
||||
&& close(light.intensity, 0.8)
|
||||
&& close(light.rotation, self.rotation)
|
||||
&& close(light.height, self.height)
|
||||
&& close(light.softness, self.softness / 100.0)
|
||||
&& close(ambient, self.ambient / 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lighting_preset_params(id: &str) -> Option<Value> {
|
||||
LIGHTING_PRESETS.iter().find(|p| p.id == id).map(|p| p.params())
|
||||
}
|
||||
|
||||
/// Identify the effective rig, including an equivalent explicit single light. Names
|
||||
/// are UI state derived from settings, so edits and older files cannot leave stale names.
|
||||
pub fn matching_lighting_preset(params: &Value) -> Option<usize> {
|
||||
let upgraded = crate::upgrade_params(crate::REVOLVE, params);
|
||||
let o = crate::revolve_options(&upgraded);
|
||||
let light = if let Some(lights) = &o.lights {
|
||||
let mut entries = lights.iter();
|
||||
let light = *entries.next()?;
|
||||
if entries.next().is_some() {
|
||||
return None;
|
||||
}
|
||||
light
|
||||
} else {
|
||||
Light {
|
||||
rotation: o.light_rotation,
|
||||
height: o.light_height,
|
||||
behind: o.light_behind,
|
||||
color: o.light_color,
|
||||
intensity: o.light_intensity,
|
||||
softness: o.light_softness,
|
||||
}
|
||||
};
|
||||
LIGHTING_PRESETS.iter().position(|preset| preset.matches(light, o.ambient))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn lighting_presets_are_valid_unique_and_standard_preserves_the_default() {
|
||||
for (i, preset) in LIGHTING_PRESETS.iter().enumerate() {
|
||||
let patch = preset.params();
|
||||
crate::lighting::validate(&patch).unwrap();
|
||||
assert_eq!(lighting_preset_params(preset.id), Some(patch.clone()));
|
||||
assert_eq!(matching_lighting_preset(&patch), Some(i));
|
||||
assert!(!patch.as_object().unwrap().contains_key("shade"));
|
||||
assert!(!patch.as_object().unwrap().contains_key("rotationX"));
|
||||
}
|
||||
assert_eq!(matching_lighting_preset(&json!({})), Some(0));
|
||||
assert!(lighting_preset_params("unknown").is_none());
|
||||
assert_eq!(crate::revolve_options(&LIGHTING_PRESETS[0].params()).light_direction(), crate::revolve_options(&json!({})).light_direction());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lighting_preset_matching_uses_effective_lights_and_detects_custom_edits() {
|
||||
let mut p = LIGHTING_PRESETS[3].params();
|
||||
p["lightColor"] = json!("#ff0000");
|
||||
p["lights"] = json!([{"rotation":0,"height":30}]);
|
||||
assert_eq!(matching_lighting_preset(&p), Some(3), "explicit light overrides stale legacy color");
|
||||
p["lights"][0]["color"] = json!("#4080ff");
|
||||
assert_eq!(matching_lighting_preset(&p), None);
|
||||
p["lights"] = json!([{}, {}]);
|
||||
assert_eq!(matching_lighting_preset(&p), None);
|
||||
for (key, value) in [("ambient", json!(26)), ("lightIntensity", json!(79)), ("lightBehind", json!(true))] {
|
||||
let mut p = LIGHTING_PRESETS[0].params();
|
||||
p[key] = value;
|
||||
assert_eq!(matching_lighting_preset(&p), None, "{key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,15 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
has_doc,
|
||||
set_params
|
||||
),
|
||||
cmd!(
|
||||
"effect.lightingPreset",
|
||||
"3D Lighting Preset",
|
||||
[],
|
||||
None,
|
||||
"{index: int, preset: standard|diffuse|topLeft|right, item?: appearance item index|null (omitted: the active item, else the object's), ids?|id?: [..], target?: object|contents} replace an applied 3D effect's light rig and ambient with an original lighting preset; preserve shading, geometry and view; all targets must have a 3D effect at index; one undo step → {ids}",
|
||||
has_doc,
|
||||
lighting_preset
|
||||
),
|
||||
cmd!(
|
||||
"effect.expandAppearance",
|
||||
"Expand Appearance",
|
||||
@@ -300,6 +309,30 @@ pub(crate) fn set_params_effects(s: &Session, p: &Value) -> Vec<String> {
|
||||
ids.iter().filter_map(effect).collect()
|
||||
}
|
||||
|
||||
fn lighting_preset(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "effect.lightingPreset";
|
||||
let patch = str_param(p, "preset")
|
||||
.and_then(effects::lighting_preset_params)
|
||||
.ok_or_else(|| bad(C, "preset must be standard, diffuse, topLeft or right"))?;
|
||||
let index = index_param(p, "index", C)?;
|
||||
let item = item_target(s, p, C)?;
|
||||
// Validate the whole selection before changing any object. An unrelated effect or
|
||||
// a missing index must not leave just some objects with a new lighting rig.
|
||||
for id in appearance_targets(s, p)? {
|
||||
let n = s.doc()?.doc.node(id).ok_or(EngineError::NoNode(id))?;
|
||||
let slot = item.effects_item(&n.appearance, C)?;
|
||||
let effect = n.appearance.effects_at(slot).and_then(|fx| fx.get(index));
|
||||
if !effect.is_some_and(|e| effects::is_three_d(&e.id)) {
|
||||
return Err(bad(C, format!("object {} needs a 3D effect at index {index}", id.0)));
|
||||
}
|
||||
}
|
||||
let mut options = p.clone();
|
||||
let map = options.as_object_mut().ok_or_else(|| bad(C, "parameters must be an object"))?;
|
||||
map.remove("preset");
|
||||
map.insert("params".into(), patch);
|
||||
set_params(s, &options)
|
||||
}
|
||||
|
||||
fn set_params(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "effect.setParams";
|
||||
let index = index_param(p, "index", C)?;
|
||||
@@ -673,6 +706,10 @@ fn expand_appearance(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests_lighting_presets.rs"]
|
||||
mod lighting_presets_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::json;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
#![allow(clippy::unwrap_used, clippy::panic)]
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_doc::NodeId;
|
||||
use vectorcraft_render::effects::{LIGHTING_PRESETS, matching_lighting_preset};
|
||||
|
||||
use crate::Session;
|
||||
|
||||
fn setup(effect: &str, item: Value) -> (Session, NodeId) {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width":400,"height":400})).unwrap();
|
||||
let id = NodeId(s.execute("path.create", &json!({"d":"M100 100L200 100L200 200L100 200Z"})).unwrap()["id"].as_u64().unwrap());
|
||||
s.execute("paint.setFill", &json!({"color":"#338ad6"})).unwrap();
|
||||
s.execute(
|
||||
"effect.apply",
|
||||
&json!({"effect":effect,"item":item,"params":{
|
||||
"rotationX":13,"rotationY":17,"rotationZ":9,"shade":false,"ambient":17,
|
||||
"lights":[{"color":"#ff8040"},{"color":"#4080ff","rotation":-35}]
|
||||
}}),
|
||||
)
|
||||
.unwrap();
|
||||
(s, id)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lighting_presets_preserve_source_and_view_and_round_trip_in_one_undo_step() {
|
||||
for effect in ["threeD.revolve", "threeD.extrude", "threeD.inflate", "threeD.rotate"] {
|
||||
for (i, preset) in LIGHTING_PRESETS.iter().enumerate() {
|
||||
let (mut s, id) = setup(effect, Value::Null);
|
||||
s.doc_mut().unwrap().mark_saved();
|
||||
let before = s.doc().unwrap().doc.clone();
|
||||
let history = s.doc().unwrap().history.undo.len();
|
||||
let p = json!({"index":0,"item":null,"preset":preset.id});
|
||||
s.check_params("effect.lightingPreset", &p).unwrap();
|
||||
s.execute("effect.lightingPreset", &p).unwrap();
|
||||
let after = s.doc().unwrap().doc.clone();
|
||||
let actual = &after.node(id).unwrap().appearance.effects[0].params;
|
||||
let mut expected = before.node(id).unwrap().appearance.effects[0].params.clone();
|
||||
expected.as_object_mut().unwrap().extend(preset.params().as_object().unwrap().clone());
|
||||
assert_eq!(*actual, expected);
|
||||
assert_eq!(matching_lighting_preset(actual), Some(i));
|
||||
assert_eq!(after.node(id).unwrap().path_data(), before.node(id).unwrap().path_data());
|
||||
assert_eq!(actual["rotationX"], 13);
|
||||
assert_eq!(actual["shade"], false);
|
||||
assert_eq!(s.doc().unwrap().history.undo.len(), history + 1);
|
||||
let reopened = vectorcraft_format::load(&vectorcraft_format::save(&after, false)).unwrap();
|
||||
assert_eq!(reopened.node(id).unwrap().appearance.effects[0].params, *actual);
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(s.doc().unwrap().doc, before);
|
||||
assert!(!s.doc().unwrap().is_dirty());
|
||||
s.execute("edit.redo", &json!({})).unwrap();
|
||||
assert_eq!(s.doc().unwrap().doc, after);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lighting_presets_target_fill_effects_and_reject_invalid_requests_atomically() {
|
||||
let (mut s, id) = setup("threeD.rotate", json!(0));
|
||||
for p in [
|
||||
json!({"index":0,"item":0,"preset":"unknown"}),
|
||||
json!({"index":0,"item":0,"preset":12}),
|
||||
json!({"index":1,"item":0,"preset":"right"}),
|
||||
json!({"index":0,"item":null,"preset":"right"}),
|
||||
json!({"index":0,"item":0,"preset":"right","params":{"ambient":200}}),
|
||||
] {
|
||||
s.doc_mut().unwrap().mark_saved();
|
||||
let before = s.doc().unwrap().doc.clone();
|
||||
let history = s.doc().unwrap().history.undo.len();
|
||||
assert!(s.execute("effect.lightingPreset", &p).is_err(), "{p}");
|
||||
assert_eq!(s.doc().unwrap().doc, before);
|
||||
assert_eq!(s.doc().unwrap().history.undo.len(), history);
|
||||
assert!(!s.doc().unwrap().is_dirty());
|
||||
}
|
||||
s.execute("effect.lightingPreset", &json!({"ids":[id.0],"index":0,"item":0,"preset":"topLeft"})).unwrap();
|
||||
let n = s.doc().unwrap().doc.node(id).unwrap();
|
||||
assert!(n.appearance.effects.is_empty());
|
||||
assert_eq!(n.appearance.effects_at(Some(0)).unwrap()[0].params["lightRotation"], 135.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lighting_presets_reject_a_mixed_selection_before_changing_any_effect() {
|
||||
let (mut s, first) = setup("threeD.rotate", Value::Null);
|
||||
let second = s.execute("shape.rectangle", &json!({"x":250,"y":100,"width":80,"height":80})).unwrap()["id"].clone();
|
||||
s.execute("effect.apply", &json!({"effect":"path.offsetPath","item":null})).unwrap();
|
||||
s.execute("select.set", &json!({"ids":[first.0,second]})).unwrap();
|
||||
s.doc_mut().unwrap().mark_saved();
|
||||
let before = s.doc().unwrap().doc.clone();
|
||||
let history = s.doc().unwrap().history.undo.len();
|
||||
assert!(s.execute("effect.lightingPreset", &json!({"index":0,"item":null,"preset":"right"})).is_err());
|
||||
assert_eq!(s.doc().unwrap().doc, before);
|
||||
assert_eq!(s.doc().unwrap().history.undo.len(), history);
|
||||
assert!(!s.doc().unwrap().is_dirty());
|
||||
}
|
||||
@@ -293,6 +293,7 @@ fn lighting_controls(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
}
|
||||
});
|
||||
ui.add_enabled_ui(d.bool("shade"), |ui| {
|
||||
lighting_presets(ui, d);
|
||||
light_list(ui, d);
|
||||
let mut selected = selected_light(d);
|
||||
let before = light_record(&selected);
|
||||
@@ -310,6 +311,26 @@ fn lighting_controls(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
});
|
||||
}
|
||||
|
||||
fn lighting_presets(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
let names = [tl!("Standard"), tl!("Diffuse"), tl!("Top Left"), tl!("Right")];
|
||||
let current = vectorcraft_effects::matching_lighting_preset(&super::form::params(d));
|
||||
ui.horizontal(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 6.0;
|
||||
label(ui, tl!("Presets"));
|
||||
let shown = current.and_then(|i| names.get(i).copied()).unwrap_or(tl!("Custom"));
|
||||
if let Some(preset) = widgets::dropdown(ui, "three-d-lighting-presets", shown, &names, VALUE_W + rail_width(ui) + 6.0)
|
||||
.and_then(|i| vectorcraft_effects::LIGHTING_PRESETS.get(i))
|
||||
&& let Some(patch) = preset.params().as_object()
|
||||
{
|
||||
d.fields.extend(patch.clone());
|
||||
d.fields.insert("__light".into(), json!(0));
|
||||
ui.memory_mut(|m| m.stop_text_input());
|
||||
super::revolve_gizmo::clear(ui.ctx());
|
||||
}
|
||||
});
|
||||
ui.add_space(4.0);
|
||||
}
|
||||
|
||||
const LIGHT_KEYS: [(&str, &str); 6] = [
|
||||
("color", "lightColor"),
|
||||
("intensity", "lightIntensity"),
|
||||
|
||||
@@ -438,3 +438,63 @@ fn light_list_stops_at_ten_and_cancel_restores_the_source() {
|
||||
dialogs::cancel(&mut h.app);
|
||||
assert_eq!(h.app.session.doc().unwrap().doc, before);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lighting_presets_preview_custom_edits_reset_and_commit_as_one_undo_step() {
|
||||
for effect in [REVOLVE, EXTRUDE, INFLATE, vectorcraft_effects::ROTATE] {
|
||||
let mut h = Harness::with("M100 100L200 100L200 200L100 200Z", effect, vec2(1280.0, 900.0));
|
||||
let before = h.app.session.doc().unwrap().doc.clone();
|
||||
h.settle();
|
||||
h.click(h.rect("Lighting").center());
|
||||
let view = h.app.ui.dialog.as_ref().unwrap().fields["rotationX"].clone();
|
||||
h.click(h.rect("Standard").center());
|
||||
h.click(h.rect("Right").center());
|
||||
assert_eq!(h.value("lightRotation"), 0.0);
|
||||
assert_eq!(h.app.ui.dialog.as_ref().unwrap().fields["rotationX"], view);
|
||||
h.drag(h.rect("Height").center(), vec2(20.0, 0.0));
|
||||
assert!(!h.rect("Custom").is_negative());
|
||||
h.click(h.rect("Custom").center());
|
||||
h.click(h.rect("Diffuse").center());
|
||||
assert_eq!(h.value("lightSoftness"), 100.0);
|
||||
assert_eq!(h.value("ambient"), 35.0);
|
||||
h.click(h.rect("Add Light").center());
|
||||
assert!(!h.rect("Custom").is_negative());
|
||||
h.click(h.rect("Custom").center());
|
||||
h.click(h.rect("Top Left").center());
|
||||
let d = h.app.ui.dialog.as_ref().unwrap();
|
||||
assert!(d.fields["lights"].is_null());
|
||||
assert_eq!(d.fields["__light"], 0);
|
||||
assert_eq!(d.f64("lightRotation", 0.0), 135.0);
|
||||
h.click(h.response("revolve-reset-all").center());
|
||||
assert!(!h.rect("Standard").is_negative());
|
||||
h.click(h.rect("Standard").center());
|
||||
h.click(h.rect("Right").center());
|
||||
dialogs::confirm(&mut h.app).unwrap();
|
||||
h.app.run("edit.undo", json!({})).unwrap();
|
||||
assert_eq!(h.app.session.doc().unwrap().doc, before);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lighting_presets_cancel_restores_an_existing_custom_light_rig() {
|
||||
let mut h = Harness::new(vec2(1280.0, 900.0));
|
||||
h.settle();
|
||||
dialogs::confirm(&mut h.app).unwrap();
|
||||
h.app
|
||||
.run(
|
||||
"effect.setParams",
|
||||
json!({"index":0,"item":null,"params":{
|
||||
"ambient":19,"lights":[{"color":"#ff8040"},{"color":"#4080ff"}]
|
||||
}}),
|
||||
)
|
||||
.unwrap();
|
||||
let before = h.app.session.doc().unwrap().doc.clone();
|
||||
h.app.run("effect.dialog", json!({"effect":REVOLVE,"index":0,"item":null})).unwrap();
|
||||
h.settle();
|
||||
h.click(h.rect("Lighting").center());
|
||||
h.click(h.rect("Custom").center());
|
||||
h.click(h.rect("Right").center());
|
||||
assert_ne!(h.app.session.doc().unwrap().doc, before);
|
||||
dialogs::cancel(&mut h.app);
|
||||
assert_eq!(h.app.session.doc().unwrap().doc, before);
|
||||
}
|
||||
|
||||
@@ -5065,6 +5065,9 @@ theme Appearance Външен вид
|
||||
Softness Мекота
|
||||
Ambient Light Околна светлина
|
||||
Light behind the object Светлина зад обекта
|
||||
3D Lighting Preset Предварителна настройка за 3D осветление
|
||||
Standard Стандартно
|
||||
Diffuse Дифузно
|
||||
# 3D light management.
|
||||
Lights Светлини
|
||||
Add Light Добавяне на светлина
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5165,6 +5165,9 @@ mark-style Japanese Japonské
|
||||
Softness Měkkost
|
||||
Ambient Light Okolní světlo
|
||||
Light behind the object Světlo za objektem
|
||||
3D Lighting Preset Předvolba 3D osvětlení
|
||||
Standard Standardní
|
||||
Diffuse Rozptýlené
|
||||
# 3D light management.
|
||||
Lights Světla
|
||||
Add Light Přidat světlo
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4828,6 +4828,9 @@ mark-style Japanese Japansk
|
||||
Softness Blødhed
|
||||
Ambient Light Omgivelseslys
|
||||
Light behind the object Lys bag objektet
|
||||
3D Lighting Preset Forudindstilling for 3D-belysning
|
||||
Standard Standard
|
||||
Diffuse Diffust
|
||||
# 3D light management.
|
||||
Lights Lyskilder
|
||||
Add Light Tilføj lyskilde
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4741,6 +4741,9 @@ effect Soft Weich
|
||||
Softness Weichheit
|
||||
Ambient Light Umgebungslicht
|
||||
Light behind the object Licht hinter dem Objekt
|
||||
3D Lighting Preset 3D-Beleuchtungsvorgabe
|
||||
Standard Standard
|
||||
Diffuse Diffus
|
||||
# 3D light management.
|
||||
Lights Lichter
|
||||
Add Light Licht hinzufügen
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4872,6 +4872,9 @@ theme Appearance Εμφάνιση
|
||||
to set spacing and orientation για ορισμό απόστασης και προσανατολισμού
|
||||
: :
|
||||
Light behind the object Φως πίσω από το αντικείμενο
|
||||
3D Lighting Preset Προεπιλογή φωτισμού 3D
|
||||
Standard Τυπικός
|
||||
Diffuse Διάχυτος
|
||||
# 3D light management.
|
||||
Lights Φώτα
|
||||
Add Light Προσθήκη φωτός
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2031 and column 19.
|
@@ -5106,6 +5106,9 @@ mark-style Japanese Japonesas
|
||||
Softness Suavidad
|
||||
Ambient Light Luz ambiental
|
||||
Light behind the object Luz detrás del objeto
|
||||
3D Lighting Preset Ajuste preestablecido de iluminación 3D
|
||||
Standard Estándar
|
||||
Diffuse Difusa
|
||||
# 3D light management.
|
||||
Lights Luces
|
||||
Add Light Añadir luz
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5054,6 +5054,9 @@ mark-style Japanese Japanilainen
|
||||
Softness Pehmeys
|
||||
Ambient Light Ympäristövalo
|
||||
Light behind the object Valo objektin takana
|
||||
3D Lighting Preset 3D-valaistuksen esiasetus
|
||||
Standard Vakio
|
||||
Diffuse Hajavalo
|
||||
# 3D light management.
|
||||
Lights Valot
|
||||
Add Light Lisää valo
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5165,6 +5165,9 @@ theme Appearance Apparence
|
||||
Softness Douceur
|
||||
Ambient Light Lumière ambiante
|
||||
Light behind the object Lumière derrière l'objet
|
||||
3D Lighting Preset Préréglage d’éclairage 3D
|
||||
Standard Standard
|
||||
Diffuse Diffus
|
||||
# 3D light management.
|
||||
Lights Lumières
|
||||
Add Light Ajouter une lumière
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5151,6 +5151,9 @@ imageTrace Outline Körvonal
|
||||
Softness Lágyság
|
||||
Ambient Light Környezeti fény
|
||||
Light behind the object Fény az objektum mögött
|
||||
3D Lighting Preset 3D világítási készlet
|
||||
Standard Normál
|
||||
Diffuse Szórt
|
||||
# 3D light management.
|
||||
Lights Fények
|
||||
Add Light Fény hozzáadása
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4828,6 +4828,9 @@ mark-style Japanese Jepang
|
||||
Softness Kelembutan
|
||||
Ambient Light Cahaya ambient
|
||||
Light behind the object Cahaya di belakang objek
|
||||
3D Lighting Preset Preset Pencahayaan 3D
|
||||
Standard Standar
|
||||
Diffuse Difus
|
||||
# 3D light management.
|
||||
Lights Lampu
|
||||
Add Light Tambah Lampu
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3801 and column 19.
|
@@ -4775,6 +4775,9 @@ lighting Light Luce
|
||||
Softness Morbidezza
|
||||
Ambient Light Luce ambientale
|
||||
Light behind the object Luce dietro l'oggetto
|
||||
3D Lighting Preset Predefinito illuminazione 3D
|
||||
Standard Standard
|
||||
Diffuse Diffusa
|
||||
# 3D light management.
|
||||
Lights Luci
|
||||
Add Light Aggiungi luce
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4814,6 +4814,9 @@ lighting Light ライト
|
||||
Softness 柔らかさ
|
||||
Ambient Light 環境光
|
||||
Light behind the object オブジェクトの背後のライト
|
||||
3D Lighting Preset 3D ライティングプリセット
|
||||
Standard 標準
|
||||
Diffuse 拡散
|
||||
# 3D light management.
|
||||
Lights ライト一覧
|
||||
Add Light ライトを追加
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4740,6 +4740,9 @@ imageTrace Outline კონტური
|
||||
In the File ფაილში
|
||||
Keys კლავიშები
|
||||
Light behind the object სინათლე ობიექტის უკან
|
||||
3D Lighting Preset 3D განათების წინასწარი პარამეტრი
|
||||
Standard სტანდარტული
|
||||
Diffuse დიფუზური
|
||||
Line {line} სტრიქონი {line}
|
||||
Line {line}: {name}: {status} სტრიქონი {line}: {name}: {status}
|
||||
Needs Attention Only მხოლოდ საყურადღებო
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4738,6 +4738,9 @@ lighting Light 광원
|
||||
Softness 부드러움
|
||||
Ambient Light 주변광
|
||||
Light behind the object 개체 뒤의 조명
|
||||
3D Lighting Preset 3D 조명 사전 설정
|
||||
Standard 표준
|
||||
Diffuse 확산
|
||||
# 3D light management.
|
||||
Lights 광원 목록
|
||||
Add Light 광원 추가
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4840,6 +4840,9 @@ mark-style Japanese Japans
|
||||
Softness Zachtheid
|
||||
Ambient Light Omgevingslicht
|
||||
Light behind the object Licht achter het object
|
||||
3D Lighting Preset Voorinstelling 3D-belichting
|
||||
Standard Standaard
|
||||
Diffuse Diffuus
|
||||
# 3D light management.
|
||||
Lights Lichtbronnen
|
||||
Add Light Lichtbron toevoegen
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5002,6 +5002,9 @@ mark-style Japanese Japońskie
|
||||
Softness Miękkość
|
||||
Ambient Light Światło otoczenia
|
||||
Light behind the object Światło za obiektem
|
||||
3D Lighting Preset Ustawienie oświetlenia 3D
|
||||
Standard Standardowe
|
||||
Diffuse Rozproszone
|
||||
# 3D light management.
|
||||
Lights Światła
|
||||
Add Light Dodaj światło
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4082,6 +4082,9 @@ axis Both Ambos
|
||||
Softness Suavidade
|
||||
Ambient Light Luz ambiente
|
||||
Light behind the object Luz atrás do objeto
|
||||
3D Lighting Preset Predefinição de iluminação 3D
|
||||
Standard Padrão
|
||||
Diffuse Difusa
|
||||
# 3D light management.
|
||||
Lights Luzes
|
||||
Add Light Adicionar luz
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -4771,6 +4771,9 @@ lighting Light Свет
|
||||
Softness Мягкость
|
||||
Ambient Light Окружающий свет
|
||||
Light behind the object Свет позади объекта
|
||||
3D Lighting Preset Предустановка 3D освещения
|
||||
Standard Стандартное
|
||||
Diffuse Рассеянное
|
||||
# 3D light management.
|
||||
Lights Источники света
|
||||
Add Light Добавить свет
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5070,6 +5070,9 @@ theme Appearance Utseende
|
||||
Softness Mjukhet
|
||||
Ambient Light Omgivande ljus
|
||||
Light behind the object Ljus bakom objektet
|
||||
3D Lighting Preset Förinställning för 3D-belysning
|
||||
Standard Standard
|
||||
Diffuse Diffust
|
||||
# 3D light management.
|
||||
Lights Ljuskällor
|
||||
Add Light Lägg till ljus
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -4755,6 +4755,9 @@ lighting Light Світло
|
||||
Softness М'якість
|
||||
Ambient Light Навколишнє світло
|
||||
Light behind the object Світло позаду об'єкта
|
||||
3D Lighting Preset Попереднє налаштування 3D освітлення
|
||||
Standard Стандартне
|
||||
Diffuse Розсіяне
|
||||
# 3D light management.
|
||||
Lights Джерела світла
|
||||
Add Light Додати світло
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 726 and column 40.
|
@@ -4757,6 +4757,9 @@ theme Appearance Giao diện
|
||||
Softness Độ mềm
|
||||
Ambient Light Ánh sáng môi trường
|
||||
Light behind the object Ánh sáng phía sau đối tượng
|
||||
3D Lighting Preset Thiết lập sẵn ánh sáng 3D
|
||||
Standard Tiêu chuẩn
|
||||
Diffuse Khuếch tán
|
||||
# 3D light management.
|
||||
Lights Danh sách đèn
|
||||
Add Light Thêm đèn
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 4003 and column 10.
|
@@ -5030,6 +5030,9 @@ lighting Light 光源
|
||||
Softness 柔和度
|
||||
Ambient Light 环境光
|
||||
Light behind the object 光源位于对象后方
|
||||
3D Lighting Preset 3D 光照预设
|
||||
Standard 标准
|
||||
Diffuse 漫射
|
||||
# 3D light management.
|
||||
Lights 光源列表
|
||||
Add Light 添加光源
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4837,6 +4837,9 @@ lighting Light 光源
|
||||
Softness 柔和度
|
||||
Ambient Light 環境光
|
||||
Light behind the object 光源位於物件後方
|
||||
3D Lighting Preset 3D 光照預設
|
||||
Standard 標準
|
||||
Diffuse 漫射
|
||||
# 3D light management.
|
||||
Lights 光源清單
|
||||
Add Light 新增光源
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1,6 +1,6 @@
|
||||
# Effects parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-20 · **Change:** minor (G2: Effect › Sketch › Note Paper; Halftone Pattern and Note Paper defaults documented as unverified VectorCraft choices; G2: Effect › Artistic › Smudge Stick, Sponge and Watercolor; Sketch › Bas Relief, Charcoal, Photocopy and Stamp, #2533; Photoshop filters 46/57, 11 remaining (8–14 h); G2: Sketch › Chrome; Sketch › Chalk & Charcoal, Graphic Pen and Reticulation and Artistic › Plastic Wrap, #2972, #2967, #2976, #3034: 37/57 Photoshop effects; 3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; Zig Zag's Smooth points make a continuous wave, #2343; G2: Effect › Sketch › Halftone Pattern; Photoshop filters 46/57, 11 remaining (8–14 h); Round Corners also rounds corners where a curve meets a line or another curve, with Live Corners' cut; straight corners unchanged; score unchanged; Revolve: automatic smooth shading and default-on Cap with continuous rims; wide shadows and glows at high zoom, #1706; stacked Transform effects, #1705; 3D on nonzero compound paths, #1724; pattern tiles redraw, #1723; scores unchanged; Roughen's Smooth turn-backs, #1643; Scribble per region, #1648; score unchanged; Warp Arc bends in the object's proportions, #1578; Zig Zag ridges evenly spaced, #1558; effect parameters checked, #1592; score unchanged; raster effects after a pattern, radial or freeform gradient fill export at their place and size, #1536; score unchanged; 3D and Materials on outlined type and other shapes of many small curves, #1481; Twist 0° to 360°, #1524; twisted walls keep their faces, #1525; score unchanged; 3D and Materials: Inflate takes Twist, Taper and Cap; score unchanged; 3D and Materials: Perspective as the documented 0°–160° angle; 3D and Materials: the documented light settings) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-21 · **Change:** minor (3D: original Standard, Diffuse, Top Left and Right lighting presets; command access, effective-setting recognition and preview/history; scores and estimates unchanged; G2: Effect › Sketch › Note Paper; Halftone Pattern and Note Paper defaults documented as unverified VectorCraft choices; G2: Effect › Artistic › Smudge Stick, Sponge and Watercolor; Sketch › Bas Relief, Charcoal, Photocopy and Stamp, #2533; Photoshop filters 46/57, 11 remaining (8–14 h); G2: Sketch › Chrome; Sketch › Chalk & Charcoal, Graphic Pen and Reticulation and Artistic › Plastic Wrap, #2972, #2967, #2976, #3034: 37/57 Photoshop effects; 3D lighting: one to ten colored lights, smooth colored Inflate, legacy white-light appearance preserved; surface batching and restored seam minimum; scores and estimates unchanged; Zig Zag's Smooth points make a continuous wave, #2343; G2: Effect › Sketch › Halftone Pattern; Photoshop filters 46/57, 11 remaining (8–14 h); Round Corners also rounds corners where a curve meets a line or another curve, with Live Corners' cut; straight corners unchanged; score unchanged; Revolve: automatic smooth shading and default-on Cap with continuous rims; wide shadows and glows at high zoom, #1706; stacked Transform effects, #1705; 3D on nonzero compound paths, #1724; pattern tiles redraw, #1723; scores unchanged; Roughen's Smooth turn-backs, #1643; Scribble per region, #1648; score unchanged; Warp Arc bends in the object's proportions, #1578; Zig Zag ridges evenly spaced, #1558; effect parameters checked, #1592; score unchanged; raster effects after a pattern, radial or freeform gradient fill export at their place and size, #1536; score unchanged; 3D and Materials on outlined type and other shapes of many small curves, #1481; Twist 0° to 360°, #1524; twisted walls keep their faces, #1525; score unchanged; 3D and Materials: Inflate takes Twist, Taper and Cap; score unchanged; 3D and Materials: Perspective as the documented 0°–160° angle; 3D and Materials: the documented light settings) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
Every entry of Illustrator's Effect menu, by its public feature name, against VectorCraft's effects catalogue
|
||||
(`effect_catalog()` in `crates/effects/src/lib.rs`) and the Effect menu built from it
|
||||
@@ -165,19 +165,20 @@ for VectorCraft and are not verified against proprietary defaults. Evidence: `cr
|
||||
|---|---|
|
||||
| Revolve | initial: live, editable profile, rotation and light gizmos, default-on Cap with continuous curved rims, smooth vector shading and round seam joins, SVG/PDF output, Expand Appearance ([revolve.md](revolve.md), #846) |
|
||||
| Extrude & Bevel, Inflate, Rotate | initial: live, depth, twist, taper, solid or hollow caps, five original bevel shapes, Inflate volume, both sides, twist, taper and cap, Rotate of every fill and stroke, Position presets, rotation and light gizmos, SVG/PDF output, Expand Appearance ([three-d.md](three-d.md)) |
|
||||
| Materials panel, lighting, ray-traced render | one to ten directional lights with per-light Color (opaque RGB, white by default), Intensity, Rotation, Height, Softness and neutral Ambient Light, Revolve and colored Inflate use smooth vector shading; Extrude & Bevel and Rotate retain planar shading; no materials, light presets, shadows or ray tracing |
|
||||
| Materials panel, lighting, ray-traced render | one to ten directional lights with per-light Color (opaque RGB, white by default), Intensity, Rotation, Height, Softness and neutral Ambient Light, Revolve and colored Inflate use smooth vector shading; Extrude & Bevel and Rotate retain planar shading; original Standard, Diffuse, Top Left and Right lighting rigs; no materials, shadows or ray tracing |
|
||||
| 3D (Classic): Extrude & Bevel, Revolve, Rotate | none |
|
||||
| Turntable (30.0 beta) | none |
|
||||
| Export 3D objects (OBJ, USDA, glTF) | none |
|
||||
|
||||
The `three-d` crate (depends on `geom` and `pathops`, with no UI or GPU dependencies) builds, rotates, projects, shades and depth-sorts the surfaces;
|
||||
the effects crate turns them into art. What's left (materials, light presets and shadows, ray-traced rendering,
|
||||
the effects crate turns them into art. What's left (materials and shadows, ray-traced rendering,
|
||||
angular cut caps, exact visibility, 3D Classic, Turntable, 3D export) is 25–45 h.
|
||||
|
||||
## Revision history
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-21 | minor | 3D: original Standard, Diffuse, Top Left and Right lighting presets; command access, effective-setting recognition and preview/history; scores and estimates unchanged |
|
||||
| 2026-10-20 | minor | G2: Effect › Sketch › Water Paper (Fiber Length, Brightness, Contrast; colours flow on damp fibrous paper, defaults unverified, #2955); measured Photoshop filters 47/57, Sketch 12/14. |
|
||||
| 2026-10-20 | minor | G2: Effect › Sketch › Note Paper (Image Balance, Graininess, Relief; embossed tones on fibrous paper); Halftone Pattern and Note Paper parameter ranges follow public control names, numeric defaults are unverified VectorCraft choices (public help gives no numbers); measured Photoshop filters 46/57, Sketch 11/14. |
|
||||
| 2026-10-19 | minor | Sketch › Chalk & Charcoal, Graphic Pen and Reticulation and Artistic › Plastic Wrap landed (#2972, #2967, #2976, #3034): 36/57 Photoshop effects (estimated; defaults unverified) |
|
||||
|
||||
+4
-3
File diff suppressed because one or more lines are too long
+18
@@ -1440,6 +1440,24 @@ See [Revolve](revolve.md) for the scope and limitations.
|
||||
{"name":"run_command","arguments":{"command":"effect.expandAppearance","params":{}}}
|
||||
```
|
||||
|
||||
## 3D lighting presets
|
||||
|
||||
`effect.lightingPreset {index: int, preset: "standard" | "diffuse" | "topLeft" | "right", item?, ids?, target?}`
|
||||
replaces the lighting rig and ambient of an existing Revolve, Extrude & Bevel, Inflate or Rotate
|
||||
effect. `item: null` addresses object-level effects; an item index addresses a fill/stroke's
|
||||
effects. All targets must have a 3D effect at `index`, otherwise nothing changes. The operation
|
||||
is one undo step and preserves Shading, geometry, source paint and the view.
|
||||
|
||||
The four original rigs use one white front light at 80% intensity. Standard keeps the existing
|
||||
default; Diffuse uses 100% Softness and 35% Ambient Light, Top Left uses Rotation 135 and Height
|
||||
45, and Right uses Rotation 0 and Height 30. Full values and the public behavior reference are in
|
||||
[3D lighting presets](three-d.md#presets). These are original settings, not imported preset files.
|
||||
The document stores their numeric settings; manual edits remain possible through `effect.setParams`.
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"effect.lightingPreset","params":{"index":0,"item":null,"preset":"topLeft"}}}
|
||||
```
|
||||
|
||||
## Extrude & Bevel, Inflate and Rotate
|
||||
|
||||
`effect.apply {effect: "threeD.extrude" | "threeD.inflate" | "threeD.rotate", params: {...}, ids?, item?}` applies
|
||||
|
||||
@@ -86,6 +86,8 @@ with the standard command.
|
||||
|
||||
## Initial limits
|
||||
|
||||
- Lighting offers Standard, Diffuse, Top Left and Right, using the [shared original rigs](three-d.md#presets).
|
||||
Other effective settings show Custom; changing the view does not change the recognized lighting preset.
|
||||
- Paths and compound paths only. Type, images and groups must be converted to paths first.
|
||||
- Open profiles have circular end caps by default; turning Cap off keeps them open. Partial-sweep angular cut sides remain open. Closed profile boundaries are swept as provided.
|
||||
- One Revolve per source object. Edit its options rather than applying another.
|
||||
|
||||
+3
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+30
-1
@@ -101,6 +101,34 @@ saves the angle.
|
||||
|
||||
## Lighting
|
||||
|
||||
### Presets
|
||||
|
||||
The Lighting tab has **Standard**, **Diffuse**, **Top Left** and **Right** choices. Choosing one
|
||||
replaces the whole light rig with one white front light at 80% intensity and sets Ambient Light.
|
||||
It leaves Shading, the object's view, geometry and other effect options unchanged. Manual edits
|
||||
remain available; the list shows **Custom** whenever the effective lighting matches none of the
|
||||
presets, including when there is more than one light. An equivalent explicit single light is
|
||||
recognized too. Reset all returns to Standard. Preview, Cancel and Undo work as for other options.
|
||||
|
||||
These are original VectorCraft settings based on the public preset names and directions. Adobe's
|
||||
documentation does not publish numeric rigs; the values are not copied from its software or files
|
||||
and are not claimed to reproduce its presets exactly. Standard retains the existing default.
|
||||
|
||||
| Preset | Rotation | Height | Softness | Ambient Light |
|
||||
|---|---:|---:|---:|---:|
|
||||
| Standard | 125.26438968275465 degrees | 30 degrees | 0% | 25% |
|
||||
| Diffuse | 125.26438968275465 degrees | 30 degrees | 100% | 35% |
|
||||
| Top Left | 135 degrees | 45 degrees | 0% | 25% |
|
||||
| Right | 0 degrees | 30 degrees | 0% | 25% |
|
||||
|
||||
`effect.lightingPreset {index: 0, item: null, preset: "standard" | "diffuse" | "topLeft" | "right", ids?, target?}`
|
||||
applies the same settings through commands, CLI and MCP. The index and item address an already
|
||||
applied 3D effect. Every target must have a 3D effect at that position; validation is atomic, and
|
||||
the whole operation is one undo step. The numeric light settings are saved, not a preset name.
|
||||
Existing documents keep their appearance unless a preset is chosen.
|
||||
|
||||
### Light settings
|
||||
|
||||
One to ten directional lights. **Lights** selects the light whose settings and artboard gizmo are edited. **Add Light** adds and selects a white front light; **Delete Light** removes the selected light while retaining at least one. Ambient Light is shared by all lights. The public panel options' Light Settings are kept in their order:
|
||||
|
||||
| Option | |
|
||||
@@ -138,7 +166,7 @@ and [Create 3D objects](https://helpx.adobe.com/illustrator/desktop/special-effe
|
||||
pages, and the archived Extrude & Bevel option list (depth 0–2,000, cap on/off, bevel height, bevel extent in or
|
||||
out, perspective). No Adobe software, assets, presets or bevel shapes were used.
|
||||
|
||||
- **Materials** (base, Adobe Substance and graphics), light presets, **shadows**
|
||||
- **Materials** (base, Adobe Substance and graphics), **shadows**
|
||||
and **ray-traced rendering** are not built: shading uses directional lights, in the paint of the fill or
|
||||
stroke the solid is built for ([Fills and strokes](#fills-and-strokes)).
|
||||
- The bevel shapes and their names are our own; custom bevel paths are not supported.
|
||||
@@ -161,4 +189,5 @@ Release measurements and a repeatable CLI scene are in [3D lighting performance]
|
||||
|
||||
| Date | Change |
|
||||
|---|---|
|
||||
| 2026-10-21 | Four original lighting presets, shared by all four 3D effects and commands, with effective-setting recognition and existing preview/history behavior. |
|
||||
| 2026-10-17 | Smooth colored Inflate lighting and surface batching; legacy white-light appearance and the 0.05 seam minimum preserved; shared light Color and multiple lights remain vector output. |
|
||||
|
||||
+3
-2
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user