Autumn Stroke
Each swipe becomes a gust of wind that drags maple leaves across a temple valley and settles into a tapered brush stroke. Write a wind-poem in five strokes.
AI Games
Two sources and the interference pattern draws itself
Copy it. Add your own twist.
Build "Wave Machine Lab" — a polished, mobile-first portrait web app for the Eazo community.
CONCEPT
A ripple tank with two or more sources. Interference fringes, diffraction through a slit and refraction over a shallow shelf are all simulated properly.
RULES & STATES
- Drag to place sources and set their frequency and phase; the wave field solves continuously with correct superposition.
- Barriers with slits can be dragged in, producing genuine single and double slit patterns.
- A shallow shelf refracts the waves honestly, bending the wavefronts, which is the classic demonstration.
- A slow-motion and a stroboscope control freeze the pattern, which is how ripple tanks are actually read.
- Result: the wave field frozen at your configuration with sources, fringe spacing and the effect shown. Share it.
OPENING
No cover page: the app opens straight into the live interactive scene, fully playable on first paint. A floating title chip plus one animated gesture hint dissolve on the first touch anywhere on the stage. Keep gentle ambient motion (drift, breathing, particles, light) at all times so the scene is never a frozen image.
GLOBAL REQUIREMENTS
- Text must never be clipped (this is the single most common defect): any text you draw on a canvas must be measured with ctx.measureText and its font size reduced in a loop until it fits inside the canvas width minus a 24px margin on each side; DOM text must wrap or shrink rather than overflow. Titles, HUD labels, counters and hints all have to be fully readable at 393px wide. Equally, no drawn text may sit under the top 56px band or inside the bottom 88px band, and HUD chips must not overlap each other or the play area's focal object.
- Language: ship a lightweight built-in i18n layer with exactly two locales, English (en) and Chinese (zh). The app ALWAYS opens in English — never auto-detect, never read navigator.language, never default to a "system" preference. Provide one small, comfortably tappable EN / 中文 toggle at the top-right, about 56px down from the top edge, clear of the status bar and the dynamic island. Chinese appears only after the user actively switches. Share output stays English in both locales. Never mix two languages on one screen.
- Fully self-contained: absolutely no external APIs of any kind — no AI calls, no third-party data, media, image or font services, no remote backend, no login, no analytics. Embed every asset, dataset and piece of content directly in the app code (procedural drawing, inline SVG, emoji or code-generated art only).
- Real Share to the Eazo Community: on the result screen add a real Share button. Compose the result card as an image on a canvas and share it via the Eazo SDK community share — call share.compose({ text, attachments: [{ type: "image", url: dataUrl, caption }] }) and READ the resolved { accepted } value. Only when accepted is true may the button say "Sent to Eazo"; when accepted is false the button must read "Open in the Eazo app to share"; on a thrown error keep the original label. Never claim the post was shared on the plain web. Keep a Replay button beside Share.
- Layout contract (this is where most builds fail — follow it exactly): the app root must follow its host container height with position: fixed; inset: 0; height: 100% — NEVER 100dvh or 100svh, because the Eazo host injects a ~60px banner above the app and dvh overflows past the screen. Size every canvas from its PARENT element's clientWidth/clientHeight through a ResizeObserver, and run that fit ONCE on mount as well (a mounted component receives no resize event, so the buffer would otherwise stay at the 300x150 default). Convert every touch point through getBoundingClientRect() read at event time — never cache the rect, never use window.innerWidth/innerHeight for sizing or hit-testing.
- Safe areas: every top-side UI element sits at least 56px below the top edge. NOTHING you draw yourself — buttons, HUD text, score, hints, legends, progress bars, captions — may fall inside the bottom 88px of the viewport, because the Eazo mobile app renders its own native toolbar over that strip and your code cannot detect it. Push the play area up instead of padding it down.
- Fill the screen: the scene must occupy the full viewport height. No dead flat colour bands or empty background strips in the lower half — if the play area has a fixed aspect ratio, extend the artwork (gradients, ground, atmosphere, particles, reflections) into the leftover space. Reviewers reject apps whose bottom half is an empty block.
- No background music and no autoplay audio of any kind. You MAY add very short procedurally synthesized WebAudio blips (oscillator/noise, created lazily inside the first user gesture) as touch feedback, with a mute control; never load an audio file.
- Complete real states: loading, empty, success and error where relevant. Every control must actually work — no alert(), no console.log placeholders, no fake results, no button that does nothing.
- Content depth: give the experience enough material that it does not feel thin — aim for at least 8-12 distinct items / levels / variations of the core content, and make the difficulty ramp gently (the first 20 seconds must be winnable by anyone). Reviewers penalise "too fast", "too few", "only one interaction".
- Visual bar: exactly ONE core rule, understandable in 3 seconds, and generous visual response to every touch — motion, particles, deformation, colour, light, camera. Prefer canvas 2D; use Three.js with primitive/procedural geometry only if the concept is genuinely 3D. Do not use the canvas roundRect API (older iOS Safari lacks it). Never hardcode a light text colour that could land on a light background — derive text colour from the active theme.
- English-only canvas: never draw a Chinese character with fillText or strokeText, in any locale. No translated subtitle under the title, no bilingual watermark, no Chinese label baked into the artwork or the result card. Chinese appears only in ordinary DOM text after the user taps the EN / 中文 toggle.
- Cover composition: the title, the single tutorial line and the single button must not overlap each other or cover the focal subject of the artwork; leave at least 12px of clear space between them and keep the whole group inside the safe area.
- Determinism: never call Math.random(), Date.now() or locale formatting during SSR render — move them into useEffect or use a seeded generator, so hydration never mismatches. Finish with zero console errors at 393x852 portrait.
FINAL CHECK BEFORE YOU HAND IT OVER (verify each one at 393x852 portrait)
1. No text touches or crosses either side edge — measure every canvas headline with ctx.measureText and shrink it until it fits with a 24px margin.
2. Nothing you draw sits above y=56 or below y=(viewport height - 88).
3. The scene fills the whole screen height — no empty colour band in the lower half.
4. The first paint is entirely English; no Chinese is drawn on the canvas in any locale.
5. Zero console errors and zero hydration warnings.
6. The app root is position:fixed; inset:0; height:100% — not 100dvh; every canvas is sized from its parent via ResizeObserver with the fit run once on mount.
7. Share on the result screen calls share.compose and reads { accepted } before changing its label.Each swipe becomes a gust of wind that drags maple leaves across a temple valley and settles into a tapered brush stroke. Write a wind-poem in five strokes.
Place gravity wells across a dusk meadow and let a stream of luminous bees paint long-exposure attractor art through your field.
Enter your birth month and day; the observatory ignites a constellation belonging to that date alone, then names it and tells its myth.
Type a word and watch each letter grow into an iridescent bismuth crystal. Orbit the cluster, tap any crystal to shatter and regrow it.