Lulucat

Jak Kimi K3 samo vyvinulo digitální tah plnicího pera

Gaoge ZhangGaoge Zhang

Chtěli jsme směrové plnicí pero z Freeformu v Lulucat Notes. Specifikací byl screenshot rukopisu. Po dvou modelech, jedné rozlišovací otázce a eliptickém hrotu píše vodové pero tak, jak má. Výzkum, kód i validaci provedlo Kimi K3 na Fireworks.

Aktualizováno

Ručně psaná anglická kurzíva se slovy „fountain pen“ nad řádkem čínské kaligrafie, vykreslená plnicím perem s eliptickým hrotem na krémovém papíru: svislé tahy jsou silné, vodorovné tenké.

Vykreslila ji Metal pipeline Lulucat Notes, o které tento příspěvek pojednává.

Lulucat Notes má obyčejné pero a zvýrazňovač. Dalším nástrojem na roadmapě bylo vodové pero — směrové plnicí pero, které znáte z Apple Notes a Freeformu, kde svislé tahy vycházejí tlusté a vodorovné tenké. Specifikací tohoto nástroje nebyl dokument. Byl jí screenshot: tři řádky rukopisu, slova „pencilkit“, „无边记“ a „这种有方向的水笔能力“ — tato schopnost směrového vodového pera.

Stejně jako u předchozí Metal pipeline odvedlo práci Kimi K3, otevřený model od Moonshotu běžící na Fireworks: měření, modelování, kód i validaci. Člověk dodal screenshot, odpověděl na jednu otázku a posoudil pocit při psaní na skutečném iPadu.

Specifikací je screenshot

Statický obrázek vám neřekne, proč je tah tenký. Řekne vám jen, jak tenký je a kde. Prvním krokem proto bylo měření. Screenshot jsme proskenovali řádek po řádku a sloupec po sloupci, sledovali posun středové čáry každého tahu, abychom získali jeho směr, a potom převedli šířku skenu na skutečnou šířku pomocí sinu daného úhlu:

TahSměrSkutečná šířka
Ascender „l“, „pencilkit“≈ 78°27.3 px
Dřík „k“, „pencilkit“≈ 90°28 px
Tah znaku 力 klesající doleva≈ 66°25.7 px
Kurzivní spojky≈ 8°11 px
Čínské vodorovné tahy (横)≈ 0°6–11 px

Poměr tlustého k tenkému je ≈ 2.5. Proložení bodem 66° dává — v téměř lineární průběh s vrcholem na svislé ose. Prakticky jde o italický hrot: vodorovnou štěrbinu, kterou vodorovné psaní nikdy neotevře.

Verze jedna: šířka ze směru

První model byl nasnadě. Pro každý vstupní bod spočítat směr, pomocí proložené křivky převést směr na šířku a při zachycení zapsat výsledek do poloměru bodu. Směr se odhadoval kauzálně — exponenciálně klesající vážený průměr z několika posledních bodů oblouku, počítaný v prostoru dvojnásobného úhlu, aby se při obrácení pohybu odhad nevyrušil. Používají se jen předchozí body, takže živý tah a potvrzený tah souhlasí bajt po bajtu.

Builder prošel unit checkem: syntetické vodorovné, svislé, 45° a reverzní cesty všechny zapsaly teoretické šířky — 0.99, 2.52, 2.00 a 0.99 bodu. Vykreslování nepotřebovalo žádný nový kód: tah s předem zapsaným poloměrem je jen řetězec kulatých otisků a naše point-sprite pipeline je už kreslila.

Na iPadu člověk potřeboval asi deset sekund, aby ho odmítl: „tohle je umělecké pero, ne vodové pero“.

Dvě vysvětlení na jednom obrázku

Proč působil špatně? Byla dvě možná vysvětlení a screenshot je nedokázal rozlišit:

  • Zámek směru. Geometrie hrotu vynucuje tenké vodorovné a tlusté svislé tahy bez ohledu na pohyb ruky. To implementovala verze jedna.
  • Tlak a rychlost. Pero reaguje na tlak a vzor ve vzorku je jen dynamika rukopisu: tahy dolů jsou přirozeně přitlačené a spojky přirozeně rychlé a lehké.

Obě vysvětlení vytvoří screenshot s tenkými vodorovnými a tlustými svislými tahy. Rozdíl se ukáže, když na vodorovný tah silně zatlačíte. Verze jedna ho nechá tenký. Tlakové pero ho zesílí. Proto jsme položili člověku jednu otázku: má se silně stlačený vodorovný tah zesílit?

„Ne. Vodorovné tahy zůstanou tenké.“

Zámek směru potvrzen. Něco dalšího však bylo špatně, protože i verze jedna byla zamčená podle směru.

Odpověď byla v koncích tahů

Další stopa se skrývala nahoře u ascenderů. Přiblížení dříků „l“ a „k“ ve vzorku ukázalo dvě věci: rovný tah si od začátku do konce drží jednu šířku a konce tahů jsou ploché diagonální řezy — tvar dlátového hrotu při odtržení. Ne kulaté tečky. Ne zúžení tlakem.

Detailní výřez dvou ručně psaných ascenderů ze vzorku, z nichž každý nahoře končí plochým diagonálním řezem a po celé délce má stejnou tloušťku.

Právě to znamenal „pocit uměleckého pera“. Verze jedna modelovala vzhled vzorku — šířku jako funkci odhadovaného směru — ale ne pero. Odhad směru je senzor: na zašuměném vstupu kmitá, v rozích se zpožďuje a každý konec tahu zaokrouhlí do kruhu. Skutečný hrot tyto problémy nemá, protože nic nepočítá. Šířka je geometrie.

Verze dvě: eliptický hrot

Konečný model nemá žádný odhad směru. Hrot je orientovaná elipsa: dlouhá osa vodorovná, krátká osa pevná. Otisky této elipsy se hustě kladou podél dráhy tahu a všechno ostatní vyplývá z geometrie:

  • Vodorovný tah vede podél otevřené hrany, takže vždy vyjde široký — konstantně tenká čára při libovolném tlaku. Přesně podle potvrzené specifikace.

  • Svislý tah protne celou dlouhou osu: , tlustý konec.

  • Diagonální tah má šířku tětivy elipsy kolmo ke směru pohybu,

  • Konce tahů jsou eliptické řezy — ploché konce ve tvaru hrotu ze vzorku, bez práce navíc.

  • Tlak mění měřítko jen dlouhé osy, , takže tlak přidá objem inkoustu do tahů dolů, ale nikdy nedokáže zesílit vodorovný tah.

Z měření vzorku jsme zachovali pt a pt, tedy stejný poměr 2.5. Otisky jsou podél oblouku vzdálené 0.5 bodu; při krátkém poloměru 0.55 bodu vychází v nejhorším případě zvlnění hrany asi na desetinu pixelu.

Vykreslování potřebovalo jeden nový fragment shader a nic dalšího. Formát vertexu — pozice, průměr, barva — už nesl všechno: průměr je dlouhá osa a krátká osa je uniform pro každý průchod. Shader vyhodnocuje SDF elipsy se stejnou půlpixelovou rampou pokrytí jako naše kulaté otisky, takže je na úrovni pixelů srovnatelný s referenční implementací Core Graphics (fillEllipse pro každý otisk). Validace prošla obvyklou branou: syntetický corpus se dvěma tahy plnicího pera, vykreslený oběma způsoby a porovnaný pixel po pixelu — nulové strukturální rozdíly; namátkově zkontrolovaný vodorovný tah měřil 12 px v obou rendererech.

Dvě vykreslení stejného ručně psaného slova „fountain“ vedle sebe: vlevo kulaté otisky s průměrem škálovaným podle směru a zaoblenými konci, vpravo eliptické otisky s plochými konci ve tvaru hrotu a stabilnější šířkou.

Verze jedna vlevo, verze dvě vpravo. Stejný ručně psaný vstup, stejná pipeline. Konce vyprávějí celý příběh.

Na iPadu nové pero prošlo okamžitě: „好,很好“ — dobře. Velmi dobře.

Nechat si nepovedený pokus

Verze jedna neskončila v koši. Je to opravdu zajímavý štětec — jen to není vodové pero. Proto vyšla jako první položka nové nabídky experimentálních štětců pod jménem, které jí dal člověk: 漏水的圆珠笔, propouštějící kuličkové pero. Panel nástrojů dostal tlačítko baňky, které otevře textový seznam experimentů; přidání dalšího stojí jeden řádek v registry. Zamítnutý model není promarněná práce, když může vyjít jako jasně označený experiment.

Jeden večer smyček

Celý oblouk — měřit, modelovat, postavit, vyzkoušet na zařízení, zeptat se, přemodelovat, přestavět, validovat — trval jeden večer. Kimi K3 na Fireworks nejen psalo kód; řídilo celou technickou stránku smyčky: vymýšlelo měřicí skeny, navrhlo rozlišovací otázku místo druhého hádání, smazalo vlastní odhad směru, když se důkazy obrátily, a rozšířilo pixel-diff harness ještě před zásahem do aplikace. Rychlost inference na Fireworks udržela smyčku interaktivní — dlouhé diffy v Metalu a Swiftu, skripty pro analýzu pixelů i nástroje pro corpus přicházely dost rychle na to, aby úzké hrdlo zůstalo tam, kam patří: u lidského úsudku.

Vzorec spolupráce byl stejný jako v příspěvku o Metal pipeline a znovu obstál: model je rychlý a přesný; člověk má na starosti vkus a end-to-end ověření. Jedna věta zpětné vazby založené na pocitu — „umělecké pero, ne vodové pero“ — stačila, aby model našel přesnou chybu modelování a nahradil ji jednodušším návrhem.

Správný model se ukázal být menší než ten špatný. Verze dvě vyšla s menším počtem pohyblivých částí než verze jedna — žádný odhad, žádné okno vyhlazování, žádný proložený exponent. Hrot šířku nepočítá. Hrot je šířka.