Thumbnail

Multi-Axis Scripting in OFS Tutorial, Tips, and Resources
Part 1: Introduction, Resources, and Setup
Introduction:
I want to share the information that i’ve gathered since I first started scripting a year ago. I don’t want to rehash or recreate an introductory guide, Silbowits already has a fantastic guide for those brand new to scripting, and I suggest you check that out if you’re new. As such, this guide assumes you have basic knowledge of scripting already.
Instead, this guide will just be some more advanced things I learned about multi-axis scripting in particular. I’ve done a fair amount of research and experimentation while learning how to script MA and would like to centralize and share what I learned with the community.
The main goal of this post is to make MA scripting more accessible to newcomers and to share knowledge among MA scripters. So please feel free to dispute sections or add input in the comments. I don’t claim to know everything, and feedback/criticism is encouraged.
Resources:
Necessary Program (Not the only option, just the only one I’ve used):
OpenFunscripter
OFS main github repository is archived and abandoned by the orginal dev. There are a few active forks of the repo that have differing goals on the direction their OFS fork follows.
-
Eroscripts/OFS seems to have the goal of becoming the new centralized repo for the abandonware. It also implements logic into OFS that the Eroscripts site uses to generate merged funscripts and heatmaps. Most of the work was done by a moderator for Eroscripts @Dimava
-
ack00gar/OFS main feature is MacOS support, with the goal of integrating modern features like AI script generation using motion data capture via fun gen. It also merged some Eroscripts/OFS commits into the repository, like logic using double values based on the commit history.
-
SaekoM/OFS fork of Eroscripts/OFS that has the double value logic created by Dimava. Main feature is an integrated 3D Simulator instead of separate app and an animated image preview exporter for easier creation of the nice embedded previews you see many scripters embed in their posts.
Recommended Programs
OFS Simulator 3D
The OFS original dev also made OFS simulator 3D to render an object that displays multi-axis movement, connecting to OFS via webhook. Unfortunately this is also abandonware at this point, and I suggest using either of these forks instead of the original.
-
ZestyRaraferu/OFS_Simulator3D This fork fixes a bug in the original that incorrrectly displays surge and sway values.
-
OppositeOdd/OFS_Simulator3D This is my own personal fork, that adds a new model and some other handy features I use as well.
- Also to add on to wata35p’s tip, if you use my fork it has rotating hotkeys, and valve hotkeys. If you want to view available hotkeys you can press ‘H’ for help.
I-Framing
I-Framing a video is very important for anyone who needs to constantly seek a video one frame at a time. It’s commonly used in video editing, but it’s also a funscript creators best friend. If you ever grew frustrated at how a video lags while seeking frame to frame in OFS, it was likely solveable by this step.
The main downside is space and resource usage, IFraming a video will blow the size up especially for high frame rates. It will also cause completely unecessary strain on a video decoder when using it for regular playback. So you should always keep the original file, and delete the IFramed copy after you finish your scripts.
Here’s an ffmpeg command example I personally use to IFrame my videos. You’ll need to keep in mind your own setup as this assumes an NVIDIA gpu.
ffmpeg command
ffmpeg -y -hide_banner -loglevel info `
-hwaccel cuda `
-i "input.mp4" `
-map 0:v:0 `
-map 0:a? `
-map 0:s? `
-c:v hevc_nvenc `
-profile:v main10 `
-pix_fmt p010le `
-preset p1 `
-rc constqp `
-qp 20 `
-g 1 `
-bf 0 `
-c:a copy `
-c:s copy `
-movflags +faststart `
"output.mp4"
Alternatively, there’s the IFramer program by @CertainlyWicked that does this but in a GUI. I don’t personally use it, as I prefer manually choosing resolution on a per video basis. But you might find it helpful.
Setup:
Initial Project Preparation:
-
Open OFS, OFS Simulator, and your IFramed Video in OFS.
-
OFS populates your stroke axis automatically. Add in the other axes you want to script. You can hide them while you focus on one axis at a time if necessary by right clicking the script preview and unchecking the box next to the displayed scripts.
-
Prep your project however you like, I prefer:
- Adding in all axes I want to script
- Creating chapters for the major sections of the video
- Filling in metadata
- Adding neutral beginning and end points for all scripts on the first and last frame of the video
- Enabling the statistics pop-out integrated into OFS.
Part 2: MA Script Definitions and Creation:
Definitions:
Visual Example
Main Channels
| Channel | Name | Definition | Neutral Value |
|---|---|---|---|
L0 |
Stroke | Translation on the Y axis | 50 |
L1 |
Surge | Translation on the Z axis | 50 |
L2 |
Sway | Translation on the X axis | 50 |
R0 |
Twist | Rotation on the Y axis | 50 |
R1 |
Roll | Rotation on the Z axis | 50 |
R2 |
Pitch | Rotation on the X axis | 50 |
Add-On Channels
| Channel | Name | Neutral Value |
|---|---|---|
V0 |
Vibration (vib) |
0 |
V1 |
Pump | 0 |
A0 |
Valve | 0 |
A1 |
Suck | 0 |
A2 |
Lube | 0 |
-
The Main Channels consist of two assigned scripts for each axis in a 3D Cartesian space, one for rotation and one for translation. Translation is movement from point A to point B on the axis, Rotation is using the axis as an anchor and rotating the 3D object without letting the position on the anchor point change.
-
X Axis: Sway, Pitch
-
Y Axis: Stroke, Twist
-
Z Axis: Surge, Roll
-
There are also bolt on mods like T-Valve, pump, vibe, squeeze that operate on a sliding scale of fully active-inactive or fully open-closed.
-
-
A Neutral value is where the device will sit in its home position.
Creating Each Axis and Visualizing in 3D:
-
I will list these in the order I typically tackle them. Then I will give reference pictures and tips I typically follow for each individual axis.
Stroke (All Stroker Devices):
Tips and Tricks
- Take your time scripting stroke, it’s like building the foundation for the rest of the script. Many times you can script the other axes accurately by pulling from your stroke axis.
In this example I made all MA scripts in like 2 minutes, all I did was copy paste the values from stroke and slightly shift them to create an oscillation type movement. I would normally then fine tune the script to smooth it out, you can see the movements are off still. But the time saved from using a well scripted stroke for initial reference can’t be understated for scenes with repetitive movement.

- Use smoothing to add detail to your stroke axis, you can turn a jerky up down movement into a smooth gradual stroke by adding two points to either side of the apex.

- Keep the stroke at lower values if you plan to have a lot of MA movement or want the movement focused on another axis, it will help prevent slipping and can help give a better end result. In this example, I know I’m going to add in a lot of twist motion later. So I decided to set stroke to a static 70 instead of a more accurate 90. I also don’t need to represent the tongue with the stroke axis like someone only scripting stroke might do, so I let the other axis handle it and left stroke static.

- Script accurate but with exaggerations, especially for stroke, then test the result and exaggerate more as required. You can script the most accurate values that display perfect in OFS only to find out the script is boring while testing. Make sure you test and verify that what you want the script to do actually feels right when used. (I’m so guilty of this in my older scripts)
Twist (Optional Module Commonly Found on SR Devices):
Tips and Tricks
-
Twist imo adds more to a script than any other axis besides stroke. So whenever you can add it, you should. This is also why I script it second, I want to ensure twist and stroke are done first and base the other funscripts around them.
-
50 is the neutral value or no rotation.
-
The values below assume top-down perspective, reverse clockwise/counter if you’re viewing bottom-up
-
51-100 will be a counter-clockwise, or right if looking straight ahead, rotation to a maximum of 135° from neutral.
-
49-0 will be a clockwise, or left if looking straight ahead, rotation to a maximum of 135° from neutral.
-
Maximum turning is 270° by a value change from 0 to 100.

-
If you want to visualize where twist should be at any given time, imagine a tongue at the bottom of the stroker. Some simulators have this built in.
-
Like stroke, twist tends to need a bit extra exaggeration to be felt in the final result, however going overboard can easily become overstimulating. When I script, I try to exaggerate by around 10 for small movements. and less for large movements. i.e an “accurate” value of 40 will become 30 for exaggeration. Or an “accurate” value of 30 will become 25. etc.
-
In this example you can see exaggerations I typically do and how I set up twist to follow screen movements. I’m focusing on how much speed between points is needed and where the end points should be. Also notice how twist takes center stage since there’s no stroke movement, it will get even more noticeable when I add in the other axes.

- You can also see a common limitation that twist cannot rotate 360 degrees infinitely, so you have to get creative on how you represent a full circular movement. Like the tongue play in the above example.
Roll (OSR2, OSR2+, SR6):
Tips and Tricks
- 50 is the neutral
- 51-100 is a clockwise rotation app. 45°
- 49-0 is a counter-clockwise rotation app. 45°
- Maximum turning is app. 90° by a value change from 0 to 100.

- How I like scripting roll depends heavily on what axes I plan to create. If I am scripting for an OSR2+ I use roll to translate some of the left/right movements that would normally be better suited for sway.
- Conversely, if I am scripting sway as well, I tend to try to only script the angle of the mouth/anus/vagina and not assign it the left/right movements. This is especially important when the angle is opposite of the direction of movement, you can only accurately script that movement with both scripts.
In the example below, you can see which movements I tend to script sway to vs which ones I script roll to. The first video is only roll, the second is both roll and sway, the third is all axes together.



- Another common technique for roll is to take work you’ve already done on the stroke axis, and use that timing to create a perfect circular movement.
- First copy your stroke axis for a section, then paste those values on roll.
- Adjust the upper and lower bounds to best fit your scene depending on how much movement you have.
- Finally select all points and adjust them to start one half phase to the right or left of stroke. As though stroke=Sin(x) and Roll=Cos(x) if you know those graphs.

Pitch (OSR2+, SR6):
Tips and Tricks
- 50 is the neutral
- 51-100 is a rotation app. 45° where the bottom of the stroker comes towards the user.
- 49-0 is a rotation app. 45° where the bottom of the stroker goes away from the user.
- Maximum turning is app. 90° by a value change from 0 to 100.

-
Most of the points made about roll apply to pitch as well, the only difference is it being tied to surge instead of sway.
-
You should really focus pitch on grinding or licking scenes, or when you want more feeling/pressure applied to the bottom or top of the penis.
-
Be careful not to apply extreme pitch values when the stroke value is also high. It’s easy for a user to slip out when this happens.
-
I tried to keep pitch simple for this section, but I did add some exaggeration to emphasize the downward and upward stroke. And I added a pitch to put pressure on the bottom of the penis during the licking portion.

-
Just like roll you can easily create a circular movement by taking stroke values, if you copy stroke values over 1 to 1 with no phase shift it should create what you see in the example.
-
If you instead phase shift them the same way we did with roll, it will create a grinding type circular motion. Where the maximum pitch up/down happens halfway between the maximum/minumum for stroke. I find this incredibly useful for cowgirl grinding scenes.

Surge (SR6):
Tips and Tricks
- 50 is the neutral
- 51-100 is a translation movement away from the user app. 3cm (tbh i’m a guy I think everything is 6 inches so i’m not sure about this measurement)
- 49-0 is a translation movement towards the user app. 3cm
- Maximum turning is app. 6cm towards to away by a value change from 0 to 100.

- in my opinion Surge and Sway are both better saved for large changes of position where the entire head/hand/center mass are moving. Leave the finer details to roll and pitch and instead use surge sway to ‘accent’ the movements handled by them.

-
Think about whether what you’re scripting is moving towards the POV or away from it while doing surge. And be consistent about how you choose to determine your anchor point of reference. I’ll explain what I mean in detail for anchor point of reference in the more advanced tips section.
-
A lot of times you can match surge to pitch axis and invert/phase shift it. You should always go through it again though, as sometimes the movement will be completely separate from the angle and you’ll need to manually script it, this happens a lot with IRL scenes i’ve noticed.

- Save your big movements for when it makes sense, else leave it to the other axes to translate the movement you want. When you do get big movements though, go ham on the surge/sway.
Sway (SR6):
Tips and Tricks
- 50 is the neutral
- 51-100 is a translation movement to the left app. 3cm if looking at the device from a front view (tbh i’m a guy I think everything is 6 inches so i’m not sure about this measurement)
- 49-0 is a translation movement right app. 3cm if looking at the device from a front view
- Maximum turning is app. 6cm right to left front view by a value change from 0 to 100.

- In my opinion Surge and Sway are both better saved for large changes of position where the entire head/hand/center mass are moving. Leave the finer details to roll and pitch and instead use surge sway to ‘accent’ the movements handled by them.

-
A lot of times you can match sway to roll axis and invert/phase shift it. You should always go through it again though, as sometimes the movement will be completely separate from the angle and you’ll need to manually script it, this happens a lot with IRL scenes i’ve noticed.
-
Save your big movements for when it makes sense, else leave it to the other axes to translate the movement you want while keeping surge/sway conservative. When you do get big movements though, go ham on the surge/sway.

Valve (Optional Module for SR Devices):
Tips and Tricks
-
Not super common for people to script this one, honestly the t-valve itself is a little lackluster but I have hope it improves in the future.
-
I won’t get super in depth for the why/proof but I believe scripters should use 0=closed 100=open when doing valve. See this post’s comment section if you want to see why.
-
Valve has 2 main methods of control: “A0=.valve.funscript=.suckManual.funscript(XTPlayer)=manual opening and closing” and “A1=.suck.funscript=automatic control based on the stroke script, creating dynamic suction”
-
I prefer .valve.funscript and manually closing the valve on downstroke when it makes sense there would be suction(i.e BJ scene not HJ scene), I fully close the valve at the strokes lowest point and don’t open it again until it makes sense for no suction in the scene.
-
You can see this in action in the example below, the idea is to have as little air space in the sleeve as possible when the valve fully closes. That way, on the up stroke it creates the negative pressure suction in the sleeve.

-
If you want to use .suck.funscript instead, the value you input into funscript is the maximum amount the valve will close. So if you set .suck.funscript to 100, the valve will alternate between 0 and 100 depending on strokes value. If you set it to 50, the valve will still open and close based on stroke values, but it will never close more than halfway (50).
-
Visually it looks like this, notice how the valve gauge follows the stroke pattern.

-
You can technically use both .suck.funscript and .valve.funscript together. The script that controls the valve will be one that sent the last change in value. If they both send values at the same time, .suck.funscript overrides .valve.funscript.
-
Example 1: You set .valve.funscript to 50 and set it to change to 100 in the next 10 seconds. You also set .suck.funscript to 50 and set to change to 100 in the next 10 seconds. .suck.funscript will control the valve instead of .valve.funscript.
-
Example 2: You set .suck.funscript to 100 static over the next 10 seconds. .valve.funscript to 50 → 100, .valve.funscript takes control even though .suck.funscript is also loaded. This is because .suck.funscript provided no change in value.
-
Disclaimer: These examples are only true if ‘polling update’ is set to true in MFP. As that’s what decides whether to send only value changes, or constant positional updates. It can also get messy if you start sending value changes simultaneously, so try to keep the script you don’t want controlling it static.
-
Others (Vibration/Lubrication/Other Modules for SR Devices):
Other Channels
-
[Vib .vib.funscript] controls vibrating mods, I don’t know much about them other than they operate on a sliding scale, 100=full power 0=off. And they pretty much have no speed limit/very high speed limit. So you don’t have to keep the slope less than 600 units/s the way you would for stroker scripts. I think dedicated vibrator toys also rename from .vib.funscript but i’m not 100% sure, if anyone knows more about them i’d be happy to update this section.
-
[Lube/Pump .lube.funscript .pump.funscript] both control lubrication pumps. 100=maximum flow 0=no flow. Which script name you should use apparently depends on how your firmware and PCB mapped the pump on your device (i.e which channel it uses A2 or V1). I don’t know much about the details on that tbh. I’ve also yet to make a script and test it out.
-
TCode and MFP/XTPlayer are designed in ways you can add more bolt on mods in the future. Right now these are the only default mapped ones, but technically you could have auxiliary channels A3/A4/etc. mapped to things like squeeze or heat mods.
Part 3: Other Tips, Creator Liberty, and Resources:
Scripting What is Felt vs What is Seen:
long ah post
Awhile back I made this EmilyMansonn post and I remember it giving me a really hard time to the point I even posted about it asking for help. My main issue was I couldn’t decide if I should script what is seen based on camera position, or what the dude would be feeling.
I ended up deciding to go with camera placement and what is seen by the viewer. My thought process was that when played back at full speed, most people are too engrossed in the video to accurately place themselves in the dudes position and judging the script as “off”. Instead, they may find it strange when the script is accurate to 3D movement because the girls head is moving right on the camera but left from the dudes POV.
This is unique to MA creators and something you’ll have to decide on for most non-pov scenes. If camera angles change frequently you may even catch yourself needing to flip scripts. This is all your choice as the scripter on how to tackle it but something you should be aware of.
Speed Limiting:
Device speed limits
Not all devices are built the same and it can be easy to make a jackhammer dick destroyer 9000 script by having insane speeds on your scripts. All the more power to you if you like that kind of thing but for safety reasons and device longetivity I suggest following these common speed limits based on the device you’re scripting for.
Disclaimer: This is what I use but i’m not the guru of all knowledge. If someone has better speed limits I’m happy to adjust this section.
Soft cap = “try to keep under”
Hard cap = “do not release anything above this speed”
If you want to view the speed at a given time open the statistics panel in OFS
-
The Handy = [400 units/s soft cap or 500 units/s hard cap]
-
OSR1/OSR2/OSR2+/SR6 = [600 units/s soft cap or 700 units/s hard cap]
-
The Handy 2 = [600 units/s soft cap or 700 units/s hard cap]
-
The Handy 2 Overclocked = [700 units/s soft cap or 800 units/s hard cap]
A Note on Extreme MA Script Values from Wata35P:
Notes
-
wata35p has great advice and I also want to emphasize the importance of testing if you want to incorporate maximum or minimum MA values. I personally hardly ever use 0 or 100 values for R1-2 or L1-L2. I’ve also never experienced bugging so I was unaware of this, it is worth noting if you do want to experiment with max range in your scripts.
-
To piggyback off their tip i’d also like to add in that you’ll tend to be safer from slipping out at lower stroke values. If you do want to have really high values for the MA axes, try lowering stroke a bit to compensate and keep the user from slipping out.
-
If you don’t want to lower stroke for whatever reason, compensate with the other axes. It makes no sense to have sway and surge at 100, then roll at 0. It’s asking for dick destruction.
Angle Scripting and Common Mistakes for Newcomers:
Notes
-
I can’t stress this enough and honestly I should have included this in the post originally. To give a visual example of what wata35p means by this see the videos below. The top example is the preferred method of scripting, where the angle of the entry point is preserved, leaving to a more realistic script.
-
The angle of the mouth doesn’t actually change much in the video, but the penis angle does due to sway movement. If you script penis angle it ends up looking slightly wrong.

- The bottom example shows what happens when you script the penis angle instead, leading to the opposite or incorrect roll/pitch values.

- I think it’s also worth noting that if you are only making roll and pitch scripts, you aren’t able to mimic movements like the example. So you should also feel free to make creative choices if you want to attempt translating the extra movement onto roll that would normally be better suited to sway.
OFS Shortcuts and Personalization:
Important Settings
OFS gives you tons of shortcuts that can save you an immense amount of time. Here’s my most used ones.
-
Numpad 0-9 + ‘-’: Default binds to enter values 0, 10, 20, etc are bound to numbers, you can set 100 to whatever but I bound it to ‘-’
-
Chapter Insert: I have insert chapter bound to ‘]’ but that only matters if you like organizing your projects with chapters.
-
Invert Selection: Default setting is ‘i’ for invert, I use this one practically everytime I script MA, like I said you can reuse your stroke script often, and invert is invaluable when trying to get the pattern right when doing that.
-
Move Selected Up/Down 10 units: You have to bind this in OFS setting but I shit you not it will save you so much time. Mine are bound [Up = ‘Y’] [Down = ‘U’]
-
Select all Right/Left of position: default is [Ctrl + Alt/Opt + Right or Left DPad] perfect when you want to shift everything after or before a point.
-
Select all [Ctrl+A], Copy [Ctrl + C], Paste [Ctrl+ V], Cut [Ctrl + X] pretty obvious but I thought i’d include it just in case.
-
Shift all selected left/right one frame: Shift + Left/Right DPad. If nothing is selected it controls the closest point.
-
Shift all selected up/down one unit: Shift + Up/Down DPad. If nothing is selected it controls the closest point.
-
If you ever see creators have that nice looking Sine wave in OFS they likely have ‘Spline Mode’ active. You can set that by right clicking on the OFS graph and selecting it.
-
Please note, spline mode is only visual in OFS and doesn’t actually make your script feel any smoother. For that you need to use the core lua function ‘add spline points’. But that can also make your script messy and complex. In my opinion it’s better just to smooth out your script manually.
Resources/Helpful Links:
Repository of Common Funscript Resources
Changelog Notes
- Edit20260804: Added extra tips from wata35p’s comment and my own input/reference videos to the main post.






