Bir çizgi eğri değil. Eşit aralıklarla dizilmiş noktalar — parmağın ne kadar hızlı geçtiği fark etmez, her nokta bir öncekinden tam aynı uzaklıkta durur. Kıpırtı bunun üstünde çalıştığı için de çizginin bir ucu diğerinden daha çok titremez.
Parmak ya da kalem her karede birkaç piksel birden atlar; addPoint() aradaki boşluğu SPACING adımlarıyla doldurur ve her noktaya bir basınç yazar. Kalem varsa basınç gerçek, fare varsa 1. Bundan sonrası hep bu dizi üzerinde çalışır.
El tek bir hızda titremez. Yavaş bir savrulma çizginin tamamını taşır, orta hızda bir salınım onu dalgalandırır, ince bir titreme kenarını kemirir. Üçü toplanınca çıkan şey gürültü değil, el oluyor.
Üç ölçek, ağırlıkları .55 / .30 / .15, RMS'lerine bölünüyor — yani KIPIRTI sürgüsü hâlâ eskiden ne demekse onu diyor. En yavaş katman boil kareleri arasında duruyor, en ince olan her karede yeniden atılıyor: çizimin iskeleti sabit kalırken mürekkebi yeniden dökülüyor. hand(), src/brushes.js.
Hiçbir şey hareket etmiyor. Aynı çizgi üç ayrı şekilde çiziliyor ve aralarında gidip geliniyor — elle çizilmiş animasyonun yüz yıldır yaptığı şey. Soldaki üç kare, sağdaki bunların dönüşü.
Saat Math.floor(now · speed · fps) ile tik'e yuvarlanıyor, sonra mod 3. Aynı tik iki kere gelirse aynı piksel çıkıyor — editör tam da bunun üstüne kurulu, aynı tikte ekranı hiç yeniden çizmiyor. Çok geçişli fırçalar (ESKİZ, HAYALET) komşu kareleri üst üste bindirdiği için döngüye girmiyor: 3'ün mod'u onlara her tikte aynı üçlüyü verir ve çizim ölürdü.
Fırça çizginin nasıl hareket ettiğini söyler. Malzeme onun neyden yapıldığını. İki ayrı soru, ve uzun süre tek cevabı vardı: her çizgi yuvarlak uçlu tek renk bir yoldu. Artık aynı omurga kurşun kalem de olabiliyor, suluboya da.
Bir malzeme hangi fırçayı boyadığını asla öğrenmiyor; kendisine bir omurga ve bir takım veriliyor, o da kendi kelimeleriyle cevap veriyor: ribbon (iki ray arasını dolduran bant, çizilen çizgi değil), rim, grit, streaks. KURŞUN kenarının dışına kırıntı savuruyor ve kâğıt renginde kareler ısırıyor; MÜREKKEP kuruyunca bandı deliyor. DÜZ, app'in ilk günden beri çizdiği çizgi — varsayılan o, çünkü bugüne kadar kaydedilmiş her çizim ondan yapılmış.
On dört fırça, ve hiçbiri bir doku değil. Her biri çizginin noktalarını her karede nereye iteceğini söyleyen küçük bir fonksiyon: YAY ağırlık merkezine göre şişip iniyor, DALGA boyunca bir dalga yürütüyor, KOŞUCU çizgiyi silip üstünde tek bir nokta koşturuyor.
Bir fırça disp(p, i, t, A, info) yazıyor — nokta, dizideki sırası, zaman, genlik, ve istenirse yerel normal ile ağırlık merkezi. Yeni bir fırça = bu listeye bir kayıt. Kaydetme, feed, GIF çıkışı, önizleme, hepsi listeyi okuyor.
Her çizgi kendi tohumunu, hızını ve kare oranını çizildiği anda donduruyor. Bu bir ayrıntı değil, tek önemli karar: hepsi aynı saatte kıpırdasaydı çizim canlı değil, video gibi okunurdu.
Tohum çizgiyle birlikte kaydediliyor, o yüzden yayınladığın çizim senin ekranında nasıl kıpırdıyorsa başkasınınkinde de öyle kıpırdıyor. Aşağıdaki altı çizgi aynı fırça, aynı yol — sadece seed ve fps farklı.
Çizim tek bir resim değil. Şerit üstünde kareler var, her karenin kendi katmanları, ve çizerken bir öncekinin hayaleti altta duruyor — soğan zarı. Kareler dururken bile kıpırdıyor, çünkü kıpırtı animasyonun değil çizginin özelliği.
Kareler film.frames içinde kendi katman kümeleri olarak duruyor; doc her zaman düzenlenen kareyi gösteriyor. GIF ve MP4 çıkışı da aynı renderDoc()'tan geçiyor, yani kaydettiğin şey ekranda gördüğün şey.
Kaydedilen tek şey sayılar. Noktalar, fırça, malzeme, boyut, genlik, hız, fps ve tohum — resim değil. Aynı sayılar her makinede aynı çizimi geri kuruyor, kıpırtısı da dahil.
Tel biçimi düz bir sayı dizisi: 400 noktalı bir çizgi ~30 kB JSON'dan ~4 kB'a düşüyor, ki bu yüklenen bir feed ile yüklenmeyen arasındaki fark. Malzeme sadece varsayılan değilse yola çıkıyor, böylece malzemelerden önce yayınlanmış her çizim baytı baytına aynı paketleniyor.