Merge pull request #3629 from Taha-Mahmoodi/feat/conte-crayon

Effects: Sketch › Conté Crayon draws the dark areas in a black crayon and the light areas in a white one on textured paper
This commit is contained in:
BFlat
2026-10-22 21:34:59 +07:00
committed by GitHub
40 changed files with 400 additions and 47 deletions
+1 -1
View File
@@ -258,7 +258,7 @@ The scores are self-assessed from our code against public documentation;
- reliable exchange of .ai files (layer structure in real files; proprietary editing data isn't written);
- an interaction-fidelity pass covering every tool's modifiers and small behaviours;
- 3D and Materials beyond the initial live Revolve (Extrude & Bevel, Inflate, Rotate, materials);
- most of the raster effects (9 of 57 still missing; Cutout, Film Grain, Neon Glow, Plastic Wrap, Poster Edges, Smudge Stick, Sponge and Watercolor are available under Artistic, Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Graphic Pen, Halftone Pattern, Note Paper, Photocopy, Plaster, Reticulation, Stamp, Torn Edges and Water Paper under Sketch) and the Effect Gallery;
- the Effect Gallery (all 57 Photoshop-style raster filters are available, approximated, under Artistic, Blur, Brush Strokes, Distort, Pixelate, Sharpen, Sketch, Stylize, Texture and Video);
- CJK composition for vertical type (vertical type itself has initial support, with a Japanese interface);
- scripting, and the rest of Variables (image and graph kinds, dataset import);
- generative AI features.
+6 -3
View File
@@ -29,7 +29,7 @@ blocking it ([Alpha gate](docs/roadmap.md#alpha-gate)).
| | Value | Kind |
|---|---|---|
| **Feature breadth** (Illustrator's menu items, tools, effects, formats exist) | **~88%** | measured in part: menu items 348/375 wired (92.8%), tools 89/92, Illustrator effects 46/50, Photoshop effects 54/57, 3D 4/4 (initial types, no materials) |
| **Feature breadth** (Illustrator's menu items, tools, effects, formats exist) | **~88%** | measured in part: menu items 348/375 wired (92.8%), tools 89/92, Illustrator effects 46/50, Photoshop effects 57/57, 3D 4/4 (initial types, no materials) |
| **Feature depth** (weighted by use, scored by behaviour) | **~75%** | estimated |
| **To beta** | **~170–270 h** one agent · ~50–80 h with 4–6 agents | estimated |
| **To full parity** | **~360–590 h** one agent · ~95–165 h with 4–6 agents | estimated |
@@ -76,7 +76,7 @@ The dimension hours overlap (feature rows hold some UI, format and AI work), so
| Strokes, brushes, width profiles | 88% | 8–15 |
| Appearance, transparency, graphic styles, masks | 97% | 1–2 |
| Live vector effects | 85% | 6–10 |
| Raster effects (Effect Gallery) — [effects-parity.md](docs/effects-parity.md) | 82% | 8–14 |
| Raster effects (Effect Gallery) — [effects-parity.md](docs/effects-parity.md) | 82% | 4–6 |
| 3D and Materials | ~25% | 30–55 |
| Type core — [type-parity.md](docs/type-parity.md) | 80% | 14–19 |
| Type advanced (CJK, spelling, Touch Type) | 50% | 20–28 |
@@ -123,11 +123,13 @@ Ranked; detail in [docs/roadmap.md](docs/roadmap.md) and [docs/gaps.md](docs/gap
2. **`.ai` files from real users** (G9): layer structure, guides, speed: 10–20 h.
3. **Launch and stability on real machines** (G10): 20–35 h.
4. **Core-tool correctness** (G11: Shape Builder regions, Asset Export borders): 8–15 h.
5. **Raster effects** (G2) alongside: the 10 remaining filters (7 Artistic, 2 Sketch, 1 more) and the Effect Gallery, 8–14 h.
5. **Raster effects** (G2) alongside: the Effect Gallery (every Photoshop-style filter is in), 4–6 h.
6. **Then:** type core and advanced type (G4), the Illustrator 2026 additions (G13), 3D (G3).
## Progress log
- 2026-10-22: Effect › Sketch › Conté Crayon: a black crayon in the dark areas and a white one in the light areas, on mid-grey paper whose texture (Brick, Burlap, Canvas, Sandstone; Scaling, Relief, Light Direction, Invert) breaks the strokes, with Foreground Level and Background Level; an original approximation, defaults unverified. Every Photoshop-style filter is now in (57/57); the Effect Gallery remains (4–6 h).
- 2026-10-22: Ruby (ふりがな) for live text: `type.ruby` sets or removes a reading over a byte range of the selected type — above it in horizontal type, right of the column in vertical type (or below/left), start/centre/end aligned, at 1–100% of the base size (default half), overhanging or squeezed to the base width. It is saved in the native file, laid out with its line growing (following lines move on), drawn on the canvas, and written in SVG and PDF as outlines where ruby is present. UI panel and type on a path are next. Headline numbers unchanged.
- 2026-10-14: Document fonts register every explicitly supplied craft-fonts family after the existing Japanese, Arabic and Thai prefix; optional empty input remains supported. Headline scores and estimates are unchanged.
@@ -190,6 +192,7 @@ The full pre-standard record of what landed is kept in [docs/roadmap.md](docs/ro
| Date | Change | Summary |
|---|---|---|
| 2026-10-22 | minor | Effects: Sketch › Conté Crayon; measured Photoshop-style filters 57/57, the Effect Gallery remains (G2 estimate 4–6 h). |
| 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. |
+15
View File
@@ -598,6 +598,21 @@ pub fn effect_catalog() -> Vec<EffectInfo> {
"{detail: 0..10 (4; finer surface texture), smoothness: 0..10 (4; softer relief before the highlights and shadows)} treats the object as polished chrome lit from the top left: bright highlights on high points and dark shadows in low ones, keeping its coverage. Original visual approximation; chosen VectorCraft defaults.",
json!({"detail": 4.0, "smoothness": 4.0}),
),
r(
"sketch.conteCrayon",
"Conté Crayon…",
SKETCH,
"{foregroundLevel: 0..20 (12; how far the black crayon reaches from the shadows into the midtones), backgroundLevel: 0..20 (10; how far the white crayon reaches from the highlights into the midtones), texture: \"brick\"|\"burlap\"|\"canvas\"|\"sandstone\" (\"canvas\"; the paper's surface, made in code), scaling: % 50..200 (100), relief: 0..50 (4), lightDirection: \"bottom\"|\"bottomLeft\"|\"left\"|\"topLeft\"|\"top\"|\"topRight\"|\"right\"|\"bottomRight\" (\"top\"), invert: bool (false; turns the surface's heights over)} redraws the object in a dense black crayon in its dark areas and a pure white crayon in its light areas, on mid-grey paper whose texture breaks the strokes and stands in relief, keeping its coverage. Public help names Foreground Level, Background Level and the texture options but not slider ranges or dialog defaults; ranges and defaults here are unverified VectorCraft choices. Original visual approximation, not a proprietary reproduction.",
json!({
"foregroundLevel": 12.0,
"backgroundLevel": 10.0,
"texture": "canvas",
"scaling": 100.0,
"relief": 4.0,
"lightDirection": "top",
"invert": false
}),
),
r(
"sketch.graphicPen",
"Graphic Pen…",
+23 -3
View File
@@ -2,8 +2,8 @@
//! Poster Edges, Rough Pastels, Smudge Stick, Sponge and Watercolor, Blur › Radial Blur and Smart Blur, Brush Strokes › Accented Edges, Angled Strokes,
//! Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes and Sumi-e, Distort › Diffuse
//! Glow, Glass and Ocean Ripple, Pixelate › Color Halftone, Crystallize, Mezzotint and Pointillize,
//! Sharpen › Unsharp Mask, Sketch › Bas Relief, Chalk & Charcoal, Charcoal, Graphic Pen, Halftone Pattern, Note Paper, Photocopy, Plaster,
//! Reticulation, Stamp and Torn Edges, Stylize ›
//! Sharpen › Unsharp Mask, Sketch › Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Conté Crayon, Graphic Pen, Halftone Pattern,
//! Note Paper, Photocopy, Plaster, Reticulation, Stamp, Torn Edges and Water Paper, Stylize ›
//! Glowing Edges, Texture
//! › Craquelure, Grain, Mosaic Tiles, Patchwork, Stained Glass and Texturizer, and Video ›
//! De-Interlace and NTSC Colors): filters over premultiplied RGBA8 pixels.
@@ -44,7 +44,7 @@ pub use sketch::{HALFTONE_TYPES, HalftonePattern};
pub use texture::{GRAIN_TYPES, Grain, LIGHT_DIRECTIONS, Light, TEXTURES, TEXTURES_LOADED, Texture};
/// The Photoshop-style effect ids (all raster effects, see [`crate::is_raster`]).
pub const PIXEL_EFFECTS: [&str; 55] = [
pub const PIXEL_EFFECTS: [&str; 56] = [
"artistic.coloredPencil",
"artistic.cutout",
"artistic.dryBrush",
@@ -82,6 +82,7 @@ pub const PIXEL_EFFECTS: [&str; 55] = [
"sketch.chalkCharcoal",
"sketch.charcoal",
"sketch.chrome",
"sketch.conteCrayon",
"sketch.graphicPen",
"sketch.halftonePattern",
"sketch.notePaper",
@@ -210,6 +211,11 @@ pub enum PixelFx {
ChalkCharcoal { chalk: f64, charcoal: f64, pressure: f64 },
/// Sketch › Chrome: polished chrome relief with `detail` (0..10) and `smoothness` (0..10).
Chrome { detail: f64, smoothness: f64 },
/// Sketch › Conté Crayon: dark areas in a black crayon, light areas in a white one, on mid-grey
/// paper; `foreground` and `background` (0..20) set how far each crayon reaches into the
/// midtones, and the paper is a `texture` surface scaled by `scaling` (0.5..2), in relief as
/// strong as `relief` (0..50), lit from `light`, its heights turned over when `invert`.
ConteCrayon { foreground: f64, background: f64, texture: Texture, scaling: f64, relief: f64, light: Light, invert: bool },
/// Sketch › Graphic Pen: fine linear ink strokes along `dir`, each `length` (1..15) points long
/// on white paper; `balance` (0..100) sets how much of the tone range becomes black ink.
GraphicPen { length: f64, balance: f64, direction: StrokeDirection },
@@ -483,6 +489,15 @@ pub(crate) fn parse(id: &str, p: &Value) -> Option<PixelFx> {
pressure: num(p, "strokePressure", 2.0).clamp(0.0, 5.0),
},
"sketch.chrome" => PixelFx::Chrome { detail: num(p, "detail", 4.0).clamp(0.0, 10.0), smoothness: num(p, "smoothness", 4.0).clamp(0.0, 10.0) },
"sketch.conteCrayon" => PixelFx::ConteCrayon {
foreground: num(p, "foregroundLevel", 12.0).clamp(0.0, 20.0),
background: num(p, "backgroundLevel", 10.0).clamp(0.0, 20.0),
texture: Texture::parse(text(p, "texture", "canvas")),
scaling: num(p, "scaling", 100.0).clamp(50.0, 200.0) / 100.0,
relief: num(p, "relief", 4.0).clamp(0.0, 50.0),
light: Light::parse(text(p, "lightDirection", "top")),
invert: flag(p, "invert", false),
},
"sketch.graphicPen" => PixelFx::GraphicPen {
length: num(p, "strokeLength", 5.0).clamp(1.0, 15.0),
balance: num(p, "lightDarkBalance", 50.0).clamp(0.0, 100.0),
@@ -617,6 +632,7 @@ impl PixelFx {
PixelFx::UnsharpMask { .. }
| PixelFx::ChalkCharcoal { .. }
| PixelFx::Chrome { .. }
| PixelFx::ConteCrayon { .. }
| PixelFx::HalftonePattern { .. }
| PixelFx::NotePaper { .. }
| PixelFx::Plaster { .. }
@@ -692,6 +708,7 @@ impl PixelFx {
PixelFx::ColoredPencil { width, .. } => Some(artistic::colored_pencil_reach(width)),
PixelFx::ChalkCharcoal { .. } => Some(sketch::CHALK_CHARCOAL_REACH),
PixelFx::Chrome { smoothness, .. } => Some(sketch::chrome_reach(smoothness)),
PixelFx::ConteCrayon { .. } => Some(sketch::CONTE_REACH),
PixelFx::FilmGrain { .. }
| PixelFx::Mezzotint { .. }
| PixelFx::HalftonePattern { .. }
@@ -778,6 +795,9 @@ impl PixelFx {
PixelFx::UnsharpMask { amount, radius, threshold } => sharpen::unsharp(px, w, h, amount, to_px(radius), threshold),
PixelFx::ChalkCharcoal { chalk, charcoal, pressure } => sketch::chalk_charcoal(px, w, h, space, chalk, charcoal, pressure),
PixelFx::Chrome { detail, smoothness } => sketch::chrome(px, w, h, space, detail, smoothness),
PixelFx::ConteCrayon { foreground, background, ref texture, scaling, relief, light, invert } => {
sketch::conte_crayon(px, w, h, space, foreground, background, texture, scaling, relief, light, invert)
}
PixelFx::GraphicPen { length, balance, direction } => brushstrokes::graphic_pen(px, w, h, space, length, balance, direction),
PixelFx::HalftonePattern { size, contrast, kind } => sketch::halftone_pattern(px, w, h, space, size, contrast, kind),
PixelFx::NotePaper { balance, graininess, relief } => sketch::note_paper(px, w, h, space, balance, graininess, relief),
+81 -5
View File
@@ -1,9 +1,12 @@
//! Effect › Sketch (Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Halftone Pattern, Note Paper, Photocopy, Plaster,
//! Reticulation, Stamp, Torn Edges and Water Paper; Graphic Pen lives in
//! Effect › Sketch (Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Conté Crayon, Halftone Pattern, Note Paper, Photocopy,
//! Plaster, Reticulation, Stamp, Torn Edges and Water Paper; Graphic Pen lives in
//! [`super::brushstrokes`]). Original filters built from public behaviour documentation:
//! <https://helpx.adobe.com/illustrator/using/summary-effects.html> (Sketch effects redraw in
//! black and white; Water Paper flows colours on damp fibrous paper) and the public Photoshop Elements Artistic filters guide. Visual
//! approximations, not proprietary reproductions.
//! black and white; Water Paper flows colours on damp fibrous paper; Conté Crayon draws dark areas
//! in black and light areas in white) and the public Photoshop Elements Sketch filters guide
//! (<https://helpx.adobe.com/photoshop-elements/using/sketch-filters.html>: Conté Crayon's
//! foreground and background levels and texture options). Visual approximations, not proprietary
//! reproductions.
use std::f64::consts::{FRAC_1_SQRT_2, TAU};
@@ -12,11 +15,12 @@ use vectorcraft_geom::{Point, Vec2};
use super::distort::displace;
use super::edges::sobel;
use super::pixelate::{Place, cell, rand, value_noise};
use super::texture::{Light, Tones, luma, premultiply, smooth_noise, straight};
use super::texture::{Light, Texture, Tones, luma, premultiply, smooth_noise, straight, texturizer};
use super::{PixelSpace, blur_plane, pick};
const SALT_CHALK: u64 = 216;
const SALT_CHROME: u64 = 0xC40_4D45;
const SALT_CONTE: u64 = 0xC047E;
const SALT_TORN: u64 = 0x746f726e5f6564;
const SALT_WATER: u64 = 208;
const EDGE_SOFT: f64 = 0.8;
@@ -362,6 +366,78 @@ pub(super) fn reticulation(px: &mut [[u8; 4]], w: usize, h: usize, space: &Pixel
});
}
/// How far (document units) Conté Crayon samples the softened tones that choose its crayons.
pub(super) const CONTE_REACH: f64 = 3.0 * TONE_SOFT + 1.0;
/// How much of a crayon is laid down where `amount` (0..1: how dark, for the dark crayon, or how
/// light, for the light one) meets its `level` (0..1) and `grain` (0..1, the paper's tooth and the
/// stroke): at level 0 only the deepest tones take the crayon, at level 1 it reaches past the
/// middle tone; the grain breaks its edge.
fn crayon(amount: f64, level: f64, grain: f64) -> f64 {
ramp((amount - (0.9 - 0.45 * level) + 0.4 * (grain - 0.5)) / 0.12 + 0.5)
}
/// Conté Crayon: the dark areas drawn in a dense black crayon and the light areas in a pure white
/// one, on mid-grey paper whose tooth (`texture` scaled by `scaling` (0.5..2), its heights turned
/// over when `invert`) and diagonal strokes break the crayons. `foreground` and `background`
/// (0..20) set how far the black and the white crayon reach into the midtones; the paper then
/// stands in relief as strong as `relief` (0..50), lit from `light`, as Texturizer draws it.
/// Coverage is kept.
#[allow(clippy::too_many_arguments)] // the effect's seven options
pub(super) fn conte_crayon(
px: &mut [[u8; 4]],
w: usize,
h: usize,
space: &PixelSpace,
foreground: f64,
background: f64,
texture: &Texture,
scaling: f64,
relief: f64,
light: Light,
invert: bool,
) {
if !([foreground, background, scaling, relief].iter().all(|v| v.is_finite()) && scaling > 0.0) {
return;
}
let Some(place) = Place::new(space, w, h) else { return };
let fg = foreground.clamp(0.0, 20.0) / 20.0;
let bg = background.clamp(0.0, 20.0) / 20.0;
let tones = Tones::new(px, w, h, TONE_SOFT / place.px);
// The tooth: how far the surface stands above its neighbours a quarter point (or half a pixel)
// away, so that crayon catches on the peaks and leaves the hollows bare.
let step = (0.25f64).max(0.5 * place.px / scaling);
let flip = if invert { -1.0 } else { 1.0 };
place.each(px, |x, y, p| {
if p[3] == 0 {
return;
}
let q = place.at(x, y);
let t = Point::new(q.x / scaling, q.y / scaling);
let tooth = if t.x.is_finite() && t.y.is_finite() {
let at = |dx: f64, dy: f64| texture.height(Point::new(t.x + dx, t.y + dy));
let ridge = (at(0.0, 0.0) - 0.25 * (at(-step, 0.0) + at(step, 0.0) + at(0.0, -step) + at(0.0, step))) / step;
let tooth = 0.5 + 0.5 * (2.0 * flip * ridge).tanh();
if tooth.is_finite() { tooth } else { 0.5 }
} else {
0.5
};
// Strokes along the two diagonals, about a point across and several long.
let (u, v) = ((q.x + q.y) * FRAC_1_SQRT_2, (q.x - q.y) * FRAC_1_SQRT_2);
let dark_stroke = value_noise(SALT_CONTE, u * 1.2, v * 0.15);
let light_stroke = value_noise(SALT_CONTE + 1, v * 1.2, u * 0.15);
let tone = tones.get(x, y);
let black = crayon(1.0 - tone, fg, 0.55 * tooth + 0.45 * dark_stroke);
let white = crayon(tone, bg, 0.55 * tooth + 0.45 * light_stroke);
let paper = 0.4 + 0.2 * tone;
let grey = ((paper + (1.0 - paper) * white) * (1.0 - black)) as f32;
*p = premultiply([grey; 3], f32::from(p[3]) / 255.0);
});
if relief > 0.0 {
texturizer(px, w, h, space, texture, scaling, relief, light, invert);
}
}
/// Torn Edges: the object in high-contrast black and white with ragged edges. `image_balance`
/// (0..50) shifts whether midtones fall to ink or paper; `smoothness` (0..15) softens tones and
/// the fraying; `contrast` (0..20) hardens the split. Coverage is kept.
+2
View File
@@ -1224,6 +1224,8 @@ fn texture_params_take_defaults_and_stay_in_range() {
("texture.texturizer", "lightDirection", LIGHT_DIRECTIONS.as_slice()),
("artistic.roughPastels", "texture", TEXTURES.as_slice()),
("artistic.roughPastels", "lightDirection", LIGHT_DIRECTIONS.as_slice()),
("sketch.conteCrayon", "texture", TEXTURES.as_slice()),
("sketch.conteCrayon", "lightDirection", LIGHT_DIRECTIONS.as_slice()),
] {
let doc = crate::effect_info(id).unwrap().params;
let parsed: Vec<PixelFx> = table.iter().map(|(_, v)| fx(id, json!({ key: v }))).collect();
+116 -2
View File
@@ -1,4 +1,4 @@
//! Sketch › Bas Relief, Charcoal, Photocopy and Stamp.
//! Sketch › Bas Relief, Charcoal, Conté Crayon, Photocopy and Stamp.
use serde_json::json;
use vectorcraft_doc::Effect;
@@ -173,9 +173,123 @@ fn bas_relief_lights_the_surfaces_facing_the_light() {
#[test]
fn sketch_filters_reach_beyond_nothing_they_do_not_paint() {
for id in ["sketch.basRelief", "sketch.charcoal", "sketch.photocopy", "sketch.stamp"] {
for id in ["sketch.basRelief", "sketch.charcoal", "sketch.conteCrayon", "sketch.photocopy", "sketch.stamp"] {
let f = fx(id, json!({}));
assert_eq!(f.outset(Rect::new(0.0, 0.0, 50.0, 50.0)), 0.0, "{id} keeps the object's coverage");
assert!(f.reach().is_some_and(|r| r.is_finite() && r > 0.0), "{id} reach");
}
}
/// The mean of channel 0 over columns `x0..x1` of every row.
fn mean(d: &[u8], w: usize, h: usize, x0: usize, x1: usize) -> f64 {
let sum: u32 = (0..h).flat_map(|y| (x0..x1).map(move |x| (x, y))).map(|(x, y)| u32::from(at(d, w, x, y))).sum();
f64::from(sum) / ((x1 - x0) * h) as f64
}
/// How many pixels of channel 0 are lighter than 192.
fn white(d: &[u8]) -> usize {
d.as_chunks::<4>().0.iter().filter(|p| p[0] > 192).count()
}
#[test]
fn conte_crayon_params_take_defaults_and_stay_in_range() {
let defaults = PixelFx::ConteCrayon {
foreground: 12.0,
background: 10.0,
texture: Texture::Canvas,
scaling: 1.0,
relief: 4.0,
light: Light::Top,
invert: false,
};
assert_eq!(fx("sketch.conteCrayon", json!({})), defaults);
assert_eq!(
fx(
"sketch.conteCrayon",
json!({"foregroundLevel": -5, "backgroundLevel": 1e308, "texture": "Brick", "scaling": 10, "relief": 99, "lightDirection": "bottomRight", "invert": true})
),
PixelFx::ConteCrayon {
foreground: 0.0,
background: 20.0,
texture: Texture::Brick,
scaling: 0.5,
relief: 50.0,
light: Light::BottomRight,
invert: true
}
);
for junk in [
json!({"foregroundLevel": "NaN", "scaling": "1e999"}),
json!({"backgroundLevel": null, "texture": 3, "relief": [1], "lightDirection": "up", "invert": "yes"}),
] {
assert_eq!(fx("sketch.conteCrayon", junk.clone()), defaults, "{junk}");
}
let doc = crate::effect_info("sketch.conteCrayon").unwrap().params;
assert!(doc.contains("unverified") && doc.contains("foregroundLevel") && doc.contains("backgroundLevel"), "{doc}");
}
/// A grey ramp: its shadows in black crayon, its highlights in white crayon, the midtones on grey
/// paper between them; grey only, coverage kept, the same on every run.
#[test]
fn conte_crayon_draws_the_shadows_black_and_the_highlights_white() {
let (w, h) = (96, 32);
let src = image(w, h, |x, _| grey((x * 255 / (w - 1)) as u8));
let out = run("sketch.conteCrayon", json!({"relief": 0}), &src, w, h);
for p in out.as_chunks::<4>().0 {
assert!(p[0] == p[1] && p[1] == p[2] && p[3] == 255, "{p:?}");
}
let (shadows, mids, lights) = (mean(&out, w, h, 0, 12), mean(&out, w, h, w / 2 - 6, w / 2 + 6), mean(&out, w, h, w - 12, w));
assert!(shadows < 40.0, "shadows {shadows}");
assert!(lights > 215.0, "highlights {lights}");
assert!(shadows + 30.0 < mids && mids + 30.0 < lights, "{shadows} {mids} {lights}");
assert_eq!(out, run("sketch.conteCrayon", json!({"relief": 0}), &src, w, h), "deterministic");
// The relief shades the paper but keeps it grey.
let lit = run("sketch.conteCrayon", json!({}), &src, w, h);
assert_ne!(lit, out);
assert!(lit.as_chunks::<4>().0.iter().all(|p| p[0] == p[1] && p[1] == p[2]));
}
/// Foreground Level spreads the black crayon into the midtones, Background Level the white one.
#[test]
fn conte_crayon_levels_spread_each_crayon_into_the_midtones() {
let (w, h) = (64, 64);
let mid = image(w, h, |_, _| grey(128));
let with = |p: serde_json::Value| run("sketch.conteCrayon", p, &mid, w, h);
let (few, many) = (with(json!({"foregroundLevel": 0, "relief": 0})), with(json!({"foregroundLevel": 20, "relief": 0})));
assert!(black(&many) > black(&few) + w * h / 4, "{} vs {}", black(&many), black(&few));
let (few, many) = (
with(json!({"foregroundLevel": 0, "backgroundLevel": 0, "relief": 0})),
with(json!({"foregroundLevel": 0, "backgroundLevel": 20, "relief": 0})),
);
assert!(white(&many) > white(&few) + w * h / 4, "{} vs {}", white(&many), white(&few));
}
/// The paper's texture, scale and inversion break the crayon differently; the relief is lit from
/// the chosen side.
#[test]
fn conte_crayon_texture_options_change_the_paper() {
let (w, h) = (64, 64);
let mid = image(w, h, |x, y| grey((64 + x + y) as u8));
let with = |p: serde_json::Value| run("sketch.conteCrayon", p, &mid, w, h);
let canvas = with(json!({"relief": 0}));
for other in [
json!({"relief": 0, "texture": "brick"}),
json!({"relief": 0, "texture": "sandstone"}),
json!({"relief": 0, "scaling": 200}),
json!({"relief": 0, "invert": true}),
] {
assert_ne!(with(other.clone()), canvas, "{other}");
}
let top = with(json!({"texture": "brick", "relief": 20, "lightDirection": "top"}));
let bottom = with(json!({"texture": "brick", "relief": 20, "lightDirection": "bottom"}));
assert_ne!(top, bottom);
assert_ne!(top, with(json!({"texture": "brick", "relief": 0, "lightDirection": "top"})));
survives(
"sketch.conteCrayon",
&[
json!({}),
json!({"foregroundLevel": "NaN", "backgroundLevel": 1e308, "scaling": -1e308, "relief": 1e308, "texture": "burlap", "invert": true}),
json!({"foregroundLevel": -1e308, "backgroundLevel": [1], "texture": {}, "lightDirection": 3, "relief": "NaN"}),
],
);
}
+2 -1
View File
@@ -60,11 +60,12 @@ const PIXELATE: [(&str, &str); 4] =
[("pixelate.colorHalftone", "{}"), ("pixelate.crystallize", "{}"), ("pixelate.mezzotint", "{}"), ("pixelate.pointillize", "{}")];
/// Effect › Sketch, at their defaults.
const SKETCH: [(&str, &str); 12] = [
const SKETCH: [(&str, &str); 13] = [
("sketch.basRelief", "{}"),
("sketch.chalkCharcoal", "{}"),
("sketch.charcoal", "{}"),
("sketch.chrome", "{}"),
("sketch.conteCrayon", "{}"),
("sketch.graphicPen", "{}"),
("sketch.halftonePattern", "{}"),
("sketch.notePaper", "{}"),
+4
View File
@@ -378,6 +378,10 @@ fn structured_junk() {
json!({"effect": "artistic.roughPastels", "params": {"strokeLength": 1e308, "strokeDetail": "NaN", "texture": -1e308, "scaling": "bad", "lightDirection": "nope"}}),
),
("effect.apply", json!({"effect": "sketch.chrome", "params": {"detail": -1e308, "smoothness": "NaN"}})),
(
"effect.apply",
json!({"effect": "sketch.conteCrayon", "params": {"foregroundLevel": "NaN", "backgroundLevel": 1e308, "texture": [1], "scaling": -1e308, "relief": "1e999", "lightDirection": 3, "invert": "yes"}}),
),
("effect.apply", json!({"effect": "sketch.graphicPen", "params": {"strokeLength": -1e308, "lightDarkBalance": "NaN", "strokeDirection": 3}})),
("effect.apply", json!({"effect": "sketch.halftonePattern", "params": {"size": -1e308, "contrast": "NaN", "patternType": 3}})),
("effect.apply", json!({"effect": "sketch.basRelief", "params": {"detail": "NaN", "smoothness": 1e308, "lightDirection": 3}})),
+2 -2
View File
@@ -301,8 +301,8 @@ fn choices(effect: &str, key: &str) -> Option<form::Choices> {
("sketch.halftonePattern", "patternType") => Some(&vectorcraft_effects::pixel::HALFTONE_TYPES),
("sketch.plaster", "lightDirection") => Some(&vectorcraft_effects::pixel::LIGHT_DIRECTIONS),
("texture.grain", "grainType") => Some(&vectorcraft_effects::pixel::GRAIN_TYPES),
("texture.texturizer" | "artistic.underpainting", "texture") => Some(&vectorcraft_effects::pixel::TEXTURES),
("sketch.basRelief" | "texture.texturizer" | "artistic.underpainting", "lightDirection") => {
("texture.texturizer" | "artistic.underpainting" | "sketch.conteCrayon", "texture") => Some(&vectorcraft_effects::pixel::TEXTURES),
("sketch.basRelief" | "texture.texturizer" | "artistic.underpainting" | "sketch.conteCrayon", "lightDirection") => {
Some(&vectorcraft_effects::pixel::LIGHT_DIRECTIONS)
}
("video.deinterlace", "eliminate") => Some(&[("Odd Fields", "odd"), ("Even Fields", "even")]),
+2
View File
@@ -217,6 +217,8 @@ fn raster_filter_dialogs_preview_and_apply() {
("pixelate.pointillize", "cellSize", "12"),
("sketch.basRelief", "lightDirection", "left"),
("sketch.charcoal", "thickness", "5"),
("sketch.conteCrayon", "texture", "brick"),
("sketch.conteCrayon", "foregroundLevel", "16"),
("sketch.halftonePattern", "patternType", "line"),
("sketch.photocopy", "darkness", "40"),
("sketch.stamp", "lightDarkBalance", "10"),
+4
View File
@@ -5257,6 +5257,10 @@ theme Appearance Външен вид
Halftone Pattern Полутонов шаблон
Torn Edges… Разкъсани краища…
Torn Edges Разкъсани краища
Conté Crayon… Креда Конте…
Conté Crayon Креда Конте
Foreground Level Ниво на преден план
Background Level Ниво на фон
Pattern Type Тип шаблон
Dot Точка
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5288,6 +5288,10 @@ mark-style Japanese Japonské
Halftone Pattern Polotónový vzorek
Torn Edges… Roztržené okraje…
Torn Edges Roztržené okraje
Conté Crayon… Křída Conté…
Conté Crayon Křída Conté
Foreground Level Úroveň popředí
Background Level Úroveň pozadí
Pattern Type Typ vzorku
Dot Tečka
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5149,6 +5149,10 @@ swatch Bright Violet Kraftig violet
Halftone Pattern Rastermønster
Torn Edges… Flængede kanter…
Torn Edges Flængede kanter
Conté Crayon… Conté-kridt…
Conté Crayon Conté-kridt
Foreground Level Forgrundsniveau
Background Level Baggrundsniveau
Pattern Type Mønstertype
Dot Prik
Export Type: Eksporttype:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -4867,6 +4867,10 @@ effect Soft Weich
Halftone Pattern Rasterungseffekt
Torn Edges… Zerrissene Kanten…
Torn Edges Zerrissene Kanten
Conté Crayon… Conté-Stift…
Conté Crayon Conté-Stift
Foreground Level Vordergrundstufe
Background Level Hintergrundstufe
Pattern Type Musterart
Dot Punkt
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5240,6 +5240,10 @@ effect Points Σημεία
Halftone Pattern Μοτίβο ημιτόνου
Torn Edges… Ξεσκισμένες άκρες…
Torn Edges Ξεσκισμένες άκρες
Conté Crayon… Κιμωλία Conté…
Conté Crayon Κιμωλία Conté
Foreground Level Επίπεδο προσκηνίου
Background Level Επίπεδο φόντου
Pattern Type Τύπος μοτίβου
Dot Κουκκίδα
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2045 and column 19.
+4
View File
@@ -5230,6 +5230,10 @@ mark-style Japanese Japonesas
Halftone Pattern Trama de semitonos
Torn Edges… Bordes desgarrados…
Torn Edges Bordes desgarrados
Conté Crayon… Lápiz Conté…
Conté Crayon Lápiz Conté
Foreground Level Nivel de primer plano
Background Level Nivel de fondo
Pattern Type Tipo de trama
Dot Punto
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5252,6 +5252,10 @@ mark-style Japanese Japanilainen
Halftone Pattern Rasterikuvio
Torn Edges… Repeytyneet reunat…
Torn Edges Repeytyneet reunat
Conté Crayon… Conté-liitu…
Conté Crayon Conté-liitu
Foreground Level Edustan taso
Background Level Taustan taso
Pattern Type Kuviotyyppi
Dot Piste
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5287,6 +5287,10 @@ theme Appearance Apparence
Halftone Pattern Trame de demi-teintes
Torn Edges… Bords déchirés…
Torn Edges Bords déchirés
Conté Crayon… Crayon Conté…
Conté Crayon Crayon Conté
Foreground Level Niveau de premier plan
Background Level Niveau d’arrière-plan
Pattern Type Type de motif
Dot Point
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5274,6 +5274,10 @@ imageTrace Outline Körvonal
Halftone Pattern Féltónus minta
Torn Edges… Szaggatott szélek…
Torn Edges Szaggatott szélek
Conté Crayon… Conté-kréta…
Conté Crayon Conté-kréta
Foreground Level Előtér szintje
Background Level Háttér szintje
Pattern Type Mintatípus
Dot Pont
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5149,6 +5149,10 @@ swatch Bright Violet Violet cerah
Halftone Pattern Pola halftone
Torn Edges… Tepi robek…
Torn Edges Tepi robek
Conté Crayon… Krayon Conté…
Conté Crayon Krayon Conté
Foreground Level Tingkat latar depan
Background Level Tingkat latar belakang
Pattern Type Jenis pola
Dot Titik
Export Type: Jenis ekspor:
Can't render this file because it contains an unexpected character in line 3816 and column 19.
+4
View File
@@ -4902,6 +4902,10 @@ lighting Light Luce
Halftone Pattern Pattern mezzetinte
Torn Edges… Bordi strappati…
Torn Edges Bordi strappati
Conté Crayon… Matita Conté…
Conté Crayon Matita Conté
Foreground Level Livello primo piano
Background Level Livello sfondo
Pattern Type Tipo di pattern
Dot Punto
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -4942,6 +4942,10 @@ lighting Light ライト
Halftone Pattern ハーフトーンパターン
Torn Edges… 破れたエッジ…
Torn Edges 破れたエッジ
Conté Crayon… コンテ…
Conté Crayon コンテ
Foreground Level 前景レベル
Background Level 背景レベル
Pattern Type パターンタイプ
Dot ドット
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5005,6 +5005,10 @@ imageTrace Outline კონტური
Halftone Pattern ნახევარტონური პატერნი
Torn Edges… დაგვერძნილი კიდეები…
Torn Edges დაგვერძნილი კიდეები
Conté Crayon… კონტე ფანქარი…
Conté Crayon კონტე ფანქარი
Foreground Level წინა პლანის დონე
Background Level ფონის დონე
Pattern Type პატერნის ტიპი
Dot წერტილი
Color Scheme ფერის სქემა
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -4865,6 +4865,10 @@ lighting Light 광원
Halftone Pattern 하프톤 패턴
Torn Edges… 찢어진 가장자리…
Torn Edges 찢어진 가장자리
Conté Crayon… 콘테 크레용…
Conté Crayon 콘테 크레용
Foreground Level 전경 레벨
Background Level 배경 레벨
Pattern Type 패턴 유형
Dot 점
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5160,6 +5160,10 @@ swatch Bright Violet Felviolet
Halftone Pattern Rasterpatroon
Torn Edges… Gescheurde randen…
Torn Edges Gescheurde randen
Conté Crayon… Conté-krijt…
Conté Crayon Conté-krijt
Foreground Level Voorgrondniveau
Background Level Achtergrondniveau
Pattern Type Patroontype
Dot Punt
Export Type: Exporttype:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5140,6 +5140,10 @@ mark-style Japanese Japońskie
Halftone Pattern Wzór rastra
Torn Edges… Postrzępione krawędzie…
Torn Edges Postrzępione krawędzie
Conté Crayon… Kredka Conté…
Conté Crayon Kredka Conté
Foreground Level Poziom pierwszego planu
Background Level Poziom tła
Pattern Type Typ wzoru
Dot Kropka
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5207,6 +5207,10 @@ mark-style Japanese Japonesas
Halftone Pattern Padrão de meio-tom
Torn Edges… Bordas rasgadas…
Torn Edges Bordas rasgadas
Conté Crayon… Lápis Conté…
Conté Crayon Lápis Conté
Foreground Level Nível do primeiro plano
Background Level Nível do plano de fundo
Pattern Type Tipo de padrão
Dot Ponto
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 6 and column 47.
+4
View File
@@ -4898,6 +4898,10 @@ lighting Light Свет
Halftone Pattern Полутоновый узор
Torn Edges… Рваные края…
Torn Edges Рваные края
Conté Crayon… Мелок Конте…
Conté Crayon Мелок Конте
Foreground Level Уровень переднего плана
Background Level Уровень фона
Pattern Type Тип узора
Dot Точка
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -5244,6 +5244,10 @@ theme Appearance Utseende
Halftone Pattern Rastermönster
Torn Edges… Riviga kanter…
Torn Edges Riviga kanter
Conté Crayon… Contékrita…
Conté Crayon Contékrita
Foreground Level Förgrundsnivå
Background Level Bakgrundsnivå
Pattern Type Mönstertyp
Dot Punkt
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 5 and column 25.
+4
View File
@@ -5329,6 +5329,10 @@ theme Appearance Görünüm
3d Light Işık
Torn Edges… Yırtık Kenarlar…
Torn Edges Yırtık Kenarlar
Conté Crayon… Conté Kalemi…
Conté Crayon Conté Kalemi
Foreground Level Ön plan düzeyi
Background Level Arka plan düzeyi
Brush Size Fırça Boyutu
Texture Coverage Doku Kapsamı
Definition Tanım
Can't render this file because it contains an unexpected character in line 5 and column 25.
+4
View File
@@ -4882,6 +4882,10 @@ lighting Light Світло
Halftone Pattern Напівтоновий візерунок
Torn Edges… Порвані краї…
Torn Edges Порвані краї
Conté Crayon… Крейда Конте…
Conté Crayon Крейда Конте
Foreground Level Рівень переднього плану
Background Level Рівень тла
Pattern Type Тип візерунка
Dot Крапка
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 733 and column 40.
+4
View File
@@ -4882,6 +4882,10 @@ theme Appearance Giao diện
Halftone Pattern Mẫu bán sắc
Torn Edges… Cạnh rách…
Torn Edges Cạnh rách
Conté Crayon… Bút chì Conté…
Conté Crayon Bút chì Conté
Foreground Level Mức tiền cảnh
Background Level Mức nền
Pattern Type Loại mẫu
Dot Chấm
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 4028 and column 10.
+4
View File
@@ -5123,6 +5123,10 @@ lighting Light 光源
Halftone Pattern 半调图案
Torn Edges… 撕边…
Torn Edges 撕边
Conté Crayon… 孔特蜡笔…
Conté Crayon 孔特蜡笔
Foreground Level 前景级别
Background Level 背景级别
Pattern Type 图案类型
Dot 网点
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 2 and column 73.
+4
View File
@@ -4934,6 +4934,10 @@ lighting Light 光源
Halftone Pattern 半色調圖樣
Torn Edges… 撕裂邊緣…
Torn Edges 撕裂邊緣
Conté Crayon… 孔特蠟筆…
Conté Crayon 孔特蠟筆
Foreground Level 前景層級
Background Level 背景層級
Pattern Type 圖樣類型
Dot 網點
# User Interface › Color Scheme
Can't render this file because it contains an unexpected character in line 6 and column 47.
+12 -10
View File
@@ -221,6 +221,7 @@ fn effect_menu_lists_the_sketch_filters_between_sharpen_and_stylize() {
"Chalk & Charcoal…",
"Charcoal…",
"Chrome…",
"Conté Crayon…",
"Graphic Pen…",
"Halftone Pattern…",
"Note Paper…",
@@ -237,19 +238,20 @@ fn effect_menu_lists_the_sketch_filters_between_sharpen_and_stylize() {
assert_eq!(sketch[1].params, json!({"effect": "sketch.chalkCharcoal"}));
assert_eq!(sketch[2].params, json!({"effect": "sketch.charcoal"}));
assert_eq!(sketch[3].params, json!({"effect": "sketch.chrome"}));
assert_eq!(sketch[4].params, json!({"effect": "sketch.graphicPen"}));
assert_eq!(sketch[5].params, json!({"effect": "sketch.halftonePattern"}));
assert_eq!(sketch[6].params, json!({"effect": "sketch.notePaper"}));
assert_eq!(sketch[7].params, json!({"effect": "sketch.photocopy"}));
assert_eq!(sketch[8].params, json!({"effect": "sketch.plaster"}));
assert_eq!(sketch[9].params, json!({"effect": "sketch.reticulation"}));
assert_eq!(sketch[10].params, json!({"effect": "sketch.stamp"}));
assert_eq!(sketch[11].params, json!({"effect": "sketch.tornEdges"}));
assert_eq!(sketch[12].params, json!({"effect": "sketch.waterPaper"}));
assert_eq!(sketch[4].params, json!({"effect": "sketch.conteCrayon"}));
assert_eq!(sketch[5].params, json!({"effect": "sketch.graphicPen"}));
assert_eq!(sketch[6].params, json!({"effect": "sketch.halftonePattern"}));
assert_eq!(sketch[7].params, json!({"effect": "sketch.notePaper"}));
assert_eq!(sketch[8].params, json!({"effect": "sketch.photocopy"}));
assert_eq!(sketch[9].params, json!({"effect": "sketch.plaster"}));
assert_eq!(sketch[10].params, json!({"effect": "sketch.reticulation"}));
assert_eq!(sketch[11].params, json!({"effect": "sketch.stamp"}));
assert_eq!(sketch[12].params, json!({"effect": "sketch.tornEdges"}));
assert_eq!(sketch[13].params, json!({"effect": "sketch.waterPaper"}));
let at = |label: &str| entries.iter().position(|e| e.path[0] == "Effect" && e.label == label).unwrap();
assert!(at("Unsharp Mask…") < at("Bas Relief…") && at("Bas Relief…") < at("Chalk & Charcoal…"));
assert!(at("Chalk & Charcoal…") < at("Chrome…"));
assert!(at("Chrome…") < at("Graphic Pen…") && at("Graphic Pen…") < at("Halftone Pattern…"));
assert!(at("Chrome…") < at("Conté Crayon…") && at("Conté Crayon…") < at("Graphic Pen…") && at("Graphic Pen…") < at("Halftone Pattern…"));
assert!(at("Halftone Pattern…") < at("Note Paper…") && at("Note Paper…") < at("Plaster…"));
assert!(at("Plaster…") < at("Reticulation…"));
assert!(at("Reticulation…") < at("Torn Edges…") && at("Torn Edges…") < at("Water Paper…") && at("Water Paper…") < at("Glowing Edges…"));
+21 -5
View File
@@ -1,6 +1,6 @@
# Effects parity
> **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)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-22 · **Change:** minor (G2: Effect › Sketch › Conté Crayon (Foreground Level, Background Level, Texture, Scaling, Relief, Light Direction, Invert; a black crayon in the dark areas and a white one in the light areas on textured mid-grey paper; ranges and defaults unverified VectorCraft choices); measured Photoshop-style filters 57/57, the Effect Gallery remains (4–6 h); 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
@@ -12,7 +12,7 @@ Part of [target-app-parity.md](target-app-parity.md); open work is in [gaps.md](
| Group | Illustrator | VectorCraft | % | Remaining (h) |
|---|---:|---:|---:|---:|
| Illustrator effects (vector and stylize) | 50 | 46 | 92% | 6–10 |
| Photoshop effects (raster, Effect Gallery) | 57 | 54 | 95% | 2–4 |
| Photoshop effects (raster, Effect Gallery) | 57 | 57 | 100% | 4–6 (the Effect Gallery) |
| 3D and Materials | 4 (+3 Classic) | 4 (initial: Extrude & Bevel, Revolve, Inflate, Rotate) | ~25% | 25–45 |
| Beyond Illustrator: Effect › Color Adjustments (6), effect plug-ins (WebAssembly) | — | 6 + plug-ins | — | — |
@@ -44,7 +44,7 @@ its resolution, PDF export warns once per object with the requested and the lowe
| Distort | Diffuse Glow, Glass, Ocean Ripple | 3/3 | — |
| Pixelate | Color Halftone, Crystallize, Mezzotint, Pointillize | 4/4 | — |
| Sharpen | Unsharp Mask | 1/1 | — |
| Sketch | Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Conté Crayon, Graphic Pen, Halftone Pattern, Note Paper, Photocopy, Plaster, Reticulation, Stamp, Torn Edges, Water Paper | 13/14 (approximate Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Graphic Pen, Halftone Pattern, Note Paper, Photocopy, Plaster, Reticulation, Stamp, Torn Edges, Water Paper; Chalk & Charcoal, Graphic Pen, Note Paper and Water Paper defaults unverified) | Conté Crayon |
| Sketch | Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Conté Crayon, Graphic Pen, Halftone Pattern, Note Paper, Photocopy, Plaster, Reticulation, Stamp, Torn Edges, Water Paper | 14/14 (approximate Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Conté Crayon, Graphic Pen, Halftone Pattern, Note Paper, Photocopy, Plaster, Reticulation, Stamp, Torn Edges, Water Paper; Chalk & Charcoal, Conté Crayon, Graphic Pen, Note Paper and Water Paper defaults unverified) | — |
| Stylize | Glowing Edges | 1/1 | — |
| Texture | Craquelure, Grain, Mosaic Tiles, Patchwork, Stained Glass, Texturizer | 6/6 | — |
| Video | De-Interlace, NTSC Colors | 2/2 | — |
@@ -52,8 +52,8 @@ its resolution, PDF export warns once per object with the requested and the lowe
The pixel-filter pipeline (`vectorcraft_effects::pixel`) is in place: each new filter is one function, a
catalogue row, a menu entry and translations. Measured throughput: 0.7–1.2 agent hours per filter
(see [calibration](target-app-parity.md#calibration)), so the 3 missing filters are ~2–4 h and the Effect
Gallery dialog another 4–6 h. These parallelize well across agents.
(see [calibration](target-app-parity.md#calibration)). Every Photoshop-style filter is in the catalogue; the Effect
Gallery dialog is the 4–6 h that remain.
Film Grain (`artistic.filmGrain`, Effect › Artistic) adds stable monochrome noise to shadows and
midtones, with Grain, Highlight Area and Intensity sliders, live preview and appearance editing.
@@ -159,6 +159,21 @@ for VectorCraft and are not verified against proprietary defaults. Evidence: `cr
`halftone_pattern_settings_survive_a_save_and_open` in `crates/engine/src/tests_rasterfilters.rs`, and
`tests_labels::effect_menu_lists_the_sketch_filters_between_sharpen_and_stylize`.
Effect › Sketch › Conté Crayon (`sketch.conteCrayon`; `pixel/sketch.rs`) redraws the object in a dense
black crayon where it is dark and a pure white crayon where it is light, on mid-grey paper, as
[Illustrator's public effects summary](https://helpx.adobe.com/illustrator/using/summary-effects.html) describes
(black for dark areas, white for light areas). Its controls follow the public
[Photoshop filter reference](https://helpx.adobe.com/photoshop/using/filter-effects-reference.html) and the
[Photoshop Elements Sketch filters guide](https://helpx.adobe.com/photoshop-elements/using/sketch-filters.html)
(foreground and background levels, texture options): Foreground Level and Background Level (0–20) set how far
each crayon reaches into the midtones; Texture (Brick, Burlap, Canvas, Sandstone, the surfaces Texturizer
draws), Scaling, Relief, Light Direction and Invert make the paper's tooth, which breaks the diagonal crayon
strokes, and its relief. The public pages publish no slider ranges or defaults, so those are unverified
VectorCraft choices; an original approximation, never compared with another application's output. Tests:
`pixel::tests_sketch::conte_crayon_*`, `tests_rasterfilters`, `command_sweep`,
`dialogs::tests::raster_filter_dialogs_preview_and_apply` and
`tests_labels::effect_menu_lists_the_sketch_filters_between_sharpen_and_stylize`.
## 3D and Materials
| Item | Ours |
@@ -178,6 +193,7 @@ angular cut caps, exact visibility, 3D Classic, Turntable, 3D export) is 25–45
| Date | Change | Summary |
|---|---|---|
| 2026-10-22 | minor | G2: Effect › Sketch › Conté Crayon (Foreground Level, Background Level, Texture, Scaling, Relief, Light Direction, Invert; a black crayon in the dark areas and a white one in the light areas on textured mid-grey paper; ranges and defaults unverified VectorCraft choices); measured Photoshop-style filters 57/57, the Effect Gallery remains (4–6 h); Sketch 14/14. |
| 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. |
+9 -9
View File
File diff suppressed because one or more lines are too long
+4 -3
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long