launchcontrol: Index | Files

package funscript

import ""

Package funscript manages the Funscript format.

Funscript is Funjack's haptic script format. It's basically JSON encoded timed positions:

	"version": "1.0",
	"inverted": false,
	"range": 90,
	"actions": [
		{"pos": 0, "at": 100},
		{"pos": 100, "at": 500},

version: funscript version (optional, default="1.0")
inverted: positions are inverted (0=100,100=0) (optional, default=false)
range: range of moment to use in percent (0-100) (optional, default=90)
actions: script for a Launch
  pos: position in percent (0-100)
  at : time to be at position in milliseconds

Movement range

Implementations may override the range value specified in the script.

Define min (bottom) and max (top) positions for the strokes. Defaults are: min=5 and max=95. The values for min and max must:

(max - min) == range
(max - min) <= 90

The defaults of 5/95 are based on the reverse engineering efforts of the Kiiroo protocol. It's not certain if 0/100 are safe to use, so for now better be safe then sorry.

Speed algorithm

The "Magic Launch Formula" is used to determine the speed of the movement commands:

Speed = 25000 * (Duration * 90/Distance)^(-1.05)

Speed: Launch speed to send to the Launch
Duration: Time in milliseconds the move should take
Distance: Amount of space to move in Launch percent (1-100)

Speed must always be a value between 20-80. As slow commands crash the Launch, and fast commands cause weird noises and will likely damage the Launch.

Movement algorithm

Scripts always starts on time 0 at the bottom (min position) unless inverted is true, then start at the top (max position). This is also the implicit previous action for the first action in the script and does not have to be present in the actions list of the script.

For each action in the script:

If the position value is equal to the previous action position do not move. Note: do not completely ignore this action but still continue to use it as the 'previous action' for the next one.

When inverted is true, flip the position value (0=100, 25=75, 70=30, etc.)

Scale the position value with the percentage in range and add the min position value. Eg:

min=0,  range=50 and pos=75 : 50*75%+0  = 37
min=10, range=90 and pos=80 : 80*90%+10 = 72+10=82
min=20, range=80 and pos=30 : 80*30%+20 = 24+20=44

Calculate the duration (ms) and distance (percent) since the previous action. Eg with a 100% range:

{"pos": 25, "at": 100}, {"pos": 100, "at": 500}

time = 500-100 = 400
distance = (100-25)*100% = 75

Use the duration and distance to calculate the speed.

Send the calculated position with the calculated speed at the time specified by the previous action.


The Launch obviously has it's speed limitations. There are two type of impossible moves. Too fast, causing the stroke to be shorter then the script requested. Too slow, causing the move to be finished earlier then requested. Because Funscript is based on relative moves this can cause portions of a script the get out of sync. Limiting the range can help making fast moves possible again, but can cause slower moves to become impossible.

Launchcontrol uses a 100ms threshold when sending message to the Launch, scripts trying to fire actions faster than that will be out of sync for those sections.


Package Files

doc.go functions.go funscript.go loader.go


const (
    // SpeedLimitMin is the slowest movement command possible. The Launch
    // crashes on very slow speeds.
    SpeedLimitMin = 20
    // SpeedLimitMax is the fasts movement command possible. The Launch
    // makes weird 'clicking' noises when moving at very fast speeds.
    SpeedLimitMax = 80
    // PositionMin is the lowest position possible.
    PositionMin = 5
    // PositionMax is the hight position possible.
    PositionMax = 95
    // Threshold is the minimum amount of time between actions.
    Threshold = 100 * time.Millisecond


var ErrOutOfRange = errors.New("out of range")

func Distance Uses

func Distance(spd int, dur time.Duration) (dist int)

Distance returns the distance (in percent) that will be moved with the given speed (in percent) and duration.

func Duration Uses

func Duration(dist int, spd int) (dur time.Duration)

Duration returns the time it will take to move the given distance (in percent) at the given speed (in percent.)

func Speed Uses

func Speed(dist int, dur time.Duration) (speed int)

Speed returns the speed (in percent) to move the given distance (in percent) in the given duration.

type Action Uses

type Action struct {
    // At time in milliseconds the action should fire.
    At  int64 `json:"at"`
    // Pos is the place in percent to move to.
    Pos int `json:"pos"`

Action is a move at a specific time.

type Loader Uses

type Loader struct {
    // contains filtered or unexported fields

Loader loads Funscripts.

func (*Loader) LimitPosition Uses

func (l *Loader) LimitPosition(lowest, highest int)

LimitPosition implements the PositionLimiter interface.

func (*Loader) LimitSpeed Uses

func (l *Loader) LimitSpeed(slowest, fastest int)

LimitSpeed implements the SpeedLimiter interface.

func (Loader) Load Uses

func (l Loader) Load(r io.Reader) (protocol.Player, error)

Load returns a player with the Funscript loaded.

func (Loader) String Uses

func (l Loader) String() string

String returns a formatted string.

type Range Uses

type Range int

Range in percent.

func (Range) Position Uses

func (r Range) Position(p int) int

Position returns the position for p limited within the range.

type Script Uses

type Script struct {
    // Version of Launchscript
    Version string `json:"version"`
    // Inverted causes up and down movement to be flipped.
    Inverted bool `json:"inverted,omitempty"`
    // Range is the percentage of a full stroke to use.
    Range Range `json:"range,omitempty"`
    // Actions are the timed moves.
    Actions []Action `json:"actions"`

Script is the Funscript container type holding Launch data.

func (Script) TimedActions Uses

func (fs Script) TimedActions(minspd, maxspd, minpos, maxpos int) (s protocol.TimedActions, stat Stats)

TimedActions creates timed Launch actions from the Scripts timed positions. The minspd/maxspd arguments are Launch speed limits in percent. The minpos/maxpos specify the position limits in percent. The second return value are statistics on the script generation.

type Stats Uses

type Stats struct {
    Count             uint64 // Amount of actions generated.
    DistanceTotal     uint64 // Total distance that will be traveled.
    SpeedTotal        uint64 // Accumulation of all commands speed param.
    SpeedOverrideFast int    // Number of times generated speed was too fast.
    SpeedOverrideSlow int    // Number of times generated speed was too slow.
    Delayed           int    // Number of actions that will be thresholded.

Stats when generated script.

func (Stats) String Uses

func (s Stats) String() string

String returns a formatted.

Package funscript imports 8 packages (graph) and is imported by 1 packages. Updated 2017-09-01. Refresh now. Tools for package owners.