כיצד בנה Kimi K3 משיכת עט נובע דיגיטלית
רצינו את העט הנובע הכיווני של Freeform בתוך Lulucat Notes. המפרט היה צילום מסך של כתב יד. אחרי שני מודלים, שאלה אחת שמבדילה ביניהם וציפורן אליפטית, עט המים כותב כפי שהוא אמור לכתוב. Kimi K3 ביצע את המחקר, כתב את הקוד ואימת את התוצאה על Fireworks.

רונדר בצינור ה-Metal של Lulucat Notes, שבו עוסק המאמר הזה.
ב-Lulucat Notes יש עט רגיל ומרקר. הכלי הבא במפת הדרכים היה עט מים — העט הנובע הכיווני שאתם מכירים מ-Apple Notes ומ-Freeform, שבו משיכות אנכיות יוצאות עבות ומשיכות אופקיות יוצאות דקות. המפרט של הכלי הזה לא היה מסמך. הוא היה צילום מסך: שלוש שורות של כתב יד, המילים “pencilkit”, “无边记” ו-”这种有方向的水笔能力” — היכולת הזאת של עט מים כיווני.
כמו בצינור ה-Metal שלפניו, את העבודה ביצע Kimi K3, המודל הפתוח של Moonshot שרץ על Fireworks: המדידה, המידול, הקוד והאימות. האדם סיפק את צילום המסך, ענה על שאלה אחת ושפט את התחושה ב-iPad אמיתי.
המפרט הוא צילום מסך
תמונה סטטית לא יכולה להסביר למה משיכה דקה. היא יכולה רק לומר כמה היא דקה והיכן. לכן הצעד הראשון היה מדידה. סרקנו את צילום המסך שורה אחר שורה ועמודה אחר עמודה, עקבנו אחר הסחיפה של קו המרכז בכל משיכה כדי למצוא את הכיוון שלה, ואז המרתנו את רוחב הסריקה לרוחב אמיתי בעזרת הסינוס של הזווית הזאת:
| משיכה | כיוון | רוחב אמיתי |
|---|---|---|
| העולה של “l”, “pencilkit” | ≈ 78° | 27.3 px |
| הגבעול של “k”, “pencilkit” | ≈ 90° | 28 px |
| התנועה היורדת שמאלה של 力 | ≈ 66° | 25.7 px |
| חיבורי כתב מחובר | ≈ 8° | 11 px |
| קווים אופקיים בסינית (横) | ≈ 0° | 6–11 px |
היחס בין עבה לדק הוא בערך 2.5. התאמת
גרסה אחת: רוחב לפי כיוון
המודל הראשון היה המובן מאליו. הוא חישב כיוון לכל נקודת קלט, המיר את הכיוון לרוחב באמצעות העקומה המותאמת, והטמיע את התוצאה ברדיוס של הנקודה בזמן הלכידה. הכיוון נאמד באופן סיבתי — ממוצע משוקלל בדעיכה מעריכית של נקודות הקשת האחרונות, שחושב במרחב של זווית כפולה כדי שהיפוך בתנועת היד לא יבטל את האומדן. משתמשים רק בנקודות מהעבר, ולכן המשיכה החיה והמשיכה המקובעת תואמות זו לזו בית אחר בית.
הבונה עבר את בדיקת היחידות שלו: מסלולים סינתטיים אופקיים, אנכיים, של 45° והיפוך הפיקו את הרוחבים התיאורטיים — 0.99, 2.52, 2.00 ו-0.99 נקודות. הרינדור לא דרש קוד חדש כלל: משיכה עם רדיוס שהוטמע מראש היא פשוט שרשרת של חותמות עגולות, וצינור ה-point-sprite שלנו כבר צייר אותן.
ב-iPad לקח לאדם בערך עשר שניות לדחות את המודל: “זה עט אמנות, לא עט מים”.
שני הסברים לתמונה אחת
למה זה הרגיש לא נכון? היו שני הסברים אפשריים, וצילום המסך לא יכול היה להבדיל ביניהם:
- נעילת כיוון. הגאומטריה של הציפורן מכריחה את האופקיות להיות דקות ואת האנכיות עבות, בלי קשר למה שהיד עושה. זה מה שגרסה אחת יישמה.
- לחץ ומהירות. העט מונע בלחץ, ודפוס הדוגמה הוא פשוט דינמיקת כתב יד: משיכות מטה נלחצות באופן טבעי, וחיבורים מהירים וקלים באופן טבעי.
שני ההסברים יוצרים צילום מסך עם אופקיות דקות ואנכיות עבות. ההבדל הוא במה שקורה כשלוחצים חזק על משיכה אופקית. גרסה אחת משאירה אותה דקה. עט שמגיב ללחץ מעבה אותה. לכן שאלנו את האדם שאלה אחת: האם משיכה אופקית שעליה לוחצים חזק צריכה להתעבות?
“לא. האופקיות נשארות דקות.”
נעילת הכיוון אושרה. אבל משהו נוסף היה שגוי, כי גם גרסה אחת הייתה נעולה לכיוון.
התשובה הייתה בקצות המשיכות
הרמז הבא היה בראשם של החלקים העולים. הגדלה של הגבעולים של “l” ושל “k” בדוגמה הראתה שני דברים: משיכה ישרה שומרת על רוחב אחד מתחילתה ועד סופה, וקצות המשיכה הם חיתוכים אלכסוניים שטוחים — הצורה של ציפורן אזמלית כשהיא מתרוממת. לא נקודות עגולות. לא היצרויות שנגרמות מלחץ.

זה מה ש”תחושת עט אמנותי” באמת אמרה. גרסה אחת מידלה את המראה של הדוגמה — רוחב כפונקציה של הכיוון המשוער — אבל לא את העט. אומדן כיוון הוא חיישן: הוא רועד מול קלט רועש, מפגר בפינות ומעגל כל קצה של משיכה לצורה עגולה. לציפורן אמיתית אין אף אחת מהבעיות האלה, כי היא לא מחשבת דבר. הרוחב הוא גאומטריה.
גרסה שתיים: ציפורן אליפטית
במודל הסופי אין כלל אומדן כיוון. הציפורן היא אליפסה מכוונת: הציר הארוך אופקי והציר הקצר קבוע. חותמות של האליפסה הזאת מונחות בצפיפות לאורך מסלול המשיכה, וכל השאר נובע מהגאומטריה:
-
משיכה אופקית נעה לאורך הקצה הפתוח, ולכן רוחבה תמיד
— קו דק וקבוע, בכל לחץ. בדיוק המפרט שאושר. -
משיכה אנכית חוצה את הציר הארוך במלואו:
, הקצה העבה. -
משיכה אלכסונית מקבלת את רוחב המיתר של האליפסה בניצב לכיוון התנועה,
-
קצות המשיכה הם חיתוכים אליפטיים — הקצוות השטוחים בצורת ציפורן מן הדוגמה, בלי עבודה נוספת.
-
הלחץ משנה את קנה המידה של הציר הארוך בלבד,
, כך שהוא מוסיף נפח דיו למשיכות מטה ולעולם אינו יכול לעבות משיכה אופקית.
מן המדידות בדוגמה שמרנו על
הרינדור דרש fragment shader חדש אחד, ולא שום דבר נוסף. פורמט הקודקוד — מיקום, קוטר וצבע — כבר הכיל הכול: הקוטר הוא הציר הארוך, והציר הקצר הוא uniform לכל מעבר. ה-shader מעריך SDF של אליפסה עם אותה מדרגת כיסוי של חצי פיקסל כמו החותמות העגולות שלנו, ולכן אפשר להשוות אותו ברמת הפיקסל למימוש הייחוס של Core Graphics (fillEllipse לכל חותמת). האימות עבר בשער הרגיל: קורפוס סינתטי עם שתי משיכות עט נובע, שרונדר בשתי הדרכים והושווה פיקסל-לפיקסל — אפס הבדלים מבניים, ומשיכה אופקית שנבדקה באקראי נמדדה באורך 12 px בשני מנועי הרינדור.

גרסה אחת משמאל, גרסה שתיים מימין. אותו קלט בכתב יד, אותו צינור. הקצוות מספרים את הסיפור.
ב-iPad העט החדש עבר מיד: “好,很好” — טוב. טוב מאוד.
לשמור את הפספוס
גרסה אחת לא נזרקה לפח. זו מברשת מעניינת — היא פשוט לא עט מים. לכן היא נשלחה כרשומה הראשונה בתפריט חדש של מברשות ניסיוניות, בשם שהאדם נתן לה: 漏水的圆珠笔, העט הכדורי הדולף. לסרגל הכלים נוסף כפתור בצורת בקבוקון שפותח רשימת טקסט של ניסויים; הוספת הניסוי הבא עולה שורה אחת ברישום. מודל שנדחה אינו עבודה מבוזבזת אם אפשר לשלוח אותו כניסוי עם תווית ברורה.
ערב אחד של לולאות
המסלול כולו — מדידה, מידול, בנייה, בדיקה במכשיר, שאלה, מידול מחדש, בנייה מחדש, אימות — ארך ערב אחד. Kimi K3 על Fireworks ניהל את כל הצד הטכני של הלולאה: תכנון סריקות המדידה, הצעת השאלה שמבדילה בין ההסברים במקום לנחש פעם שנייה, מחיקת אומדן הכיוון שלו עצמו כשהראיות השתנו, והרחבת רתמת ה-pixel-diff לפני שנגע באפליקציה. מהירות ההסקה של Fireworks שמרה על הלולאה אינטראקטיבית — דיפי Metal ו-Swift ארוכים, סקריפטים לניתוח פיקסלים וכלי corpus הגיעו מהר מספיק, כך שצוואר הבקבוק שנותר היה השיפוט האנושי.
דפוס שיתוף הפעולה היה זהה לזה שתיארנו במאמר על צינור ה-Metal, והוא עבד שוב: המודל מהיר ומדויק; האדם אחראי לטעם ולבדיקה מקצה לקצה. משפט אחד של משוב המבוסס על התחושה — “עט אמנות, לא עט מים” — הספיק כדי שהמודל ימצא את שגיאת המידול המדויקת ויחליף אותה בתכנון פשוט יותר.
המודל הנכון התברר כקטן יותר מהמודל השגוי. גרסה שתיים נשלחה עם פחות חלקים נעים מגרסה אחת — בלי אומדן, בלי חלון החלקה ובלי מעריך מותאם. הציפורן לא מחשבת את הרוחב. הציפורן היא הרוחב.