Hogyan épített Kimi K3 digitális töltőtollvonást
A Lulucat Notesba a Freeform irányfüggő töltőtollát szerettük volna. A specifikáció egy kézírásról készült képernyőkép volt. Két modell, egy döntő kérdés és egy ellipszis alakú tollhegy után a víztoll úgy ír, ahogy kell. A kutatást, a kódot és a validációt Kimi K3 végezte a Fireworksnél.

Az ebben a bejegyzésben bemutatott Lulucat Notes Metal-folyamattal renderelve.
A Lulucat Notesban van egy egyszerű toll és egy szövegkiemelő. Az ütemterv következő eszköze egy víztoll volt — a Freeformból és az Apple Notesból ismert irányfüggő töltőtoll, amelynél a függőleges vonások vastagon, a vízszintesek vékonyan jelennek meg. Az eszköz specifikációja nem dokumentum volt. Egy képernyőkép volt: három sor kézírás, a „pencilkit”, a „无边记” és a „这种有方向的水笔能力” szavak — ez az irányfüggő víztoll-képesség.
A korábbi Metal-folyamathoz hasonlóan ezt a munkát is Kimi K3 végezte, a Moonshot Fireworkson futó nyílt modellje: a mérést, a modellezést, a kódot és a validációt. Az ember átadta a képernyőképet, válaszolt egy kérdésre, és egy valódi iPaden ítélte meg a toll érzetét.
A specifikáció egy képernyőkép
Egy statikus kép nem tudja megmondani, miért vékony egy vonás. Csak azt mutatja meg, mennyire vékony, és hol. Ezért az első lépés a mérés volt. Soronként és oszloponként végigpásztáztuk a képernyőképet, minden vonás középvonalának elmozdulását követve meghatároztuk az irányát, majd a pásztázott szélességet a szög szinuszával valódi szélességgé alakítottuk:
| Vonás | Irány | Valódi szélesség |
|---|---|---|
| Az „l” felszálló szára, „pencilkit” | ≈ 78° | 27.3 px |
| A „k” törzse, „pencilkit” | ≈ 90° | 28 px |
| A 力 balra lefelé tartó lendülete | ≈ 66° | 25.7 px |
| Kurzív összekötő vonások | ≈ 8° | 11 px |
| Kínai vízszintesek (横) | ≈ 0° | 6–11 px |
A vastag és a vékony aránya ≈ 2.5. A
Első verzió: szélesség az irányból
Az első modell kézenfekvő volt. Minden bemeneti ponthoz kiszámította az irányt, az illesztett görbén keresztül szélességgé alakította, majd a rögzítés pillanatában belevéste az eredményt a pont sugarába. Az irányt oksági módon becsültük — az ív utolsó néhány pontjának exponenciálisan csökkenő súlyozott átlagaként, kettős szögterben számolva, hogy a haladási irány megfordulása ne oltsa ki a becslést. Csak a korábbi pontokat használjuk, így az élő és a véglegesített vonás bájtról bájtra megegyezik.
A builder megfelelt a saját egység-ellenőrzésén: a szintetikus vízszintes, függőleges, 45°-os és megfordított útvonalak az elméleti szélességeket sütötték be — 0.99, 2.52, 2.00 és 0.99 pontot. A rendereléshez egyáltalán nem kellett új kód: az előre beírt sugarú vonás csupán kerek lenyomatok lánca, és a point-sprite pipeline-unk már megrajzolta ezeket.
Az iPaden az embernek körülbelül tíz másodpercébe telt elutasítani: „ez művésztoll, nem víztoll”.
Egy kép, két lehetséges történet
Miért tűnt rossznak? Két lehetséges magyarázat volt, és a képernyőkép nem tudta szétválasztani őket:
- Irányzár. A tollhegy geometriája vékony vízszinteseket és vastag függőlegeseket kényszerít ki, bármit is csináljon a kéz. Ezt valósította meg az első verzió.
- Nyomás és sebesség. A toll nyomásvezérelt, a minta pedig csupán a kézírás dinamikája: a lefelé húzások természetesen erősebben nyomottak, az összekötők pedig természetesen gyorsak és könnyűek.
Mindkét magyarázat vékony vízszinteseket és vastag függőlegeseket eredményez a képernyőképen. A különbség akkor jelenik meg, amikor erősen rányomunk egy vízszintes vonásra. Az első verzió vékonyan hagyja. A nyomásérzékeny toll megvastagítja. Ezért feltettünk az embernek egy kérdést: vastagabbá kell válnia annak a vízszintes vonásnak, amelyre erősen rányomunk?
„Nem. A vízszintesek vékonyak maradnak.”
Az irányzár megerősítést nyert. De valami más is hibás volt, mert az első verzió szintén irányzáras volt.
A válasz a vonások végeiben volt
A következő nyom a felszálló szárak tetején volt. A mintában az „l” és a „k” törzsének kinagyítása két dolgot mutatott: egy egyenes vonás elejétől a végéig megtartja ugyanazt a szélességet, a vonásvégek pedig lapos, átlós vágások — egy vésőhegy alakja, amikor felemelkedik. Nem kerek pontok. Nem nyomás okozta elvékonyodások.

Ezt jelentette valójában a „művésztoll érzése”. Az első verzió a minta kinézetét modellezte — a szélességet a becsült irány függvényeként —, de nem a tollat. Az iránybecslő egy szenzor: zajos bemeneten remeg, a sarkokban lemarad, és minden vonásvéget kör alakúra kerekít. Egy valódi tollhegynek egyik problémája sincs, mert nem számol semmit. A szélesség geometria.
Második verzió: ellipszis alakú tollhegy
A végső modellben egyáltalán nincs iránybecslő. A tollhegy egy tájolt ellipszis: a hosszú tengely vízszintes, a rövid tengely rögzített. Ennek az ellipszisnek a lenyomatait sűrűn helyezzük el a vonás útvonala mentén, és minden más a geometriából következik:
-
A vízszintes vonás a nyitott él mentén halad, ezért a szélessége mindig
— állandóan vékony vonal, bármilyen nyomás mellett. Pontosan a megerősített specifikáció. -
A függőleges vonás a teljes hosszú tengelyt keresztezi:
, a vastag vég. -
Az átlós vonás a haladási irányra merőlegesen veszi az ellipszis húrjának szélességét,
-
A vonásvégek ellipszisből vágott végek — a mintán látható, lapos tollhegy alakú végek, külön munka nélkül.
-
A nyomás csak a hosszú tengelyt skálázza,
, így tintamennyiséget ad a lefelé húzásokhoz, és soha nem vastagíthatja meg a vízszintest.
A minta mérései alapján megtartottuk a
A rendereléshez egy új fragment shader kellett, semmi más. A vertex format — pozíció, átmérő, szín — már mindent hordozott: az átmérő a hosszú tengely, a rövid tengely pedig egy meneten belüli uniform. A shader ugyanazzal a félpixeles fedettségi rámpával értékeli ki az ellipszis SDF-jét, mint a kerek lenyomataink, így pixelpontosan összehasonlítható a Core Graphics referenciaimplementációjával (fillEllipse lenyomatonként). A validáció a szokásos ellenőrzésen ment át: egy két töltőtollvonást tartalmazó szintetikus korpuszt mindkét módon rendereltünk, majd képpontról képpontra összevetettük — nulla szerkezeti eltérés, és egy véletlenszerűen ellenőrzött vízszintes vonás mindkét renderelőben 12 px-t mért.

Az első verzió balra, a második jobbra. Ugyanaz a kézírásos bemenet, ugyanaz a pipeline. A végek mindent elmondanak.
Az iPaden az új toll azonnal átment: „好,很好” — Jó. Nagyon jó.
A mellélövés megtartása
Az első verzió nem került a kukába. Érdekes ecset — egyszerűen nem víztoll. Ezért egy új kísérleti ecsetmenü első elemeként szállítottuk, azon a néven, amelyet az ember adott neki: 漏水的圆珠笔, a szivárgó golyóstoll. Az eszköztár kapott egy lombik alakú gombot, amely megnyitja a kísérletek szöveges listáját; a következő hozzáadása egyetlen sor a regisztrációban. Egy elutasított modell nem elvesztegetett munka, ha egyértelműen felcímkézett kísérletként kiadható.
Egy este iterációi
A teljes ív — mérés, modellezés, építés, eszközön való kipróbálás, kérdés, újramodellezés, újraépítés, validáció — egy estét vett igénybe. Kimi K3 a Fireworkson a ciklus teljes technikai oldalát vitte: kidolgozta a mérési pásztázásokat, a második találgatás helyett javasolta a döntő kérdést, a bizonyítékok megfordulásakor törölte a saját iránybecslőjét, és még az alkalmazás módosítása előtt kibővítette a pixel-diff tesztkörnyezetet. A Fireworks következtetési sebessége interaktívan tartotta a ciklust — a hosszú Metal- és Swift-diffek, a pixelanalizáló szkriptek és a korpuszeszközök elég gyorsan érkeztek ahhoz, hogy a megmaradó szűk keresztmetszet az emberi ítélet legyen.
Az együttműködés mintája ugyanaz volt, mint a Metal-folyamatról szóló bejegyzésben, és ismét bevált: a modell gyors és pontos; az emberé az ízlés és a teljes folyamatot lefedő ellenőrzés. Egyetlen, az érzetre vonatkozó visszajelzés — „művésztoll, nem víztoll” — elég volt ahhoz, hogy a modell megtalálja a pontos modellezési hibát, és egyszerűbb tervvel váltsa fel.
A helyes modell kisebbnek bizonyult a rossznál. A második verzió kevesebb mozgó alkatrésszel került ki, mint az első — nem volt benne becslő, simítási ablak vagy illesztett kitevő. A tollhegy nem számítja ki a szélességet. A tollhegy maga a szélesség.