ditto.site แปลง URL ของหน้าเว็บหนึ่งหน้าให้เป็นโปรเจกต์ Next.js ที่รันได้จริง โดยไม่ให้ LLM เขียนโค้ดสักบรรทัด
ditto.site คือเครื่องมือโอเพนซอร์สที่รับ URL ของหน้าเว็บสาธารณะหนึ่งหน้า แล้วแปลงเป็นโปรเจกต์ Next.js หรือ Vite React ที่รันได้จริง จุดต่างคือมันไม่ให้ LLM เดาโค้ด แต่ใช้วิธีคอมไพล์จากสิ่งที่เบราว์เซอร์เรนเดอร์ออกมา ป้อนข้อมูลชุดเดิมกี่ครั้งก็ได้ไฟล์เหมือนเดิม

ป้อน URL ของหน้าเว็บสาธารณะสักหน้าให้ ditto.site สิ่งที่ได้ไม่ใช่แค่ไฟล์ HTML จากการกดเซฟหน้าเว็บเก็บไว้ แต่เป็นโฟลเดอร์โปรเจกต์ Next.js ซึ่งเป็นเฟรมเวิร์กสำหรับสร้างเว็บด้วย React และนำไปรันดูได้จริง ditto.site จะสร้างโปรเจกต์ทั้งชุดขึ้นมาใหม่จากหน้าเว็บนั้น
โค้ดชุดนั้นไม่ได้มาจากโมเดลภาษาอย่าง LLM แบบที่อยู่เบื้องหลัง ChatGPT คอมไพเลอร์ของ ditto.site ใช้วิธีต่างออกไป โดยอ่านสิ่งที่เบราว์เซอร์เรนเดอร์ออกมาจริงๆ แล้วคอมไพล์เป็นโค้ดตามกฎที่กำหนดไว้ตายตัว ไม่ว่าจะป้อนข้อมูลชุดเดิมที่จับจากหน้าเว็บเข้าไปกี่รอบ ไฟล์ที่ได้ก็เหมือนกันทุก byte
ทีมผู้พัฒนาในชื่อ ion-design เปิดโค้ดทั้งชุดไว้บน GitHub ภายใต้ MIT license
clone ตรงนี้ไม่ใช่ git clone
คำว่า clone ที่ ditto.site ใช้ไม่เหมือนคำสั่ง git clone ที่นักพัฒนาคุ้นกัน มันไม่ได้ดึงโค้ดเดิมจาก repo ลงมา และไม่ต้องใช้ source code ของเว็บนั้นเลยสักบรรทัด แค่มี URL ที่ยังเปิดได้ก็พอ
ระบบจะเปิดหน้าเว็บนั้นในเบราว์เซอร์จริงและบันทึกทุกอย่างที่แสดงออกมา ข้อมูลที่บันทึกมีทั้ง DOM หรือโครงสร้างหน้าเว็บที่เบราว์เซอร์ประกอบเสร็จแล้ว สไตล์ที่คำนวณค่าแล้ว กล่อง layout แต่ละชิ้น CSS ฟอนต์ ภาพหน้าจอ และไฟล์ asset อย่างรูปกับไอคอน ระบบยังบันทึกสถานะตอนเอาเมาส์ไปชี้หรือกด รวมถึงการเคลื่อนไหวเท่าที่สังเกตซ้ำได้อย่างปลอดภัย
จากนั้นระบบจะจัดข้อมูลก้อนนี้ให้อยู่ในรูปแบบกลางที่เป็นระเบียบ ใช้กระบวนการตายตัวสรุปโครงสร้าง แล้วเขียนออกมาเป็นโปรเจกต์พร้อมวางไฟล์ asset ให้ครบ ขั้นตอนสุดท้ายคือการตรวจงาน ซึ่งเลือกเปิดหรือปิดได้
deterministic คือจุดที่มันต่างจริง

deterministic หมายถึงการให้ผลลัพธ์ที่แน่นอน ในทางปฏิบัติ ถ้านำข้อมูลชุดเดิมที่จับจากหน้าเว็บมาป้อนเข้าคอมไพเลอร์เป็นรอบที่สอง ไฟล์ที่ได้จะเหมือนรอบแรกทุกตัวอักษร
ถ้าเป็นงานที่ให้โมเดลภาษาเขียนโค้ดขึ้นมาใหม่ ไม่มีอะไรการันตีว่ารอบสองจะได้ไฟล์หน้าตาเดิม ชื่อ component อาจเปลี่ยน ลำดับ class อาจสลับ ทั้งที่ผลบนจอดูคล้ายกัน พอเป็นแบบนี้ การไล่ diff ว่ารอบนี้อะไรเปลี่ยนไปบ้างก็ทำได้ยาก
ผลลัพธ์ที่แน่นอนแบบนี้จึงสำคัญกับงานที่ต้อง clone เว็บเดิมซ้ำหลายรอบ เพราะถ้าไฟล์ที่ได้ต่างจากครั้งก่อน แปลว่าหน้าเว็บต้นทางเปลี่ยนจริง ไม่ใช่โมเดลสุ่มคำออกมาคนละแบบ
ถ้ายังไม่มีต้นแบบอยู่ในมือ ก็เหมาะจะให้ เครื่องมือ AI อย่าง coding agent ปั้นหน้าเว็บขึ้นมาจากคำสั่งภาษาคน ส่วน ditto.site ตอบโจทย์อีกแบบ คือมีหน้าเว็บที่ทำงานอยู่แล้วและอยากได้โค้ดเบสที่หน้าตาตรงกับของจริงไว้เป็นจุดตั้งต้น
สิ่งที่ ditto.site ก๊อปไม่ได้

ตัวคอมไพเลอร์คัดลอกเฉพาะสิ่งที่เบราว์เซอร์แสดงให้เห็น ไม่ได้คัดลอกการทำงานเบื้องหลังบนเซิร์ฟเวอร์ เอกสารของโปรเจกต์จึงระบุไว้ตรงๆ ว่าระบบทำซ้ำอะไรไม่ได้บ้าง
- app logic ที่ตัวคอมไพเลอร์ไม่รองรับ ตรรกะเบื้องหลังที่ไม่ได้แสดงผลออกมาบนหน้าจอจะไม่ติดมาด้วย
- ระบบล็อกอินและ auth หน้า login อาจดูเหมือนต้นฉบับทุกจุด แต่กดแล้วไม่มีอะไรเกิดขึ้น
- การจ่ายเงิน ระบบไม่ได้จำลองกระบวนการชำระเงินมาให้
- personalization เนื้อหาที่เปลี่ยนไปตามผู้ใช้แต่ละคนจะได้มาแค่เวอร์ชันที่เบราว์เซอร์เห็นตอนจับภาพ
- third-party JavaScript ที่ไม่รู้จัก สคริปต์จากภายนอกที่ระบบไม่รู้จักจะไม่ทำงานต่อ
พูดอีกแบบคือได้หน้าตาเว็บที่เหมือนจริงมาก แต่ไม่ได้ระบบที่ทำงานอยู่ข้างใน ถ้าเป้าหมายคือได้เว็บที่ทำงานครบทุกปุ่ม เครื่องมือนี้ตอบโจทย์นั้นไม่ได้
แอปที่สร้างออกมามีอะไรอยู่ข้างใน
โฟลเดอร์ที่ได้ไม่ใช่แค่ไฟล์หน้าเว็บที่กองรวมกัน แต่เป็นโปรเจกต์ที่จัดโครงสร้างไว้ให้แก้ต่อได้
- โปรเจกต์ Next.js หรือ Vite React ที่รันได้จริง เลือกได้ว่าอยากได้ตัวไหน
- หน้าและ route module ที่ประกอบขึ้นใหม่ แยกเป็นไฟล์ตามโครงสร้างของเฟรมเวิร์ก ไม่ได้ยัดรวมไว้ไฟล์เดียว
- asset ฟอนต์ ไอคอน manifest และ metadata ที่จับมาได้ พร้อมใช้ในโปรเจกต์เลย ไม่ต้องไล่ดาวน์โหลดเอง
- robots, sitemap, llms.txt และ JSON-LD ถ้าเว็บต้นทางมี ไฟล์ฝั่ง SEO ที่มักโดนลืมตอนทำใหม่
- runtime helper ตัวเล็กชื่อ ditto จัดการ interaction และ motion เท่าที่ระบบรองรับ
- ไฟล์เอกสารอย่าง AGENTS.md กับ ARCHITECTURE.md ที่สร้างให้อัตโนมัติ เพื่ออธิบายว่าไฟล์ไหนคืออะไรและแก้ตรงไหนได้บ้าง มีไว้ให้ทั้งคนและ AI agent อ่าน
ลองเองบนเครื่องด้วย CLI ห้าบรรทัด
วิธีที่เริ่มได้เร็วคือรันบนเครื่องตัวเองผ่าน CLI โดยพิมพ์คำสั่งในหน้าต่างเทอร์มินัล วิธีนี้ไม่ต้องขอ key และไม่ต้องส่งอะไรออกไปยังเซิร์ฟเวอร์ของใคร คำสั่งชุดแรกใช้ดึงเครื่องมือลงมา ส่วน URL ที่อยากแปลงจะอยู่ในคำสั่งบรรทัดสุดท้าย
git clone https://github.com/ion-design/ditto.site.git
cd ditto.site
npm ci
npx playwright install chromium
npm run clone -- https://example.com/ --out=./outputแอปที่สร้างเสร็จจะอยู่ที่ output/<site>/app จากนั้น CLI จะพิมพ์สรุปให้ก๊อปไปใช้ต่อได้เลย ทั้งคำสั่ง cd … && npm install && npm run dev และรายชื่อไฟล์ที่แก้ได้อย่างปลอดภัย ได้แก่ src/app/content.ts กับโฟลเดอร์ src/app/components/ ส่วนคู่มือเต็มอยู่ใน AGENTS.md ของแอปที่เพิ่งสร้าง
ถ้าไม่อยากก๊อปคำสั่งไปวางเอง ให้เติม --serve เข้าไป มันจะ clone แล้วติดตั้ง dependency ก่อนเปิด dev server ให้ต่อเนื่องจนจบ ถ้าอยากให้เปิดเบราว์เซอร์ด้วยก็เติม --open ต่อท้าย
ตัวเลือกที่ปรับได้ตอนสั่ง clone มีสามตัวหลัก
| ตัวเลือก | ค่าเริ่มต้น | ปรับเป็น | เลือกเมื่อไหร่ |
|---|---|---|---|
mode | single | multi | อยากได้หลายหน้า ไม่ใช่หน้าเดียว |
styling | tailwind | css | โปรเจกต์ปลายทางไม่ได้ใช้ Tailwind |
framework | next | vite | อยากได้ Vite + React แทน Next.js |
ถ้าไม่ใส่ --out ผลลัพธ์จะอยู่ที่ runs/<site>/<timestamp>/ โดยมี symlink runs/<site>/latest ชี้ไปที่รอบล่าสุดเสมอ สคริปต์ที่ใช้ทำงานต่อจึงอ้างพาธเดิมได้โดยไม่ต้องรู้ timestamp
ต่อเข้ากับ agent ผ่าน REST API และ MCP
อีกทางคือใช้บริการที่โฮสต์ไว้แล้ว แต่ต้องขอ API key ก่อน โดยขอได้ที่เว็บ ditto.site หรือส่ง POST /v1/signup/request พร้อมอีเมล ระบบจะส่งลิงก์ยืนยันกลับมา เมื่อกดลิงก์ คีย์จะแสดงให้เห็นครั้งเดียวและเปิดดูซ้ำไม่ได้
เอกสารระบุข้อควรระวังเรื่องการเก็บคีย์ไว้อย่างชัดเจนว่า ควรเก็บคีย์ไว้ใน environment variable ของเครื่องเท่านั้น อย่าใส่คีย์ตรงๆ ในคำสั่ง เพราะคีย์จะค้างอยู่ทั้งใน shell history, log และแชท และห้าม commit ขึ้น repo เด็ดขาด ถ้าคีย์หลุดออกไปแล้ว สามารถเปลี่ยนคีย์ใหม่จาก dashboard ได้ทุกเมื่อ
export DITTO_API_URL="https://api.ditto.site"
export DITTO_API_KEY="ditto_live_example"
curl -sS -X POST "$DITTO_API_URL/v1/clones" \
-H "authorization: Bearer $DITTO_API_KEY" \
-H "content-type: application/json" \
-d '{"url":"https://example.com/","options":{"mode":"single","styling":"tailwind","framework":"next"}}'สิ่งที่ตอบกลับมาคือ JSON ก้อนเดียวที่รวมไฟล์ทั้งแอปไว้ครบ แต่ละไฟล์มี path ชนิด เนื้อหา ขนาด และค่า sha256 กำกับมาด้วย ถ้าอยากได้เป็นโปรเจกต์จริงบนดิสก์ ก็ส่งต่อเข้า unpacker ของ repo ที่ checkout ไว้แล้ว
curl -sS -X POST "$DITTO_API_URL/v1/clones" \
-H "authorization: Bearer $DITTO_API_KEY" \
-H "content-type: application/json" \
-d '{"url":"https://example.com/","options":{"mode":"single"}}' \
| npm run --silent unpack -- - ./outถ้างานใหญ่หน่อย ระบบจะส่งเข้าคิวแทนการตอบกลับทันที กรณีนี้ต้องเรียก GET /v1/clones/:id เช็กสถานะก่อน แล้วค่อยดึงผลลัพธ์มา unpack หรือจะดาวน์โหลดแอปทั้งชุดเป็นไฟล์ archive ก้อนเดียวผ่าน GET /v1/clones/:id/bundle?format=tgz ก็ได้
ถ้าอยากให้ AI agent สั่งงานเอง ให้ใช้ MCP ซึ่งเป็นมาตรฐานกลางที่เปิดให้ agent เชื่อมต่อกับเครื่องมือภายนอกได้ วิธีตั้งค่าคือชี้ mcpServers.ditto ไปที่ https://api.ditto.site/mcp แล้วใส่ header Authorization แบบ Bearer จากนั้นสั่งงานด้วยประโยคธรรมดาได้เลย เช่น บอกให้ ditto MCP server clone https://example.com ออกมาเป็นแอป Next.js
MCP server ตัวนี้ไม่ส่งไฟล์ทั้งแอปให้ agent อ่านรวดเดียว แต่จะส่ง job id ข้อมูลกำกับ รายการไฟล์ และตัวอ้างอิงไฟล์มาก่อน จากนั้น agent ค่อยเลือกอ่านเฉพาะไฟล์ที่ต้องใช้จริง วิธีนี้ช่วยประหยัดพื้นที่ context ซึ่งเป็นโจทย์ที่ต้องนึกถึงเสมอเมื่อ เทียบว่า Agent Skills กับ MCP ทำงานคนละหน้าที่กันอย่างไร ส่วนเครื่องมือหลักที่เปิดให้ agent เรียกมี clone_website, get_clone_status, get_clone_result, list_clone_files, read_clone_files และ get_clone_bundle
ถ้าไม่อยากส่ง URL ออกไปนอกบ้าน ก็รัน API เองในเครื่องได้ วิธีที่เร็วสุดคือ SSRF_ALLOW_LOOPBACK=true npm run dev:api แล้วยิงไปที่ http://localhost:8787/v1/clones โดยไม่ต้องมีฐานข้อมูล ถ้าอยากได้ระบบคิวเต็มรูปแบบ ต้องเปิด Postgres กับ MinIO ด้วย docker compose up -d ตั้งค่า DATABASE_URL รัน npm run db:migrate แล้วรันทั้ง npm run dev:api และ npm run dev:worker
กติกาที่ต้องอ่านก่อนเอาไปใช้กับเว็บคนอื่น
การยกหน้าเว็บคนอื่นมาทั้งหน้าเป็นความสามารถที่มาพร้อมข้อกำหนด ซึ่งทีมผู้พัฒนาเขียนไว้ในเอกสารตั้งแต่ต้น
ถ้านำไป deploy เป็นบริการ ก็ต้องระวังเรื่องความปลอดภัยของระบบด้วย สองเส้นทางหลักคือ /v1/clones* กับ /mcp และควรล็อกไว้หลัง API-key auth เสมอ เพราะถ้าเปิดทิ้งไว้ ใครก็สั่งเซิร์ฟเวอร์ของเราให้เปิดเว็บอะไรก็ได้
อีกจุดที่ต้องระวังคือระบบสมัครเพื่อขอคีย์ ถ้าตั้ง SIGNUP_ENABLED=true ในโหมดที่มีฐานข้อมูล ใครก็ตามที่ยืนยันอีเมลได้จะขอคีย์เองได้เลย ตัวระบบเก็บเฉพาะค่า hash ของคีย์ ไม่ได้เก็บคีย์ตรงๆ ไว้ ส่วนบน production ควรตั้ง SIGNUP_DIRECT_ENABLED=false เว้นแต่ตั้งใจเปิดให้สร้างคีย์โดยไม่ต้องยืนยันตัวตนจริงๆ
แล้วเอาไปทำอะไรได้บ้าง
เครื่องมือนี้เหมาะกับงานที่ต้องเริ่มจากของที่มีอยู่แล้ว เช่น เว็บเก่าที่โค้ดหายไปแต่หน้ายังออนไลน์อยู่ หรือหน้า landing page ที่อยากรื้อมาทำใหม่บนเฟรมเวิร์กปัจจุบัน แทนที่จะเริ่มจากจอเปล่าแล้วจัดหน้าใหม่ทีละกล่อง ก็จะได้โครงที่ตรงกับของจริงเป็นจุดตั้งต้น แล้วค่อยแก้ต่อจากตรงนั้น
ditto.site ยกออกมาได้เฉพาะส่วนที่เบราว์เซอร์เรนเดอร์ให้เห็น ส่วนเนื้อหาที่สร้างมูลค่าจริงๆ ให้เว็บยังคงอยู่หลังระบบล็อกอินและระบบจ่ายเงินเหมือนเดิม
ที่มา: โปรเจกต์ ion-design/ditto.site บน GitHub
ชอบเรื่องแนวนี้ มีอีบุ๊คฟรีให้อ่านต่อ
สร้าง Claude Skill แบบไม่ต้องรู้โค้ด คู่มือสร้าง Claude Skill ของคุณเองด้วยการคุยกับ Claude Code เป็นภาษาไทย
กดสมัครแล้วเราจะส่งเทคนิค AI และของแจกใหม่ๆ ให้ทางอีเมล เลิกรับได้ตลอด
Claude Cowork · The Business Playbook

ฉบับภาษาไทย 15 บท เรียนรู้ผ่านโปรเจกต์จำลองต่อเนื่องทั้งเล่ม ตั้งแต่ตั้งค่า Workspace จัดการไฟล์ เชื่อมแอป ตั้งระบบอัตโนมัติ จนถึงสร้าง Plugin


