frame:constraint, comma-separated, 1-based.
1:WD exact W+D ·
2:+W W must be held ·
3:-D D must NOT be held ·
4:+W-D W held & D not held ·
5:!WD anything except W+D ·
6: no keys
frame (1-based)
The Appel TAS Editor lets you record, edit, and replay frame-perfect inputs for the game Appel. Write inputs in the Frame Inputs tab, watch them play out on the canvas, scrub the timeline, and use the Brute Force Solver to automatically find better sequences.
The layout is split into a left panel (game canvas + player state) and a right panel (level code, inputs/solver, replay). A timeline runs along the bottom showing every frame's key state.
| 1. Load a level | Paste a level code into the Level Code field at the top-right and press Enter. |
| 2. Write inputs | Switch to the Frame Inputs tab and type your input sequence (see syntax below). |
| 3. Playback | Press Q to restart from frame 0. The game runs automatically at the current FPS. |
| 4. Export | The Replay Code box updates automatically. Click Import Replay Code to load one back in. |
| Q | Restart the TAS from frame 0. |
| V | Pause — or, if already paused, advance exactly one frame (frame-step). |
| B | Resume playback (unpause). |
| C | Step back one frame (rewind by one). |
| 1 · 2 · 3 | Save state to slot 1, 2, or 3 at the current frame. |
| 4 · 5 · 6 | Load state from slot 1, 2, or 3 (loads the frame saved with that slot). |
| H | Toggle Handplay Mode — lets you record inputs live by holding keys and pressing V. |
| Space | Pause / Unpause |
Save states are stored in memory only — they are lost on page refresh.
Each token is a set of keys followed by a frame count. Keys are W (up/jump), A (left), S (down), D (right). They are case-insensitive.
| D1 | Hold D (right) for 1 frame. |
| WD5 | Hold W + D simultaneously for 5 frames. |
| _6 | No keys held for 6 frames (underscore = empty). |
| 6 | Also means no keys for 6 frames (number alone). |
| (D1 SD1)50 | Repeat the contents of the parentheses 50 times. |
| break | Auto-pauses playback at this frame so you can inspect the state. |
| // comment | Everything after // on a line is ignored. |
The active token is highlighted in yellow in the editor as the TAS plays.
Updates every frame with the physics engine's internal state. Key fields:
| PLAYER_X / Y | Pixel position of the player. |
| PLAYER_SX / SY | Horizontal / vertical speed (sub-pixels per frame). |
| is_jumping | Frames since the last jump started. |
| is_falling | Frames spent falling (airborne without jumping). |
| player_state | Internal state code (idle, run, jump, fall, dead…). |
| player_wall | Which wall the player is touching, if any. |
| flipped | Whether the sprite is mirrored (facing left). |
| friction | Current friction coefficient applied this frame. |
The strip at the bottom shows every frame as a coloured band — each key combination gets its own colour. The yellow playhead follows the current frame.
| Click / drag | Seek to any frame instantly. |
| Zoom slider | Controls how many pixels represent one frame (1–20). |
The solver searches all possible key combinations over a short window of frames to find the sequence that best satisfies your Optimization Goal.
| Player State | Captures the physics state at the current TAS frame as the search starting point. Click Get Current Player State. |
| Search Depth | Number of frames to search ahead. Higher = slower but potentially better results. |
| Optimization Goal | A JS expression evaluated at the final frame. Any player-state field can be used (e.g. PLAYER_X, Math.abs(PLAYER_SX)). Choose Maximize or Minimize. |
| Frame Pins | Lock specific frames to certain inputs. Format: frame:constraint. Examples: 1:+W (W must be held on frame 1), 2:-D (D must NOT be held), 3:WD (exact W+D only). |
| Kill Zone | A JS expression — if it evaluates to true on any frame, that branch is pruned early (e.g. PLAYER_X > 300 to discard runs that go too far right). |
| Enabled Combos | Toggle which key combinations the solver is allowed to try. The number cap limits how many total frames that combo may appear in the result. |
| TAS Output | The best sequence found is shown here in TAS format, ready to paste into the Frame Inputs editor. |
Preset goals: Max X = move as far right as possible · Max Speed = maximise horizontal speed · X and SX = weighted position + speed combo.
The Replay Code box (Frame Inputs tab, bottom) contains the game's native binary-encoded replay format. It is regenerated automatically whenever your inputs change.
To load someone else's replay, paste it into the Replay Code box and click Import Replay Code. This converts it back to TAS-format inputs in the editor so you can inspect or modify it frame by frame.
Press H to toggle Handplay Mode (status turns orange). In this mode you record inputs frame-by-frame at the current playhead position — works when the TAS is paused.
| Hold W/A/S/D | The keys you physically hold are shown in the Keys status field. |
| V (while in Handplay) | Commits one frame with the currently-held keys, inserted at the playhead position rather than appended to the end. If the playhead is inside an existing token with a different combo, that token is split. If the combos match, the token is simply extended by 1. The playhead then advances one frame. |
| H again | Exit Handplay Mode and return to normal operation. |
Tip: seek to any frame mid-sequence with the timeline, then use Handplay to overwrite or insert frames there without touching the rest of the TAS.
You can freely reposition the camera at any time — including while paused or frame-stepping.
| Click & drag canvas | Pan the camera in any direction. Works during playback and while paused. |
| Double-click canvas | Snap the camera back to the default (player-following) position. |
| Use break | Place a break token just before a tricky section. The TAS pauses automatically so you can study the player state before continuing. |
| Save states | Save (1–3) at a known-good frame, experiment with V/C to step forward/back, then reload (4–6) if things go wrong. |
| Lower FPS | Drop the FPS field to 1–5 to watch slow-motion and read each frame's state clearly. |
| Solver + paste | Pause at a tough spot, run the solver for a few frames, copy the output, and paste it into the inputs editor at that position. |
| Parentheses | Use (…)N to repeat long patterns compactly — great for corridors or repeated jumps. |