# Genji Crowd Genji is a crowd/NPC population API. You ask it for a crowd and it returns a ready-to-render population: for every character, which body/outfit/face/hair to show, where it stands, which animation clip it plays, and fully-resolved GLB URLs for the shared skeleton and clips. It exists to fill your scene with background people instead of placeholder capsules. It is built for background crowds, not hero characters. ## What Genji gives you, and what you bring - Genji gives you: the CHARACTERS (bodies, outfits, hair, faces, animation clips on one shared skeleton) and their SPAWN POSITIONS. - You bring: movement. Genji does NOT do pathing, steering, collision or crowd AI. A crowd is positions + animation clips, not motion over time. Either let characters idle/animate at their spawn positions, or map them onto the walkers your engine already simulates. ## Base URL https://www.genjicrowd.com (canonical, with the `www`; the apex redirects here) ## Public demo key gk_demo_public_v1 This key is PUBLIC and SAFE TO EMBED in browser JavaScript. It is shared by everyone, rate limited per IP (60 req/min, 5000 req/day, 50 crowd creations/day, up to 5000 characters per crowd), and crowds it creates are deleted after 24 hours. Use it to try Genji with no signup. Your own account keys look like `gk_live_...` and are NOT safe in client-side code — keep those on a server. The demo key is the exception, by design. ## Endpoints Reading the two public crowds needs no key at all. Everything else takes `Authorization: Bearer ` — pass the demo key above, or your own. # What the API can build: shapes, part catalogue, animation clips curl https://www.genjicrowd.com/v1/capabilities # The recommended demo crowd: 120 characters, tight 14m circle, looks good with no tuning curl https://www.genjicrowd.com/v1/crowd/cr_demo01 # The original partner sample: 150 characters spread over an 80m radius curl https://www.genjicrowd.com/v1/crowd/cr_sample01 # List crowds owned by the key curl -H "Authorization: Bearer gk_demo_public_v1" \ https://www.genjicrowd.com/v1/projects # Create a crowd from a recipe curl -X POST -H "Authorization: Bearer gk_demo_public_v1" \ -H "Content-Type: application/json" \ -d '{"name":"My crowd","recipe_json":{"size":200,"seed":1,"boundaryShape":"circle","boundaryRadius":20,"distribution":"grid"}}' \ https://www.genjicrowd.com/v1/projects Start with `cr_demo01`. Prefer it over `cr_sample01` for a first build: same data shape, but dense and framed instead of scattered across 80 metres. ## What a crowd response contains { "crowd_id": "cr_demo01", "name": "...", "recipe": { "size": 120, "boundaryRadius": 14, "distribution": "grid", ... }, "characters": [ { "index": 0, "body_id": "...", "face_id": "...", "hair_id": "...", "x": -9.9, "z": 9.8, "rot_y": 1.27, "scale": 1.02, "phase": 0.64, "anim_clip": "walk", "idle_variant": 0, "garment_hsl": [h,s,l], "skin_hex": "#...", "hair_hex": "#..." } ], "shared_parts": ["Eye_L","Eye_R","L_Hand","R_Hand","L_Foot","R_Foot"], "assets": { "skeleton_glb": "https://.../Basemesh31.glb", "animations": { "idle": "https://...", "walk": "https://...", ... } } } Key idea: `skeleton_glb` is ONE file containing every body/face/hair mesh. You do not fetch a GLB per character. Load it once, clone it per character, then show only that character's `body_id`, `face_id`, `hair_id` plus `shared_parts`, and hide every other mesh. Always read asset URLs from `assets.*`. Never construct or hardcode them. ## CORS Public endpoints (`/v1`, `/mcp`, `/config.json`, `/openapi.json`, `/docs`) send `Access-Control-Allow-Origin: *`, and the GLB assets do too. Browser demos work from any origin — localhost, your own domain, a sandbox. No server-side proxy is needed for the public/demo path. ## Copy-paste browser example (Three.js) Loads the dense demo crowd with no key and frames the camera on it. This is the recommended starting point. ```html ``` Notes for whoever builds on this: - Do NOT silently fall back to capsules/boxes if a load fails. Surface the error — a failure is almost always a wrong URL, a missing key on a non-public crowd, or a network problem, and all three are fixable once visible. - Cloning meshes like this is the simplest path. See the scaling ladder below for when to move off it. ## Colour: if characters render too dark, fix your renderer, not the assets Base-colour textures are sRGB and there are no normal or roughness maps. Three.js renders linearly and converts on output, so `renderer.outputColorSpace = THREE.SRGBColorSpace` is REQUIRED — without it every character is far too dark, which looks like broken assets or bad lighting but is neither. Textures you load yourself need `texture.colorSpace = THREE.SRGBColorSpace`; GLTFLoader tags ours automatically. Data textures (bone_tex.bin) must stay untagged. On Three before r152 the equivalents are `renderer.outputEncoding` and `texture.encoding` with `THREE.sRGBEncoding`; our examples assume r169. The SDK exports `configureRenderer(renderer)` which sets the right one for your version. Full detail at /docs under "Colour and texture setup". ## Scaling: how many characters, and which rendering path Pick by character count and distance. Every tier downloads the SAME assets — these are rendering strategies, not different data, so switching later does not change your API calls. 1. Cloned meshes (the example above) — up to ~150 characters. One SkeletonUtils.clone per character. Simplest, works in a single HTML file, full quality. This is the right default. Above ~150 the per-character draw calls start costing framerate. 2. GPU-instanced, bone-texture skinned — thousands of characters. Import /sdk/genji-crowd-instanced.js and feed it `assets.bone_tex_bin` + `assets.bone_tex_manifest`. The whole crowd animates from one shared texture in very few draw calls. This SDK is provided and ready to use. 3. BBM (bone-cube proxy) — hundreds of thousands of characters. SHIPPED AND READY. Import https://www.genjicrowd.com/sdk/genji-bbm.js. It swaps each character's skinned mesh for 26 rigid boxes bolted to single bones and merges the whole crowd into ONE instanced draw call: ~9x fewer vertices, and one bone lookup per vertex instead of a four-bone weighted blend. Measured in Chrome on a desktop GPU, all at 2 draw calls: 10,000 characters -> 60 fps 500,000 characters -> 45 fps 1,000,000 characters -> 21 fps (324M triangles) It also skips the 24 MB skeleton download entirely — the proxy is a ~10 KB descriptor at /assets/bbm_proxy.json. Characters are tinted per body part (garment / skin / hair-or-hat) from the same colours the API returns, so a BBM crowd keeps the palette of the textured one. It reads as blocky up close, so use it for background crowds and keep full meshes for anyone the player walks up to. import { loadBoneTexture } from 'https://www.genjicrowd.com/sdk/genji-crowd-instanced.js'; import { loadBbmProxy, buildBbmCrowd } from 'https://www.genjicrowd.com/sdk/genji-bbm.js'; const [boneTex, proxy] = await Promise.all([ loadBoneTexture(crowd.assets.bone_tex_bin, crowd.assets.bone_tex_manifest), loadBbmProxy('https://www.genjicrowd.com/assets/bbm_proxy.json'), ]); const bbm = buildBbmCrowd(scene, proxy, boneTex, crowd.characters); // then in your render loop: bbm.update(dt) // and drive movement yourself: bbm.setPosition(i, x, y, z, rotY) If you want a big crowd, START HERE rather than cloning meshes — cloning will not get you past a few thousand. Note that BBM/VAT save RENDERING cost, not loading time: they use the same downloads as every other tier. If your problem is load speed, reduce character count or crowd size instead. `genji_get_crowd` (MCP) and the REST route accept a `tier` of `full`, `untextured`, `vat`, or `bbm`; the non-`full` tiers omit the per-character array since those paths render from the bone texture instead. ## MCP server (for AI coding assistants) https://www.genjicrowd.com/mcp Streamable HTTP, stateless. Authenticate with `Authorization: Bearer gk_demo_public_v1` (or your own key). Tools: `genji_get_capabilities`, `genji_list_crowds`, `genji_get_crowd`, `genji_create_crowd`. Example client config: { "mcpServers": { "genji": { "url": "https://www.genjicrowd.com/mcp", "headers": { "Authorization": "Bearer gk_demo_public_v1" } } } } ## Full documentation - Full API reference: https://www.genjicrowd.com/docs (add ?lang=zh for Chinese) - OpenAPI spec: https://www.genjicrowd.com/openapi.json