Case study
HIKARI CLINIC · Ketamine-Assisted Psychotherapy
A generative mandala that redraws itself, for a psychiatric clinic in Okayama, Japan.
Concept, art direction, generative visual, front-end, bilingual editorial. One person, end to end.

Two things that don't usually go together
Dr. Norihide Ensako has been seeing psychiatric patients for over twenty-five years. In 2009, he opened Japan's first clinic with an in-house isolation tank, ran transpersonal therapy workshops for a long stretch, and put himself in ayahuasca ceremonies in the Peruvian Amazon and psilocybin sessions in Oregon.
That person was about to begin ketamine-assisted psychotherapy. In Japan it is still off-label, self-funded, and almost unknown to the public.
The site had two jobs that don't usually sit together.
Already to be the space of treatment. Ketamine-assisted psychotherapy is not a prescription. There is a prepared space, a session held with a therapist, and a long integration after. A pharmacy-like site would get this work wrong.
Never to step outside the rules. Japanese medical advertising law is strict. Off-label use, self-funded care, unproven claims: all of it is covered. One overstated sentence puts the clinic at risk.
Often, if you raise one, the other falls.
The visual: a mind redrawing itself
The hero is not an image. It is a system that draws a mandala, live, in the browser. Different every time you arrive.
Ketamine is thought to open a state, for a while after dosing, in which the brain forms new connections more readily. A window of neuroplasticity. The work of the therapy is to use that window: to loosen a fixed self-image and let it settle into a new shape.
So this is not a picture of a mandala. That process is running now.
Thousands of particles follow a flow field, fold across an axis of symmetry, and lay ink for about ninety frames. A form rises. It grows, settles, stops.
Then a small button in the corner: Redraw.
The clinic's founder has entered an isolation tank several hundred times to know altered states from the inside. Before it was explained, he saw what the system was doing.
Different every time, same face.





The last screen
On most sites, a successful submit is the most lifeless moment: a stock thank-you, a checkmark, and the world of the brand falls away. Here, the instant the message lands, the generative mandala at the core of the brand draws itself on the spot.
The visual language from the hero answers quietly at the end of the action. Not completion as UI, but we received you as experience, returned to someone who took a hard step while carrying pain.
The mandala that appears is one of a kind. It will never form the same way twice. It leaves that one step with a mark of its own.

Restraint was the design
The temptation in this field is obvious: flashy fractals, sacred geometry, third eyes, saturated colour.
All of it would have been a mistake.
This site was not made for anyone after a recreational psychedelic experience. The people who arrive have spent years on antidepressants without relief. They are tired, they are careful, and often someone from their family is sitting beside them.
Quiet, clinical, and warm at once. That was the tone we looked for. Mincho serif for Japanese headings. Cormorant Garamond in italic for the English subtitles. Sage and warm grey. Generous white space. The mandala at low opacity, off to one side, never competing with the text.
One generative element per page. Nothing else moves.
Language: two documents, not one translation
The Japanese headline reads: もう一度、こころに光を。 Once more, light into the heart.
The English is not a translation of it:
Where light finds you again.
The subject inverts. Japanese offers light; English lets light do the finding. The structure is shared: one word, 光 / light, set in a different colour, and everything else is written natively for its reader.
The same reaches the interface. Each language gets its own natural wording: 描き直す in Japanese, Redraw in English.


Writing about a treatment you cannot promise
The copy does not promise an outcome.
What is known, where the evidence stops, what the clinic actually does. Cost, risk, side effects, the reach of compensation. What is needed sits on a dedicated page.
In a field full of overstatement, holding back lands harder.
There is a long explainer too. History from ritual to clinical trial, set and setting, integration, where the research stands now, answers to common misconceptions. Written so someone with no background can decide whether to bring this to their family.
What it is made of
- Next.js (App Router), TypeScript, Tailwind
- Canvas2D generative system, seeded, ~60fps
- Full JA/EN internationalisation with transcreated copy
- Multi-step intake form with screening logic and consent gates
- Long-form article layout with sticky table of contents
- Consent-gated analytics; privacy policy covering sensitive personal data under Japanese law
The part most people skip
Below is for developers. It documents a performance problem, and why the obvious solution was the wrong one.
The mandala was too slow
In one version, the generative system ran hot. For every particle, the noise field was sampled four times — a central-difference gradient across three dimensions, 2D space plus time. Mirrored by symmetry, that came to several thousand lines a frame, all composited in MULTIPLY.
The obvious move was to port it to WebGL.
But first I worked out where the cost actually was.
The bottleneck was not rendering. It was JavaScript — the per-particle noise. Moving the drawing to the GPU would not have touched it.
1: the flow field
I stopped computing a gradient per particle. The field is baked into a low-resolution grid (64×64), and particles just read it back with bilinear interpolation. The grid only needs refreshing every few frames.
The per-particle hot loop stopped calling noise at all — four noise() calls a frame became a single interpolated read from the cached field. The image did not change.
Practical notes: bake gradient vectors into the grid, not raw scalars. Check grid resolution against the noise's spatial frequency. Pad the outer edge to avoid out-of-bounds reads. Interpolate between the old and new field for a few frames when swapping, or the motion hitches.
2: the ink sheet
Then a platform-specific problem. On macOS and Ubuntu it ran fine. On Windows it crawled.
The cause was MULTIPLY, applied per line. Multiply is not expressible with fixed-function GPU blending, so every composite has to read back what is already on the surface. Each semi-transparent stroke demanded a texture read and write, and on Windows the bandwidth choked.
The depth of the image comes from accumulation over time: ninety-odd frames of ink laid over each other. Intersections within a single frame contribute far less.
Several thousand `MULTIPLY` composites per frame became one. Each frame's lines go to an offscreen sheet in source-over, and the sheet is composited once. The temporal depth survived intact.
function bloomStep() {
inkSheet.clear(); // must clear every step
inkSheet.blendMode(SOURCE_OVER); // no blending cost inside the sheet
for (const p of particles) {
drawSymmetric(inkSheet, p);
}
paint.blendMode(MULTIPLY);
paint.image(inkSheet, 0, 0); // one blend per step
}Alpha needs recalibrating: the per-line alpha and the sheet alpha compound. You cannot carry the old values over.
Why I did not reach for WebGL
Porting it would not automatically have made it faster. "Use WebGL and it will be fast" is not true on its own — it depends on where the cost is and how far you chase it. Here, working it out first pointed somewhere else.
And WebGL cannot reliably draw thin lines. gl.lineWidth is known to be clamped to 1.0 across most implementations — ALIASED_LINE_WIDTH_RANGE reports [1,1]. The mandala is almost all hairlines. Matching that means extruding every line into a quad. A rewrite, not a port.
On AI
AI wrote the implementation. It did not decide that the mandala should model neuroplasticity. It did not choose Mincho over Gothic. It did not know that MULTIPLY was the bottleneck, or that the Japanese and English headlines needed different subjects. It did not read twenty-five years of a psychiatrist's practice and find the line running through it.
Speed is the tool. Judgment is the person.
What AI removed was the implementation cost that had made this kind of work impossible to sustain for a long stretch. Concept, motion, code, copy. Split across roles, thinning a little at every handoff: that was why.
When I started this work, the web was a place you could still play in. As it was tuned toward conversion numbers, the things with texture went first. They cost too much to build.
That cost is gone. One person can hold all of it. You can build the thing you actually wanted to build.
Putting something alive back on the web. That is this studio.