- Exponential smoothing เป็นเทคนิคเรียบง่ายที่ใช้ได้กว้างกับแอนิเมชันที่ต้องเคลื่อนไปหาค่าเป้าหมายอย่างนุ่มนวล เช่น ปุ่มสลับ กล้อง องค์ประกอบ UI และระดับเสียงของออดิโอ
- สมการหลักคือ
position += (target - position) * (1 - exp(- speed * dt)) และตอบสนองต่อ การเปลี่ยนเป้าหมาย ได้อย่างเป็นธรรมชาติ โดยอาศัยเพียงตำแหน่งปัจจุบันกับตำแหน่งเป้าหมาย
- การเคลื่อนที่เชิงเส้นและ easing แบบทั่วไปมักต้องจัดการเรื่องคลิกระหว่างทาง อินพุตกล้องที่รวดเร็ว ค่า
dt ที่มาก ทำให้เกิดการกระโดด การสั่น หรือคิวอินพุต แต่ exponential smoothing ลดความซับซ้อนด้วยโครงสร้างเดียวกัน
1 - exp(- speed * dt) มาจาก คำตอบของสมการเชิงอนุพันธ์ ที่สมการอัปเดตแบบสัดส่วนกำลังแก้อยู่ โดยเมื่อ dt เล็กจะเกือบเหมือนสูตรเดิม และเมื่อ dt ใหญ่ก็ยังหลีกเลี่ยง overshoot ได้
- แม้จะไปไม่ถึงค่าเป้าหมายแบบแม่นตรงทางคณิตศาสตร์ แต่ด้วยข้อจำกัดของความแม่นยำแบบ floating point และขีดจำกัดการรับรู้การเปลี่ยนแปลงของผู้ใช้ ในแอนิเมชันจริงก็ถือว่าเสร็จสมบูรณ์ได้เพียงพอ
ปัญหาที่เห็นได้ชัดจากปุ่มสลับ
- ตำแหน่งสวิตช์ของปุ่มสลับคำนวณได้อย่างง่ายดายด้วย
turned_on ? max_x : min_x แต่เมื่อสถานะเปลี่ยน ตำแหน่งจะย้ายแบบฉับพลันทันที ทำให้ ขาดความมีชีวิตชีวา
- แอนิเมชันแบบเชิงเส้นมักเขียนโดยอัปเดตตำแหน่งด้วยความเร็วคงที่แล้วจำกัดให้อยู่ในช่วง
position.x += (turned_on ? 1 : -1) * speed * dt;
position.x = clamp(position.x, min_x, max_x);
- การเคลื่อนที่ด้วยความเร็วคงที่ทำให้ตำแหน่งเป็น ฟังก์ชันเชิงเส้น ของเวลา จึงอาจดูแข็งทื่อ
- หากใส่ easing function เพิ่มเข้าไป ก็ทำให้การเคลื่อนไหวดูนุ่มนวลขึ้นได้
- cubic smoothstep แบบคลาสสิก:
3t² - 2t³
- easing แบบรากที่สอง:
sqrt(t)
smoothstep มีสมมาตร 1 - f(t) = f(1 - t) จึงใช้โค้ดเดียวกันได้ทั้งแอนิเมชันไปข้างหน้าและย้อนกลับ
- ส่วน
sqrt ต้องใช้สูตรต่างกันตามทิศทาง
- ตอนเปิด:
sqrt(t)
- ตอนปิด:
1 - sqrt(1 - t)
sqrt เริ่มต้นเร็วแล้วค่อย ๆ ช้าลงเมื่อเข้าใกล้เป้าหมาย แต่แม้จะเป็นเพียงปุ่มสลับ 2 สถานะ ก็ยังต้องมี การจัดการสถานะ อย่าง t ทิศทาง และการคำนวณ easing
- หากผู้ใช้คลิกซ้ำระหว่างที่แอนิเมชันยังเล่นอยู่ วิธี easing แบบเดิมอาจทำให้เกิด ความไม่ต่อเนื่อง จากการที่ตำแหน่งกระโดดทันที
สูตรของ exponential smoothing
- Exponential smoothing คือการกำหนดตำแหน่งเป้าหมายไว้ แล้วค่อย ๆ ดึงตำแหน่งปัจจุบันเข้าไปหาเป้าหมายทีละนิด
target = (state.value ? max_x : min_x);
position.x += (target - position.x) * (1 - exp(- dt * speed));
- ปริมาณที่อัปเดตถูกกำหนดจาก
target - position.x ซึ่งเป็นความต่างระหว่างตำแหน่งปัจจุบันกับเป้าหมาย
1 - exp(- dt * speed) คือ ค่าสัมประสิทธิ์การอินเตอร์โพเลต ที่กำหนดว่าแต่ละเฟรมจะขยับเข้าใกล้เป้าหมายมากแค่ไหน
- แม้เป้าหมายจะเปลี่ยนกลางทาง ก็สามารถเคลื่อนไปยังเป้าหมายใหม่ต่อได้ทันที โดยไม่ต้องเก็บเวลาแอนิเมชันหรือสถานะทิศทางแยกต่างหาก
- ในตัวอย่างปุ่มสลับ มันให้ความรู้สึกเริ่มเร็วและช้าลงเมื่อใกล้เป้าหมายคล้าย easing แบบ
sqrt แต่ลดปัญหาการกระโดดเมื่อมีการคลิกกลางทาง
ข้อดีที่เด่นขึ้นอีกในงานเคลื่อนกล้อง
- ปัญหาเดียวกันนี้เกิดขึ้นกับกล้องที่เคลื่อนที่บนแผนที่เช่นกัน
- หากทำอินเตอร์โพเลตด้วยความเร็วคงที่แบบง่าย ๆ ก็มักใช้เครื่องหมายของทิศทางเป้าหมายในแต่ละแกน
position.x += sign(target.x - position.x) * speed * dt;
position.y += sign(target.y - position.y) * speed * dt;
- เมื่อถึงจุดสิ้นสุดของแอนิเมชัน เครื่องหมายของ
target - position อาจสลับไปมาระหว่างบวกกับลบ ทำให้เกิด การสั่น
- เพื่อป้องกันสิ่งนี้ จำเป็นต้องมีฟังก์ชันอัปเดตแยกที่จำกัด
delta ให้อยู่ในช่วง max_delta
float update(float & value, float target, float max_delta)
{
float delta = target - value;
delta = min(delta, max_delta);
delta = max(delta, -max_delta);
value += delta;
}
- หากจะใช้ cubic easing กับการเคลื่อนกล้อง ก็ต้องใส่อีเวนต์การเคลื่อนที่ที่ร้องขอไว้ในคิวแล้วประมวลผลทีละรายการ ทำให้โครงสร้างซับซ้อนขึ้น
- วิธีที่เพิกเฉยต่ออินพุตของผู้ใช้ระหว่างแอนิเมชันจะให้ความรู้สึกน่าหงุดหงิดมากสำหรับผู้ใช้
- ถ้าใช้ exponential smoothing ก็สามารถจัดการการเคลื่อนกล้องได้ด้วยโค้ดแทบจะเหมือนกับปุ่มสลับ
position.x += (target.x - position.x) * (1.0 - exp(- speed * dt));
position.y += (target.y - position.y) * (1.0 - exp(- speed * dt));
- หากผู้ใช้คลิกอย่างรวดเร็ว ความต่างระหว่างเป้าหมายกับตำแหน่งปัจจุบันจะมากขึ้น จึงทำให้กล้อง เร็วขึ้นอย่างเป็นธรรมชาติ
ทำไมต้องเป็น 1 - exp(- speed * dt)
- สมการอัปเดตแบบสัดส่วนอย่างง่ายเขียนได้ดังนี้
position += (target - position) * speed * dt;
- สมการนี้เคลื่อนที่เร็วขึ้นเมื่อความต่างระหว่างเป้าหมายกับตำแหน่งปัจจุบันมากขึ้น และไม่ต้องมีสถานะเพิ่มเติมนอกจากตำแหน่งปัจจุบันกับตำแหน่งเป้าหมาย
- หากเขียนด้วย
lerp ก็จะได้สมการเดียวกัน
position = lerp(position, target, speed * dt);
- เมื่อ
speed * dt เข้าใกล้ 0 จะเคลื่อนที่ช้า และเมื่อเข้าใกล้ 1 จะเข้าใกล้เป้าหมายอย่างรวดเร็ว
- ถ้า
speed * dt มากกว่า 1 จะเกิด overshoot คืออินเตอร์โพเลตเลยผ่านเป้าหมายไป
- ในตัวอย่าง เมื่อ
speed = 220 และ dt = 1 / 125 จะได้ speed * dt มากกว่า 1 ทำให้เกิดการสั่น
- ถ้า
speed * dt < 2 ความต่างเชิงสัมบูรณ์อาจยังลดลงได้ แต่ถ้า speed * dt > 2 ก็แทบไม่ให้พฤติกรรมที่ใช้งานได้
- เราอาจจำกัดค่าสัมประสิทธิ์อินเตอร์โพเลตด้วย
min(1, speed * dt) ได้ แต่ก็ไม่ใช่คำตอบที่จัดการกรณี dt ใหญ่ได้อย่างลื่นไหล
- โค้ดอาจทำงานช้า จนเฟรมเรตตก
- ผู้ใช้อาจสลับไปแท็บหรือหน้าต่างอื่น ทำให้โค้ดหยุดไปพักหนึ่งแล้วกลับมาพร้อม
dt ที่ยาวหลายวินาที
- ในการจำลองฟิสิกส์ เราอาจจำกัด
dt ที่มากเกินไปหรือแบ่งเป็นหลายอัปเดตได้ แต่ในงานแอนิเมชัน การให้กล้องและปุ่มยังทำงานอย่างเป็นธรรมชาติแม้ dt จะใหญ่ จะส่งผลดีกับประสบการณ์ผู้ใช้มากกว่า
คำตอบในมุมของสมการเชิงอนุพันธ์
- รูปแบบ
A += B * dt โดยทั่วไปสอดคล้องกับการแก้เชิงตัวเลขของ สมการเชิงอนุพันธ์ dA/dt = B
- สมการอัปเดตอย่างง่ายกำลังแก้สมการต่อไปนี้อยู่
d(position) / dt = (target - position) * speed
- หากกำหนดตัวแปร
x = position, a = target, c = speed จะได้ว่า
dx / dt = (a - x) * c
- เมื่อแก้สมการนี้โดยตรง จะได้รูปแบบดังนี้
x = x0 + (a - x0) * (1 - exp(-c * t))
- ดังนั้น ถ้าสูตรที่ถูกต้องเมื่อ
dt เล็กคือ position += (target - position) * speed * dt สูตรที่ใช้ได้กับ dt ใด ๆ ก็คือ
position += (target - position) * (1 - exp(- speed * dt));
- จาก Taylor expansion ที่ว่า
exp(x) ≈ 1 + x เมื่อ x เล็ก จึงได้ว่าเมื่อ dt เล็ก 1 - exp(-speed * dt) ≈ speed * dt และกลับไปเทียบเท่าสูตรเดิม
- แม้
speed * dt จะใหญ่มาก exp(-speed * dt) ก็จะเข้าใกล้ 0 และ 1 - exp(...) จะเข้าใกล้ 1 ทำให้เคลื่อนไปยังค่าที่ใกล้เป้าหมายได้อย่างเสถียร
- สมการเดียวกันนี้เขียนด้วย
lerp ได้เช่นกัน
position = lerp(position, target, 1 - exp(- speed * dt));
position = lerp(target, position, exp(- speed * dt));
การเลือกค่า speed
- แอนิเมชันทั่วไปมักคิดในรูป ระยะเวลา เช่น “เคลื่อนที่ให้เสร็จภายใน 0.125 วินาที” แต่ในทางเทคนิคแล้ว exponential smoothing ต้องใช้เวลาอนันต์จึงจะไปถึงเป้าหมายได้อย่างแม่นตรง
exp(- speed * time) จะเล็กลงเรื่อย ๆ ตามเวลา แต่ไม่มีวันเป็น 0 ดังนั้นหากค่าเริ่มต้นกับค่าเป้าหมายต่างกัน position ก็จะไม่เท่ากับ target แบบสมบูรณ์ในทางคณิตศาสตร์
- ในทางปฏิบัติ มันจะไปถึงขีดจำกัดความแม่นยำของ floating point หรือความต่างของตำแหน่งกล้องจะเล็กจนผู้ใช้มองไม่ออก จึงดูเหมือนว่าแอนิเมชันสิ้นสุดแล้ว
- ความหมายของ
speed คือ ภายในเวลา 1 / speed นั้น position จะเข้าใกล้ target มากขึ้นพอดี e = 2.71828... เท่า
- ในการใช้งานจริง มักตั้ง
speed ไว้ในช่วง 5..50 และถ้าเทียบกับความเร็วของแอนิเมชันแบบเชิงเส้นหรือ cubic ที่ให้ความรู้สึกใกล้กัน ค่า 2 * speed ของ exponential smoothing อาจให้ความรู้สึกเหมาะสม
ความเชื่อมโยงกับการประมวลผลสัญญาณ
- หากค้นหาคำว่า “exponential smoothing” หรือ “exponential moving average” จะพบบทความ Exponential smoothing บน Wikipedia
- เมื่อ
dt คงที่และ target เปลี่ยนทุกครั้งที่วนลูป ค่าอาจอัปเดตตามดัชนีรอบได้ในลักษณะประมาณนี้
factor = 1 - exp(- speed * dt)
- โดยทั่วไปมักกำหนด
factor เองเป็นค่าระหว่าง 0 และ 1
- exponential smoothing แบบไม่ต่อเนื่องคือ อะนาล็อกแบบไม่ต่อเนื่อง ของวิธีที่ใช้ในแอนิเมชัน
- ในงานประมวลผลสัญญาณ มันก็ถูกใช้ด้วยเหตุผลเดียวกัน คือทำงานได้โดยอาศัยเพียงค่าเฉลี่ยปัจจุบัน โดยไม่ต้องเก็บรายการค่าก่อนหน้าหรือสถานะซับซ้อน
- ในออดิโอดิจิทัล
dt มักถูกตรึงไว้เป็นค่ากลับของความถี่การสุ่มตัวอย่างคือ 1 / freq
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ดูเหมือนประเด็นสำคัญตรงนี้ยังไม่ได้ถูกพูดถึงมากพอ นี่ไม่ใช่แค่ เส้นโค้ง easing อีกแบบหนึ่งระหว่าง 0 ถึง 1 หรือ
smoothstep()แต่เป็น วิธีแบบไร้สถานะ ที่จัดการอินพุตแทบทุกแบบได้อย่างสม่ำเสมอ จึงมีประโยชน์มากถ้าเคยใช้ทรานซิชันของ CSS น่าจะคุ้นกับปัญหานี้ หากกำหนดระยะเวลาไว้ที่ 400ms ทำไมต้องเป็น 400ms พอดี? ไม่ควรขึ้นอยู่กับระยะทางที่ต้องเคลื่อนที่หรือ?
อย่างที่หลายคนบอก exponential smoothing มีปัญหาว่ามันเข้าใกล้จุดหมายแบบเชิงเส้นกำกับ แต่ไม่มีวันไปถึงจริง ๆ วิธีแก้ที่เห็นได้ชัดคือหยุดแอนิเมชันเมื่อสเต็ปเล็กกว่าค่า threshold แต่ก็ไม่งดงามนัก
ตอนใช้แนวทางคล้ายกันกับ inertial scrolling การเพิ่มพจน์แรงเสียดทานจำลองเข้าไปมีประโยชน์ พจน์นี้จะหักล้างพจน์เอ็กซ์โปเนนเชียล ทำให้ในทางปฏิบัติทำตัวเหมือนความเร็วขั้นต่ำ ตัวอย่างใน Desmos อยู่ที่นี่: https://www.desmos.com/calculator/98ufbuzxhj
Dถึงจุดหมาย exponential smoothing คือการอัปเดตแบบ Euler ของdD/dt=-C*DและคำตอบคือD(t)=A*exp(-C*t)จึงเข้าใกล้ 0 แบบเชิงเส้นกำกับแต่ไม่ถึงเปลี่ยนเป็นสมการที่ไปถึง 0 ได้ภายในเวลาจำกัด เช่น
dD/dt=-C*sqrt(D)ก็พอ คำตอบจะเคลื่อนที่คล้ายพาราโบลาครึ่งหนึ่ง แล้วเมื่อถึง 0 ก็อยู่ตรงนั้นต่อไป การอัปเดตแบบ Euler ของสมการนี้ก็ ไร้สถานะ ตามต้องการเช่นกันในฐานะนักพัฒนาเกม ผมมองว่า UI ส่วนใหญ่เหมาะกับ easing tween ที่มีระยะเวลากำหนดไว้ล่วงหน้ามากกว่า แต่เมื่ออยากทำให้การเคลื่อนไหวต่อเนื่องและคาดเดาไม่ได้ ซึ่งไม่มีจุดเริ่มต้นกับจุดจบชัดเจน ดูลื่นขึ้น แอนิเมชันอีกชนิดนี้มีประโยชน์มาก
เช่น เวลาผู้เล่นลากไทล์บนกริดด้วยเมาส์แล้วอยากให้มัน snap เข้ากริด หรือกรณีขยับกล้องเหมือนในตัวอย่างของบทความ
ในกรณีแบบนี้ เคล็ดลับการอินเตอร์โพเลตแบบเอ็กซ์โปเนนเชียล มีประโยชน์มาก แต่ไม่ค่อยเป็นที่รู้จัก เกมจำนวนมากใช้การอินเตอร์โพเลตเชิงเส้นที่ไม่แม่นพอ แล้วเจอปัญหาว่าเมื่อมีคนรันบนจอ 240Hz แอนิเมชันให้ความรู้สึกแปลกไปหมด ต่างจากยุคที่ 60fps เป็นมาตรฐาน
เลยดีใจที่เห็นบทความนี้ ความรู้เฉพาะทางเกินพอดีแบบนี้มักถ่ายทอดกันแบบมุขปาฐะจากซีเนียร์สู่จูเนียร์ในทีมราวกับการฝึกงานช่าง จึงเข้าถึงได้ยาก
ผมชอบบทความนี้ แต่สำหรับสวิตช์ toggle ผมอยากบอกว่าการตัดสินของผู้เขียนที่ว่า
sqrtดีกว่าฟังก์ชันกำลังสามนั้นผิดในเชิงวัตถุวิสัย ถ้าดูวิธีที่ สวิตช์ toggle จริง ๆ มักทำงาน ฟังก์ชันกำลังสามเป็นตัวเลือกที่ดีกว่าสำหรับสถานการณ์นี้ลองนึกถึงสวิตช์เบรกเกอร์ไฟฟ้าในบ้าน หรือสวิตช์ที่มักเห็นบนอะนาล็อกซินธ์กับอุปกรณ์เสียง อุปกรณ์เหล่านี้มุ่งเน้นสุนทรียะบางอย่าง และแอมป์กีตาร์ Hughes & Kettner ตัวเล็กที่ผมมีก็มีสวิตช์สองตัวที่กดแล้วให้ความรู้สึกดี
สวิตช์แบบนี้ตอนแรกจะมีแรงต้านเล็กน้อย แล้วเพราะโครงสร้างสปริง มันจะดีด “แป๊ก” ไปยังตำแหน่งใหม่ทันที พฤติกรรมนี้ใช้ ฟังก์ชันกำลังสาม จำลองได้ดีกว่า
sqrtหรือ exponential smoothingนอกจากข้อทักท้วงเล็ก ๆ นี้ บทความดีมาก แสดงให้เห็นว่าการใช้แอนิเมชันให้ดี เช่น easing function ที่เหมาะสม ช่วยยกระดับประสบการณ์ผู้ใช้ได้ แต่ถ้านำไปใช้แบบไม่ระมัดระวังเหมือนตัวอย่างการอินเตอร์โพเลตเชิงเส้น ก็อาจทำให้รำคาญและทำลายประสบการณ์ได้
[0] ก็ขึ้นอยู่กับชนิดของสวิตช์ toggle ด้วย อย่างไรก็ตาม ชนิดที่เห็นในอุปกรณ์อย่าง Minimoog ก็มีพฤติกรรม “ต้านก่อนแล้วดีดแป๊กไปตำแหน่งใหม่” ทำให้ใช้งานสนุก อนึ่ง ไม่ได้อวดอุปกรณ์นะ ผมไม่มี Minimoog
ผมยังคงทึ่งอยู่เรื่อย ๆ ว่า เทคนิคไม่เชิงเส้น ง่าย ๆ เพิ่มความสนุกให้การโต้ตอบออนไลน์ได้บ่อยแค่ไหน ในกรณีการรับรู้สี มันยังเป็นกุญแจสำคัญในการเข้าใจว่าทำไมสีสองสีถึงแยกไม่ออกพอสำหรับบางคน
สิ่งที่แปลกคือมนุษย์ไม่ได้เข้าใจความเร่งได้ดีเสมอไป อย่าวิ่งหนีขึ้นเนินโดยเชื่อว่าไฟจะเคลื่อนที่ด้วยความเร็วแทบคงที่เหมือนบนพื้นราบ ไฟจะเร่งความเร็วเมื่อไต่ขึ้นเนิน
เด็ก ๆ เรียนรู้ได้เร็วว่าลูกบอลที่ถูกขว้างเคลื่อนที่ไปตามพื้นด้วยความเร็วเท่าไร แต่ก็มักไม่เข้าใจดีนักว่าด้วยแรงโน้มถ่วง มันจะเคลื่อนที่เร็วแค่ไหนตอนมากระแทกมือ
น่าสนใจที่บทความนี้ส่วนใหญ่สุดท้ายก็กลับไปที่ easing ดูเหมือนว่าคนรุ่นใหม่แต่ละรุ่นต้องค้นพบสิ่งนี้ด้วยตัวเองอีกครั้ง
ผมจำได้ว่าเคยหลงใหลเว็บไซต์ทดลองของ Yugo Nakamura ในช่วงปลายยุค 90 เป็นหนึ่งในเว็บไซต์ยุคแรก ๆ ที่ผมเห็นซึ่งใช้ easing อย่างเสรีจนให้ความรู้สึกเป็นธรรมชาติ: https://www.youtube.com/watch?v=NLt7Gwnt3WY
ด้วยเหตุผลบางอย่าง ผมอยากมี toggle แบบนี้ แตะหรือคลิกค้างไว้แล้วมันค่อย ๆ เคลื่อนไปประมาณ 75% ของเป้าหมาย พอปล่อยแล้วค่อยดีดส่วนที่เหลือไปทันที
จากมุมมอง UX ก็ไม่แน่ใจว่าจะมีความหมายอะไร อาจหมายความว่าการตั้งค่าจะถูกนำไปใช้จริงหรือบันทึกในตอนสุดท้าย
หรืออาจเป็นส่วนหนึ่งของกล่องโต้ตอบ “แน่ใจจริง ๆ หรือ?” ก็ได้ ระหว่างกดค้าง การตั้งค่าจะถูกใช้ แต่ก่อนที่มันจะดีดเข้าที่ สามารถกด Escape เพื่อย้อนกลับได้
input:checked + .slider:active:before { transform: translateX(8px); transition: 1s; }input:not(:checked) + .slider:active:before { transform: translateX(18px); transition: 1s; }ชอบบทความนี้มาก เคยเขียนเทคนิคที่แทบจะเหมือนกันเป๊ะเมื่อราว 10 ปีก่อน ตอนนั้นเรียกว่า
lazy-easyและยังใช้อยู่จนถึงตอนนี้บางครั้งเราก็แค่อยากได้แอนิเมชันที่ลื่นไหล โดยไม่ต้องทำ state management ทั้งหมด: https://www.hailpixel.com/articles/lazy-animation-with-lazy-...
ตัวบทความเองดีมาก เดโมดูเหมือนจะทำงานได้ดีใน Chrome แต่ใน Firefox มันค้างระหว่างเลื่อน และการเรนเดอร์หน้าหยุดไปโดยสิ้นเชิง
จริง ๆ แล้วเป็นแนวทางที่ค่อนข้างดี และก็ดีในฐานะ proof of concept ของเทคนิคแอนิเมชัน/อีซิงด้วย นึกถึง Flickity ขึ้นมามาก
https://metafizzy.co/blog/initial-demos/
https://metafizzy.co/blog/math-time-resting-position/
https://metafizzy.co/blog/particle-to-slider/
https://metafizzy.co/blog/flickity-begins/
โดยเฉพาะเดโมนี้: https://codepen.io/desandro/pen/myXdej
เทคนิคนี้ไม่ได้มีประโยชน์แค่กับสวิตช์เท่านั้น ที่จริงคงไม่มีใครใช้องค์ประกอบแบบนี้กับสวิตช์ และคงไม่รันลูป
requestAnimationFrame20 ลูปพร้อมกันทั่วทั้งไซต์ด้วย คงไม่ใส่องค์ประกอบที่ตั้งใจทำให้พังลงไปเช่นกันนอกจากนี้ยังไม่มี optimization ที่หยุดเรนเดอร์เมื่อเดลต้าเล็กพอ และน่าจะยังมีการปรับแต่งเล็ก ๆ อีกเป็นสิบอย่างเพื่อให้ถึงระดับ production
ดูจากปฏิกิริยาตรงนี้แล้ว เหมือนหลายคนไม่ได้อ่านบทความแล้วก็เดาเอาเอง มองเห็นแต่ต้นไม้ไม่เห็นป่า หรือไม่ก็มีอคติและช่างเยาะเย้ยเกินไปจนเอาการตัดสินแบบไม่มืออาชีพมาแชร์เพื่อให้ดูฉลาด
HN กลายเป็นเหมือน Reddit ตั้งแต่เมื่อไหร่กัน?
ส่วนประเด็นที่ว่า HN กำลังเปลี่ยนเป็นเหมือน Reddit นั้น บางทีในแวดวงเทคโนโลยีโดยรวมอาจมีบรรยากาศถากถางแบบคลุมเครืออยู่ก็ได้ มีความไม่ไว้วางใจรองรับอยู่ว่ารัฐบาลและบริษัทต่าง ๆ ตั้งใจจะใช้เทคโนโลยีทรงพลังที่กำลังเกิดขึ้นอย่างไร และพวกเขากำลังสร้างมันขึ้นมาเพื่อจำกัดและควบคุมปัจเจกบุคคล มากกว่าจะเพิ่มเสรีภาพของปัจเจกหรือไม่
ใกล้เคียงกับแก่นแท้ของ Emotional Design(https://en.wikipedia.org/wiki/Emotional_Design) เลยทีเดียว แม้จะเป็นแอนิเมชันเล็ก ๆ ก็ยังมีเรื่องให้พูดถึงได้มากมาย