Doop
Doop is an open-source multiplayer design canvas and design MCP for Claude Code, Codex, and any AI agent. Design side by side with agents — free in beta.
Parametric 3D/4D Perlin animations in the browser — Vanilla JS, seamless loop, video export.
Translation pending
DesignJavaScript · SwiftGitHub @johannes-kaindlOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Parametric 3D/4D Perlin animations in the browser — vanilla JS, no build, seamless loop, WebM export. Worker-accelerated.
Taken from the repository README
Loading the full README.
Read the full README ↗Parametric 3D/4D Perlin animations in the browser — worker-accelerated, video export, seamless loop. Fully client-side, no dependencies, no build.
Grown out of two older hobby projects (_archiv/texturizer.ipynb from
early 2023 + _archiv/perlin_noise/ from May 2023) into a focused
browser tool. Designed for static hosting, embedding on a homepage, and
as the basis for an Obsidian plugin.
# Variant A — just double-click
open index.html # macOS
start index.html # Windows
xdg-open index.html # Linux
# Variant B — local server (handy for hot-reload during development)
python3 -m http.server 8000
# → http://localhost:8000
Hit ▶ or Space, click a preset chip, or move any slider — the live preview updates after every input.
a + b·cos(2π(c·t+d)),
fully editable), Flow (renders the noise as a vector field — hue = local
gradient direction)Tile X / Tile Y make the noise wrap modulo a
configurable cell period, so the output repeats seamlessly as a
background texture(z, w), closes
mathematically without any "breathing" artifactMediaRecorderEvery image is a single frame from a built-in preset, rendered by the tool
itself — and reproducible from the presets via
scripts/render-readme-images.js. Together
they show the range of colour modes and features.
Three seamless 2.5-second loops, rendered from the built-in presets via
scripts/render-readme-videos.js.
The WebMs live under docs/examples/ and are directly
linkable from the live demo
(handy for embedding into other docs).
New here? Start with Getting started. Every parameter and control: control reference.
Short version of the most important controls:
| Element | Function |
|---|---|
| Left sidebar | All parameters (resolution, noise, loop, color, presets, export) |
| Large canvas | Live preview (always matches the current slider/input state) |
| ▶ / Space | Play / pause |
| ⏮ | Slider back to 0 |
| t slider | Time scrub (loop: [0, 1), otherwise free) |
| fps / frames | Only used for video export |
Drop the looping animation onto any page with the <perlin-noise> custom
element — renderer only, no controls:
<script src="perlin.js"></script>
<script src="perlin-presets.js"></script>
<script src="perlin-engine.js"></script>
<script src="perlin-element.js"></script>
<perlin-noise preset="aurora" autoplay></perlin-noise>
Configure it with a built-in preset name, a src pointing at a preset
JSON exported from the studio, or the params JS property. It fills its
container responsively (render resolution capped via max-resolution,
default 1280), respects prefers-reduced-motion, and pauses while
off-screen. Works from file:// too — except src, which needs an HTTP
server (use preset or .params locally).
▶ See it live: pages.jkaindl.de/perlin-studio/examples/embed.html — source in examples/embed.html.
Main thread (UI) Web Worker
┌─────────────────┐ ┌────────────────┐
│ RAF loop │ params/t │ makePermutation│
│ gatherParams() │──────────▶│ fbm3/fbm4 │
│ │ │ colorize() │
│ putImageData │ ImageData │ │
│ (zero-copy) │◀──────────│ postMessage │
│ │ │ (transferable)│
└─────────────────┘ └────────────────┘
Full technical docs (math, pipeline, edge cases): docs/explanation/architecture.md.
There is nothing to compile, bundle, or install. The seven scripts you see in
Project layout are the shipped artifact: plain ES5-compatible
JavaScript, each attaching one window global, loaded in order by
index.html. No package.json, no node_modules, no transpiler, no
framework.
That is a deliberate design constraint, not a gap:
file://. Double-clicking index.html gives you the full
tool — no server, no toolchain, no network. The Perlin worker is loaded from
an inline Blob (MTPerlin.WORKER_SOURCE), with an automatic main-thread
fallback where a browser's CSP blocks it.rsync the directory onto any webhost and
it works. No CI step stands between the source and what visitors run.<perlin-noise> drops into any page with four
<script> tags — no build tooling imposed on whoever embeds it.The cost is a deliberate one: no TypeScript, no npm ecosystem, and hand-rolled
solutions where a dependency would be quicker. Quality is gated by
scripts/check-syntax.mjs (parses every deployable script) and
scripts/smoke-test.js (Perlin math invariants) rather than by a compiler —
both run before the site is published.
If you want to change this, talk to the maintainer first — see AGENTS.md.
| Browser | Status |
|---|---|
| Chrome / Edge (Chromium) ≥ 90 | ✅ full incl. worker; exports MP4/H.264 (Chrome ≥ 126) or VP9 WebM |
| Firefox ≥ 90 | ✅ full; exports WebM (VP8/VP9) — no MP4 muxer |
| Safari ≥ 14 | ✅ live preview; exports MP4/H.264 (Safari ≥ 14.1 / iOS ≥ 14.5); some versions block the worker under file:// → falls back to main thread |
| Mobile Safari / Chrome Mobile | ✅ live preview; MP4 export (iOS ≥ 14.5); may require a longer touch gesture |
The app is responsive and works on mobile — the worker path keeps the animation smooth even at low resolutions.
.
├── index.html # UI markup
├── styles.css # theme (dark + light, system-following with topbar toggle override)
├── perlin.js # math/API (3D + 4D noise, color modes, worker source)
├── perlin-presets.js # gradients, built-in presets, resolveParams (shared)
├── perlin-engine.js # headless render engine (worker + RAF loop)
├── perlin-gl.js # optional WebGL2 renderer (port of the noise maths)
├── perlin-studio.js # controller (UI, recording, presets, events)
├── perlin-element.js # <perlin-noise> embeddable custom element
├── manifest.webmanifest # PWA manifest (installable)
├── assets/ # static assets (favicon, PWA icons, README images)
├── examples/
│ └── embed.html # <perlin-noise> embedding demo
├── docs/ # documentation, see docs/README.md (Diátaxis)
│ ├── tutorials/ # getting started
│ ├── how-to/ # task guides, troubleshooting
│ ├── reference/ # controls, colour modes, preset format, element
│ ├── explanation/ # architecture, design choices
│ ├── internal/ # notes for contributors and agents
│ └── examples/ # rendered WebM loops (for README + embedding)
├── scripts/
│ ├── render-readme-images.js # renders assets/*.png from perlin.js
│ └── render-readme-videos.js # renders docs/examples/*.webm (Node → ffmpeg)
├── _archiv/ # historical predecessors (READ-ONLY)
│ ├── perlin_noise/ # Python original
│ ├── texturizer.ipynb # Texturizer notebook
│ └── old_texturizer_combined/ # first browser version, incl. Texturizer
├── LICENSE # AGPL-3.0
├── CHANGELOG.md
├── CONTRIBUTING.md
├── SECURITY.md # threat model + reporting
└── AGENTS.md # context file for AI assistants
The documentation is split by what you need it for (index):
<perlin-noise> element.Issues and PRs welcome. Developer quickstart: CONTRIBUTING.md.
Security-related reports — please don't file them publicly. See SECURITY.md.
AI assistants (Claude Code, etc.) get their orientation in AGENTS.md.
Shipped since the original list:
Tile X / Tile Y make the output repeat (v0.10.0)<perlin-noise> renderer element (v0.12.0)Still on the wishlist:
main.ts with a modal + canvas embed (separate repo)<perlin-studio> element — the full editor (controls + canvas) as a
single embeddable tag, building on the shared PerlinEngineConsidered and explicitly deferred:
gif.js would be
the project's first JavaScript dependency. The Discord/Slack
reach gain doesn't justify breaking the "no dependencies"
principle.Perlin Studio is dual-licensed — see LICENSING.md for the full picture:
The Perlin permutation table and the "Improved Noise" algorithm come from Ken Perlin's freely published Java reference (2002), reimplemented here in JS.