Doop
Doop: 오픈소스 멀티플레이어 디자인 캔버스 및 AI 에이전트용 MCP
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Watch a photo get painted: multi-size brush strokes that follow the image and converge on it. Deterministic, zero dependencies, in a browser canvas.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
painterly (adjective): of a painting or its style, characterised by visible
brushwork and the rendering of form through colour and tone rather than by line.
This is a program that takes a photo and paints it that way, in your browser,
while you watch.
A big brush lays in the underpainting. Finer brushes come back only where the
picture still disagrees with the photo. Every stroke runs along the image
instead of across it, so brushwork follows fur, edges and the line of a roof.
It finishes in 45 seconds at any size — 20 for the underpainting — then stops.README 전문 보기 ↗painterly (adjective): of a painting or its style, characterized by visible brushwork and the rendering of form through color and tone rather than by line. This is a program that takes a photo and paints it that way, in your browser, while you watch.
Live: davemaynard.github.io/painterly
A big brush lays in the underpainting. Finer brushes come back only where the picture still disagrees with the photo. Every stroke runs along the image instead of across it, so brushwork follows fur, edges and the line of a roof. It finishes in 45 seconds at any size — 20 for the underpainting — then stops.
Run npm run size to regenerate the first two.
| Library, gzipped | 7.7 KB |
| Demo page script and its worker, gzipped | 11.2 KB |
| Runtime dependencies | 0 (a Mersenne Twister is bundled, see NOTICE) |
| Planning a 1050 × 1400 photo | ~1.2 s on an M4 Mac mini, ~108,000 strokes |
| A plan crossing back from the worker | 15 MB packed into typed arrays, not 110 MB of objects |
| Longest frame CI will accept | 60 ms painting, 100 ms skipping to the end |
npm install github:davemaynard/painterly
import {brushes, createPainter, plan, rasterFromImageData} from 'painterly';
const context = canvas.getContext('2d');
if (!context) throw new Error('no 2d context');
context.drawImage(photo, 0, 0, canvas.width, canvas.height);
const source = rasterFromImageData(context.getImageData(0, 0, canvas.width, canvas.height));
// Pure data: every stroke, in painting order.
const painting = plan(source, {seed: 7});
// The hand: paints any prefix of the plan onto a 2D context.
const painter = createPainter(context, painting, brushes.bristle);
painter.paintTo(painting.strokes.length);
plan() takes options for the brush radii, the error threshold, stroke length
and curvature, and an onLayer callback that hears from it after each brush;
the defaults are tuned for photos around 1400 px. flow: 'tensor' trades the
1998 paper's swirls for calm: stroke directions are smoothed first, so a sky or
a lawn is laid in coherent runs that take their heading from the nearest real
edge. Plan and Stroke are plain
typed objects, so a plan can be serialized, replayed, or rendered by something
other than the bundled painter. packPlan() and unpackPlan() turn a plan into
a handful of typed arrays and back, exactly: the form to post from a worker or
keep around, at a seventh of the memory.
cli/ paints a photo on disk in one of three media and writes a JPEG, in a
few seconds at 1800 px. It is its own small package, so the library keeps no
runtime dependencies; it runs its TypeScript directly on Node 22.18 or later.
npm install # also builds the library the CLI paints with
(cd cli && npm install && npm link) # puts `painterly` on your PATH
painterly photo.jpg # matte oil, to ~/Downloads/photo-oil.jpg
painterly photo.heic --style gouache --size 2400 --out painting.jpg --open
All three plan with flow: 'tensor' and paint with the same hand; a style is
the rest of the recipe, in cli/src/styles.ts.
The canvas is cut into bands painted by one process each, which is what makes
it quick; the bands match a single canvas up to a few levels of antialiasing.
HEIC is read through macOS's sips.
src/image/ measures the photo: a float RGB raster, a linear-time Gaussian
blur (three box blurs), luminance, a Sobel gradient, and the same gradient
smoothed through its structure tensor for calmer strokes. No canvas, no DOM.src/plan/ decides the strokes, and names the two styles. Aaron Hertzmann's
Painterly Rendering with Curved Brush Strokes of Multiple Sizes
(SIGGRAPH 1998), ported and credited in the module header, with three habits
kept from the 2020 sketches: a canvas primed with the photo's dominant hue
family, a shuffled stroke order so the hand looks human, and seeded randomness.src/paint/ is the hand: a Brush says how many bristles a stroke becomes,
how translucent, how far each hair's color and weight wander, and how ragged
its start and finish are. bristle is the 2020 look, ribbon is this port's
first brush and the underpainting's default, round is the pointillist sketch
that never finished, flat is a house-painter's brush.src/demo/ is the page: photo picker, a layer-paced schedule, a player that
paints under a per-frame budget and jumps between the brushes' stages from
copies taken at the handovers, and a planner on its own thread that reports
each brush as it goes and plans the other photos behind the one playing. The
transport is a DVD player's rather than a scrubber on purpose: strokes go down
over one another and cannot be lifted, so there is no playing backwards, and
the moments worth returning to are where each brush begins. Back, play and on
are three drawn glyphs, the same geometry as the carets on the selects; the
stages beside them show where the painting has got to.cli/ is the command line: the three media, the finishes that sit the paint
on its support (relief, paper tooth, pigment pooling, ink), and the band
painters.processing/ holds the 2020 Processing sketches this grew out of, untouched.TypeScript, Canvas 2D, no framework. tsup builds the library to dist/ and
the page script and its worker straight into docs/, which GitHub Pages serves
as is; CI rebuilds docs/ and fails on a diff.
npm install
npm run check # Biome and tsc
npm test # the planner on synthetic images in Node, then the page in Chromium:
# determinism across loads, scrub-back equals paint-forward, phone width
npm run build
npm run gif # re-record docs/demo.gif from the page (needs ffmpeg)
npm run still # re-shoot docs/still.jpg, the photo-and-painting pair above
npm run size # re-measure the Numbers table
npm install --prefix cli
npm run check --prefix cli # tsc over the CLI (Biome covers it from the root)
npm test --prefix cli # bands against one canvas, the palette, the noise, and each style end to end
npm run styles --prefix cli # repaint docs/styles.jpg
The dog is mine. The others are from Unsplash, free to use under the Unsplash License and credited on the page: Jonny Gios, Cristina Anne Costello, Pietro De Grandi. All are shipped resized with their metadata stripped.
Dave Maynard, a front-end engineer in Atlanta. The dog is mine; everything else is credited below.
MIT. The bundled Mersenne Twister is BSD-3-Clause; see NOTICE.