LoveScript

LoveScript is a programming language designed to express warm and romantic feelings. It is based on the metaphor of love as an algorithm: relationships are processes, emotions are variables, and confessions are output strings. LoveScript is created to turn logic into romance and code into confessions.

General concepts

The canvas used by LoveScript has a square aspect ratio. A Cartesian coordinate system has been introduced on the canvas: the X—axis is directed from left to right, and the Y-axis is directed from top to bottom. The coordinate center is located in the upper-left corner. The lower right corner has coordinates (1, 1). All sizes are also specified in these coordinates, so size = 1 indicates an object with a size equal to 100% of the canvas.

Syntax of the Language

The syntax of the language is described by the following formal grammar. Below are the non-terminal symbols and their derivation rules. Any two elements of the grammar (except for elements forming literals and identifiers) can be separated by an arbitrary number of whitespace characters, tab characters, and line break characters.

Start Symbol

  <start> ::= <list>

A program is a list of statements.

List of Statements

  <list> ::= <statement> <list> | ε

A list of statements (statement) can consist of:

  • one statement followed by a list of statements;
  • or be empty (ε).

Statement

  <statement> ::= <for> | <if> | <using> | <call> | <comment>

A statement can be:

  • a for loop,
  • a conditional if statement (with an optional else block),
  • a using block,
  • a function call,
  • a comment

For Loop

  <for> ::= 'for' '(' 'let' <identifier> 'from' <number> 'to' <number> ')' '{' <list> '}'

The for loop structure is described by the following rule:

  1. Keyword for.
  2. Inside parentheses: a variable declaration using let, followed by the variable name, the keywords from and to with the initial and final values.
  3. The loop body is enclosed in curly braces, containing a list of statements.

Example:

  for (let i from 1 to 10) {
    ...
  }

Conditional If

  <if> ::= 'if' '(' <expression> ')' '{' <list> '}' 
           [ 'else' '{' <list> '}' ]?

The conditional construct begins with the word if, followed by an expression in parentheses. The if block (the body of if) is enclosed in curly braces. The optional else block, also enclosed in curly braces, is executed if the condition is false.

Example:

  if (i % 2 == 0) {
    ...
  } else {
    ...
  }

Using Block

  <using> ::= 'using' '(' <expression> ')' '{' <list> '}'

The using block is used to apply global settings. The global settings expression is specified inside parentheses, and the body of the using block contains a list of statements to be executed with the applied global settings.

Example:

  using (blendMode(value = 'multiply')) {
    ...
  }

Expressions

  <expression> ::= <call> | 
                   <expression> '?' <expression> ':' <expression> |
                   <identifier> | <string> | <number> |
                   '(' <expression> ')' |
                   <expression> ('==' | '!=' | '>=' | '>' | '<=' | '<' | '+' | '-' | '/' | '*' | '%') <expression>

An expression can contain:

  • a function call;
  • a ternary operator;
  • an identifier;
  • a string literal;
  • a number literal;
  • another expression inside parentheses;
  • a binary operator applied to two expressions.

The operator precedence (from lowest to highest):

  1. Ternary operator
  2. == and !=
  3. >=, >, <=, <
  4. + and -
  5. /, * and %

Function Call

  <call> ::= <identifier> '(' <arguments> ')'

A function call begins with the function identifier, followed by parentheses with arguments.

Arguments

  <arguments> ::= <argument> [, <argument>]* | ε

Arguments are a list of arguments separated by commas. The list of arguments can be empty (ε).

  <argument> ::= <identifier> '=' <expression>

Each argument has the form: parameter name (identifier), assignment sign (=), and value (expression).

String Literals

  <string> ::= "'" <string_contents> "'"

A string is enclosed in single quotes.

  <string_contents> ::= <string_char>*

  <string_char> ::= [^\\'] | ('\\' .)

The string_contents can contain any characters except single quote and backslash (unless escaped).

Number Literals

  <number> ::= '-'? [0-9]* '.' [0-9]+ | '-'? [0-9]+ ('.' [0-9]+)?

A number consists of an optional sign «-» at the beginning, followed by optional integer and fractional parts (at least one of them must be present).

Identifiers

  <identifier> ::= [a-zA-Z_][a-zA-Z_0-9]*

Identifiers must start with a letter of the Latin alphabet or an underscore, and can then contain letters, digits, or underscores.

Comments

  <comment> ::= '//' [^\n]*

Comments start with two forward slashes // and continue until the end of the line. Comments are ignored during program execution and are used for explanations in the code.

Example:

// This is a comment
fill(bg = solidBackground(color = 'pink'))  // Fill background with pink color

// Draw a heart in the center
heart(
  bg = solidBackground(color = 'red'),
  size = 0.5
)

Data Types

number

The numbers are represented in the IEEE-754 64-bit format.

color

Describes a color. At the program level, it is described as a string literal containing the color in hex format, or as a string literal describing one of the predefined colors: 'transparent', 'red', 'green', 'blue', 'yellow', 'pink', 'black', 'white'.

bg

Describes the background. Cannot be directly specified as a literal, can only be obtained from a function.

using

Describes global settings. Cannot be directly specified as a literal, can only be obtained from a function. To apply settings, they need to be passed to the using block.

Available Functions

radialGradient

  • Description: Returns a background with a radial gradient consisting of two colors: start and end.
  • Arguments:
      - start (color, required): Initial color of the gradient.
      - end (color, required): Final color of the gradient.
  • Returns: bg

linearGradient

  • Description: Returns a background with a linear gradient consisting of two colors: start and end, as well as an angle of inclination (angle).
  • Arguments:
      - start (color, required): Initial color of the gradient.
      - end (color, required): Final color of the gradient.
      - angle (number, required): Inclination angle of the gradient in degrees counterclockwise.
  • Returns: bg

solidBackground

  • Description: Returns a single-color background.
  • Arguments:
      - color (color, required): Background color.
  • Returns: bg

pattern

  • Description: Adds background patterns of the specified color.
  • Arguments:
    • type (string, required): Pattern type. Valid values: 'triangle', 'circle', 'rhomb', 'heart', 'flower', 'star', 'square'.
    • color (color, required): Pattern color.
    • size (number, required): Pattern element size (from 0.01 to 1).
    • space (number, required): Space between elements (from 0 to 1).
    • angle (number): Pattern tilt angle.
    • distortion (number): Element distortion (from 0 to 100).
    • distortionSize (number): Distortion area size (from 0.001 to 100).
    • speed (number): Distortion animation speed (from 0 to 50).
  • Returns: void

fill

  • Description: Fills the background with the specified bg.
  • Arguments:
    • bg (bg, required): Background object.
  • Returns: void

heart

  • Description: Draws a heart using the specified bg and size. Use the mode parameter to switch between "shape" (default) and "dots". In dots mode, circles are drawn at vertices instead of the heart shape.
  • Arguments:
    • bg (bg, required): Background object.
    • size (number, required): Heart size (from 0 to 2).
    • x (number): X position.
    • y (number): Y position.
    • vertices (number): Number of vertices (from 3 to 64).
    • distort (number): Distortion of the shape (from 0 to 10).
    • borderWidth (number): Border thickness (from 0 to 0.2).
    • borderColor (color): Border color.
    • mode (string): Rendering mode. Valid values: 'shape', 'dots'.
    • dotSize (number): Dot size in dots mode (from 0 to 0.5).
  • Returns: void

alpha

  • Description: Sets global transparency for all elements as a percentage.
  • Arguments:
    • value (number, required): Transparency value (from 0 to 100).
  • Returns: using

blendMode

  • Description: Sets global composition operation defined by the value.
  • Arguments:
    • value (string, required): Blending mode. Valid values: 'source-over', 'lighter', 'multiply', 'screen', 'overlay', 'darken', 'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light', 'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity'.
  • Returns: using

transform

  • Description: Sets global transformation for all elements. Available transformations: translateX, translateY, rotate, scale, skew, skewX, skewY. All transformations are applied relative to the center of the canvas (0.5, 0.5).
  • Arguments:
    • translateX (number): X offset.
    • translateY (number): Y offset.
    • rotate (number): Clockwise rotation. Specified in degrees.
    • scale (number): Scale change.
    • scaleX (number): Scale change along the X axis.
    • scaleY (number): Scale change along the Y axis.
    • skew (number): Same as skewX.
    • skewX (number): Distorts the element by shifting its parts along the X axis. Specified in degrees.
    • skewY (number): Distorts the element by shifting its parts along the Y axis. Specified in degrees.
  • Returns: using

rgb

  • Description: Combines numeric values of red, green, and blue into one color.
  • Arguments:
    • r (number, required): Red component (from 0 to 255).
    • g (number, required): Green component (from 0 to 255).
    • b (number, required): Blue component (from 0 to 255).
    • a (number): Alpha channel (from 0 to 1).
  • Returns: color

hsl

  • Description: Combines numeric values of hue, saturation, and lightness into one color.
  • Arguments:
    • h (number, required): Hue (from 0 to 360).
    • s (number, required): Saturation (from 0 to 100).
    • l (number, required): Lightness (from 0 to 100).
    • a (number): Alpha channel (from 0 to 1).
  • Returns: color

mix

  • Description: Mixes two colors in a given ratio (linear interpolation). Useful for creating smooth transitions between colors.
  • Arguments:
    • color1 (color, required): First color.
    • color2 (color, required): Second color.
    • ratio (number, required): Mix ratio (from 0 to 1). At 0 returns color1, at 1 returns color2.
  • Returns: color

Animation Functions

animate

  • Description: Returns a value from 0 to 1 based on time with easing. Used for creating animations.
  • Arguments:
    • duration (number, required): Animation duration in seconds (minimum 0.01).
    • easingCurve (string): Easing curve. Valid values: 'linear', 'quad', 'cubic', 'quart', 'back', 'elastic', 'bounce', 'heartbeat'.
    • easingMode (string): Easing mode. Valid values: 'in', 'out', 'in-out'. Ignored for heartbeat.
    • loop (string): Loop mode. Valid values: 'repeat', 'mirror'.
    • offset (number): Animation start delay in seconds (minimum 0).
  • Returns: number

Example:

heart(
  bg = solidBackground(color = 'red'),
  size = 0.3 + animate(duration = 1, easingCurve = 'heartbeat') * 0.1
)

map

  • Description: Maps a value from one range to another. Useful for scaling animation values.
  • Arguments:
    • value (number, required): Value to map.
    • inMin (number): Input range minimum (default 0).
    • inMax (number): Input range maximum (default 1).
    • outMin (number, required): Output range minimum.
    • outMax (number, required): Output range maximum.
  • Returns: number

Example:

heart(
  bg = solidBackground(color = 'red'),
  size = map(value = animate(duration = 2), outMin = 0.2, outMax = 0.5)
)

sin

  • Description: Returns the sine of an angle in degrees (same unit as rotate). Useful for circular motion and wave patterns.
  • Arguments:
    • angle (number, required): Angle in degrees.
  • Returns: number

cos

  • Description: Returns the cosine of an angle in degrees (same unit as rotate). Useful for circular motion and wave patterns.
  • Arguments:
    • angle (number, required): Angle in degrees.
  • Returns: number

Example of circular motion:

for (let i from 0 to 5) {
  heart(
    bg = solidBackground(color = 'red'),
    size = 0.1,
    x = 0.5 + cos(angle = i * 60 + animate(duration = 2) * 360) * 0.3,
    y = 0.5 + sin(angle = i * 60 + animate(duration = 2) * 360) * 0.3
  )
}

Sound Functions

audio

  • Description: Defines an audio track using ABC notation. Does not render anything on the canvas. ABC notation is a text format for writing music.
  • Arguments:
    • abc (string, required): ABC notation body (notes and rhythm).
    • key (string): Key signature (default: C). Examples: 'C', 'G', 'Am', 'F#m'.
    • tempo (number): Tempo in beats per minute (from 1 to 300).
    • play (string): Playback mode. Valid values: 'loop', 'single'.
    • unitNoteLength (string): Base note duration. Examples: '1/4', '1/8'.
    • instrument (string): Instrument. Valid values: 'piano', 'bass', 'pad', 'lead', 'pluck', 'flute', 'bell', 'hearth', 'synth', 'snare', 'hihat', 'kick', 'guitar', 'chip', 'organ'.
    • offset (number): Playback start offset in seconds (minimum 0).
  • Returns: void

Example:

audio(
  abc = 'CDEF GABc|',
  tempo = 120,
  instrument = 'piano',
  play = 'loop'
)

ABC notation basics:

  • Notes are written as letters: C D E F G A B (uppercase — lower octave), c d e f g a b (lowercase — upper octave)
  • Duration: C2 — half note, C/2 — eighth note, C — quarter note
  • Rests: z (quarter rest), z2 (half rest)
  • Bar line: |

volume

  • Description: Returns the current audio volume level from 0 to 1. Useful for creating audio-reactive visualizations that respond to music.
  • Arguments: none
  • Returns: number

Example of audio-reactive visualization:

audio(
  abc = 'C2 E2 G2 c2|',
  tempo = 120,
  instrument = 'piano',
  play = 'loop'
)

heart(
  bg = solidBackground(color = 'red'),
  size = 0.3 + volume * 0.2
)