# Zhuzhiliao: Browser Simulation of a Traditional Chinese Bamboo Toy

> Zhuzhiliao is a single HTML file that simulates the 竹知了 bamboo noise toy using Web Audio API and Canvas 2D, with real audio samples embedded directly in the file. It has no dependencies, no build step, and works offline indefinitely. The source is public for learning but redistribution and public deployment are explicitly prohibited by the license.

**imsai-sh/zhuzhiliao** — 竹知了 —— 一转就哇哇叫的传统玩具，Web 模拟版。零依赖单文件，真实录音采样，移动端优先。

- Repository: https://github.com/imsai-sh/zhuzhiliao
- Website: https://imsai.top
- Stars: 2,888 · Forks: 339
- Language: HTML
- License: NOASSERTION
- Published: 2026-09-16 · Updated: 2026-09-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/imsai-sh-zhuzhiliao

## What Zhuzhiliao Simulates and Why It Is Single-File

The 竹知了 is a traditional Chinese street toy: a bamboo tube with a membrane at one end and a stick attached to a rosin-coated string threaded through it. Swinging it in circles causes the string to alternate between sticking and slipping on the rosin, sending pulses along the string into the membrane, which resonates and produces the distinctive "waa waa" sound. The toy is inexpensive to make and was common at street markets, but the README notes that physical examples are increasingly rare to find.

Zhuzhiliao is a browser simulation of that toy. The entire implementation lives in a single index.html file with no external scripts, no CSS files, and no bundler. The README describes this as a deliberate design choice: save the file once and it can be played offline, without a network connection, for as long as a browser capable of running HTML5 exists. The audio sample is embedded directly in the HTML as an AAC data URI rather than loading from a separate file.

The project sits at a specific intersection: a toy that has nostalgic meaning for a generation of Chinese internet users, implemented with a level of technical care that makes the physics and audio synthesis worth examining independently of the subject matter.

## The Audio Engine: Real Sample with Synthesis Fallback

The primary audio source is a real recording of a bamboo cicada toy. The author extracted a 1.72-second clip from a video recording, selecting exactly four "waa" cycles with envelope boundaries aligned automatically. A 50-millisecond equal-power crossfade was baked into the loop point so the sample loops without clicks. The result is embedded in the HTML as AAC audio.

During playback, the Web Audio API plays the sample and adjusts the playback rate based on the rotation speed detected by the physics simulation. The recording was made at approximately 2.33 rotations per second; rotating faster than that makes the audio pitch and speed increase, matching what happens with a physical toy.

If the browser cannot decode the embedded AAC sample, the audio engine falls back to a fully synthesized chain. The README documents the synthesis approach in a comparison table:

- The sawtooth oscillator covers the resin slip-stick friction, with frequency rising from 55 to 195 Hz as speed increases, shaped through tanh soft-clipping to add harmonic roughness.
- A 24 to 45 Hz sine amplitude modulator adds the granular texture of cicada resonance.
- Three parallel bandpass resonant filters at 1050, 2150, and 3350 Hz model the bamboo membrane and tube cavity resonance.
- The "waa waa" sweep is produced by a bandpass filter whose center frequency tracks the rotation phase.

This fallback chain means the simulation degrades gracefully on browsers that block AAC playback rather than going silent entirely. Audio initialization is deferred until the first touch or click event, following browser user-activation rules, and the iOS interrupted state and older browsers lacking roundRect support are both handled with explicit fallbacks.

## The Physics Model

The bamboo tube is modeled as a point mass attached to a stick by an elastic string that can pull but not push. The simulation applies three forces: gravity pulling the mass down, string tension pulling toward the attachment point only when the string is taut, and air resistance proportional to velocity. The integration step is fixed at 1/240 of a second.

The key variable that drives the audio is the angular velocity of the tube around the stick. The faster the tube rotates and the tighter the string remains, the louder and brighter the sound. The README states that angular velocity below approximately 1.1 rotations per second, or a slack string, produces no sound. After the user releases the pointer, the physics simulation continues to run and lets the audio fade out naturally as kinetic energy dissipates through air resistance.

On touch screens, the anchor point of the stick is automatically moved above the user's finger to prevent the hand from obscuring the animated tube. Multitouch inputs are mutually exclusive: only the first contact drives the simulation.

## Running the Simulation

On a desktop or laptop, opening index.html directly in a browser is sufficient. No build step, no server, and no internet connection are required.

To test on a mobile device over a local network, start a static file server in the project directory:

```bash
python3 -m http.server 8123
```

Then connect the phone to the same Wi-Fi network and navigate to http://[computer-IP]:8123 on the device. The device motion feature requires either HTTPS or a local file origin, since browsers do not dispatch motion sensor events on plain HTTP from a network address. At a plain http:// LAN address, the button for the shake mode is hidden automatically.

Three interaction modes exist: drawing circles on the screen to swing the toy manually, tapping the toy or pressing the spacebar to trigger automatic swinging, and shaking the phone (accelerometer-driven) to swing by physical motion. On iOS, the device motion mode requires granting permission to the motion and orientation sensor on first use.

The "waa" count at the bottom of the page counts only manual swings, not automatic ones. The count is stored in the browser's localStorage and is private to the device. The README states that the page loads and then makes no further network requests.

## Technical Architecture of the Single File

The index.html contains Canvas 2D for rendering and Web Audio API for sound, both managed without any library. The static scene elements (background graphics) are pre-composited into an offscreen canvas layer to avoid redrawing them on every animation frame. After eight seconds of no interaction, the audio thread is suspended to reduce power consumption on mobile devices.

The SEO and platform integration metadata in the document head is unusually thorough for a single-page toy. The README describes it explicitly: OG and Twitter card meta tags, JSON-LD structured data (WebSite and WebApplication/VideoGame), a noscript block with a plain-text toy description for crawlers that do not execute JavaScript (the README mentions Baidu's spider specifically), a robots.txt, sitemap.xml, and a 1200x630 og-image.jpg.

The 404.html in the root is present specifically to support Cloudflare Pages hosting behavior. Without a 404.html, Cloudflare Pages returns a 200 status with the index page content for unknown paths, which is a soft-404 that miscounts in analytics and harms search indexing. The sw.js service worker and manifest.webmanifest support Progressive Web App installation.

An earlier version of the project included a Cloudflare Worker and Durable Object backend for global visitor counts and real-time waa tallies. The README notes this was taken down and the backend code removed from the repository; the git history contains the implementation for those who want to review how it worked.

## What p5.js Represents as an Alternative Approach

p5.js is a JavaScript library for creative coding that wraps Canvas drawing and provides access to audio through the p5.sound library. It is the standard starting point for browser-based visual and audio experiments in educational and creative contexts. A simulation like zhuzhiliao could be built with p5.js.

The practical difference is the delivery model. A p5.js sketch loads the library from a CDN or requires local serving, adding several hundred kilobytes of dependency code and a network requirement or a directory of files. Zhuzhiliao is one file that works by double-clicking. The README explicitly frames this as the point: the design goal is that someone saves the file today and it plays correctly without any supporting infrastructure two decades from now.

For a project where the toy itself is the artifact, not just a demonstration of a technique, the single-file constraint shapes every technical decision in the implementation. The embedded audio, the from-scratch physics, and the fallback synthesis chain all follow from that constraint rather than from a preference for one API over another.

## License: Not Open Source

The README is explicit on this point: the project is not open source in the OSI sense. The source is public for technical study and personal use, but the license does not permit redistribution of any kind, including modified versions, whether or not they are monetized. Public deployment on any domain other than imsai.top is not authorized. Commercial use is prohibited. Removing or altering the copyright notice terminates the license.

The README also specifies a content restriction: the project or any modification of it cannot be used to publish content that uses a real person's name, image, or voice without permission. This clause was added in response to a discovered case where someone had replaced the author's original hand-drawn cicada illustration with a real person's likeness in an unauthorized public deployment.

The last push to the repository was on 2026-08-14. The repository is not archived. The license situation means zhuzhiliao functions as a read-only reference: the code is available to study, but any production use requires written permission from the author.

## Conclusion

Zhuzhiliao is worth studying if you are interested in how Web Audio API synthesis, Canvas-based physics, and embedded media can be combined in a single self-contained HTML file. The rope-and-mass physics model, the real audio sample with fallback synthesis chain, and the device motion integration are each implemented from scratch without any library, which makes the code a compact reference for those techniques. However, the license does not permit redistribution or public deployment under any circumstances, so it cannot be used as a base for a deployed project. The only authorized deployment is at imsai.top. If you need a deployable starting point, the code can be studied but must not be reused.

## FAQ

### Can I deploy Zhuzhiliao on my own website?

No. The license explicitly prohibits redistribution and public deployment on any domain other than imsai.top. Any deployment on another domain is unauthorized regardless of whether it is modified or monetized.

### How does the device motion swing mode work in Zhuzhiliao?

On mobile, the accelerometer data from devicemotion events drives the swing arm directly, using the rotation of the device in its own coordinate frame. On iOS, the browser requires a permission grant for motion sensors on first use. At plain http:// LAN addresses, the button is hidden because browsers do not dispatch sensor events without a secure context.

### What happens if the browser cannot decode the embedded audio sample?

The audio falls back to a fully synthesized chain built from a sawtooth oscillator, amplitude modulation, and three parallel bandpass resonant filters that model the bamboo membrane and tube cavity. The fallback is activated automatically if AAC decoding fails.

## Sources

- [imsai-sh/zhuzhiliao on GitHub](https://github.com/imsai-sh/zhuzhiliao)
- [Issues](https://github.com/imsai-sh/zhuzhiliao/issues)
- [Project website](https://imsai.top)
- [README](https://github.com/imsai-sh/zhuzhiliao/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/imsai-sh-zhuzhiliao
