Kimi K3 đã xây dựng một nét bút máy kỹ thuật số như thế nào
Chúng tôi muốn có nét bút máy có hướng như Freeform trong Lulucat Notes. Đặc tả chỉ là một ảnh chụp chữ viết tay. Sau hai mô hình, một câu hỏi phân biệt và một ngòi hình elip, bút nước đã viết đúng như nó cần viết. Kimi K3 thực hiện nghiên cứu, viết mã và kiểm chứng trên Fireworks.

Được kết xuất bởi pipeline Metal của Lulucat Notes, pipeline được nói đến trong bài viết này.
Lulucat Notes có một cây bút thường và một bút highlight. Công cụ tiếp theo trong lộ trình là bút nước — loại bút máy có hướng mà bạn biết từ Apple Notes và Freeform, trong đó nét dọc ra dày còn nét ngang ra mỏng. Đặc tả cho công cụ này không phải là một tài liệu. Nó là một ảnh chụp màn hình: ba dòng chữ viết tay, các từ “pencilkit”, “无边记” và “这种有方向的水笔能力” — khả năng bút nước có hướng này.
Giống như pipeline Metal trước đó, công việc này do Kimi K3 thực hiện, một mô hình mở của Moonshot chạy trên Fireworks: đo lường, mô hình hóa, code và kiểm chứng. Con người cung cấp ảnh chụp, trả lời một câu hỏi và đánh giá cảm giác trên một iPad thật.
Đặc tả là một ảnh chụp màn hình
Một hình ảnh tĩnh không thể cho biết vì sao một nét lại mỏng. Nó chỉ có thể cho biết nét mỏng bao nhiêu và ở đâu. Vì vậy, bước đầu tiên là đo lường. Chúng tôi quét ảnh chụp theo từng hàng và từng cột, theo dõi độ lệch của đường trung tuyến mỗi nét để lấy hướng, rồi chuyển chiều rộng quét thành chiều rộng thật bằng sin của góc đó:
| Nét | Hướng | Chiều rộng thật |
|---|---|---|
| Nét vươn của “l”, “pencilkit” | ≈ 78° | 27.3 px |
| Thân dọc của “k”, “pencilkit” | ≈ 90° | 28 px |
| Nét quét rơi sang trái của 力 | ≈ 66° | 25.7 px |
| Nét nối chữ cursive | ≈ 8° | 11 px |
| Nét ngang tiếng Trung (横) | ≈ 0° | 6–11 px |
Tỉ lệ dày trên mỏng ≈ 2.5. Khớp
Phiên bản một: chiều rộng theo hướng
Mô hình đầu tiên rất trực tiếp: tính hướng cho mỗi điểm đầu vào, ánh xạ hướng sang chiều rộng qua đường cong đã khớp, rồi ghi kết quả vào bán kính của điểm lúc lấy mẫu. Hướng được ước lượng theo nhân quả — một trung bình có trọng số suy giảm theo hàm mũ trên vài điểm cuối của cung, tính trong không gian góc nhân đôi để việc đảo hướng di chuyển không triệt tiêu ước lượng. Chỉ dùng các điểm trong quá khứ, nên nét đang vẽ và nét đã chốt khớp nhau từng byte.
Builder vượt qua unit check: các đường tổng hợp ngang, dọc, 45° và đảo chiều đều bake được các chiều rộng lý thuyết — 0.99, 2.52, 2.00 và 0.99 points. Phần render không cần thêm code: một nét có bán kính đã bake chỉ là một chuỗi con dấu tròn, và pipeline point-sprite của chúng tôi vốn đã vẽ chúng.
Trên iPad, con người mất khoảng mười giây để bác bỏ nó: “đây là bút nghệ thuật, không phải bút nước”.
Hai lời giải thích phù hợp với cùng một hình ảnh
Vì sao nó cho cảm giác sai? Có hai cách giải thích ứng viên, và ảnh chụp không thể phân biệt chúng:
- Khóa hướng. Hình học của ngòi ép nét ngang mỏng và nét dọc dày, bất kể tay làm gì. Đó là điều phiên bản một đã triển khai.
- Áp lực và tốc độ. Bút được điều khiển bằng lực nhấn, còn mẫu trên ảnh chỉ là động lực học của chữ viết tay: các nét đi xuống tự nhiên được nhấn mạnh, các nét nối tự nhiên nhanh và nhẹ.
Cả hai đều tạo ra ảnh chụp có nét ngang mỏng và nét dọc dày. Khác biệt nằm ở chuyện gì xảy ra khi bạn nhấn mạnh một nét ngang. Phiên bản một giữ nó mỏng. Bút điều khiển bằng lực nhấn làm nó dày lên. Vì vậy chúng tôi hỏi con người một câu: một nét ngang bị nhấn mạnh có nên dày hơn không?
“Không. Nét ngang vẫn mỏng.”
Khóa hướng được xác nhận. Nhưng còn một điều khác sai, vì phiên bản một cũng đã khóa hướng.
Câu trả lời nằm ở các đầu nét
Manh mối tiếp theo nằm ở đỉnh các nét vươn. Phóng to thân dọc của “l” và “k” trong mẫu cho thấy hai điều: một nét thẳng giữ nguyên một chiều rộng từ đầu đến cuối, còn các đầu nét là vết cắt chéo phẳng — hình dáng của ngòi đục khi nhấc lên. Không phải chấm tròn. Không phải phần thu nhỏ do lực nhấn.

Đó là điều “cảm giác bút nghệ thuật” muốn nói. Phiên bản một mô hình hóa vẻ ngoài của mẫu — chiều rộng là hàm của hướng ước lượng — chứ không phải cây bút. Bộ ước lượng hướng là một cảm biến: nó rung trên đầu vào nhiễu, trễ quanh các góc và làm tròn mọi đầu nét thành hình tròn. Một ngòi thật không gặp những vấn đề đó, vì nó không tính toán gì cả. Chiều rộng chính là hình học.
Phiên bản hai: một ngòi hình elip
Mô hình cuối cùng hoàn toàn không có bộ ước lượng hướng. Ngòi là một hình elip có hướng: trục dài nằm ngang, trục ngắn cố định. Các con dấu hình elip được đặt dày dọc theo đường nét, còn mọi thứ khác đều xuất phát từ hình học:
-
Một nét ngang di chuyển dọc theo cạnh mở, nên luôn có độ rộng
— một đường mảnh cố định ở mọi lực nhấn. Đúng với đặc tả đã được xác nhận. -
Một nét dọc đi qua toàn bộ trục dài:
, tức phần dày nhất. -
Một nét chéo lấy độ rộng dây cung của hình elip theo phương vuông góc với hướng di chuyển,
-
Các đầu nét là những vết cắt hình elip — các đầu phẳng hình ngòi trong mẫu, có sẵn mà không cần xử lý thêm.
-
Lực nhấn chỉ scale trục dài,
, nên làm tăng thể tích mực trên các nét đi xuống và không bao giờ làm một nét ngang dày lên.
Từ các phép đo mẫu, chúng tôi giữ
Phần render chỉ cần một fragment shader mới, không cần gì khác. Định dạng vertex — vị trí, đường kính, màu — vốn đã mang theo mọi thứ: đường kính là trục dài, còn trục ngắn là một uniform theo mỗi pass. Shader đánh giá SDF hình elip bằng cùng ramp độ phủ nửa pixel như các con dấu tròn của chúng tôi; nhờ vậy nó có thể so sánh theo pixel với reference implementation của Core Graphics (fillEllipse cho mỗi con dấu). Kiểm chứng đi qua cổng quen thuộc: một corpus tổng hợp có hai nét bút máy được render theo cả hai cách rồi so sánh từng pixel — không có khác biệt cấu trúc, và một nét ngang được spot-check đo được 12 px ở cả hai renderer.

Phiên bản một ở bên trái, phiên bản hai ở bên phải. Cùng đầu vào viết tay, cùng pipeline. Các đầu nét kể câu chuyện.
Trên iPad, cây bút mới vượt qua ngay: “好,很好” — tốt. Rất tốt.
Giữ lại cú trượt
Phiên bản một không bị ném vào thùng rác. Nó là một cây cọ thực sự thú vị, chỉ không phải bút nước. Vì vậy, nó được xuất bản như mục đầu tiên trong menu cọ thử nghiệm mới, dưới cái tên con người đặt cho nó: 漏水的圆珠笔, tức bút bi rỉ nước. Thanh công cụ có thêm một nút hình bình cầu mở ra danh sách văn bản của các thử nghiệm; thêm mục tiếp theo chỉ cần một dòng trong registry. Một mô hình bị bác bỏ không phải công sức lãng phí nếu có thể xuất bản nó như một thử nghiệm được gắn nhãn rõ ràng.
Một buổi tối các vòng lặp
Toàn bộ chu trình — đo, mô hình hóa, xây dựng, đưa lên thiết bị, hỏi, mô hình hóa lại, xây dựng lại, kiểm chứng — mất một buổi tối. Kimi K3 trên Fireworks thực hiện toàn bộ phần kỹ thuật của vòng lặp: thiết kế các lượt quét đo lường, đề xuất câu hỏi phân biệt thay vì đoán lần thứ hai, xóa bộ ước lượng hướng của chính nó khi bằng chứng đổi chiều, và mở rộng pixel-diff harness trước khi chạm vào ứng dụng. Tốc độ suy luận của Fireworks giữ vòng lặp ở trạng thái tương tác — các diff Metal và Swift dài, script phân tích pixel và công cụ corpus đều đến đủ nhanh để nút thắt còn lại là phán đoán của con người.
Mô hình cộng tác giống hệt điều chúng tôi đã viết trong bài về pipeline Metal, và một lần nữa nó phát huy hiệu quả: mô hình nhanh và chính xác; con người quyết định gu thẩm mỹ và kiểm chứng đầu-cuối. Một câu phản hồi dựa trên cảm giác — “bút nghệ thuật, không phải bút nước” — là đủ để mô hình định vị chính xác lỗi mô hình hóa và thay nó bằng một thiết kế đơn giản hơn.
Mô hình đúng hóa ra nhỏ hơn mô hình sai. Phiên bản hai được xuất bản với ít bộ phận chuyển động hơn phiên bản một — không có bộ ước lượng, không có cửa sổ làm mượt, không có số mũ đã khớp. Ngòi không tính toán chiều rộng. Ngòi chính là chiều rộng.