Orgasm AyvaScript

A basic orgasm routine that can be run in Ayva Stroker Lite when you’re about to cum :blush:.

When activated, this script will transition into a stroke that has a randomly generated bpm curve, oscillating between fast and slow until slowing down to a complete stop. It will be different every time.

A video demonstration with the default parameters is available here.

The JSON file you can use to import this routine directly into Ayva Stroker: orgasm.txt (3.8 KB).

Note: Unfortunately EroScripts wasn’t allowing the uploading of JSON files when this post was created, so you will need to rename the extension to .json before importing it.

The source code is included at the end of this post for your convenience (you can also view the source in Ayva Stroker after importing as well).

There are parameters at the top of the script that can be customized to change the behavior to your liking:

  • strokeName: Name of the stroke you want to use for the finale. Can be a custom stroke or library pattern.
  • addTwist: Whether or not to add a random twist motion to the movement.
  • minBpm: Slowest speed. The behavior will end at this speed.
  • maxBpm: Fastest speed.
  • orgasmLength: Length of the routine in seconds.
  • postOrgasmLength: Length of the slow stroke after the orgasm (performed at minBpm ).
  • noise: How much variation to put into the stroke pattern (number between 0 and 1).
  • initialTransitionTime: When activated in Free Play mode, this is how many seconds it takes to transition into the finale stroke.

The algorithm that generates the bpm curve is a simple midpoint displacement. It can be configured with the following parameters:

  • iterations: How many iterations of the algorithm to perform.
  • reductionFactor: Controls how “erratic” the displacement ends up being. Lower values are more erratic, higher are smoother.

To learn more about AyvaScripts and how to create or use them, see the AyvaScript Documentation.

If you like my work, please consider supporting me through Patreon.

Thank You and Happy Stroking! :heart:


Orgasm AyvaScript Source Code:

/**
 * Customizable Parameters
 */
const strokeName = "short-high-roll-backward";
const addTwist = true;
const minBpm = 10;
const maxBpm = 220;
const orgasmLength = 25;
const postOrgasmLength = 15;
const noise = 0.5;
const initialTransitionTime = 1;

/**
 * BPM Randomization Parameters (Using Midpoint Displacement Algorithm)
 * 
 * See the following link for details about this algorithm:
 * https://bitesofcode.wordpress.com/2016/12/23/landscape-generation-using-midpoint-displacement
 */
const iterations = 5;         // 2^iterations = number of points
const reductionFactor = 0.3; // Lower = more erratic. Higher = smoother.

let controlPoints = [1, 0];
let bounds = 0.5;
for (let i = 0; i < iterations; i++) {
  const newControlPoints = [];

  for (let j = 0; j < controlPoints.length - 1; j++) {
    const left = controlPoints[j];
    const right = controlPoints[j + 1];
    const midpoint = (left + right) / 2;
    const displacement = Ayva.map(Math.random(), 0, 1, -bounds, bounds);

    newControlPoints.push(left);
    newControlPoints.push(Math.min(1, Math.max(0, midpoint + displacement)));

    if (j === controlPoints.length - 2) {
      newControlPoints.push(right);
    }
  }

  controlPoints = newControlPoints;
  bounds = bounds * (1 / Math.pow(2, reductionFactor));
}

const bpmControlPoints = controlPoints.map((point) =>
  Ayva.map(point, 0, 1, minBpm, maxBpm)
);

/**
 * Setup
 */
const currentStroke = GLOBALS.input;
const strokeConfig = TempestStroke.library[strokeName];

Object.keys(strokeConfig).forEach((axis) => {
  // Add noise to each axis if not already present.
  strokeConfig[axis].noise = strokeConfig[axis].noise || noise;
});

const currentTwist = strokeConfig.R0 || strokeConfig.twist;

if (
  addTwist &&
  (!currentTwist || (currentTwist.from === 0.5 && currentTwist.to === 0.5))
) {
  // Add a random twist if not already present.
  strokeConfig.twist = {
    from: Ayva.map(Math.random(), 0, 1, 0.1, 0.3),
    to: Ayva.map(Math.random(), 0, 1, 0.7, 0.9),
    phase: 1,
    ecc: Math.random(),
    noise,
  };
}

const duration = new VariableDuration(orgasmLength);

const bpmProvider = () => {
  // Follow the curve specified via bpmControlPoints.
  const progress = duration.percentage * (bpmControlPoints.length - 1);
  const index = Math.floor(progress);

  if (index >= bpmControlPoints.length - 1) {
    return bpmControlPoints[bpmControlPoints.length - 1];
  }

  const start = bpmControlPoints[index];
  const end = bpmControlPoints[index + 1];

  const result = Ayva.map(
    index ? progress % index : progress,
    0,
    1,
    start,
    end
  );

  return result;
};

let finishStroke;
if (currentStroke) {
  // If a stroke is already playing, transition out of it.
  finishStroke = currentStroke.transition(
    strokeConfig,
    bpmProvider,
    initialTransitionTime
  );
} else {
  finishStroke = new TempestStroke(strokeConfig, bpmProvider).bind(ayva);
}

/**
 * Perform Stroke
 */
while (!duration.complete) {
  yield finishStroke.next();
}

/**
 * Perform strokes at the slowest speed for a little while...
 */
const postOrgasmDuration = new VariableDuration(postOrgasmLength);
while (!postOrgasmDuration.complete) {
  yield finishStroke.next();
}

/**
 * Try not to stop in the middle of a stroke...
 */
const nextStrokeAngle = Math.PI * (Math.floor(finishStroke.angle / Math.PI) + 1);
while (finishStroke.angle < nextStrokeAngle) {
  yield finishStroke.next();
}

/**
 * End by moving slowly back to home position.
 */
yield ayva.$
  .stroke({ 
    to: 0.5, duration: 4, value: Ayva.RAMP_PARABOLIC })
  .surge(0.5)
  .sway(0.5)
  .twist(0.5)
  .roll(0.5)
  .pitch(0.5);

ayva.stop();

4 Likes