Shuffle text in the DOM while preserving visual rendering — a lightweight anti-copy protection technique.
在不改变视觉呈现的前提下,打乱 DOM 中的文本顺序,以降低直接复制文本的可用性。
- Read typography metrics (font, line-height, available width) from the target element
- Compute per-character positions using
@chenglou/pretextandcanvas.measureText - Wrap each character in an absolutely-positioned
<span> - Randomise the DOM order while keeping absolute positions intact
The result: text looks the same but the underlying DOM (and therefore clipboard content) is scrambled.
| Package | Description | README |
|---|---|---|
article-shuffle |
Core DOM APIs and layout utilities | packages/core |
react-article-shuffle |
React component and hook | packages/react |
pnpm add article-shuffleimport { shuffleAll, shuffleElement } from 'article-shuffle'
// Shuffle a single element
shuffleElement(document.querySelector('p')!)
// Shuffle all matching descendants
shuffleAll(document.querySelector('article')!)pnpm add react-article-shuffleimport { ShuffleText } from 'react-article-shuffle'
export function ArticlePreview() {
return (
<ShuffleText
blocks={[
'The first paragraph stays visually readable.',
'The copied result no longer follows the original reading order.',
]}
blockAs="p"
/>
)
}| Page | Link |
|---|---|
| Main demo | https://shuffle-article.vercel.app |
| Playground | https://shuffle-article.vercel.app/playground |
| Main demo | Playground |
|---|---|
![]() |
![]() |
Note
Requires Node.js ≥ 20 and pnpm 10.
pnpm install # install dependencies
pnpm dev # start demo dev server
pnpm check # type-check the workspace
pnpm test # run tests
pnpm build # full verification build (check → test → packages → demo)shuffle-article/
├── packages/core # publishable core library
├── packages/react # publishable React wrapper
└── apps/demo # Vite demo app

