算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
illustration-line-interior【设计与创意】Draws original hand-written SVG spot scenes in the Line interior style, wide airy rooms or terraces where slim, realistic people do design and coding work. A thin uniform indigo outline (1.4 px at 480 wide) runs around mostly white fills. Sparse flat accents (teal, sage, coral, mustard, lavender, peach wood) cover under 7% of the card. Pale lavender …
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
A calm, editorial line style: a whole room at small scale, people at about one seventh head-to-height, every shape outlined once in thin indigo and filled white, with a few flat accents. It suits product marketing that wants "people at work" without loud colour.
Use illustration-outlined-cartoon for big-headed characters with a near-black ~2.4 px ink line and bold fills. Use illustration-framed-panel when the scene should sit inside a coloured panel on a pastel card. Use illustration-flat when there should be no outlines at all.
Extracted from a set of 42 original design-and-coding cards in 14 styles; the three cards in examples/ are this style's shipped cards.
One thin, uniform indigo outline (1.4 px) around white-filled shapes in a wide, airy room, with flat colour on under 7% of the card.
Measured from the three examples (fills and strokes, 1x renders). White and the card make up about 85% of the pixels, indigo line about 2%, accents 4–7%.
| Role | Hex | Where it goes |
|---|---|---|
| Indigo ink | #3a2d66 | every outline, the floor line, eye dots, indigo hair (hair is a filled ink shape) |
| Wall line | #cfc9e0 | background decor strokes only (bricks, lamps, posters, clouds, birds, skyline, railing). Never a fill |
| White | #ffffff | default fill for everything: furniture, shirts, screens, pots, books, sneakers, mugs |
| Peach wood | #f9c99a | wood: ladder rails and boards, posts, stool, crate, a striped pot |
| Mustard | #f5c35a | one book, a duck, bulbs, sneakers, sticky notes, earring stud, a top |
| Orange | #f6a85e | a pot, trousers, a duck beak, shine arcs on brown hair, one code dash |
| Coral | #ef5b5b | sneakers or soles, a label, a marker tip, a mug band, one code dash, window dot |
| Teal | #3fa58a | a book, a top, a mug band, a hammock stripe, a check mark |
| Sage / Leaf | #8cc79b / #5fae7a | light and dark leaves, alternating leaf by leaf |
| Lavender | #ab9ee6 | a book, a top, page lines, keyboard lines, a sneaker sole |
| Purple | #7f6cc4 | a book, trousers, shine arcs on indigo hair, one code dash |
| Denim | #7f9fdc | jeans |
| Brown | #7b4b3a | brown hair, coffee in a cup |
| Skin | #f3cdb0 #e2a57c #b47852 #7a4b33 | light, medium, deep, dark; two people in a card get two different tones |
<g id="xx-bg" fill="none" stroke="#cfc9e0" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">. Foreground: <g id="xx-fg" stroke="#3a2d66" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">. Shapes inherit the stroke; each sets its own fill.M190 146h0.1).xm(), 3 px, stroke 1), 2–4 per pot or box. Never on clothing.font-family="ui-monospace, monospace" font-weight="700", 4.4–5.2 px, 2–5 letters (JS, CSS, UX, API, CACHE) on a small label rect, stroke="none".head() from the toolkit. It draws a 3/4 profile facing left or right: one face path with the nose and chin in the contour, an ear on the back side, a near eye dot (r 1.15) and a far eye dot (r 1.0) 4.9 apart, two 1 px brows, a nostril tick and a short mouth arc. No cheek colour, no pupils, no open mouths. Calm, slightly smiling.#3a2d66 (1–4 shine arcs in purple #7f6cc4) or brown #7b4b3a (shine in orange #f6a85e). Presets: afro, bun, side, crop (+ beard, glasses, earring). The afro's back mass returns as behind: draw it before the torso.head(x, y, rot, opts) rotates in screen degrees (+ = clockwise). That nods a right-facing head DOWN and a left-facing head UP. Tilt 4–9° toward what the person looks at.torso(hx, hy, { style: 'tee' | 'top', facing, fill, skin }) draws the neck, a soft shirt shape 30–34 wide (crew-neck tee or fitted top with a small V collar) and two 1 px folds, all placed from the head centre. TORSO_ANCHORS[style] gives the shoulder, hip and waistband points relative to the head centre. Mirror their x for a left-facing figure. Tops are white or one accent.sleeve(S, arm.u, 13, 5.8) caps the upper arm; drawn after the arm. A flatter sleeve (half-width under 6) avoids a shoulder-pad look.bentArm() with half-widths 4.4–5 shoulder, 4–4.4 elbow, 3.2–3.4 wrist. It gives a pointed outer elbow; add the 3 px crease line from arm.I. Upper arm 27–40, forearm 24–33. Use solveElbow(S, wrist, 35, 30, flip) and try both flip values: the right one hangs the elbow below the shoulder-to-wrist line. Keep the wrist 45–60 px from the shoulder. Closer, and the arm folds into a chicken wing.wristFor(HANDS[name].tip, target, angle, scale, flip). It returns the wrist point to solve the arm to.rest hand show below the torso. A figure with one arm reads as "an arm is missing".HANDS): 17 local units at scale 1.05–1.15, so 18–20 px long, about the face from chin to brow. Fingers are 3–4 rounded bands with 0.9 separation lines; the middle finger is longest, the little finger shortest. Shapes: type (palm down on keys), cup (wrapped round a mug, thumb over the rim), wrap (same, thumb hidden behind the object), marker (fist round a pen, with HANDS.marker.pen()), point (index out, thumb tucked), rest (relaxed).references/craft.md, then pass flip = true when the thumb belongs on +y.trouserLeg() for standing legs (tapered, flat hem, 5.2 px rolled cuff band, 4–10 px of ankle skin); bentLeg() + cuffAndAnkle() for sitting or stepping. sneaker() is 25 × 10.6 with a 3 px sole band and two lace ticks; heel at the floor point, mirrored with scale(-1 1). End each trouser leg at the shoe's shoeOpening(heel, rot, mirror).heel = liftedHeel(toeX, 22–28, mirror), then sneaker(\translate(heel) rotate(deg)`). For a mirrored shoe use rotate(-deg) scale(-1 1)andshoeOpening(heel, -deg, true)`.rotAbout()); the rear heel lifted so only the toe touches the floor; lying in a hammock with the laptop on the thighs; sitting on a stool, one foot on the rung, holding a cup.bricks(), 14 × 6, rows 7 apart), 1–2 pendant lamps hanging from the card's top edge (lampDome(), lampCone()), 1 framed poster on a nail (poster()) with a simple icon inside. Outdoors: 2–3 outline clouds, 2–3 birds, a skyline and a railing instead of bricks.leaf() (lance leaves with veins), figLeaf() (fiddle-leaf fig), blade() (snake plant), stems as 1.4 px open curves from the pot, leaves alternating sage and leaf green. Pots: pot(), white with x marks, peach with 1 px bands, or orange.#ffffff rect first.M56 308H424M40 308h10M430 308h10. Every foot, pot, leg and caster stands on it. The band below (y 308–360) stays empty.translate(-8 0) to nudge a whole figure; rotate(-7 284 180) on the upper-body group (neck, torso, head, sleeve) to lean it over the hips.1. A parts toolkit. scripts/interior.mjs (no dependencies) has every repeated part with the examples' numbers: layers, floor, bricks, lamps, poster, cloud, leaves, pots, limb, bentArm, solveElbow, sleeve, torso, trouserLeg, bentLeg, cuffAndAnkle, sneaker, shoeOpening, liftedHeel, rotAbout, HANDS + hand() + place() + wristFor(), head() and mirrorPath(). Run node scripts/interior.mjs --demo /abs/work/demo.svg from the skill folder (write it into your work folder, not the skill) and render it to see every part. The demo output is a parts sheet: four heads, six hands with thumbs up, two plants, the lamps, the bricks and a standing figure built from the parts.
A complete figure, tested: a woman facing left points at a chart. Save it as card.mjs next to your card, fix the import path, and run node card.mjs.
import fs from 'node:fs';
import * as LI from '/abs/path/to/illustration-line-interior/scripts/interior.mjs';
const { W, C, SKIN, FL, P, f } = LI, id = 'sn-', sk = SKIN.medium;
const HC = [300, 102], A = LI.TORSO_ANCHORS.top, rel = q => [HC[0] - q[0], HC[1] + q[1]]; // facing left: mirror x
const LEAN = -5, PV = [300, 188]; // lean toward the left, about the hips
const h = LI.head(HC[0], HC[1], -4, { hair: 'bun', facing: 'left', skin: sk, hairColor: C.brown, earring: true });
const heelB = LI.liftedHeel(300, 24, true); // rear heel up, toe on the floor
const legF = LI.trouserLeg([[296, 188], [293, 230], [291, 270], [290, 291]], [10, 8, 6.2, 5.8], LI.shoeOpening([297, FL], 0, true), C.denim, sk);
const legB = LI.trouserLeg([[306, 188], [309, 230], [313, 262], [316, 282]], [10.6, 8.4, 6.4, 5.8], LI.shoeOpening(heelB, -24, true), C.denim, sk);
let fg = LI.floor(id);
fg += `<rect x="150" y="96" width="70" height="54" rx="2" fill="${W}"/><path d="M158 138l14-16 10 9 12-15 16 12" fill="none" stroke="${C.teal}" stroke-width="1.8"/>`;
fg += legB.skin + LI.sneaker(`translate(${P(heelB)}) rotate(-24) scale(-1 1)`, C.coral, W) + legB.leg;
fg += legF.skin + LI.sneaker(`translate(297 ${FL}) scale(-1 1)`, C.coral, W) + legF.leg;
fg += `<rect x="284" y="${HC[1] + A.waistTop}" width="33" height="5" rx="0.8" fill="${C.denim}"/>`;
fg += `<g transform="rotate(${LEAN} ${P(PV)})">${LI.torso(HC[0], HC[1], { style: 'top', facing: 'left', fill: C.lav, skin: sk })}${h.front}</g>`;
// near arm = LEFT (she faces left); back of the hand visible, index pointing left -> thumb UP.
// HANDS.point keeps its thumb on local -y; at 186 deg local -y points DOWN, so flip = true.
const S = LI.rotAbout(rel(A.nearShoulder), LEAN, PV), ang = 186, tip = [221, 124];
const Wr = LI.wristFor(LI.HANDS.point.tip, tip, ang, 1.1, true);
const arm = LI.bentArm(S, LI.solveElbow(S, Wr, 36, 30), Wr, 4.6, 4.2, 3.3);
fg += `<path d="${arm.d}" fill="${sk}"/><path d="M${P(arm.I)}l${f(-arm.u[0] * 3)} ${f(-arm.u[1] * 3)}" fill="none" stroke-width="1"/>`;
fg += `<path d="${LI.sleeve(S, arm.u, 13, 5.8)}" fill="${C.lav}"/>` + LI.place(LI.hand('point', sk), Wr[0], Wr[1], ang, true, id + 'hand', 1.1);
const bg = LI.bgLayer(id, LI.bricks(60, 80, [[0, 0], [15, 0], [7, 7]]) + LI.lampDome(380, 40));
fs.writeFileSync('card.svg', LI.svgWrap(bg + LI.fgLayer(id, fg), 'Snippet test, Line interior style'));
It still needs the far arm, a plant, the hero prop and the room. It shows the order: legs → waistband → leaned torso and head → near arm → sleeve → hand.
2. Hands without a wrist wedge. Draw the hand outline twice: once filled with stroke="none", once as an open path (the Z removed), then the 0.9 finger lines, then the thumb. hand() does this. A closed stroke across the wrist draws a dark wedge where the forearm meets the hand.
3. Lean by group rotation. Put the torso (with its neck), any backpack or strap and the head in one <g transform="rotate(-7 hipX hipY)">. Solve the arms in card coordinates from rotAbout(shoulder, -7, [hipX, hipY]), so the hand still lands on the object, and draw the arm, sleeve and hand outside the group.
4. Screen and board content in colour, not ink. Code on a monitor is 4–6 rows of round-capped dashes, stroke-width="1.8", each dash one accent (purple, teal, coral, lavender, orange), on a white screen with three window dots (coral, mustard, teal, r 0.9). Diagrams are 1.2 px boxes and arrows in ink, one box in coral and one in teal.
hand() (fill pass plus open outline).flip.bentArm() and the crease line.flip.#cfc9e0, 1 px, unfilled, and sits at least 8 px clear of the figure's head.examples/books.svg: "Books". A reaching pose with a −7° lean and a bent near arm gripping a book on the shelf (thumb on top). The far hand holds an open book at the hip. Afro back hair is drawn behind the torso. Ladder shelf with labelled books, a duck, a desk with a monitor, lance-leaf plant.examples/remote-work.svg: "Remote Work". Lying in a hammock with both hands on a laptop (type hands, mirrored for left and right). Outdoor variant of the background (clouds, birds, skyline, railing), string lights, a crate with a mug, monstera leaves, a snake plant. A clipPath hides the legs behind the hammock rim.examples/whiteboard.svg: "Whiteboard". Two people: one reaching up with a marker fist and a wrap hand on a mug, one seated on a stool with a cup hand, beard and glasses. Diagram content in 1.2 px ink and accent strokes, sticky notes, casters on the floor line, fig plant.Run every command from this skill's folder. Card paths can be absolute.
ob-).card.mjs) that imports scripts/interior.mjs by absolute path and writes card.svg. Start from the Techniques snippet. Look at the --demo parts sheet once. Hand-place the figure and the hero prop; take everything repeated from the toolkit. Print the solved shoulder, elbow and wrist points so you can find them when you zoom.references/craft.md). Choose the HANDS shape and flip.node scripts/render.mjs card.svg card.png.node scripts/render.mjs --sheet sheet.png examples/books.svg examples/remote-work.svg examples/whiteboard.svg card.svg. Ask "same hand, same set?": line weight, white share, density, floor, decor.node scripts/render.mjs card.svg z-hand.png --zoom x,y,w,h --scale 8. Do the thumb proof from references/craft.md for every hand.references/craft.md and the Verify list below. Fix, re-render, re-sheet. Expect four or more rounds.node scripts/lint.mjs card.svg --prefix ob- --palette style.json. Fix every ERROR. Each WARN must be a deliberate tint.#3a2d66 at 1.4; details are 1, finger lines 0.9; no other weights apart from code dashes (1.8) and diagram strokes (1.2).#cfc9e0, 1 px, unfilled, and never overlaps a head.lint.mjs --palette style.json passes with no unexplained WARN.