bullet-heaven.ahraz.me
An agent-ready bullet hell maker built with Phaser and WebMCP.
First seen 2026-11-05 · Last seen 2026-11-05 · Source: webmcp.com
Answer 4 · Act 15 · Transact 1 · Score: Not yet scored
Tool inspector
apply_encounter
Builds an entire encounter in one call and replaces every existing wave with it. Prefer this over repeated edit_wave and edit_emitter calls whenever you are creating a level or restructuring more than one wave; use the edit_ tools to adjust an encounter that is already close. Every field except each emitter's x and y is optional and falls back to a sensible default, so a playable level can be as short as a list of emitter positions. Returns { updated: 'encounter', waveCount, emitterCount, waves }, where each 'waves' entry carries the generated id, name and emitterIds that a follow-up edit_ call needs; the encounter is not echoed back, so read get_maker_state with a waveId to inspect one wave. The whole replacement is a single undo step, so control_history reverts it in one call. The result reflects the state after this call, so no follow-up read is needed. The result's 'evaluation' reports whether the project has been measured since it changed; on verified: false, run evaluate_encounter before calling the edit an improvement. This returns to the editor first, on its own. From a landing page or shared play link that needs a page load, it opens the editor and asks you to retry once WebMCP reconnects rather than editing during teardown. Call get_maker_state immediately before this: the person edits the same live state you do.
Page: /editor
Input schema
| Property | Type | Required | Description |
|---|---|---|---|
waves |
array | yes | The waves to build, in play order. This replaces every existing wave. |
Raw JSON schema
{
"type": "object",
"properties": {
"waves": {
"minItems": 1,
"maxItems": 24,
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1,
"maxLength": 80,
"description": "A name for this wave that a later wave can reference through start.waveId. Only needed when something references it; otherwise one is generated."
},
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"enabled": {
"type": "boolean",
"description": "A disabled wave is skipped, by both the playtest and evaluation."
},
"start": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"encounter_start",
"at_time",
"after_wave_cleared",
"defeat_count"
],
"description": "What starts the wave, and which of the other start fields apply: 'encounter_start' takes delay, 'at_time' requires time, 'after_wave_cleared' requires waveId and takes delay, 'defeat_count' requires waveId and count."
},
"delay": {
"type": "number",
"minimum": 0,
"maximum": 3600,
"description": "Seconds to wait once the condition is met. For type encounter_start or after_wave_cleared."
},
"time": {
"type": "number",
"minimum": 0,
"maximum": 3600,
"description": "Seconds from the start of the encounter. Required by type at_time."
},
"waveId": {
"type": "string",
"minLength": 1,
"description": "The earlier wave this one waits on, matching that wave's own 'id'. Required by type after_wave_cleared and defeat_count, and it must appear earlier in the waves array."
},
"count": {
"type": "integer",
"minimum": 1,
"maximum": 999,
"description": "Emitters of the referenced wave that must be defeated first. Required by type defeat_count."
}
},
"required": [
"type"
],
"additionalProperties": false,
"description": "When the wave begins. Omit it and the wave starts after the previous entry in the array clears, which is what a linear level wants."
},
"emitters": {
"minItems": 1,
"maxItems": 24,
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"enabled": {
"type": "boolean"
},
"angle": {
"type": "number",
"minimum": -180,
"maximum": 180,
"description": "Facing in screen-space degrees: 0 points right and -90 points up."
},
"radius": {
"type": "number",
"minimum": 2,
"maximum": 64,
"description": "Body size in pixels. This is also the damage circle, so a smaller emitter is harder to hit."
},
"visibleInPlay": {
"type": "boolean",
"description": "Whether the body is drawn during Play. It still fires when hidden."
},
"combatType": {
"type": "string",
"enum": [
"destructible",
"invulnerable"
],
"description": "'destructible' can be shot down. 'invulnerable' cannot, and rejects hitPoints and countsTowardClear."
},
"hitPoints": {
"type": "integer",
"minimum": 1,
"maximum": 999,
"description": "Shots to destroy. Requires combatType destructible."
},
"countsTowardClear": {
"type": "boolean",
"description": "Whether the wave waits for this emitter to be defeated. Requires combatType destructible; when true the lifetime must be until_defeated, because the wave is waiting for it."
},
"lifetimeType": {
"type": "string",
"enum": [
"until_defeated",
"duration",
"until_wave_complete"
],
"description": "'until_defeated' lasts until shot down and is the only lifetime valid for an emitter that counts toward wave clear. 'duration' needs lifetimeSeconds. 'until_wave_complete' disappears when the wave ends."
},
"lifetimeSeconds": {
"type": "number",
"minimum": 0,
"maximum": 3600,
"description": "Seconds the emitter lives. Required by, and only valid with, lifetimeType duration."
},
"movementType": {
"type": "string",
"enum": [
"stationary",
"patrol"
],
"description": "'patrol' moves between (x, y) and (endX, endY) and needs all three patrol fields; 'stationary' rejects them."
},
"endX": {
"type": "number",
"minimum": -0.5,
"maximum": 1.5,
"description": "Patrol endpoint, normalized like x. Requires movementType patrol."
},
"endY": {
"type": "number",
"minimum": -0.5,
"maximum": 1.5,
"description": "Patrol endpoint, normalized like y. Requires movementType patrol."
},
"movementSpeed": {
"type": "number",
"minimum": 1,
"maximum": 1200,
"description": "Patrol speed in pixels per second. Requires movementType patrol."
},
"x": {
"type": "number",
"minimum": -0.5,
"maximum": 1.5,
"description": "Horizontal position, normalized 0-1 across the arena. Values slightly outside that range place the emitter off-screen."
},
"y": {
"type": "number",
"minimum": -0.5,
"maximum": 1.5,
"description": "Vertical position, normalized 0-1 across the arena."
},
"patterns": {
"minItems": 1,
"maxItems": 32,
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 80
},
"enabled": {
"type": "boolean"
},
"initialDelay": {
"type": "number",
"minimum": 0,
"maximum": 3600,
"description": "Seconds after the emitter appears before it first fires."
},
"interval": {
"type": "number",
"minimum": 0.05,
"maximum": 30,
"description": "Seconds between volleys."
},
"burstCount": {
"type": "integer",
"minimum": 1,
"maximum": 99,
"description": "Volleys fired back to back, burstInterval apart, each interval."
},
"burstInterval": {
"type": "number",
"minimum": 0,
"maximum": 30,
"description": "Seconds between the volleys of one burst."
},
"volleys": {
"anyOf": [
{
"type": "string",
"const": "continuous"
},
{
"type": "integer",
"minimum": 1,
"maximum": 999
}
],
"description": "How many volleys the pattern fires in total, or 'continuous' to fire for as long as the emitter lives."
},
"formationType": {
"type": "string",
"enum": [
"single",
"fan",
"ring"
],
"description": "'single' fires one projectile, 'fan' spreads formationCount across spreadAngle, 'ring' spreads formationCount over 360 degrees. A fan or ring needs formationCount."
},
"formationCount": {
"type": "integer",
"minimum": 1,
"maximum": 128,
"description": "Projectiles per volley. Requires formationType fan or ring, and is required when creating one; a single formation fires one projectile and rejects it."
},
"spreadAngle": {
"type": "number",
"minimum": 0,
"maximum": 360,
"description": "Total width of a fan in degrees. Requires formationType fan; a ring already covers 360 degrees."
},
"aimMode": {
"type": "string",
"enum": [
"at_player",
"fixed"
],
"description": "'at_player' samples the player's position each volley; 'fixed' fires along the emitter's angle."
},
"rotationPerVolley": {
"type": "number",
"minimum": -180,
"maximum": 180,
"description": "Degrees the aim advances per volley; this is what makes a spiral."
},
"speed": {
"type": "number",
"minimum": 20,
"maximum": 2000,
"description": "Projectile speed in pixels per second."
},
"acceleration": {
"type": "number",
"minimum": -5000,
"maximum": 5000,
"description": "Pixels per second squared, up to maxSpeed."
},
"maxSpeed": {
"type": "number",
"minimum": 20,
"maximum": 4000,
"description": "Ceiling for an accelerating projectile, in pixels per second. Must be at least speed; omit it and it follows a raised speed up."
},
"angularVelocity": {
"type": "number",
"minimum": -720,
"maximum": 720,
"description": "Degrees per second the projectile curves as it travels."
},
"lifetime": {
"type": "number",
"minimum": 0.05,
"maximum": 60,
"description": "Seconds a projectile lives before it is culled."
},
"collisionRadius": {
"type": "number",
"minimum": 1,
"maximum": 32,
"description": "Damage circle in pixels, independent of renderRadius."
},
"renderRadius": {
"type": "number",
"minimum": 1,
"maximum": 48,
"description": "Drawn size in pixels. Purely visual."
},
"color": {
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$",
"description": "Projectile color as a six-digit CSS hex value."
}
},
"additionalProperties": false
},
"description": "Firing patterns for this emitter. Omit it for one default pattern; several patterns on one emitter fire independently and layer into a composite attack."
}
},
"required": [
"x",
"y"
],
"additionalProperties": false
}
}
},
"required": [
"emitters"
],
"additionalProperties": false
},
"description": "The waves to build, in play order. This replaces every existing wave."
}
},
"required": [
"waves"
],
"additionalProperties": false
}
Similar websites
wfsim.app
A Warframe calculator that simulates the fight instead of estimating it — builder, simulator, optimizer. Every formula cites its source, and the golden tests ar…
commonplace-webmcp.vercel.app
Commonplace is an editable social reading space built for people and their browser agents.
pixelforge-studio.appcaster.chatgpt.site
A professional browser pixel-art editor for drawing, frame animation, palettes, sprite sheets, GIF export, and WebMCP automation.
pixelite.taskcraft.site
Pixelite