mcpField
T
threejs-particle-morph

threejs-particle-morph

github.com/rheinmirDesign & UI1075 installsUpdated 2w ago
Repository

About threejs-particle-morph

threejs-particle-morph is a Three.js skill for web effects in which particles gather into an image or logo as the page scrolls, then disperse when scrolling back. It samples source-image pixels to create particle targets and exposes configurable particle parameters.

Key features

  1. 01Build particle targets from image pixels
  2. 02Gather particles according to scroll progress
  3. 03Disperse particles on reverse scroll
  4. 04Configure particle and sampling parameters
  5. 05Provide a resource cleanup method

Use cases

  1. 01Form a portfolio hero logo as the page scrolls
  2. 02Create a scroll effect that assembles an image from particles
  3. 03Disintegrate an image when scrolling back

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/rheinmir/setup --skill threejs-particle-morph

After installing, type/threejs-particle-morphin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

assets/
demo.css
demo.html
demo.js

Details

From the project README

Skill: threejs-particle-morph

Component Three.js thuần — hàng nghìn particle rải ngẫu nhiên trong không gian 3D, hội tụ dần thành ảnh sample từ pixel khi user cuộn trang, tan rã lại khi cuộn ngược.

WHAT

Purpose và context
  • Purpose: dựng một particle cloud Three.js (THREE.Points + BufferGeometry) hội tụ từ vị trí ngẫu nhiên thành ảnh/logo theo tiến độ cuộn trang và tan rã lại khi cuộn ngược — ưu tiên copy nguyên bản gốc, bản vanilla trong assets/ là dự phòng.
  • Trigger (when to use):
    • Hero section/portfolio cần hiệu ứng "ảnh được ghép lại từ các hạt" khi cuộn tới.
    • User nói "particle image", "hạt hội tụ thành ảnh", "point cloud morph", "three.js particle scroll".
  • Non-goals: KHÔNG dùng cho hiệu ứng chuyển ảnh liền mạch kiểu zoom-blur (đó là blur — shader trên 1 plane, không có particle rời rạc) và KHÔNG dùng cho hiệu ứng cuộn nhẹ không cần WebGL (đó là scroll-effects). Không viết lại code gốc của tác giả.
Mental model

ảnh nguồn → canvas ẩn (sampleResolution) → getImageData + stride + alphaThreshold → targets (+ màu) · starts random → scroll → targetProgress → progress (damping) → position = lerp(starts, targets, progress) → PointsMaterial render.

Input và output contract
FieldRequired?Ý nghĩa
Inảnh/logo nguồn (imageUrl)khôngthiếu → demo tự vẽ chữ mẫu lên canvas ẩn để sample
InparticleCount, particleSize, sampleResolution, alphaThresholdkhôngtham số khởi tạo ParticleMorph
Inràng buộc dự án (được kéo lib ngoài không?)cóquyết định bản gốc (mặc định) hay assets/ vanilla
Outcomponent trong dự áncófile gốc copy nguyên (giữ comment ghi công) hoặc assets/demo.* đã adapt; có destroy()
Outbằng chứng verifycóảnh chụp progress 0/0.5/1 + console sạch
Rules và capabilities
  • RULE-01 (MUST): Hiệu năng: số particle càng nhiều càng nặng CPU (vòng lặp ghi lại position mỗi frame) lẫn GPU. Ngưỡng an toàn gợi ý cho máy tầm trung: ≤ 5.000–10.000 particle. Đo bằng DevTools Performance/FPS meter TRƯỚC KHI tăng particleCount, đừng đoán — nhất là khi thêm particle cho ảnh lớn/nhiều chi tiết (tăng sampleResolution cũng tăng chi phí sample lúc init(), dù chỉ chạy một lần).
  • RULE-02 (MUST): Ba container (three) phải cài qua npm (npm install three) và import qua bundler cho production — bản demo dùng importmap trỏ CDN (unpkg.com/[email protected]) CHỈ để chạy độc lập không cần bundler, không dùng bản CDN cũ ghim version như blur từng làm. Khi wire vào dự án thật: xoá <script type="importmap">, npm install three, đổi import * as THREE from 'three' sang import qua bundler.
  • RULE-03 (SHOULD): alphaThreshold/brightness filter trong _buildSamples() loại pixel nền trong suốt/tối — ảnh nền trong suốt (PNG logo) cho kết quả gọn hơn ảnh nền đặc (JPEG); ảnh nền đặc sẽ sample luôn cả nền trừ khi crop trước.
  • RULE-04 (MUST): Verify bằng playwright-verify — chụp ở progress 0/0.5/1 (cuộn tới 3 mốc), đọc console (WebGL context lỗi thường im lặng, không throw JS error rõ ràng).
  • RULE-05 (MUST): Bản gốc dùng TRƯỚC — copy nguyên file, đừng viết lại; giữ comment ghi công dòng đầu; chỉ sửa nội dung/ảnh/màu; chạy local qua HTTP, không file://.
  • Capabilities: đọc/copy asset từ repo ngoài công khai; ghi file front-end vào dự án; chạy trang qua HTTP + trình duyệt headless để chụp/đọc console.
Failure boundaries
  • Không mở được link gốc / không kéo được lib ngoài → dùng assets/ vanilla (nhánh B01).
  • FPS tụt khi tăng particleCount → blocked việc tăng thêm: đo lại, giữ ≤ 5.000–10.000 particle.
  • Console báo lỗi WebGL context (thường im lặng) → failed verify, chưa bàn giao.
  • Ảnh nền đặc sample cả nền → crop trước hoặc dùng PNG nền trong suốt.

HOW

Main workflow
StepTypeInputsActionOutputs/exitFailure/next
W01judgmentràng buộc dự ánChọn nguồn: bản gốc Rheinmir/uiux-asset (mặc định) hay assets/ vanillanguồn đã chọnkhông kéo lib ngoài → B01
W02effectlink chạy + codeMở link chạy xem đúng hiệu ứng → copy nguyên file .html (+ _assets/) vào dự ánfile trong dự án, còn comment ghi công—
W03effectfileChỉ sửa nội dung/ảnh/màu (hoặc imageUrl/particleCount/particleSize với bản vanilla)component đã adapt—
W04deterministictrang qua HTTPVerify bằng playwright-verify: chụp progress 0/0.5/1, đọc console3 ảnh + console sạchlỗi WebGL/FPS → sửa, lặp W03
W05effectdự án thậtWire production: xoá importmap, npm install three, import qua bundlerbuild chạy—

Chi tiết từng bước (nguồn chân lý cho W01–W05):

Bản gốc — dùng TRƯỚC (copy nguyên file, đừng viết lại)

Code gốc NGUYÊN VĂN của tác giả (CodePen public = MIT) nằm ở repo ngoài Rheinmir/uiux-asset — gallery chạy thật: https://rheinmir.github.io/uiux-asset/scroll-effects/ . Quy trình: mở link chạy để xem đúng hiệu ứng → copy nguyên file .html (+ thư mục _assets/ nếu file trỏ tới) vào dự án → giữ comment ghi công dòng đầu → chỉ sửa nội dung/ảnh/màu. Chạy local qua HTTP, không file://. git clone --depth 1 https://github.com/Rheinmir/uiux-asset nếu cần cả bộ offline.

Pen gốc — tác giảLink
Scroll-Driven Particle WebGL Image Matrix — ycwchạy · code
GSAP ScrollSmoother and Three.js — cmalvenchạy · code
GSAP ScrollTrigger Disintegration Effect — dev_loopchạy · code

assets/ trong skill này chỉ là bản rút gọn vanilla tự viết — dùng khi dự án KHÔNG được kéo lib ngoài; mặc định dùng bản gốc ở trên.

Assets

assets/demo.html + assets/demo.css + assets/demo.js — đọc rồi ADAPT (đổi imageUrl, particleCount, particleSize khi khởi tạo ParticleMorph). Demo tự vẽ chữ mẫu lên canvas ẩn để sample khi không truyền imageUrl, nên chạy được ngay không cần ảnh/network.

Cơ chế
  • Sample ảnh: vẽ ảnh nguồn (hoặc canvas vẽ tay) lên <canvas> ẩn kích thước sampleResolution, đọc getImageData(). Duyệt pixel theo bước nhảy (stride tính từ particleCount mong muốn so với tổng pixel) — KHÔNG lấy hết mọi pixel, quá nặng — giữ pixel đủ sáng/không trong suốt (alphaThreshold) làm toạ độ đích + màu RGB.
  • Particle: mỗi toạ độ sample = 1 particle trong THREE.Points (BufferGeometry attribute position). Vị trí khởi tạo (starts) random trong một khối không gian lớn ("nổ tung"), vị trí đích (targets) là toạ độ pixel đã sample, lưu song song trong hai Float32Array riêng (không phải hai attribute GPU).
  • Scroll → progress: một scroll listener duy nhất, rAF-throttle (không GSAP/ScrollTrigger — bản demo cố tình viết thuần để không trùng phụ thuộc với gsap-scrolltrigger-pin), tính targetProgress từ scrollY / (scrollHeight - innerHeight).
  • Lerp mỗi frame: progress được làm mượt dần tới targetProgress (damping đơn giản, không phải animate trực tiếp scrollY), rồi mỗi phần tử position[i] = lerp(starts[i], targets[i], progress), set geometry.attributes.position.needsUpdate = true.
  • Màu + kích thước: PointsMaterial({ size, sizeAttenuation: true, vertexColors: true }) — giữ màu ảnh gốc qua attribute color tĩnh (set một lần lúc build, không đổi theo progress).
  • Cleanup: viết dạng class có destroy() — huỷ requestAnimationFrame, gỡ scroll/resize listener, gọi geometry.dispose(), material.dispose(), renderer.dispose().
Branches
IDKindGuardHành viSkip / failureRejoin
B01conditional_requireddự án KHÔNG được kéo lib ngoàidùng assets/demo.html + assets/demo.css + assets/demo.js, ADAPT tham số khởi tạo ParticleMorph—W04
B02capability_optionalcần cả bộ offlinegit clone --depth 1 https://github.com/Rheinmir/uiux-assetcó mạng tới gallery → skipW02
Validation và stopping

Kiểm bằng chạy thật: playwright-verify chụp 3 mốc cuộn + đọc console (WebGL lỗi thường im lặng); hiệu năng đo bằng DevTools Performance/FPS meter, không đoán. Review mắt: ảnh hội tụ đúng hình ở progress 1, tan rã ở 0. Dừng khi 3 ảnh đúng + console sạch.

Examples
  • Positive: hero portfolio cần logo PNG hội tụ khi cuộn → copy nguyên scroll-driven-particle-webgl-image-matrix.html từ gallery, giữ comment ghi công, đổi ảnh logo → chụp 0/0.5/1 thấy hạt rải → nửa hình → logo đủ, console sạch.
  • Boundary/failure: dự án cấm lib CDN ngoài → dùng assets/demo.js, particleCount 30.000 làm FPS tụt → hạ về ≤ 10.000 theo đo, rồi verify lại.
  • Boundary: user muốn chuyển ảnh A→B kiểu zoom-blur trên một plane → không dùng skill này, chuyển blur.

Origin

Comments

Markdown supported