Skip to content

About

Generate Magic Eye-style autostereograms from a text prompt

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

text-to-stereogram

Magic Eye book on a desk — Create your own illusion

Generate a Magic Eye-style autostereogram from a text prompt.

As far as I can tell, this is the first fully generative text-to-stereogram tool. Most others need you to supply your own image and only render it in a preset pattern; this one generates the hidden subject, the depth map, and a themed surface pattern from one text prompt.


How it works

prompt
  → rewrite          (reshape the prompt; write a matching tile prompt)
  → image ∥ tile     (subject + seamless pattern, in parallel)
  → depth            (in-browser Depth Anything by default)
  → prepareDepth     (histogram stretch, ground-ramp control, continuous subject)
  → render           (oversampled SIRDS + pattern strip)
  → plate            (+ fusion-guide dots)

npm run dev mocks the AI calls with local fixtures. No API keys are required for that path. Live providers are opt-in (see below).


Quick start

npm install
cp .env.example .env
npm run dev          # Vite + mocked AI

To run the Netlify function runtime locally (still mocked unless live flags are set):

npm run dev:netlify

Open the URL Vite prints. Type a term and press Enter. Add ?debug for the floating debug panel (see below).

Live APIs (opt-in)

Default local path needs no keys — mocks only. To hit real providers, set flags + keys in .env (see .env.example) and run npm run dev:netlify. npm run dev always mocks, even if live flags are set.

Primary live stack (what production uses):

Step Provider
Rewrite Anthropic
Subject + tile images fal.ai (IMAGE_PROVIDER=fal-flux)
Depth In-browser Depth Anything (no paid API)

Replicate is a fallback, not the default path. It remains wired for:

  • Image gen if you set IMAGE_PROVIDER=replicate-flux (instant rollback from fal)
  • Server depth if in-browser depth fails, or you opt in with ?serverdepth
  • Optional keep-warm pings when server depth is live
Flag Effect
USE_LIVE_APIS=1 all services live
USE_LIVE_IMAGE=1 image gen live (fal or Replicate, per IMAGE_PROVIDER)
USE_LIVE_DEPTH=1 server depth live (Replicate; unused on the default client-depth path)
USE_LIVE_REPLICATE=1 shorthand for image + server depth live
USE_LIVE_REWRITE=1 Anthropic rewrite

Live calls also run in production (where the live flags and keys are set in the Netlify dashboard).

Debug panel & URL flags

Append ?debug to show a floating bottom-right debug panel (minimized by default; expand with the ▸ debug toggle). End users only get Reveal / Hide and Download — everything else lives here:

  • Views — plate (stereogram), layers (source + depth + tile), ghost (client-side decode of the hidden form; free, no API)
  • Decode QA — background period, subject fraction / coherence / depth, flat verdict
  • Render params — live readout of the URL flags below (eye sep, tile scale, depth path, etc.)
  • Shaped prompt — the rewritten subject prompt after the rewrite step
  • Term atlas — link to the public /atlas page (see below)
Flag What it does
?debug Mount the debug panel
?fresh Bypass Stage-1 / Stage-2 cache reads; force a full regeneration (still writes back)
?dots Force the random-dot renderer instead of the pattern tile (A/B)
?serverdepth Use Replicate server depth instead of in-browser Depth Anything
?eyesep=<in> Override eye separation in inches (clamped 1.5–5); widens/narrows the pattern period
?tilescale=<n> Motif density: how much the tile is pre-shrunk before strip crop (1–6, default 2.5)
?relief / ?norelief Force subject-relief stretch on/off (auto-on for person rewrites)
?shading / ?noshading Force shading-relief injection on/off (same auto rule)
?nosmooth Skip the soft-edge / terrace-damping blur on subject depth
?calibrate Diagnostic depth card (known squares) for viewing / fusion checks

Flags combine as usual, e.g. ?debug&fresh&dots. Renderer / depth flags take effect on cache hits too (hits re-render locally); only ?fresh re-runs the paid upstream calls.

Term Atlas

Public page at /atlas (also linked from the debug panel). Lists search terms that have landed in the shared Stage-2 cache — successful gens other visitors can hit without waiting. Sort by recent or by hit count; each row shows the cached subject (+ tile when present) and first/last/hit meta. The shaped rewrite prompts are not listed.


Repo map

src/
  App.tsx                 app state + UI
  Atlas.tsx / Atlas.css   Term Atlas page (/atlas)
  stereogram/
    stereogram.ts         SIRDS (random-dot fallback)
    patternStereogram.ts  texture-mapped renderer
    postprocess.ts        prepareDepth()
    depthFromImage.ts     image → Float32Array depth
    depthBrowser.ts       in-browser Depth Anything
    decode.ts             plate decode + flat check
  lib/                    API client, caches, share card
netlify/functions/        rewrite / image / depth / cache / warm / term-atlas
public/mock/              mock fixtures for local dev
public/demo/              landing plates

Stack: Vite, React, TypeScript (strict), plain CSS, Netlify Functions.


Implementation notes

  • Wait state. The generated subject image is the hidden content of the stereogram. The loading UI does not show it.
  • Depth vs pattern. Pattern tiles make depth errors more visible than random dots. Change depth post-processing and the pattern renderer separately when debugging.
  • Continuous subject depth. The default path keeps subject depth continuous. Hard depth planes can terrace smooth forms and make depth-estimator halos more visible.
  • Fusion-guide dots. Two dots at the top of the plate sit one background period apart. Two dots becoming three usually means a correct one-period lock; four often means a two-period lock.
  • Caching. Cached results store rewrite/image/depth/tile artifacts, not the finished canvas. A cache hit still runs the local render path. The Term Atlas lists Stage-2 cached terms publicly.
  • Depth default. Depth Anything V2 Small runs in the browser via transformers.js (WebGPU when available). Server depth is a fallback.

Viewing

Use divergent viewing: look through the plate from about a foot away until the two guide dots become three. If the hidden form sinks instead of coming forward, you are cross-viewing (same encoding, inverted depth).


Credits

Mike Deal, with help from Claude and Grok.

Not affiliated with or endorsed by Magic Eye Inc. Magic Eye® is a registered trademark of Magic Eye Inc.

License

MIT

About

Generate Magic Eye-style autostereograms from a text prompt

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages