Kimi K3 ಡಿಜಿಟಲ್ ಫೌಂಟನ್ ಪೆನ್ ಸ್ಟ್ರೋಕ್ ಅನ್ನು ಹೇಗೆ ನಿರ್ಮಿಸಿತು
Lulucat Notes ನಲ್ಲಿ Freeformನ ದಿಕ್ಕು ಆಧಾರಿತ ಫೌಂಟನ್ ಪೆನ್ ನಮಗೆ ಬೇಕಿತ್ತು. ಸ್ಪೆಕ್ ಒಂದು ಕೈಬರಹದ ಸ್ಕ್ರೀನ್ಶಾಟ್ ಆಗಿತ್ತು. ಎರಡು ಮಾದರಿಗಳು, ಅವುಗಳನ್ನು ಬೇರ್ಪಡಿಸುವ ಒಂದು ಪ್ರಶ್ನೆ ಮತ್ತು ಒಂದು ಎಲಿಪ್ಸ್ ಪೆನ್ಟಿಪ್ ನಂತರ, ವಾಟರ್ ಪೆನ್ ಇರಬೇಕಾದ ರೀತಿಯಲ್ಲಿ ಬರೆಯಲು ಆರಂಭಿಸಿತು. ಸಂಶೋಧನೆ, ಕೋಡ್ ಮತ್ತು ಮೌಲ್ಯಮಾಪನವನ್ನು Fireworksನಲ್ಲಿ Kimi K3 ಮಾಡಿತು.

ಈ ಪೋಸ್ಟ್ ಕುರಿತು ಇರುವ Lulucat Notes Metal pipeline ನಿಂದ render ಮಾಡಲಾಗಿದೆ.
Lulucat Notes ನಲ್ಲಿ ಒಂದು ಸಾಮಾನ್ಯ pen ಮತ್ತು ಒಂದು highlighter ಇವೆ. Roadmap ನಲ್ಲಿ ಮುಂದಿನ tool ಒಂದು water pen ಆಗಿತ್ತು — Apple Notes ಮತ್ತು Freeform ನಲ್ಲಿ ನಿಮಗೆ ಪರಿಚಿತವಾದ directional fountain pen; ಅದರಲ್ಲಿ vertical strokes ದಪ್ಪವಾಗಿ, horizontal strokes ತೆಳುವಾಗಿ ಬರುತ್ತವೆ. ಈ tool ನ spec ಒಂದು document ಆಗಿರಲಿಲ್ಲ. ಅದು ಒಂದು screenshot ಆಗಿತ್ತು: ಮೂರು ಸಾಲುಗಳ handwriting, ಮತ್ತು “pencilkit”, “无边记”, “这种有方向的水笔能力” ಎಂಬ ಪದಗಳು — ಈ directional water-pen ability.
ಹಿಂದಿನ Metal pipeline ನಂತೆ, ಈ ಕೆಲಸವನ್ನು Fireworks ನಲ್ಲಿ run ಆಗುತ್ತಿದ್ದ Moonshot ನ open model Kimi K3 ಮಾಡಿತು: measurement, modeling, code ಮತ್ತು validation ಎಲ್ಲವೂ. ಮನುಷ್ಯ screenshot ಕೊಟ್ಟನು, ಒಂದು question ಗೆ ಉತ್ತರಿಸಿದನು ಮತ್ತು ನಿಜವಾದ iPad ಮೇಲೆ ಅದರ feel ಅನ್ನು ತೀರ್ಮಾನಿಸಿದನು.
Spec ಒಂದು screenshot
ಒಂದು static image ಒಂದು stroke ಏಕೆ ತೆಳುವಾಗಿದೆ ಎಂದು ಹೇಳಲಾರದು. ಅದು ಎಷ್ಟು ತೆಳುವಾಗಿದೆ ಮತ್ತು ಎಲ್ಲಿ ತೆಳುವಾಗಿದೆ ಎಂಬುದನ್ನು ಮಾತ್ರ ತೋರಿಸಬಲ್ಲದು. ಆದ್ದರಿಂದ ಮೊದಲ ಹೆಜ್ಜೆ measurement ಆಗಿತ್ತು. Screenshot ಅನ್ನು row by row ಮತ್ತು column by column scan ಮಾಡಿ, ಪ್ರತಿ stroke ನ centerline drift ಅನ್ನು track ಮಾಡಿ ಅದರ direction ಅನ್ನು ಪಡೆದೆವು. ನಂತರ ಆ angle ನ sine ಬಳಸಿ scan width ಅನ್ನು true width ಗೆ ಬದಲಾಯಿಸಿದೆವು:
| ಸ್ಟ್ರೋಕ್ | ದಿಕ್ಕು | ನಿಜವಾದ ಅಗಲ |
|---|---|---|
| “l” ಅಸೆಂಡರ್, “pencilkit” | ≈ 78° | 27.3 px |
| “k” ಕಂಬ, “pencilkit” | ≈ 90° | 28 px |
| 力 ನ ಎಡಕ್ಕೆ ಬೀಳುವ ಸ್ವೀಪ್ | ≈ 66° | 25.7 px |
| ಕರ್ಸಿವ್ ಸಂಪರ್ಕಗಳು | ≈ 8° | 11 px |
| ಚೀನೀ ಅಡ್ಡಗೆರೆಗಳು (横) | ≈ 0° | 6–11 px |
ದಪ್ಪ-ತೆಳು ಅನುಪಾತ ≈ 2.5. 66° ಬಿಂದುವಿಗೆ
ಆವೃತ್ತಿ ಒಂದು: ದಿಕ್ಕಿನಿಂದ ಅಗಲ
ಮೊದಲ model ಸಹಜವಾಗಿ ತೋರುವುದೇ ಆಗಿತ್ತು. ಪ್ರತಿ input point ಗೆ direction compute ಮಾಡಿ, fitted curve ಮೂಲಕ direction ಅನ್ನು width ಗೆ map ಮಾಡಿ, capture ಸಮಯದಲ್ಲಿ result ಅನ್ನು point ನ radius ಒಳಗೆ bake ಮಾಡುವುದು. Direction ಅನ್ನು causal ರೀತಿಯಲ್ಲಿ estimate ಮಾಡಲಾಯಿತು — arc ನ ಕೊನೆಯ ಕೆಲವು points ಮೇಲೆ exponentially decaying weighted average; travel reversal ಆಗಿದರೂ estimate cancel ಆಗದಂತೆ ಅದನ್ನು doubled-angle space ನಲ್ಲಿ compute ಮಾಡಲಾಯಿತು. Past points ಮಾತ್ರ ಬಳಸಲಾಗುತ್ತದೆ, ಆದ್ದರಿಂದ live stroke ಮತ್ತು committed stroke byte for byte ಒಂದೇ ಆಗುತ್ತವೆ.
Builder ತನ್ನ unit check ಅನ್ನು pass ಮಾಡಿತು: synthetic horizontal, vertical, 45° ಮತ್ತು reversal paths ಎಲ್ಲವೂ theoretical widths ಅನ್ನು bake ಮಾಡಿದವು — 0.99, 2.52, 2.00 ಮತ್ತು 0.99 points. Rendering ಗೆ ಯಾವುದೇ ಹೊಸ code ಬೇಕಾಗಲಿಲ್ಲ: baked-radius stroke ಎಂದರೆ round stamps ಗಳ ಒಂದು chain ಮಾತ್ರ, ಮತ್ತು ನಮ್ಮ point-sprite pipeline ಅವುಗಳನ್ನು ಈಗಾಗಲೇ draw ಮಾಡುತ್ತಿತ್ತು.
iPad ಮೇಲೆ, ಮನುಷ್ಯನಿಗೆ ಅದನ್ನು reject ಮಾಡಲು ಸುಮಾರು ಹತ್ತು ಸೆಕೆಂಡುಗಳೇ ಬೇಕಾದವು: “ಇದು water pen ಅಲ್ಲ, art pen.”
ಒಂದು ಚಿತ್ರಕ್ಕೆ ಹೊಂದುವ ಎರಡು ವಿವರಣೆಗಳು
ಅದು ಏಕೆ ತಪ್ಪಾಗಿ feel ಆಯಿತು? ಎರಡು candidate explanations ಇದ್ದವು, ಮತ್ತು screenshot ಅವುಗಳನ್ನು ಬೇರ್ಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ:
- ದಿಕ್ಕಿನ ಲಾಕ್. Nib geometry, ಕೈ ಏನೇ ಮಾಡಿದರೂ, horizontals ಅನ್ನು ತೆಳುವಾಗಿಯೂ verticals ಅನ್ನು ದಪ್ಪವಾಗಿಯೂ ಇರಿಸುತ್ತದೆ. Version one implement ಮಾಡಿದ್ದು ಇದೇ.
- ಒತ್ತಡ ಮತ್ತು ವೇಗ. Pen pressure-driven ಆಗಿದೆ, ಮತ್ತು sample ನ pattern ಕೇವಲ handwriting dynamics: downstrokes ಸಹಜವಾಗಿ ಒತ್ತಲ್ಪಟ್ಟವು, connectors ಸಹಜವಾಗಿ ವೇಗವಾದವು ಮತ್ತು ಹಗುರವಾದವು.
ಎರಡೂ thin horizontals ಮತ್ತು thick verticals ಇರುವ screenshot ಅನ್ನು produce ಮಾಡುತ್ತವೆ. ವ್ಯತ್ಯಾಸವೆಂದರೆ horizontal stroke ಮೇಲೆ ಬಲವಾಗಿ ಒತ್ತಿದಾಗ ಏನಾಗುತ್ತದೆ ಎಂಬುದು. Version one ಅದನ್ನು thin ಆಗಿಯೇ ಇಡುತ್ತದೆ. Pressure pen ಅದನ್ನು thick ಮಾಡುತ್ತದೆ. ಆದ್ದರಿಂದ ನಾವು ಮನುಷ್ಯನಿಗೆ ಒಂದು question ಕೇಳಿದೆವು: hard-pressed horizontal ಇನ್ನಷ್ಟು ದಪ್ಪವಾಗಬೇಕೇ?
“ಇಲ್ಲ. Horizontals thin ಆಗಿಯೇ ಇರಲಿ.”
Direction lock ಖಚಿತವಾಯಿತು. ಆದರೆ ಇನ್ನೇನೋ ತಪ್ಪಾಗಿತ್ತು, ಏಕೆಂದರೆ version one ಕೂಡ direction-locked ಆಗಿತ್ತು.
ಉತ್ತರ stroke ends ನಲ್ಲಿ ಇತ್ತು
ಮುಂದಿನ clue ascenders ನ ಮೇಲ್ಭಾಗದಲ್ಲಿತ್ತು. Sample ನ “l” ಮತ್ತು “k” stems ಅನ್ನು zoom ಮಾಡಿದಾಗ ಎರಡು ವಿಷಯಗಳು ಕಂಡವು: ಒಂದು straight stroke ಆರಂಭದಿಂದ ಅಂತ್ಯದವರೆಗೆ ಒಂದೇ width ಅನ್ನು ಉಳಿಸಿಕೊಳ್ಳುತ್ತದೆ, ಮತ್ತು stroke ends flat diagonal cuts ಆಗಿವೆ — ಮೇಲಕ್ಕೆ ಎತ್ತಿಕೊಳ್ಳುತ್ತಿರುವ chisel nib ನ ಆಕಾರ. Round dots ಅಲ್ಲ. Pressure tapers ಅಲ್ಲ.

“Art pen feel” ಎಂದರೆ ನಿಜವಾಗಿ ಇದೇ. Version one sample ನ look ಅನ್ನು — estimated direction ನ function ಆಗಿ width ಅನ್ನು — model ಮಾಡಿತ್ತು, ಆದರೆ pen ಅನ್ನು model ಮಾಡಿರಲಿಲ್ಲ. Direction estimator ಒಂದು sensor: noisy input ನಲ್ಲಿ ಅದು jitter ಆಗುತ್ತದೆ, corners ಬಳಿ lag ಆಗುತ್ತದೆ, ಮತ್ತು ಪ್ರತಿ stroke end ಅನ್ನು circle ಆಗಿ round ಮಾಡುತ್ತದೆ. ನಿಜವಾದ nib ಗೆ ಈ ಸಮಸ್ಯೆಗಳೇ ಇಲ್ಲ, ಏಕೆಂದರೆ ಅದು ಏನನ್ನೂ compute ಮಾಡುವುದಿಲ್ಲ. Width geometry ಆಗಿದೆ.
ಆವೃತ್ತಿ ಎರಡು: ಒಂದು ಎಲಿಪ್ಸ್ ಪೆನ್ಟಿಪ್
Final model ನಲ್ಲಿ direction estimator ಒಂದೂ ಇಲ್ಲ. Nib ಒಂದು oriented ellipse: long axis horizontal, short axis fixed. ಈ ellipse ನ stamps ಅನ್ನು stroke path ಉದ್ದಕ್ಕೂ ದಟ್ಟವಾಗಿ ಇಡಲಾಗುತ್ತದೆ, ಮತ್ತು ಉಳಿದದ್ದೆಲ್ಲ geometry ಯಿಂದಲೇ ಬರುತ್ತದೆ:
-
Horizontal stroke open edge ಉದ್ದಕ್ಕೂ ಸಾಗುತ್ತದೆ, ಆದ್ದರಿಂದ ಅದು ಯಾವಾಗಲೂ
ಅಗಲವಾಗಿ ಬರುತ್ತದೆ — ಯಾವುದೇ pressure ನಲ್ಲೂ constant thin line. ಖಚಿತವಾದ spec ಇದೇ. -
Vertical stroke ಸಂಪೂರ್ಣ long axis ಅನ್ನು ದಾಟುತ್ತದೆ:
, thick end. -
Diagonal stroke, ಪ್ರಯಾಣದ ದಿಕ್ಕಿಗೆ perpendicular ಆಗಿರುವ ellipse ನ chord width ಅನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ,
-
Stroke ends elliptical cuts — sample ನ flat nib-shaped ends — ಆಗುತ್ತವೆ; ಇದಕ್ಕೆ ಹೆಚ್ಚುವರಿ ಕೆಲಸವೇ ಇಲ್ಲ.
-
Pressure long axis ಅನ್ನು ಮಾತ್ರ scale ಮಾಡುತ್ತದೆ,
, ಆದ್ದರಿಂದ downstrokes ನಲ್ಲಿ pressure ink volume ಅನ್ನು ಹೆಚ್ಚಿಸಬಹುದು, ಆದರೆ horizontal ಅನ್ನು ಎಂದಿಗೂ fatten ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ.
Sample measurements ನಿಂದ
Rendering ಗೆ ಒಂದು ಹೊಸ fragment shader ಮಾತ್ರ ಬೇಕಾಯಿತು. Vertex format — position, diameter, color — ಈಗಾಗಲೇ ಎಲ್ಲವನ್ನೂ ಹೊತ್ತಿತ್ತು: diameter long axis, short axis per-pass uniform. Shader ನಮ್ಮ round stamps ಗಳಂತೆಯೇ half-pixel coverage ramp ಬಳಸಿ ellipse SDF ಅನ್ನು evaluate ಮಾಡುತ್ತದೆ. ಅದರಿಂದ ಅದು Core Graphics reference implementation (fillEllipse per stamp) ಜೊತೆ pixel-comparable ಆಗುತ್ತದೆ. Validation ಸಾಮಾನ್ಯ gate ಮೂಲಕ ನಡೆಯಿತು: ಎರಡು fountain strokes ಇರುವ synthetic corpus ಅನ್ನು ಎರಡೂ ರೀತಿಯಲ್ಲಿ render ಮಾಡಿ pixel by pixel compare ಮಾಡಿದೆವು — ರಚನಾತ್ಮಕ ವ್ಯತ್ಯಾಸಗಳು ಶೂನ್ಯ, ಮತ್ತು ಪರಿಶೀಲಿಸಿದ ಅಡ್ಡ ಸ್ಟ್ರೋಕ್ ಎರಡೂ ರೆಂಡರರ್ಗಳಲ್ಲಿ 12 px ಎಂದು ಅಳೆಯಿತು.

Version one ಎಡಕ್ಕೆ, version two ಬಲಕ್ಕೆ. ಅದೇ handwritten input, ಅದೇ pipeline. Ends ಕಥೆಯನ್ನು ಹೇಳುತ್ತವೆ.
iPad ಮೇಲೆ ಹೊಸ pen ತಕ್ಷಣ pass ಆಯಿತು: “好,很好” — ಒಳ್ಳೆಯದು. ಬಹಳ ಒಳ್ಳೆಯದು.
ತಪ್ಪಿದದ್ದನ್ನೂ ಉಳಿಸಿಕೊಳ್ಳುವುದು
Version one bin ಗೆ ಹೋಗಲಿಲ್ಲ. ಅದು ಆಸಕ್ತಿದಾಯಕ brush — water pen ಅಲ್ಲ, ಅಷ್ಟೇ. ಆದ್ದರಿಂದ ಮನುಷ್ಯ ಕೊಟ್ಟ ಹೆಸರಿನಡಿ ಹೊಸ experimental-brush menu ಯ ಮೊದಲ entry ಆಗಿ ಅದನ್ನು ship ಮಾಡಿದೆವು: 漏水的圆珠笔, leaky ballpoint. Toolbar ಗೆ flask button ಸೇರಿತು; ಅದು experiments ನ text list ಅನ್ನು ತೋರಿಸುತ್ತದೆ. ಮುಂದಿನದನ್ನು add ಮಾಡಲು registry ಯಲ್ಲಿ ಒಂದು line ಸಾಕು. ತಿರಸ್ಕರಿಸಿದ model ಅನ್ನು ಸ್ಪಷ್ಟವಾಗಿ label ಮಾಡಿದ experiment ಆಗಿ ship ಮಾಡಬಹುದಾದರೆ, ಅದು ವ್ಯರ್ಥವಾದ ಕೆಲಸವಲ್ಲ.
ಒಂದು ಸಂಜೆಗಿನ ಸುತ್ತುಗಳು
ಸಂಪೂರ್ಣ arc — measure, model, build, device, question, remodel, rebuild, validate — ಒಂದು ಸಂಜೆ ತೆಗೆದುಕೊಂಡಿತು. Fireworks ನಲ್ಲಿ Kimi K3 ಈ loop ನ ಸಂಪೂರ್ಣ technical side ಅನ್ನು ನಡೆಸಿತು: measurement scans ರೂಪಿಸುವುದು, ಎರಡನೇ ಬಾರಿ guess ಮಾಡುವ ಬದಲು discriminating question ಪ್ರಸ್ತಾಪಿಸುವುದು, evidence ಬದಲಾಗುತ್ತಿದ್ದಂತೆ ತನ್ನದೇ direction estimator ಅನ್ನು ಅಳಿಸುವುದು, ಮತ್ತು app ಅನ್ನು ಮುಟ್ಟುವ ಮೊದಲು pixel-diff harness ಅನ್ನು ವಿಸ್ತರಿಸುವುದು. Fireworks ನ inference speed loop ಅನ್ನು interactive ಆಗಿ ಇರಿಸಿತು — ಉದ್ದದ Metal ಮತ್ತು Swift diffs, pixel-analysis scripts ಮತ್ತು corpus tooling ಎಲ್ಲವೂ ಉಳಿದ bottleneck ಮಾನವೀಯ judgment ಆಗುವಷ್ಟು ವೇಗವಾಗಿ ಬಂದವು.
Collaboration pattern Metal pipeline post ನಲ್ಲಿ ಇದ್ದದ್ದೇ ಆಗಿತ್ತು, ಮತ್ತು ಇಲ್ಲಿಯೂ ಅದು ಕೆಲಸ ಮಾಡಿತು: model ವೇಗವಾದುದು ಮತ್ತು ನಿಖರವಾದುದು; taste ಮತ್ತು end-to-end verification ಮನುಷ್ಯನ ಜವಾಬ್ದಾರಿ. “art pen, not water pen” ಎಂಬ feel-based feedback ನ ಒಂದು ವಾಕ್ಯವೇ model ಗೆ ನಿಖರವಾದ modeling error ಅನ್ನು ಪತ್ತೆಹಚ್ಚಿ, ಅದನ್ನು ಇನ್ನಷ್ಟು ಸರಳವಾದ design ನಿಂದ ಬದಲಿಸಲು ಸಾಕಾಯಿತು.
ಸರಿಯಾದ model ತಪ್ಪಾದ model ಗಿಂತ ಚಿಕ್ಕದಾಗಿ ಹೊರಹೊಮ್ಮಿತು. Version two, version one ಗಿಂತ ಕಡಿಮೆ moving parts ಜೊತೆ ship ಆಯಿತು — estimator ಇಲ್ಲ, smoothing window ಇಲ್ಲ, fitted exponent ಇಲ್ಲ. Nib width ಅನ್ನು compute ಮಾಡುವುದಿಲ್ಲ. Nib ಅದೇ width.