Kimi K3 உடன் Lulucat Notes-ன் ரெண்டரிங் பைப்லைனை மீண்டும் கட்டமைத்தல்
எங்கள் Core Graphics டைல் பைப்லைன் ஆறு சிறிய படிகளில் Metal point-sprite பைப்லைனாக மாறியது; ஒவ்வொரு படியும் உண்மையான iPad-ல் சரிபார்க்கப்பட்டது. இந்தக் குறியீடு Fireworks-ல் Kimi K3-உடன் pair-program செய்யப்பட்டது.
கடந்த வாரம், Lulucat Notes-ல் ஒரு lasso selection-ஐ இழுத்தபோது கண்ணுக்குத் தெரியும் அலை உருவானது: ஒரே frame-ல் சில screen tiles selection-ஐ அதன் புதிய நிலையில் காட்ட, மற்றவை இன்னும் பழைய நிலையையே காட்டின. முழு rendering pipeline-ஐ — Core Graphics bitmap மற்றும் CATiledLayer — Metal-ஆக மாற்றினோம்; இந்த மாற்றம் ஆறு சிறிய படிகளில் செய்யப்பட்டது, அடுத்த படியைத் தொடங்குவதற்கு முன் ஒவ்வொரு படியும் உண்மையான iPad-ல் சரிபார்க்கப்பட்டது.
இந்தக் குறியீடு Fireworks-ல் இயங்கும் Moonshot-ன் open model ஆன Kimi K3-உடன் pair-program செய்யப்பட்டது. மனிதர் வழிநடத்தி, முடிவெடுத்து, சோதித்தார்; model கிட்டத்தட்ட ஒவ்வொரு வரியையும் எழுதியது.
பைப்லைன்
பழைய pipeline-ல் மெதுவாக ஒன்றிலிருந்து ஒன்று விலகிய இரண்டு வகை drawing இருந்தன: குறைந்த செலவில் display செய்வதற்காக strokes bitmap-ல் பதியப்பட்டன; tiles-க்கு அதிக detail தேவைப்பட்டபோதெல்லாம் அவை vectors ஆக மீண்டும் வரையப்பட்டன. புதிய pipeline-க்கு சரியாக ஒரே ஒரு யோசனை: மை போன்ற அனைத்தும் ஒரு point sprite. ஒரு pen stroke, ஒரு highlighter sweep, ஒரு eraser dab ஆகியவை ஒரே 32-byte vertex — position, diameter, color —; ஒரே shader pair மூலம், stroke-ன் arc length வழியாக ஒரு point இடைவெளியில் அமைந்த GPU-rasterized circles ஆக வரையப்படுகின்றன.
![]()
ஒரு point இடைவெளியில், வட்டங்களின் சங்கிலி கணிதரீதியாக முழுமையான capsule-இலிருந்து சுமார் 0.075 points விலகுகிறது — எங்கள் canvas density-யில் ஒரு pixel-ன் ஐந்தில் ஒரு பங்கு. அதற்குப் பதிலாக, மூன்று கருவிகளும் ஒரே code path-ஆகச் சுருங்குகின்றன; GPU தனக்குச் சிறந்ததைச் செய்கிறது.
இந்த யோசனையைச் சுற்றி architecture எளிமையானது. Committed ink ஒரே 4096² texture-ல் உள்ளது. UIScrollView தொடர்ந்து இருக்கிறது, ஆனால் pure gesture engine-ஆக மட்டும் குறைக்கப்பட்டுள்ளது: அதன் contentOffset மற்றும் zoomScale ஒவ்வொரு frame-லும் ஒரு viewport uniform-க்கு feed ஆகின்றன, எனவே panning மற்றும் zooming எதையும் எழுதுவதில்லை. ஒவ்வொரு frame-லும் ஐந்து draws:
flowchart TB
subgraph frame["Every frame: five draws"]
direction TB
paper["1 · paper blit"] --> ink["2 · committed ink"]
ink --> live["3 · live stroke"]
live --> sel["4 · selection"]
sel --> dash["5 · lasso dashes"]
end
commit["stroke commit<br/>append stamps"] --> tex[("ink texture<br/>4096² render target")]
replay["regional replay<br/>erase · delete · move · undo"] --> tex
tex -. "sampled or re-drawn" .-> ink
திருத்தங்கள் texture-க்கு நேரடியாக எழுதுகின்றன. ஒரு stroke-ஐ commit செய்வது அதன் stamps-ஐ append செய்கிறது. Erasing, deleting, moving, undoing ஆகியவை ஒரு scissor rectangle-ன் கீழ் பாதிக்கப்பட்ட region-ஐ replay செய்கின்றன: region-ஐ clear செய், அதை intersect செய்யும் strokes-ஐ மீண்டும் வரை, அவ்வளவுதான். Partial erasure முந்தைய பதிவின் ownership semantics-ஐத் தக்கவைக்கிறது — ஒரு erasure, அது ink-ஐ அகற்றும் stroke-க்கே சொந்தமானது — ஒவ்வொரு erased stroke-ஐயும் ஒரு scratch texture-ல் வரைந்து, அதன் சொந்த erasure paths-ஐ destination-out blending-உடன் (
இவை அனைத்தையும் தொடங்கிய selection இப்போது point sprites ஆகவும் வரையப்படுகிறது. அதை இழுப்பது ஒரு uniform offset-ஐ மட்டும் புதுப்பிக்கிறது. பூஜ்ய texture writes, பூஜ்ய tile invalidations — அந்த அலை கட்டமைப்புரீதியாக மறைந்துவிட்டது; குறைக்கப்படவில்லை.
காவலர்: ஒரு pixel diff
நாங்கள் Core Graphics renderer-ஐ நீக்கவில்லை. அதை offline reference implementation-ஆகக் குறைத்தோம்; device-ல் capture செய்யப்பட்ட உண்மையான stroke data மீது ஒவ்வொரு Metal மாற்றமும் அதற்கு எதிரான pixel comparison-ஐக் கடக்க வேண்டும். ஏற்பு அளவுகோல் “identical pixels” அல்ல — இரண்டு சரியான rasterizers anti-aliased edges வழியாக சில gray levels அளவு நியாயமாக வேறுபடலாம். இந்த gate கட்டமைப்பைச் சார்ந்தது: missing ink இல்லை, offset இல்லை, color drift இல்லை, மேலும் ink-இலிருந்து தொலைவில் எங்கும் பெரிய வேறுபாடு இல்லை.
![]()
இந்த harness, offline renderer-ஐ உருவாக்கும்போது நாங்கள் சந்தித்த ஐந்து bugs-களில் நான்கைப் பிடித்தது; அனைத்தும் output-ஐ pixel level-க்கு crop செய்து கண்டறியப்பட்டன: Swift/Metal struct stride mismatch (28 bytes versus 32, ஏனெனில் Metal float4-ஐ 16-க்கு align செய்கிறது — screen முழுவதும் color blocks ஆனது), [[point_size]]-ஐ fragment shader-ல் varying ஆக வாசிக்க முடியாதது (ஒவ்வொரு stamp-மும் square ஆக வந்தது), ஒரே command buffer-ல் இரண்டு render encoders இணைந்து இருந்தது (எல்லாம் கருப்பானது), மற்றும் வேகமான strokes-ன் முதல் millimeter கண்ணுக்குத் தெரியாமல் போகச் செய்த missing start dab.
ஆறு படிகள், ஒரு மறுஎழுத்து அல்ல
Migration plan ஆறு independently shippable படிகளைக் கொண்டது: pixel diff-ஐக் கடக்கும் offline renderer; zero visual change கொண்ட display shell; GPU-ல் live stroke; GPU-ல் selection; texture-க்கு நேரடியாக எழுதும் mutations; high-zoom vector re-drawing (“zero visual change” அதைத் தேவைப்படுத்தியதால் இரண்டாம் படியில் இணைக்கப்பட்டது). ஒவ்வொரு படியும் மேசையில் இருந்த iPad Pro-வில் ஒரு மனிதர் எழுதுதல், அழித்தல், zoom செய்தல், இழுத்தல் ஆகியவற்றைச் சோதிப்பதுடன் முடிந்தது — simulator அல்ல, screenshot diff அல்ல.
Automated check அனைத்தும் தவறவிட்ட மூன்று bugs-ஐ device பிடித்தது. 100% zoom-க்கு மேல், strokes இருமுறை வரையப்பட்டன — கீழே மென்மையான texture, மேலே கூர்மையான sprites — மனிதர் சில நொடிகளில் கவனித்த மங்கலான blur போலத் தோன்றியது. ஒரு stroke-ஐ commit செய்யும்போது ஒரு frame மினுங்கியது, ஏனெனில் பழைய overlay texture update-உடன் ஒத்திசைவின்றி cross-fade ஆகி மறைந்தது. 170% zoom-க்கு மேல், ஒவ்வொரு note-ம் மறைந்தது: visibility-culling rectangle தனது scaled coordinate space-ல் contentOffset-ஐப் பயன்படுத்தியதால், zoom செய்யும்போது strokes-இலிருந்து விலகியது. மூன்றும் ஒரு வரியிலிருந்து ஒரு function வரையிலான fixes; அவற்றில் எதுவும் நாங்கள் முன்கூட்டியே எழுதியிருக்கக்கூடிய எந்த test-லும் இல்லை, ஏனெனில் அவற்றைத் தேட வேண்டும் என்று எங்களுக்குத் தெரியவில்லை. UI-first consumer app-ல் மனிதர் loop-ல் இருப்பதன் காரணம் இதுதான்.
Kimi K3-உடன் வேலை செய்வது எப்படி இருக்கிறது
முதலில், வேகம். “discuss, write, build, install, look” என்ற loop நிமிடங்களில் ஓடியது; வேகமாகப் பதிலளிக்கும் model ஒரு நாளில் நீங்கள் afford செய்யக்கூடிய loop-களின் எண்ணிக்கையை மாற்றுகிறது.
இரண்டாவதாக, இது over-engineer செய்வதில்லை. இந்த codebase வெளிப்படையான house rules-ல் இயங்குகிறது — launch-க்கு முன் backward-compatibility scaffolding இல்லை, ஒரு device அது அவசியம் என்று நிரூபித்தால் மட்டுமே complexity — மேலும் K3 நினைவூட்டாமலேயே அவற்றைப் பின்பற்றுகிறது. அது “பின்னர் பயன்படும்” என்று spatial indexes சேர்க்கவில்லை, ஒவ்வொரு call-ஐயும் defensive checks-ல் சுற்றவில்லை, speculative abstraction செய்யவில்லை. இதற்கு prompt செய்வது, house rules-ஐப் படித்து அவற்றை உண்மையாக நம்பும் திறமையான சக ஊழியருடன் வேலை செய்வது போன்றது.
மூன்றாவதாக, tools கொடுத்தால் இது அவற்றை ஆர்வமாகப் பயன்படுத்துகிறது. நாங்கள் image utilities-ஐ இணைத்தோம் — view, ஒரு pixel region-க்கு crop, resize — மேலும் மேலே குறிப்பிடப்பட்ட ஐந்து harness bugs-ஐக் கண்டறிய model தனது renderer output-ஐத் தானாக crop செய்யத் தொடங்கியது. Tool இருப்பது, பார்க்க வேண்டும் என்பதை அதற்கு நினைவூட்டியது.
மறுபக்கம்: notes மறையச் செய்த coordinate-space bug உட்பட, இந்தக் கதையில் உள்ள பெரும்பாலான bugs-ஐ K3 எழுதியது. அதன் வரம்புகள் உண்மையானவை. வேலையைப் பாதுகாப்பானதாக்கியது model சரியாக இருப்பது அல்ல; harness rendering drift-ஐப் பிடித்ததும், மனிதர் feel-ஐப் பிடித்ததும்தான். இருந்தாலும், அன்றாடப் பயன்பாட்டில் நாங்கள் பயன்படுத்தும் frontier closed models — Opus-class systems — இலிருந்து இதை நம்பகமாக வேறுபடுத்த முடியவில்லை. சில அம்சங்களில் இது தெளிவாகச் சிறந்தது: வேகமாகவும், codebase-ஐ defensive design-ஆல் நிரப்பும் மனப்போக்கு மிகவும் குறைவாகவும் இருந்தது.
இனிமேல் நாங்கள் எப்படிக் கட்டமைக்க விரும்புகிறோம்
நாங்கள் big-spec agentic development-ஐ முடித்துவிட்டோம் — ஒரு model-க்கு பெரிய specification-ஐக் கொடுத்து, அது உருவாக்கியதை அப்படியே ஏற்றுக்கொள்ளும் பாணி. இதன் failure mode மோசமான code அல்ல; யாருக்கும் புரியாத code.
இங்கே வேலை செய்ததும், இனிமேல் வைத்துக்கொள்ளப் போவதும் இதுதான்: சிறிய படிகள்; ஒவ்வொன்றும் தொடங்குவதற்கு முன் விவாதிக்கப்படும், கட்டமைப்பதற்கு முன் மனிதரால் புரிந்துகொள்ளப்படும், அது இயங்கவிருக்கும் device-ல் சரிபார்க்கப்படும். Model-ன் வேலை விரைவாகவும் துல்லியமாகவும் இருப்பது, மேலும் uncertainty பற்றி நேர்மையாக இருப்பது. Human-ன் வேலை judgment, taste, மற்றும் e2e verification — குறிப்பாக UI-first consumer software-க்கு, ஏனெனில் “சரியானது” எப்படி உணர வேண்டும் என்பதை specification விவரிக்க முடியாது. Fireworks-ல் இயங்கும் Kimi K3 இந்த loop-க்கு சரியாகப் பொருந்துகிறது: loop-ஐ இறுக்கமாக வைத்திருக்கப் போதுமான வேகம், படிகளைச் சிறியதாகவும் சுத்தமாகவும் வைத்திருக்கப் போதுமான திறன்.
அலை மறைந்துவிட்டது, pipeline இரண்டு யோசனைகளுக்குப் பதிலாக ஒன்றாகிவிட்டது, மேலும் எங்களை அங்கே கொண்டு வந்த process தொடர்ந்து இருக்கும்.