Nekoscript
Introduction
NekoScript is a custom scripting language designed for game development in Nekoplay. Its syntax is lightweight, expressive, and familiar to those who know JavaScript, but includes unique features that make it more suitable for writing game logic.
Contents
Syntax
Variables
Data Types
Operators
Conditionals
Loops
Game Oriented
Functions
Data Structures
Constants
Javascript Objects and Functions
Syntax →
Syntax
Comments
Nekoscript uses the same comment style as other languages like JavaScript or C:
// Single-line comment
/*
Multi-line
comment
*/
/**
MEOW: TODO: FIXME: NOTE:
BUG: OPTIMIZE: HACK: XXX:
@example {type} Name - https://jsdoc.app/
*/
Case Sensitivity
NekoScript is case sensitive. This means Variable, variable and VARIABLE are three different identifiers.
End of Line
Using ; at the end of each line is not mandatory. The interpreter considers a new line sufficient to separate instructions, except in ambiguous contexts.
{
foo()
bar()
}
{
foo(); bar();
}
Variables →
Variables
In NekoScript there are two main ways to declare variables: local and global. Unlike JavaScript, let, const or var are not used.
local
Used to declare variables whose scope is limited to the block where they are defined, such as a function or control structure (if, for, etc).
This variable only exists within the block where it was defined.
func greet() {
local myVariable = "Hello "
local my_variable = "World!"
meow(myVariable + my_variable)
}
greet()
global
Used to declare variables accessible from anywhere in the code.
global group_name = "BlackPink"
global name_list = ["Jennie", "Jisoo", "Rose", "Lisa"]
global group = {
name: group_name,
members: name_list,
}
Since Nekoplay 1.3.0 you can declare global variables without the global keyword.
group_name = "Itzy"
leader_name = "Yeji"
Multiple Definitions
You can assign multiple variables at once, even swapping their values
local x, y = $camera
a, b, = b, a
Reassignment
Variables can be reassigned later:
local player_name
global score = 0 // No puedes definir globales vacias;
player_name = "Miku"
score = 75
Assign a random value ?[]
You can assign a random value to a variable directly.
local group_name = ?['BlackPink', 'Itzy', 'TripleS']
meow(group_name)
local songs = ['Pink Venom', 'Swipe', 'Generation']
defaultSong = ?songs
self
Nekoscript utiliza la palabra clave para referirse al contexto actual de objeto o función.
player = {
name: "Lia",
song: "Blossom",
current_song: self.song,
}
Data Types →
Data Types
NekoScript uses a variety of data types, similar to other languages, but with some key differences in how they are written and used.
Numbers
Numbers can be integers or decimals, written in the usual way:
myNumber = 69
myDecimal = 4.20
Text (Strings)
Strings are written with single quotes, double quotes, or as literals:
global group = ["Yeji", "Lia", "Ryujin", "Chaeryeong", "Yuna"]
local current_song = 'Dalla Dalla'
Strings written in single quotes can access objects using ${}
local song = "Wannabe"
meow('Current Song: ${song}')
// Current Song: Wannabe
Single quotes can also be used to write multiline strings
song_lyrics = 'I’m so bad bad 차라리 이기적일래
눈치 보느라 착한 척
상처받는 것보다 백번 나아'
Booleans
NekoScript uses standard boolean values: true & false
settings.music = false
player.isAlive = true
Arrays and Objects
You can define arrays (lists) and objects (dictionaries or maps), which we'll cover in depth in section 8. For now, a quick example:
local names = ["Jennie", "Jisoo", "Chaeyoung", "Lalisa"]
local maknae = {
name: "Yuna"
birthday: "9 of December"
}
Null / Undefined
NekoScript is based on JavaScript, using null and undefined.
task = null
settings.song = undefined
typeof - Check the type of an object
You can check the type of the object using typeof
typeof <object>
local songs = ["Generation", "Rising", "Dimension", "Colorful"]
typeof songs
// array
Returns the type as string:
"boolean"
"string"
"number"
"array"
"object"
"function"
"image"
"audio"
"input"
"button"
"progress"
"body"
"material"
"joint"
Operators →
Operators
NekoScript offers a series of operators that allow performing mathematical, logical, and comparison operations.
Arithmetic Operators
Used to perform basic mathematical operations:
+Additiona + b
-Subtractiona - b
*Multiplicationa * b
/Divisiona / b
%Remaindera % b
**Powera ** b
Comparison Operators
Used to compare values
==Equalitya == b
!=Inequalitya != b
>Greater thana > b
<Less thana < b
>=Greater than or equal toa >= b
<=Less than or equal toa < b
Logical Operators
To combine conditions and boolean values:
&&ANDa && b
||ORa || b
!NOT!a
Assignment Operators
Assignment operators combine operations with reassignment:
=Simple assignment
+=Add and assign
-=Subtract and assign
*=Multiply and assign
/=Divide and assign
Conditionals →
Conditionals
Conditional structures allow executing certain parts of the code only if specific conditions are met.
if
Evaluates a condition and executes the block if it's true:
if <condition> { <block> }
if score > 999 {
endLevel("Perfect!");
}
elseif
Allows evaluating a second condition if the first one isn't met:
} elseif <condition> { <block> }
if score > 999 {
endLevel("Perfect!");
} else if score > 599 {
endLevel("Good!");
}
else
Executes a block if none of the previous conditions were met:
} else { <block> }
if level.ready {
player.animation('Lets a go!')
} else {
player.animation('idle')
}
otherwise
Works similarly to else but is more formal.
} otherwise { <block> }
if level.ready {
player.greet('Good Morning!')
} otherwise {
player.animation('salute')
}
switch
Evaluate multiple cases of the same condition. Used together with case, default & break
▹case defines a possible action
▹default defines the default action
▹break stops checking other cases
switch <expression> {
case <expression>:
<block>
break;
default:
<block>;
}
local group_name = "TripleS"
global number_of_members = 0
switch (group_name) {
case "BlackPink":
number_of_members = 4
break;
case "Itzy":
number_of_members = 5
break;
case "TripleS":
number_of_members = 24
break;
}
meow('${group_name} has ${number_of_members} members!')
// TripleS has 24 members!
Loops →
Loops
NekoScript offers a variety of repetition structures to execute blocks of code multiple times.
Classic for
Allows manual control of initialization, condition, and update of a variable. Written separated by commas, not semicolons, and without parentheses:
for <initial operation>, <condition>, <repeated operation> { <block> }
for local i = 0, i < 10, i++ {
print(i);
}
for...in for Arrays
Iterates over array elements:
for <element> in <array> { <block> }
for <element>, <index> in <array> { <block> }
for name in game.players {
print(name);
}
for player, position in game.leaderboard {
player.rank = calculateRank(position)
}
for...of
Iterates over object properties:
for <key> of <object> { <block> }
for <key>, <value> of <object> { <block> }
for icon of game.powerups {
draw.image(icon.texture, icon.dim)
}
for name, mission of game.missions {
print(`${name}: ${mission}`);
}
while
Repeats the block while the condition is met:
while <condition> { <block> }
while score < 1000 {
score++
}
repeat
A simple alternative to for and while, with very clean syntax:
repeat <times> { <block> }
repeat <times>, <identifier> { <block> }
repeat 10 {
player.life++
}
repeat 12, factor {
score += factor
}
forever
Repeats the block until the end of time or until the program breaks:
forever { <block> }
local i = 0;
forever {
i += 1
}
Usar forever con precaución ⚠: Congelará tu navegador.
Game Oriented →
Game Oriented
Nekoscript includes control structures designed for game development leveraging access to @dt (delta time).
sometimes
Execute a code block with 50% probability.
sometimes { <block> }
sometimes {
spawnPowerUp()
}
maybe
Execute a code block with custom probability.
maybe <probability> { <block> }
maybe 20 {
spawnPowerUp()
} // 20% probability
maybe 75 {
spawnPowerUp()
} // 75% probability
every
Allows executing a code block every certain number of seconds.
every <seconds> { <block> }
every 3 {
background.pulse()
}
every 10 {
dynamicTiles.flip()
} otherwise {
dynamicTiles.move()
}
wait
Delays the execution of a block until a continuous number of seconds has passed.
wait <seconds> { <block> }
wait 5 {
levelStart()
}
wait 200 {
spawnBoss()
} otherwise {
updateEnemies()
}
message
Defines a global state
message <message>
message "levelReady"
remove..."message"
Removes a global state
remove <message>
remove "levelLoading"
on..."message"
Checks a global state
on <message> { <block> }
on "levelReady" {
startStage()
}
once
Executes a block only once
once { <block> }
once {
resetCounters()
}
once..."message"
Executes a block only once by checking a global state.
once <message> { <block> }
once "levelLoading" {
spawnEnemies()
}
twice
Despite the name, this instruction executes a block only once like once but can execute again if not called in sequence.
twice { <block> }
twice {
player.jump()
}
Functions →
Functions
NekoScript allows defining and using functions in a clear and concise way. Functions can be named or anonymous (without a name), and can take any number of arguments.
Declaring a function
In nekoscript the func keyword is used to declare functions
purr <name>(<arguments>) { <function> }
func toggleColor(col) {
set.color(col == #f0f ? #000 : #f0f)
}
toggleColor(#f0f)
purr toggleColor(col) {
set.color(col == #f0f ? #000 : #f0f)
}
toggleColor(#f0f)
Anonymous functions
You can also define nameless functions, useful for assigning them to variables or objects:
purr (<arguments>) { <function> }
global transform_size = purr (size, scale) {
return size * scale;
}
local finalSize = transform_size(64, 8);
global transform_size = func (size, scale) {
return size * scale;
}
local finalSize = transform_size(64, 8);
Arrow functions
<arguments> => { <function> }
NekoScript allows defining quick functions with an arrow-like syntax (=>). This form is ideal for callbacks or single-line functions:
local addScore = score => score + 10;
Also works with multiple parameters:
local calculateDamage = (attack, defense) => attack - defense;
And in methods like .each you can write:
global name_list = ["Lis", "米歇尔", "지운", "ちぇりー"]
name_list.each(name => {
print(`${name} is ready!`);
});
async & await
In NekoScript you can define asynchronous functions using the async keyword. These functions allow waiting for operations that take time.
async functions are only useful when you use await inside them. You can only use await inside an async function. The result of an async function is a promise.
async func fetchPlayerData(player_id) {
local playerData = await get.json(server + player_id);
return parseData(playerData)
}
fetchPlayerData('Xxtnkii69xX')
return
Used inside a function to indicate the value that function should return. When a return is executed, the function stops immediately and delivers that value to where it was called.
purr get_performance(score, bonus) {
return 100 / (score + bonus);
}
local playerPerformance = get_performance(player.score, level.bonus);
Data Structures →
Data Structures
NekoScript offers two main data structures: arrays (also known as lists) and objects (structures with key-value properties). These structures allow storing and organizing information.
Arrays
An array is an ordered collection of values. It is defined using square brackets [ ], separating elements with commas ,:
global name_list = ["Yeji", "Lia", "Ryu", "Chaeryeong", "Yuna"]
You can access its elements using indexes, starting from 0:
name_list[3]
// Chaeryeong
And you can also define an element at a fixed index:
name_list[3] = "Ryujin";
methods
[].push()
Adds an element to the end and returns the new length
[1, 2, 3].push(4)
// [1, 2, 3, 4]
// 4
[].pop()
Deletes the last element and returns it
[1, 2, 3].pop()
// [1, 2]
// 3
[].shift()
Deletes the first element and returns it
[1, 2, 3].shift()
// [2, 3]
// 1
[].unshift()
Adds an element to the beginning and returns the new length
[1, 2, 3].unshift(0)
// [0, 1, 2, 3]
// 4
[].join()
Joins elements into a string
["a", "b", "c"].join('-')
// a-b-c
[1, 2, 3].join('_')
// 1_2_3
[].slice()
Returns a portion of the list
[1, 2, 3, 4, 5].slice(1, 3)
// [2, 3]
[].splice()
Deletes or replaces elements and returns the deleted element
[1, 2, 3, 4, 5].splice(2, 1, 'three')
// [1, 2, 'three', 4, 5]
// 3
[1, 2, 3, 4, 5].splice(1, 2)
// [1, 4, 5]
// [2, 3]
[].includes()
Check if an Array contains a value
['alpha', 'bravo', 'charlie'].includes('bravo')
// true
[].map()
Returns a new array with the result of applying the function to each element
[1, 2, 3].map(x => x * 2)
// [2, 4, 6]
[].filter()
Returns a new array with elements that meet the condition
[1, 2, 3, 4].filter(x => x * 2 == 4)
// [2]
[].find()
Returns the first element that meets the condition
[1, 2, 3, 4].find(x => x == 2)
// 2
[].each()
Executes a function for each element
[1, 2, 3, 4].each(n, index => print('Number' + n + 'at index: ' + index))
properties
[].length
Returns the number of elements
['a', 'b', 'c'].length
// 3
Objects
Objects are collections of properties, defined between curly braces {} with key and value defined with colons : and separated by commas ,:
local inventory = {
weapon: "Magic Wand",
armor: "Iron Armor",
potions: ["Health", "Mana"],
}
You can access a property using the dot .:
inventory.weapon
// Magic Wand
inventory["armor"]
// Iron Armor
And also modify it:
inventory.weapon = "Dark Sword"
These structures can be nested, combined, and freely used as function arguments, calculation results, or parts of game states.
array = [
{},
[],
{};
]
object = {
array: [],
object: {},
}
Constants →
Engine Constants
NekoScript includes a series of special built-in constants in the runtime environment. These constants are always available and provide direct access to system information, game state, scene data, and other internal utilities.
Variables
These variables behave as real-time values. You can read them at any time to get information about the current state of the engine or game.
$dtDelta Time: time elapsed since the last frame.Number
$fpsFrames Per Second.Number
$cameraCurrent camera position, as an array [x, y].Array
$sceneName (String) of the current scene.String
$timeTotal time since the game was started (in seconds).Number
$sceneTimeTime since the current scene was loaded (in seconds).Number
$keysList of pressed keys (by name: "ArrowUp", "z", etc).Array
$scancodesList of pressed keys (by physical keyboard code).Array
$messagesList of messages.Array
$leftThe leftmost point of the screen.Number
$rightThe rightmost point of the screen.Number
$topThe topmost point on the screen.Number
$downThe bottommost point on the screen.Number
$widthThe horizontal size of the game.Number
$heightThe vertical size of the screen.Number
These variables can be used directly in any expression.
Functions
These functions allow performing special transformations or calculations related to the engine.
$position(x, y)Converts fixed coordinates to engine coordinates (for camera, zoom, scale, etc.).Array
$size(w, h)Adjusts size to system proportions.Array
Javascript →
Available JavaScript Functions and Objects
NekoScript is built on a JavaScript foundation, so many of the language's standard functions and objects are available.
Standard functions
These are perhaps the most useful functions for game development.
MathStatic properties and methods for mathematical operations.Math ↗
StringObject used to manipulate text.String ↗
NumberConstants and methods for manipulating numeric values.Number ↗
JSONStatic methods for converting values to and from Json.Json ↗
RegExpManipulate text patterns.RegExp ↗
DateRepresents a moment in time.Date ↗
BooleanValues representing the result of a logical operationBoolean ↗
ArrayCollection of multiple values (variables, objects, other arrays) under a single nameArray ↗
ObjectCollection of values or entities (variables, objects, arrays, functions, methods) with key names.Object ↗
Example:
local gameSave = {
score: Math.round(99.5),
isComplete: false, // Boolean
name: getMember().replace(/Member\s*/, ""), // RegExp
playerLevel: Number.parseInt("99"),
keyItems: ["Microphone", "Tea Set"], // Array
lastSave: new Date(),
}; // Object
local savedDataString = JSON.stringify(gameSave);
Basic global functions
These functions are available just like in JavaScript:
isFinite()
inNaN()
parseFloat()
parseInt()
Special values
undefined
NaN
Infinity
Global objects
ObjectBooleanSymbol
Numbers and DatesNumberBigIntMathDate
Text and RegExStringRegExp
StructuresArrayMapSetWeakMapWeakSet
Special TypesInt8ArrayUint8ArrayUint8ClampedArrayInt16ArrayUint16ArrayInt32ArrayUint32ArrayBigInt64ArrayBigUint64ArrayFloat32ArrayFloat64Array
ConcurrencyPromiseAsyncFunction
UtilitiesJSONReflectProxyIntl
Standard Errors
Error
TypeError
ReferenceError
SyntaxError
RangeError
URIError
EvalError
AggregateError