Sheepram is a tool for solving Minecraft Onejump angle optimization problems. With custom language and numerical optimizer written entirely from scratch.
For the movement mathematics, expression representation, and optimization algorithm, see the Technical Guide.
For a detailed, complete example of modelling and solving a c4.5 p2p neo, see the P2P example.
Describe the movement timeline with the built-in Mothball-style DSL. The script generates the model length, drag, acceleration, and movement-relative angle offsets. Sheepram then optimizes the facing angles only.
initGnd(0.3169516131491288) sj.w sa.wa(11)
| Function | Movement state |
|---|---|
w |
Walking |
s |
Sprinting |
sn |
Sneaking |
sns |
Sneaking while sprinting |
st |
No movement input |
Note
Sheepram does not have sprint delay.
Movement functions support these modifiers:
| Syntax | Description |
|---|---|
j suffix |
Performs the movement as a jump, for example sj. |
a suffix |
Performs the movement in air, for example sa. |
.input |
Sets the movement keys using any valid combination of w, a, s, and d, for example s.wa or sa.d. Without it, movement defaults to forward (w). |
(duration) |
Repeats the movement for a positive whole-number duration, for example sa.wa(11). The duration may be a literal or a global variable. |
Examples:
sj.w // sprint-jump forward for one tick
sa.wa(11) // sprint in air, holding W+A, for 11 ticks
sn.s // sneak backward
st // no input for one tick
r(3) { s.w sa.w }
| Command | Description |
|---|---|
initGnd(vel)/ initAir(vel) |
Sets the initial velocity. Two variants differs by previous slip (initGnd takes the current slip when it is executed). One of them must appear exactly once and should normally be the first command. |
slip(value) |
Sets the ground slipperiness used by subsequent ground movements. The default is 0.6. |
speed(level)/slow(level) |
Sets the Speed/Slowness effect level. The level must be a whole number from 0 to 255. |
ix / ix(ticks) |
Forces X inertia by setting X drag to zero for the next movement tick, or for the next positive-integer number of movement ticks. Calling ix(...) while an X inertia queue is still active is an error. |
iz / iz(ticks) |
Forces Z inertia by setting Z drag to zero for the next movement tick, or for the next positive-integer number of movement ticks. Calling iz(...) while a Z inertia queue is still active is an error. |
mv(drag, accel, duration = 1) |
Adds a custom movement segment with the given drag, acceleration and optional duration. |
r(count) { ... } |
Repeats a non-empty block of movement functions and commands. loop(...) and repeat(...) are aliases. |
Command arguments may use arithmetic and variables from the global-variable table.
Markers give a name to a value at the current point in the Mothball timeline. Each marker command accepts exactly one name:
| Command | Marked value |
|---|---|
X(name) |
X position |
Z(name) |
Z position |
Vx(name) |
X velocity |
Vz(name) |
Z velocity |
F(name) |
Facing angle |
T(name) |
Turn to the next tick |
For example:
initGnd(0.31695) sj.w Z(z1) sa.wa(7) Z(z2)
This records the Z position after sj.w as z1, and the Z position after the
following seven air ticks as z2. Marker names can then be used as expressions
in the objective, constraints, and postprocessor:
z2 - z1 > 1.6
In this case, equivalent to:
Z[8] - Z[1] > 1.6
A marker name cannot conflict with a global variable, reserved name, or
another marker. Vx(), Vz(), and T() cannot mark the terminal tick because
they require a following tick.
This is the value you want to optimize.
Examples:
X[n]Z[n]- a custom expression written in the scripting language
Optional, but useful for:
- reusing constants
- defining indices relative to something else
You can write constraints using the custom scripting language.
Supported indexed variables:
| Variable | Meaning |
|---|---|
X[i] |
X position at tick i |
Z[i] |
Z position at tick i |
Vx[i] |
X velocity: X[i+1] - X[i] |
Vz[i] |
Z velocity: Z[i+1] - Z[i] |
F[i] |
Facing angle (degrees) |
T[i] |
Turn: F[i+1] - F[i] |
Example:
// Every non-comment line is parsed as a constraint
F[1] - F[0] = -45
// Equivalent to T[0] = -45
// Probably useful in noja
X[m] - X[0] > 8/16
// m must be defined in the table above
X[m2] > 0.5
// Since X[0] and Z[0] are always 0, you can omit them
// Yes, something goofy like X[X[X[X[0]]]] still compiles
Z[m2] - Z[m-1] > 1 + 0.6
Z[n] - Z[m-1] < 1.5625 + 0.6
Vx[it] < 0.005/0.91
// Means you hit inertia on X while tick = it in the air
// Use ix before that movement tick in the movement scriptNonlinear expressions such as X[1] * X[2] are not supported and will not compile.
The postprocessor lets you:
- shift the coordinate origin (affects the output table and plot)
- change table precision
X Origin and Z Origin are full expression fields. They accept the same
variables, markers, and model expressions as the objective and constraints.
For example, a marker declared with X(x1) in Mothball can be used as:
X Origin: x1 + 0.3
Z Origin: Z[m-1]
Table entries are evaluated from top to bottom. A variable may reference previously defined variables. Redefining a user variable overwrites its previous value.
The declaration order is:
global variables → Mothball model → n
Global variables cannot reference n. After Mothball generates the model,
n becomes available to the objective, constraints, and postprocessor. It is
reserved and cannot be redefined.
The double rotator trick represents the initial velocity as the sum of two
velocity vectors with independently optimized directions. To cover an exact
speed range
Then:
By the triangle inequality, the resulting speed satisfies:
For a normal ground tick with slip 0.6:
slip(1/0.91)
initGnd((min+max)/2)
mv(0.91*0.6, (max-min)/2)
slip(0.6)For an air tick:
slip(1/0.91)
initGnd((min+max)/2)
mv(0.91, (max-min)/2)
slip(0.6)Setting the initial drag to 1 makes the two velocities additive. The
mv(...) drag controls whether the combined velocity receives ground or air
drag on the following tick. The mv(...) tick is visible in the result table
and counts normally in all indices.
Numerical stability: Avoid choosing a
minthat is extremely small relative tomax. This makes$A$ and$B$ nearly equal, so reaching the lower speed bound requires near-perfect cancellation. In that region, tiny changes to either facing angle can cause large changes in the resulting direction and make optimization less reliable.
Download the .zip for your platform from the latest release.
- Unzip the downloaded file.
- Drag
Sheepram.appintoApplications. - Open
Sheepram.app.
- Unzip the downloaded file.
- Open the extracted folder.
- Double-click
Sheepram.exe.
Keep all shipped files in the extracted folder:
Sheepram.exeasset/- bundled
.dllfiles
GLFW Error 65544: WGL: Failed to make context current: The handle is invalid.
This can happen on dual-GPU laptops (integrated + discrete GPU) when Windows runs the app on the wrong GPU path.
- Open
Settings→System→Display→Graphics. - Add
Sheepram.exe. - Click
Options. - Choose
High performance. - Save and restart the app.
If needed, also force Sheepram.exe to use the discrete GPU in the NVIDIA / AMD control panel.
- If downloaded from workflow artifacts, unzip first to get
Sheepram-<version>-linux-x86_64.tar.gz. - Extract
Sheepram-<version>-linux-x86_64.tar.gz. - Open a terminal in the extracted folder.
- Run:
chmod +x Sheepram
./SheepramSheepram is the launcher script. It loads bundled libraries from lib/ before starting Sheepram.bin.
Optional launcher:
chmod +x Sheepram.desktopThen open Sheepram.desktop from your desktop environment.
Sheepram stores preferences and presets in the user data directory:
- macOS:
~/Library/Application Support/Sheepram - Windows:
%APPDATA%\Sheepram - Linux:
~/.local/share/Sheepram
Build:
make imgui-deps
make debug( domake releasefor more performant build )
Run:
./build/SheepramNote
Sheepram was rewritten in Odin.
The previous C++ implementation is preserved on the
legacy-cpp branch.

