เทคนิคการโค้ดลายมือของฉัน
(amygoodchild.com)สคริปต์แบบบล็อก
- บทความก่อนหน้านี้พูดถึงตัวอักษรภาษาอังกฤษในเวอร์ชันพิมพ์บล็อก
- สรุปแล้ว ทำขึ้นผ่านกระบวนการดังนี้:
- เขียนโค้ดกำหนดจุดสำคัญของเส้นทางสำหรับตัวอักษรแต่ละตัว (ประมาณ 10 จุดต่อตัวอักษร)
- ใช้อัลกอริทึมเส้นโค้งของ Chaikin เพื่อทำให้เส้นทางเรียบขึ้น
- แปลงเส้นทางให้เป็นรูปทรงที่มีความหนาแปรผัน
- ใช้ p5js วาดเส้นทางของรูปทรง
- หน้าตาออกมาเป็นแบบนี้
- บทความเกี่ยวกับวิธีสร้างประโยคด้วยระบบนี้จะตามมาเร็ว ๆ นี้ ฝากสมัครรับจดหมายข่าวเพื่อรอติดตาม
- เดิมทีการกำหนดเส้นทางของตัวอักษรต้องทำด้วยมือมาก โดยเขียนตำแหน่งลงในโค้ดและปรับจุดต่าง ๆ จนกว่าตัวอักษรจะดูถูกต้อง
- ตอนทำลายมือแบบตัวเขียน ฉันทำให้กระบวนการนี้ง่ายขึ้น
การออกแบบตัวอักษร
- ฉันสร้างเครื่องมือสำหรับกำหนดและแสดงผลจุดสำคัญของเส้นทาง เพื่อให้เข้าถึงได้ง่ายใน p5js editor
- มันแสดงตัวอักษรตัวอย่างและมีพื้นที่สำหรับออกแบบตัวอักษรใหม่
- ขั้นตอนถัดไปมีดังนี้:
- คลิกวางจุดสำคัญของเส้นทาง แล้วเส้นทางโค้งแบบ Chaikin ที่ได้จะถูกแสดง
- กด
pเพื่อสลับไปยังโหมดแก้ไข - เลือกจุดแล้วลากไปยังตำแหน่งที่ต้องการ
- กด
enterเพื่อพิมพ์เส้นทางออกสู่คอนโซล
- ฉันทำตัวเลือกไว้ 2-3 แบบสำหรับตัวอักษรแต่ละตัว
- เส้นทางที่ได้มีลักษณะดังนี้:
[{x:0.7,y:22.5},{x:8.2,y:18.1},{x:8.9,y:11.2},{x:3.7,y:11.4},{x:1.7,y:18.9},{x:8.4,y:22.4},{x:17.7,y:22.0}] - ฉันอยากใช้ลายมือของตัวเองเป็นแนวทาง จึงเขียนตัวอย่างทั้งตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ แล้วโหลดภาพเข้าไปในเครื่องมือโดยตรงเพื่อไล่ตามเส้น
- ใช้ปุ่ม w/a/s/d เพื่อจัดภาพให้อยู่ในตำแหน่งที่ถูกต้อง และใช้ปุ่ม r/e เพื่อซูมเข้า/ออก
- ตัวเลขคือพิกัด x y สำหรับวางส่วนนั้นในหน้าต่างสร้างตัวอักษร
- หลังจากสร้างเส้นทางทั้งหมด วาดเส้นโค้ง และแปลงเป็นรูปทรงที่มีความกว้างแปรผันแล้ว ตัวอักษรแต่ละตัวมีหน้าตาแบบนี้
ทำให้เป็นตัวเขียน
- บางครั้งการเชื่อมตัวอักษรเข้าด้วยกันก็ง่าย เพียงไปต่อจากเส้นทางจุดสำคัญของตัวหนึ่งไปยังเส้นทางถัดไปโดยตรง แล้วใช้งานเส้นโค้ง Chaikin กับทั้งหมดในครั้งเดียว
- แต่คู่ตัวอักษรบางคู่เข้ากันได้ไม่ดี
- ตัวอย่างเช่น ในคู่ na จุดสุดท้ายของ n อยู่ต่ำ แต่จุดแรกของ a อยู่สูง ทำให้เกิดเส้นทางที่พาดทแยงผ่าน a และดูเหมือน e
- ในคู่ ti นั้น t จบเหนือเส้นฐาน และ i เริ่มที่เส้นฐาน ทำให้เกิดสันที่ดูไม่เป็นธรรมชาติ
- เพื่อแก้ปัญหานี้ เราสามารถเพิ่มจุดพิเศษที่จุดเริ่มต้นของ a และลบสองจุดสุดท้ายของ t ได้
- แต่เราไม่สามารถเปลี่ยนตัวอักษรแบบนี้ได้ในทุกสถานการณ์
- ตัวอย่างเช่น ถ้า a อยู่ต้นคำ จุดที่เพิ่มเข้ามาจะอยู่ผิดที่ และถ้ามันตามหลังตัวอักษรอย่าง w ก็จะเกิดเส้นที่พาดผ่าน a ในอีกแบบหนึ่ง
- ถ้า t จับคู่กับ k มันก็จะเสียรูป
- จุดเริ่มต้นและจุดสิ้นสุดของเส้นทางตัวอักษรจึงต้องเปลี่ยนไปตามตำแหน่งสัมพันธ์กับตัวอักษรอื่น
- ตอนแรกฉันตั้งใจจะระบุคู่ที่ “มีปัญหา” เป็นกรณีเฉพาะแล้วเขียนกฎให้แต่ละคู่ แต่สุดท้ายฉันเพิ่มตัวเลขไว้ที่ต้นและท้ายของแต่ละเส้นทางเพื่อบอกว่า:
- ไม่ได้เชื่อมกับตัวอักษรอื่น (0)
- เชื่อมกับตัวอักษรอื่นแถวเส้นฐาน (1)
- เชื่อมกับตัวอักษรอื่นเหนือเส้นฐานขึ้นมาเล็กน้อย (2)
- เชื่อมกับตัวอักษรอื่นแถว x-height (3)
- ตัวอย่าง:
- ตอนนี้เส้นทางของแต่ละตัวอักษรมีหน้าตาแบบนี้ สังเกตเลขหนึ่งหลักที่ต้นและท้าย:
[0,{x:12.2,y:13.2},{x:13.5,y:11.0},{x:6.2,y:8.4},{x:1.1,y:13.0},{x:1.8,y:19.0},{x:7.0,y:23.4},{x:15.2,y:23.6},{x:18.4,y:22.1},1] - ฉันทดสอบทุกคู่ตัวอักษรแล้ว
- ตรงนี้คุณจะเห็นว่าฉันมีตัวเลือกเส้นทางหลายแบบสำหรับแต่ละตัวอักษร และตัวอักษรจะถูกแก้ไขไปตามตัวข้างเคียง
- ตามอุดมคติแล้ว ฉันอยากมีตัวเลือกเส้นทางอย่างน้อย 5-6 แบบต่อตัวอักษรแต่ละตัว แต่ต้องหาสมดุลกับขนาดไฟล์ด้วย
การสร้างคำ
- เมื่อมีการสร้างคำ:
- สำหรับแต่ละตัวอักษร จะมีการเลือกเส้นทางพื้นฐานจากตัวเลือก 2-3 แบบ
- ข้อมูลเกี่ยวกับปลายของเส้นทางจะถูกส่งต่อไปยังตัวอักษรข้างเคียง (เนื่องจากตัวเลือกเส้นทางต่าง ๆ ของตัวอักษรเดียวกันอาจมีปลายทางต่างกัน จึงต้องเลือกเส้นทางของตัวอักษรทั้งหมดก่อน)
- จากนั้นเส้นทางพื้นฐานจะถูกปรับให้ตอบสนองต่อตัวอักษรเพื่อนบ้าน เช่น ถ้าความสูงปลายของตัวอักษรก่อนหน้าเป็น 2 ก็อาจลบ 1 จุดที่จุดเริ่มต้นของเส้นทางนี้ หรือถ้าความสูงต้นของตัวอักษรถัดไปเป็น 1 ก็อาจเพิ่มจุดพิเศษในตำแหน่งหนึ่ง
- ฟังก์ชันปรับแต่งอาจซับซ้อนอยู่บ้าง ตัวอย่างเช่น ฟังก์ชันสำหรับตัวอักษร q มีดังนี้:
// ip = path // pc = previous letter ending info // nc = next letter starting info // n = index of chosen path for this letter adjust: (ip, pc, nc, n) => { // add a break to the end of this letter with a 70% chance if (rand() < 0.7 ) ip.splice(-1, 1, 0); // if [2] from the 4 options has been chosen for this path if (n < 2) { // if previous letter ends at 3 replace first two points with different point if (pc == 3) ip.splice(1, 2, {x:10,y:12}); // otherwise if not 0 add a point to the start else if (pc > 0) ip.splice(1, 0, {x:10,y:20}); } // if there is no break between this and next letter (0) if (nc > 0 && ip[ip.length-1] != 0){ // replace last two points with different point ip.splice(-3, 2, {x:16,y:34}); } } - แต่บ่อยครั้งมันก็สั้น ตัวอย่างเช่น ฟังก์ชันสำหรับตัวอักษร n มีดังนี้:
adjust: (ip, pc, nc) => { // if next letter starts at 3 create a break at random or move the last point if (nc == 3) rand() < 0.3 ? ip.splice(-1, 1, 0) : ip.splice(-2, 1, {x:17,y:23.8}); } - ถัดจากนั้น เส้นทางพื้นฐานของตัวอักษรทั้งหมดจะถูกเชื่อมเข้าด้วยกัน โดยในขั้นตอนนี้จะมองข้ามค่า 1, 2, 3 ในเส้นทาง แต่ทุกครั้งที่เจอ 0 จะเริ่มเส้นทางใหม่เพื่อสร้างจุดขาด
- จากนั้นจึงทำให้เส้นทางเป็นเส้นโค้ง แปลงเป็นรูปทรงที่มีความกว้างแปรผัน และเพิ่มความสั่นเล็กน้อยด้วย Perlin noise แล้วลายมือแบบตัวเขียนจะออกมาหน้าตาแบบนี้
- บทความเกี่ยวกับวิธีสร้างประโยคนี้จะตามมาเร็ว ๆ นี้ ฝากสมัครรับจดหมายข่าวเพื่อรอติดตาม
- เพื่อความสนุก นี่คือการเปรียบเทียบลายมือที่โค้ดขึ้นแล้วนำไปรันผ่าน plotter กับลายมือจริงแบบวางคู่กัน
หนักแค่ไหน?
- คลาสตัวอักษรสำหรับพิมพ์บล็อกมีขนาด 9.7kb
- ตอนนี้คลาสตัวอักษรแบบตัวเขียนมีขนาด 26.1kb (หลังบีบอัด)
- คลาสนี้มีหลายเส้นทางสำหรับตัวอักษรแต่ละตัวและมีฟังก์ชันปรับจุด จึงมีขนาดใหญ่กว่า แต่ก็มีวิธีประหยัดพื้นที่แบบอื่นอยู่บ้าง
- น่าจะยังประหยัดได้อีก ฉันไม่ใช่จอมเวท code golf แต่ก็มีไอเดียบางอย่าง
- ตัวอย่างเช่น ตอนนี้ตัวอักษรถูกออกแบบโดยยึดขนาดฟอนต์พื้นฐาน 20 แล้วค่อยสเกลตามทีหลัง นั่นหมายความว่าหลายจุดถูกกำหนดเป็นค่าอย่าง x: 14.5 แต่ถ้าเปลี่ยนขนาดพื้นฐานเป็น 200 ก็จะกำหนดจุดเป็น 145 ได้และตัดเลขทศนิยมทิ้ง การเปลี่ยนนี้ต้องทำอย่างระมัดระวัง จึงอยู่ในรายการสิ่งที่จะทำภายหลัง
วิธีใช้งาน
- จุดประสงค์หลักของลายมือนี้คือใช้กับชื่อเรื่อง ป้ายกำกับ และโน้ตขยุกขยิกในไดอะแกรมที่ฉันกำลังทำอยู่
- แต่การเล่นกับตัวข้อความเองก็สนุกมากเช่นกัน
- เพราะฉันเข้ารหัสเส้นทางไว้ จึงสามารถเล่นกับเส้นทางได้แทนการใช้ฟอนต์ เช่น เปลี่ยนตำแหน่งตัวอักษร หรือเปลี่ยนความหนาของตัวอักษรแต่ละตัว
- ขั้นต่อไป ฉันวางแผนจะนำลายมือนี้ไปรวมเข้ากับไดอะแกรม แต่ก็มีแผนจะทำบางอย่างที่โฟกัสกับตัวข้อความเองด้วย มันสวยมากและมีความเป็นไปได้อีกมาก
ความเห็นของ GN⁺
- บทความนี้นำเสนอตัวอย่างที่น่าสนใจของกระบวนการแปลงลายมือให้เป็นดิจิทัลด้วย JavaScript และ p5.js ซึ่งอาจเป็นโอกาสที่ดีสำหรับวิศวกรซอฟต์แวร์ในการฝึกทักษะการเขียนโค้ดผ่านโปรเจกต์เชิงสร้างสรรค์
- คุณสามารถเรียนรู้วิธีนำอัลกอริทึมทางคณิตศาสตร์อย่างเส้นโค้งของ Chaikin ไปใช้ในโปรเจกต์จริงได้ ซึ่งช่วยเพิ่มความเข้าใจด้านกราฟิกโปรแกรมมิง
- คุณสามารถเรียนรู้วิธีจัดการกับตรรกะที่ซับซ้อนอย่างฟังก์ชันปรับเส้นทาง ซึ่งเป็นทักษะสำคัญในการเพิ่มความยืดหยุ่นและการขยายต่อของโค้ด
- โปรเจกต์นี้ยังจัดการกับปัญหาเชิงปฏิบัติอย่างการปรับขนาดไฟล์ให้เหมาะสม ซึ่งเป็นสิ่งสำคัญในการพัฒนาซอฟต์แวร์จริง
- เมื่อนำเทคนิคนี้ไปใช้ ควรคำนึงว่าการกำหนดเส้นทางและการเขียนฟังก์ชันปรับแต่งอาจใช้เวลามาก แต่ผลลัพธ์ที่ได้จะให้รูปแบบข้อความที่มีความเป็นเอกลักษณ์และเฉพาะตัวอย่างมาก
ยังไม่มีความคิดเห็น