illustration-line-interior

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Illustration: Line interior

插图:Line interior

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.
一种平静的编辑式线稿风格:以小尺度呈现整个房间,人物身高约为头部长度的七倍;每个形状仅以一条纤细的靛蓝线勾勒,并采用白色填充,再加入少量平涂强调色。它适合希望在不使用浓烈色彩的情况下呈现“工作中的人们”的产品营销场景。 对于采用近黑色 ~2.4 px 墨线和大胆填充的大头角色,使用
illustration-outlined-cartoon
。若场景应位于粉彩卡片的彩色面板内,使用
illustration-framed-panel
。若完全不应出现轮廓线,则使用
illustration-flat
。
内容提取自一套包含 14 种风格、共 42 张原创设计与编码主题卡片;
examples/
中的三张卡片是此风格已发布的成品。

The look in one sentence

风格一句话概述

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.
在宽敞通透的房间中,所有白色填充的形状外围都采用统一、纤细的靛蓝色描边(1.4 px),并以平涂色彩进行点缀,强调色占卡片面积不超过 7%。

Palette

调色板

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%.
RoleHexWhere 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
  • Never: gradients, opacity, drop shadows, hatching, black, grey fills, the wall-line colour as a fill, a coloured background rect.
  • One accent per object. A person wears at most two accents plus white: top, trousers, and sneakers where either the upper or the sole is white.
  • No two large accent shapes of the same hue touch (a coral shoe on a coral rug). Keep the big shapes (shelf, board, desk, hammock) white or peach.
根据三个示例的实测结果(填充和描边,1x 渲染),白色与卡片本身约占全部像素的 85%,靛蓝线约占 2%,强调色占 4–7%。
角色Hex使用位置
靛蓝墨线
#3a2d66
所有轮廓线、地面线、眼睛点、靛蓝头发(头发为实心墨色形状)
墙面色线
#cfc9e0
仅用于背景装饰描线(砖块、吊灯、海报、云、鸟、天际线、栏杆),绝不作为填充色
白色
#ffffff
所有内容的默认填充色:家具、衬衫、屏幕、花盆、书籍、运动鞋、马克杯
桃木色
#f9c99a
木质元素:梯架扶手和木板、立柱、凳子、板条箱、带条纹的花盆
芥末黄
#f5c35a
一本书、一只鸭子、灯泡、运动鞋、便利贴、耳钉、一件上衣
橙色
#f6a85e
花盆、裤子、鸭嘴、棕色头发上的高光弧线、一段代码短划线
珊瑚红
#ef5b5b
运动鞋或鞋底、标签、马克笔笔尖、杯身色带、一段代码短划线、窗口圆点
蓝绿色
#3fa58a
一本书、一件上衣、杯身色带、吊床条纹、对勾
鼠尾草绿 / 叶绿色
#8cc79b
/
#5fae7a
深浅叶片颜色,逐片交替使用
淡紫色
#ab9ee6
一本书、一件上衣、书页线、键盘线、运动鞋底
紫色
#7f6cc4
一本书、裤子、靛蓝头发上的高光弧线、一段代码短划线
牛仔蓝
#7f9fdc
牛仔裤
棕色
#7b4b3a
棕色头发、杯中咖啡
肤色
#f3cdb0
#e2a57c
#b47852
#7a4b33
浅色、中等肤色、深肤色、最深肤色;同一张卡片中的两个人使用两种不同色调
  • 绝不使用:渐变、透明度、投影、排线、黑色、灰色填充、将墙面色线用作填充色、彩色背景矩形。
  • 每个物体仅使用一种强调色。一个人除白色外最多使用两种强调色:上衣、裤子,以及鞋面或鞋底其中之一为白色的运动鞋。
  • 不得让两个颜色相同的大型强调色形状相互接触,例如珊瑚红鞋子与珊瑚红地毯。大型形状(搁架、写字板、书桌、吊床)应保持白色或桃木色。

Line and fill

线稿与填充

  • Two layers. Background:
    <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
    .
  • Outlines are strokes on filled shapes, never filled outline shapes. Every foreground shape gets a fill (white if nothing else), so overlap hides what is behind. Depth comes only from overlap order: draw back to front, far limbs before the torso.
  • Weights at 480 wide: 1.4 for every outline; 1 for detail lines (fabric folds, leaf veins, book bands, lace ticks, ear inner, brows, nose, mouth, steam, x marks, hair shine); 0.9 for finger separations; 1.2 for whiteboard diagram strokes; 1.7–1.8 coloured dashes for code on screens; 2.2 for bullet dots (
    M190 146h0.1
    ).
  • Shading: none. No tone steps, no hatching, no highlights. A fold is one 1 px curve, 4–8 px long, 2–3 per garment.
  • Texture: tiny x marks (
    xm()
    , 3 px, stroke 1), 2–4 per pot or box. Never on clothing.
  • Lettering:
    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"
    .
  • Rounded corners: rx 0.6–1 on books and bricks, 1.5–2.5 on furniture tops and frames.
  • 分成两层。背景:
    <g id="xx-bg" fill="none" stroke="#cfc9e0" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
    。前景:
    <g id="xx-fg" stroke="#3a2d66" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round">
    。形状会继承描边属性,每个形状自行设置
    fill
    。
  • 轮廓必须是填充形状上的描边,绝不能使用填充出来的轮廓形状。每个前景形状都要有填充色;没有指定颜色时使用白色,以便通过重叠遮挡后方内容。景深仅依靠重叠顺序表现:先画后方,再画前方;远侧肢体先于躯干绘制。
  • 在宽度为 480 时,所有轮廓线均为 1.4;细节线为 1(衣物褶皱、叶脉、书籍束带、鞋带刻度、耳内、眉毛、鼻子、嘴巴、蒸汽、叉号、头发高光);手指分隔线为 0.9;白板图示描边为 1.2;屏幕代码使用 1.7–1.8 的彩色短划线;圆点为 2.2(
    M190 146h0.1
    )。
  • 不使用明暗塑造。不要色阶、排线或高光。衣物褶皱是一条长 4–8 px 的 1 px 曲线,每件衣服使用 2–3 条。
  • 纹理:在花盆或箱子上使用微小叉号(
    xm()
    ,3 px,描边宽度 1),每个花盆或箱子放 2–4 个。绝不能放在衣物上。
  • 文字:
    font-family="ui-monospace, monospace" font-weight="700"
    ,字号 4.4–5.2 px,在小型标签矩形上放置 2–5 个字母(JS、CSS、UX、API、CACHE),并设置
    stroke="none"
    。
  • 圆角:书籍和砖块使用 0.6–1 的圆角,家具台面和画框使用 1.5–2.5 的圆角。

Characters

角色

  • Proportions: a standing figure is 229–235 px from crown to sole; the head (chin to crown) is 33–36 px, so 1:7. Slim: shoulders about 30 wide, legs with hip half-width 9.6–11 tapering to 5.6–5.8 at the hem.
  • Head: build it with
    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.
  • Hair: one flat shape in indigo
    #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.
  • Neck and torso:
    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.
  • Sleeves:
    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.
  • Arms:
    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.
  • Put a fingertip on a target with
    wristFor(HANDS[name].tip, target, angle, scale, flip)
    . It returns the wrist point to solve the arm to.
  • The far arm in a profile view: show it. Swing it back behind the hip (or forward behind a held object), drawn before the torso, so a forearm and a
    rest
    hand show below the torso. A figure with one arm reads as "an arm is missing".
  • Hands (toolkit
    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).
  • Every hand shape has its thumb on local −y. Decide LEFT or RIGHT and PALM or BACK with the table in
    references/craft.md
    , then pass
    flip = true
    when the thumb belongs on +y.
  • Legs and feet:
    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)
    .
  • Rear foot on its toes:
    heel = liftedHeel(toeX, 22–28, mirror)
    , then
    sneaker(\
    translate(heel) rotate(deg)`)
    . For a mirrored shoe use 
    rotate(-deg) scale(-1 1)
    and
    shoeOpening(heel, -deg, true)`.
  • Poses that work: reaching up to a shelf or board, or pressing a button, with the upper body leaning 4–9° (rotate the upper-body group about the hip and the shoulder points with
    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.
  • 比例:站立人物从头顶到鞋底为 229–235 px;头部从下巴到头顶为 33–36 px,因此比例为 1:7。人物纤细:肩宽约 30;腿部臀点半宽为 9.6–11,向裤脚收窄至 5.6–5.8。
  • 头部:使用工具包中的
    head()
    绘制。它会绘制朝左或朝右的 3/4 侧面:一条包含鼻子和下巴轮廓的面部路径、后侧耳朵、近侧眼点(半径 1.15)和远侧眼点(半径 1.0),两眼相距 4.9;还包括两条 1 px 眉毛、一个鼻孔刻度和一段短嘴弧。不要脸颊颜色、瞳孔或张开的嘴,神情平静并略带微笑。
  • 头发:使用一块扁平形状填充靛蓝色
    #3a2d66
    (搭配 1–4 条紫色
    #7f6cc4
    高光弧线),或填充棕色
    #7b4b3a
    (搭配橙色
    #f6a85e
    高光)。预设包括:
    afro
    、
    bun
    、
    side
    、
    crop
    (另有
    beard
    、
    glasses
    、
    earring
    )。
    afro
    的后侧发量作为
    behind
    返回,应在躯干之前绘制。
  • head(x, y, rot, opts)
    按屏幕角度旋转(正数为顺时针)。这样会让朝右的头部向下点头,让朝左的头部向上抬起。向人物所关注的方向倾斜 4–9°。
  • 颈部和躯干:
    torso(hx, hy, { style: 'tee' | 'top', facing, fill, skin })
    绘制颈部、宽 30–34 的柔和上衣形状(圆领 T 恤或带小 V 领的修身上衣)和两条 1 px 褶皱;所有位置都以头部中心为基准。
    TORSO_ANCHORS[style]
    给出相对于头部中心的肩部、髋部和腰带位置。朝左人物需镜像这些点的 x 坐标。上衣应为白色或一种强调色。
  • 袖子:
    sleeve(S, arm.u, 13, 5.8)
    覆盖上臂,并在手臂之后绘制。使用较扁的袖子(半宽小于 6),避免产生垫肩效果。
  • 手臂:
    bentArm()
    的肩部半宽为 4.4–5、肘部为 4–4.4、腕部为 3.2–3.4。它会形成尖外侧肘部;再添加来自
    arm.I
    的 3 px 肘部褶皱线。上臂长 27–40,前臂长 24–33。使用
    solveElbow(S, wrist, 35, 30, flip)
    ,并尝试两个
    flip
    值:正确的值会让肘部落在肩部至腕部连线的下方。腕部与肩部应保持 45–60 px 距离;距离过近会让手臂折成“鸡翅膀”。
  • 使用
    wristFor(HANDS[name].tip, target, angle, scale, flip)
    将指尖放到目标位置。它会返回用于解算手臂的腕部坐标。
  • 侧面视角也要画出远侧手臂。将其向后摆至臀部后方,或向前放在所持物体后方,并在躯干之前绘制,使前臂和
    rest
    手型能从躯干下方露出。隐藏其中一只手臂会让人物看起来“少了一条胳膊”。
  • 手部(工具包
    HANDS
    ):在 1.05–1.15 的缩放下为 17 个本地单位,因此长 18–20 px,约等于从下巴到眉毛的脸部长度。手指由 3–4 条圆头指带组成,使用 0.9 的分隔线;中指最长,小指最短。手型包括:
    type
    (掌心向下放在键盘上)、
    cup
    (环握马克杯,拇指搭在杯沿上)、
    wrap
    (同样环握,但拇指藏在物体后方)、
    marker
    (握笔成拳,并配合
    HANDS.marker.pen()
    )、
    point
    (伸出食指,收起拇指)、
    rest
    (自然放松)。
  • 每种手型的拇指都位于本地坐标的 −y 方向。根据
    references/craft.md
    中的表格判断 LEFT 或 RIGHT,以及 PALM 或 BACK;当拇指应位于 +y 时传入
    flip = true
    。
  • 腿和脚:站立腿部使用
    trouserLeg()
    (逐渐收窄、平直裤脚、5.2 px 卷边、露出 4–10 px 脚踝肤色);坐姿或迈步使用
    bentLeg()
    与
    cuffAndAnkle()
    。
    sneaker()
    尺寸为 25 × 10.6,包含 3 px 鞋底色带和两条鞋带刻度;鞋跟位于落地点,并通过
    scale(-1 1)
    镜像。每条裤腿都应结束于鞋子的
    shoeOpening(heel, rot, mirror)
    。
  • 后脚踮起:
    heel = liftedHeel(toeX, 22–28, mirror)
    ,然后使用
    sneaker(\
    translate(heel) rotate(deg)`)
    。镜像鞋子使用 
    rotate(-deg) scale(-1 1)
    和
    shoeOpening(heel, -deg, true)`。
  • 适用姿势:伸手够向搁架或写字板,或按下按钮;上半身围绕髋部倾斜 4–9°(使用
    rotAbout()
    旋转上半身组及肩部坐标);后脚跟抬起,仅脚尖触地;躺在吊床中并将笔记本电脑放在大腿上;坐在凳子上,一只脚踩在横档上,同时拿着杯子。

Decor and props

装饰与道具

  • Background layer (wall line, unfilled), all of it pale and secondary: 2–3 brick clusters of 3–5 bricks (
    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.
  • Foreground, per card: one hero prop in the middle that carries the subject (ladder shelf 98 × 203, whiteboard on wheels 160 × 256, hammock between posts 260 wide); one tall plant in a pot at one end (60–68 wide, 150–185 tall); one secondary piece at the other end (desk with a monitor and mug, a short snake plant, a stool with a colleague); 2–4 small props (mug with two 1 px steam curls, books with band lines and labels, a rubber duck, sticky notes, a monitor with window dots and coloured code dashes).
  • Plants:
    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.
  • Never: sparkles, confetti, floating icons, speech bubbles, shadows under objects, rugs, more than two items on the floor beside the hero.
  • 背景层使用墙面色线且不填充,所有元素都必须浅淡并处于次要位置:2–3 组砖块,每组 3–5 块(
    bricks()
    ,14 × 6,行间距 7);1–2 盏从卡片顶边垂下的吊灯(
    lampDome()
    、
    lampCone()
    );一幅用钉子挂在墙上的带框海报(
    poster()
    ),内部配简单图标。户外场景改用 2–3 朵轮廓云、2–3 只鸟,以及天际线和栏杆,不使用砖块。
  • 每张卡片的前景设置一个位于中央、承载主题的主道具(梯形搁架 98 × 203、带轮白板 160 × 256、支柱间宽 260 的吊床);一端放一盆高植物(宽 60–68,高 150–185);另一端放一个次要物件(带显示器和马克杯的书桌、矮蛇皮植物、与同事同坐的凳子);另加 2–4 个小道具(带两缕 1 px 蒸汽的马克杯、带束带线和标签的书籍、橡皮鸭、便利贴、带窗口圆点和彩色代码短划线的显示器)。
  • 植物:
    leaf()
    (带叶脉的披针形叶片)、
    figLeaf()
    (琴叶榕叶)、
    blade()
    (蛇皮植物叶);茎使用从花盆伸出的 1.4 px 开放曲线,叶片在鼠尾草绿和叶绿色之间交替。
  • 花盆:使用
    pot()
    ;可为带 x 标记的白色、带 1 px 色带的桃木色,或橙色。
  • 绝不使用:闪光点、彩纸、漂浮图标、对话气泡、物体下方的阴影、地毯,以及主道具旁超过两个地面物件。

Composition

构图

  • No background rect: the card is white (the examples have none). If the host page is not white, add a square full-bleed
    #ffffff
    rect first.
  • Floor line at y 308:
    M56 308H424M40 308h10M430 308h10
    . Every foot, pot, leg and caster stands on it. The band below (y 308–360) stays empty.
  • Content spans x 33–445. Only lamp cords touch an edge (the top). Everything else stays at y ≥ 25.
  • Left to right: tall plant (x 33–121) | hero prop with the figure acting on it (x 115–335) | secondary furniture or plant (x 330–445). Mirror this freely, but keep the hero central.
  • Figures: 94–190 px wide, 235 tall standing. One focal action, at the figure's hands.
  • Density: about 10–14 foreground objects including plant leaves; generous white space between groups. Busy is wrong here.
  • Group transforms the examples use:
    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.
  • 不设置背景矩形:卡片为白色,示例中也没有背景矩形。如果宿主页面不是白色,应先添加一个铺满画面的
    #ffffff
    正方形矩形。
  • 地面线位于 y 308:
    M56 308H424M40 308h10M430 308h10
    。每只脚、花盆、腿部及脚轮都要落在地面上。下方 y 308–360 的区域保持空白。
  • 内容横跨 x 33–445。只有灯绳可以接触边缘(顶部);其他所有元素都保持在 y ≥ 25。
  • 从左到右依次为:高植物(x 33–121)|承载人物动作的主道具(x 115–335)|次要家具或植物(x 330–445)。可以自由镜像,但主道具必须位于中央。
  • 人物:宽 94–190 px,站立时高 235 px。画面中只保留一个焦点动作,并发生在人物手部所在的位置。
  • 密度:前景约有 10–14 个物体,包括植物叶片;各组物体之间应留出大量空白。此风格不适合画面过于繁忙。
  • 示例使用的组变换:使用
    translate(-8 0)
    轻微移动整个人物;在上半身组(颈部、躯干、头部、袖子)上使用
    rotate(-7 284 180)
    ,让人物以髋部为支点前倾。

Techniques

技巧

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
.
js
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.
1. 部件工具包。
scripts/interior.mjs
不依赖任何外部包,并按照示例中的数值实现了所有重复部件,包括:图层、地面、砖块、吊灯、海报、云、叶片、花盆、
limb
、
bentArm
、
solveElbow
、
sleeve
、
torso
、
trouserLeg
、
bentLeg
、
cuffAndAnkle
、
sneaker
、
shoeOpening
、
liftedHeel
、
rotAbout
、
HANDS
+
hand()
+
place()
+
wristFor()
、
head()
和
mirrorPath()
。在 skill 文件夹中运行
node scripts/interior.mjs --demo /abs/work/demo.svg
,并渲染输出,即可查看所有部件。演示输出是一张部件表,包含四个头部、六种竖拇指手型、两种植物、吊灯、砖块,以及一个使用这些部件搭建的站立人物。
下面是一个经过测试的完整人物:一名朝左的人物指向图表。将代码保存为卡片旁的
card.mjs
,修正 import 路径,然后运行
node card.mjs
。
js
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'));
这段代码仍需补充远侧手臂、植物、主道具和房间。它展示的绘制顺序为:腿部 → 腰带 → 倾斜的躯干和头部 → 近侧手臂 → 袖子 → 手部。
2. 手腕处不出现深色楔形。 将手部轮廓绘制两次:第一次填充并设置
stroke="none"
,第二次绘制移除
Z
的开放路径;然后添加 0.9 的手指分隔线,最后绘制拇指。
hand()
已实现这一过程。横跨手腕的闭合描边会在前臂与手部连接处形成深色楔形。
3. 通过组旋转实现倾斜。 将躯干(连同颈部)、背包或背带以及头部放入同一个
<g transform="rotate(-7 hipX hipY)">
中。使用
rotAbout(shoulder, -7, [hipX, hipY])
在卡片坐标系中解算手臂,使手部仍能准确落在目标物体上;手臂、袖子和手部应绘制在该组之外。
4. 屏幕和写字板内容使用彩色,而不是墨线。 显示器中的代码由 4–6 行圆头短划线组成,描边宽度为
1.8
,每条短划线使用一种强调色(紫色、蓝绿色、珊瑚红、淡紫色、橙色)。屏幕为白色,并带有三个窗口圆点(珊瑚红、芥末黄、蓝绿色,半径 0.9)。图示使用 1.2 px 的墨线方框和箭头,其中一个方框为珊瑚红,另一个为蓝绿色。

Failure modes

常见失败模式

  • Too much colour. The first Books draft (scored 6) had a mustard top, a brown shelf, an orange pot and x marks on the clothes. The redraw that reached 8 used colour more sparingly. Keep big shapes white or peach, and accents under 7% (white ≥ 83%).
  • The subject reads as something else. A developer standing at a desk read as "standing desk", not "Books". The figure must do the subject: pull the book off the shelf, draw on the board.
  • Bolt-upright clip-art figure. Lean the upper body 4–9°, put the weight on one leg, lift the rear heel. Front-facing symmetric poses score a point lower.
  • Dark wedge at the wrist. A closed outline across the wrist. Use
    hand()
    (fill pass plus open outline).
  • Thumb on the wrong side. Two shipped hands were copies of a right-hand template on a left arm (Remote Work's far typing hand, Whiteboard's mug hand), and both had to be mirrored. Work out handedness per hand, then
    flip
    .
  • Mitten or rake hands. Fingers must be grouped bands of different lengths with rounded tips, 18–20 px long. Larger reads as a glove.
  • Arm with no elbow. A straight tube from shoulder to object reads as a prosthetic. Use
    bentArm()
    and the crease line.
  • Chicken-wing arm. The target sat 33 px from the shoulder, so a 66 px arm folded up with the elbow out. Move the prop or the figure until the wrist is 45–60 px from the shoulder, and try the other
    flip
    .
  • One-armed figure. A profile figure with the far arm hidden reads as missing an arm. Swing the far arm back so its forearm and hand show behind the hip.
  • Stray ticks. A 1 px fold line within 4 px of a limb's edge, or a strap end poking 2 px out from under a sleeve, reads as a slip. End a covered shape at least 3 px inside the shape that covers it, and keep folds away from other contours.
  • Floating feet or pots. Sneaker heels sit at y 308 exactly. A rotated rear shoe touches the floor with its toe. Check every contact at 8x.
  • X marks on clothes. They read as stains. Keep them on pots and boxes.
  • Background competing with the figure. Decor drawn in indigo or filled looks like foreground clutter. It is wall-line
    #cfc9e0
    , 1 px, unfilled, and sits at least 8 px clear of the figure's head.
  • Weight drift. A 2 px outline or a 0.6 px detail breaks the style at once. Use exactly 1.4, 1 and 0.9.
  • 颜色过多。 第一版 Books 草稿评分为 6,其中包含芥末黄上衣、棕色搁架、橙色花盆,以及衣物上的 x 标记。重新绘制后评分为 8,颜色的使用明显更克制。大型形状应保持白色或桃木色,强调色面积低于 7%(白色至少占 83%)。
  • 主体被误读。 一名站在桌旁的开发者看起来像“站立式书桌”,而不是“Books”。人物必须直接完成主体动作,例如从书架上取下书籍,或在白板上绘制内容。
  • 人物像直立卡通剪贴画。 上半身应倾斜 4–9°,重心放在一条腿上,并抬起后脚跟。正面对称的姿势评分会低 1 分。
  • 手腕处出现深色楔形。 这是跨手腕闭合轮廓造成的。应使用
    hand()
    ,即填充层加开放轮廓层。
  • 拇指方向错误。 已发布版本中的两只手都是右手模板的复制品,却被放在左臂上,即 Remote Work 的远侧打字手和 Whiteboard 的拿杯手,两者最终都必须镜像。应逐只手判断左右手和手心朝向,再设置
    flip
    。
  • 手像连指手套或耙子。 手指必须是长度各异的 3–4 组圆头指带,整体长 18–20 px。尺寸过大会看起来像手套。
  • 手臂没有肘部。 从肩膀直伸到物体的管状手臂会像义肢。应使用
    bentArm()
    ,并添加肘部褶皱线。
  • “鸡翅膀”手臂。 目标距离肩膀仅 33 px,导致长 66 px 的手臂向上折叠、肘部向外突出。应移动道具或人物,使腕部与肩部保持 45–60 px 距离,并尝试另一个
    flip
    值。
  • 人物只有一只手臂。 侧面人物若隐藏远侧手臂,会显得缺少一条手臂。应将远侧手臂向后摆动,让前臂和手部从臀部后方露出。
  • 出现游离刻线。 距离肢体边缘不足 4 px 的 1 px 褶皱线,或从袖子下方伸出 2 px 的背带末端,都会看起来像绘制失误。被遮挡的形状至少应缩入遮挡物内部 3 px,并让褶皱远离其他轮廓。
  • 脚或花盆悬空。 运动鞋鞋跟必须准确位于 y 308。旋转的后脚应通过脚尖接触地面。应在 8x 放大图中检查所有接触点。
  • 衣物上出现 x 标记。 这些标记看起来像污渍。只能将其放在花盆和箱子上。
  • 背景与人物争夺注意力。 使用靛蓝色或填充状态的背景装饰会看起来像前景杂物。背景必须采用 1 px 的墙面色线
    #cfc9e0
    、不得填充,并且与人物头部至少保持 8 px 距离。
  • 线宽漂移。 2 px 的轮廓或 0.6 px 的细节线会立即破坏风格。必须严格使用 1.4、1 和 0.9。

Examples

示例

  • 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.
  • examples/books.svg
    :“Books”。人物以 −7° 前倾,近侧手臂弯曲并抓住搁架上的一本书,拇指朝上。远侧手在臀部位置拿着打开的书。
    afro
    后侧发型绘制在躯干后方。场景包含带标签书籍的梯形搁架、一只鸭子、带显示器的书桌和披针形叶片植物。
  • examples/remote-work.svg
    :“Remote Work”。人物躺在吊床中,双手放在笔记本电脑上,使用镜像的
    type
    手型。背景采用户外版本,包含云、鸟、天际线和栏杆,并加入串灯、板条箱、马克杯、龟背竹叶和蛇皮植物。使用
    clipPath
    将腿部隐藏在吊床边缘后方。
  • examples/whiteboard.svg
    :“Whiteboard”。两个人物:一人伸手向上,使用
    marker
    拳型手部,另一只手使用
    wrap
    手型拿着马克杯;另一人坐在凳子上,使用
    cup
    手型,并留有胡须和眼镜。图示内容采用 1.2 px 墨线和强调色描边,场景还包括便利贴、脚轮和琴叶榕。

Workflow

工作流程

Run every command from this skill's folder. Card paths can be absolute.
  1. Brief. Name the subject in a few words and write the one action that shows it (who does what to which prop). Pick the hero prop and the pose.
  2. Plan the layout on the 480 × 360 grid: floor y 308, plant at one end, hero prop centred, secondary piece at the other end. Pick the skin tones, hair presets and the 2 accents each person wears. Choose an id prefix (
    ob-
    ).
  3. Write a generator (
    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.
  4. Hands first, on paper. For each hand, write down LEFT or RIGHT, PALM or BACK, and the finger direction, then the thumb side (see
    references/craft.md
    ). Choose the
    HANDS
    shape and
    flip
    .
  5. Render:
    node scripts/render.mjs card.svg card.png
    .
  6. Sheet with the examples:
    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.
  7. Zoom every hand, face, foot and contact:
    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.
  8. Critique against the five criteria in
    references/craft.md
    and the Verify list below. Fix, re-render, re-sheet. Expect four or more rounds.
  9. Lint:
    node scripts/lint.mjs card.svg --prefix ob- --palette style.json
    . Fix every ERROR. Each WARN must be a deliberate tint.
所有命令都在此 skill 的文件夹中运行。卡片路径可以使用绝对路径。
  1. 简报。 用几个词命名主题,并写出一个能够展示主题的动作,即谁对哪个道具做什么。选择主道具和姿势。
  2. 规划布局。 在 480 × 360 网格上进行规划:地面位于 y 308,一端放植物,中央放主道具,另一端放次要物件。选择肤色、发型预设,以及每个人使用的两种强调色。确定 id 前缀(
    ob-
    )。
  3. 编写生成器。 创建
    card.mjs
    ,通过绝对路径导入
    scripts/interior.mjs
    ,并输出
    card.svg
    。以上述技巧代码片段为起点。查看一次
    --demo
    部件表。手工安排人物和主道具的位置;所有重复部件都从工具包中获取。输出解算后的肩部、肘部和腕部坐标,以便放大时查找。
  4. 先在纸上确定手型。 对每只手记录 LEFT 或 RIGHT、PALM 或 BACK、手指方向和拇指所在侧,参见
    references/craft.md
    。选择
    HANDS
    手型及
    flip
    。
  5. 渲染。 运行
    node scripts/render.mjs card.svg card.png
    。
  6. 与示例生成对比表。 运行
    node scripts/render.mjs --sheet sheet.png examples/books.svg examples/remote-work.svg examples/whiteboard.svg card.svg
    。检查“手型和整体风格是否一致?”,包括线宽、白色占比、密度、地面线和装饰。
  7. 放大检查。 逐一检查手部、面部、脚部和接触点:
    node scripts/render.mjs card.svg z-hand.png --zoom x,y,w,h --scale 8
    。按照
    references/craft.md
    对每只手执行拇指朝向验证。
  8. 批评与修正。 根据
    references/craft.md
    中的五项标准及下方验证清单进行检查。修正后重新渲染并重新生成对比表。预计需要四轮或更多迭代。
  9. Lint。 运行
    node scripts/lint.mjs card.svg --prefix ob- --palette style.json
    。修复所有 ERROR。每条 WARN 都必须对应有意的色调选择。

Verify

验证清单

  • Every foreground outline is
    #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).
  • Background decor is
    #cfc9e0
    , 1 px, unfilled, and never overlaps a head.
  • On the sheet, the colour looks no heavier than the examples (they measure 84–86% white pixels, accents 4–7%). The big shapes are white or peach, and nothing uses a gradient, opacity or shadow.
  • Floor line at y 308 with both end dashes, and every foot, pot, leg and caster touches it.
  • Lamps hang from y 0; nothing else touches a card edge; the y 308–360 band is empty.
  • A standing person is about 230 px tall with a head about 34 px (1:7).
  • Each person wears at most two accents plus white; two people have different skin tones.
  • Every hand is 18–20 px long, has 3–4 grouped fingers with 0.9 separation lines, and its thumb is on the side the craft table gives (thumb proof done).
  • Every arm has a shoulder, a pointed elbow with a crease, and a wrist narrower than the hand. Both arms show, even in profile.
  • The upper body leans or twists; the weight is on one leg or on a seat.
  • The subject reads at 1x from the figure's action alone, without the labels.
  • No x marks on clothing; 2–4 on pots or boxes at most.
  • lint.mjs --palette style.json
    passes with no unexplained WARN.
  • 所有前景轮廓均为 1.4 的
    #3a2d66
    ;细节线为 1,手指线为 0.9;除代码短划线 1.8 和图示描边 1.2 外,不使用其他线宽。
  • 背景装饰使用 1 px、未填充的
    #cfc9e0
    ,且绝不与人物头部重叠。
  • 在对比表中,色彩的视觉重量不超过示例水平;示例的白色像素占 84–86%,强调色占 4–7%。大型形状为白色或桃木色,不使用渐变、透明度或阴影。
  • 地面线位于 y 308,并带有两端短划线;每只脚、花盆、腿部和脚轮都与其接触。
  • 吊灯从 y 0 垂下;其他元素不接触卡片边缘;y 308–360 区域保持空白。
  • 站立人物高约 230 px,头部高约 34 px,比例为 1:7。
  • 每个人除白色外最多使用两种强调色;两个人使用不同肤色。
  • 每只手长 18–20 px,包含 3–4 组手指和 0.9 的分隔线,拇指方向符合工艺表,并通过拇指朝向验证。
  • 每条手臂都有肩部、带褶皱线的尖肘部,以及比手部更细的腕部。即使是侧面视角,也要显示两条手臂。
  • 上半身有倾斜或扭转;重心落在一条腿上或座位上。
  • 在 1x 尺寸下,仅凭人物动作就能读懂主体,无需依赖标签。
  • 衣物上没有 x 标记;花盆或箱子上最多放 2–4 个。
  • lint.mjs --palette style.json
    通过检查,且没有无法解释的 WARN。