Skip to main content

An Introduction to Cross-Platform Game Development for Frontend Developers

· 9 min read
Li Jin
A Dora SSR developer.

Hello everyone! I’m a game engine enthusiast and a programmer with a solid background in frontend development. If you’ve ever wondered how to transition from crafting websites to developing games, you’re in the right place!

Today, let’s talk about using Dora SSR—a game engine that supports TSX and runs cross-platform natively. It’s a seamless way to step into the world of game development. Don’t worry, game engines aren’t as inaccessible as they might seem; in fact, they have surprising similarities to the frontend tools we’re used to.

1. Game Client Development as Frontend Development

First off, let’s define what a game engine is. Simply put, a game engine is a collection of tools and libraries that help developers build games, handling graphics, sound, physics calculations, or collision detection. For frontend developers, think of it as a specialized browser that runs games.

Dora SSR manages game scenes with a tree structure similar to the HTML DOM—quite familiar territory for us. Imagine swapping out HTML div elements with various game objects and replacing CSS animations with game animations. The concepts and even some of the coding practices are not that different. Exciting, isn’t it?

2. From TypeScript to TSX: Applying Frontend Tech in Games

Many frontend developers are familiar with TypeScript and React’s JSX syntax. In the open-source Dora SSR game engine, we embrace TSX, offering a game development interface similar to frontend programming patterns. Yes, you heard that right—TSX!

Developing games with TSX means you can leverage your existing frontend tech stack—components, modules, and other modern frontend technologies—directly in game development. Moreover, Dora SSR’s performance optimizations ensure smooth operations even in complex game scenarios.

3. Challenge: Craft an "Angry Birds"-like Game in Under 100 Lines of Code

Enough with the theory; let’s dive into some practical work. Let’s see how to write a game similar to "Angry Birds" using less than 100 lines of TSX code in Dora SSR. Before starting, setting up the development environment with Dora SSR is straightforward: install the package, open the browser, and let’s start coding! For installation and getting started, see: Dora Startup!

Accidentally installed as an APK on your phone? Access it over the same local network for on-device development and debugging

Accidentally installed as an APK on your phone? Access it over the same local network for on-device development and debugging

1. Crafting the Simplest Game Scene

Before diving into the actual code, we can start with a special comment that tells Dora SSR’s Web IDE to automatically hot-reload the code upon saving with Ctrl + S, allowing real-time preview of the code execution results.

// @preview-file on

We then import the necessary libraries and components. Our code editor also assists by automatically suggesting the required modules, which can be included later in the coding process:

import { React, toNode, useRef } from 'dora-x';
import { Body, BodyMoveType, Ease, Label, Line, Scale, TypeName, Vec2, tolua } from 'dora';

Displaying an image in Dora SSR is simple, just use the <sprite> tag, and then instantiate it into a game object with the toNode() function.

toNode(<sprite file='Image/logo.png' scaleX={0.2} scaleY={0.2}/>);

Now, you’ve pretty much got the hang of most of Dora SSR’s game development tricks. Start creating your own game (seriously).

2. Crafting the Game Box Component

Next, the colliding boxes in our game are defined by the Box component, which accepts properties such as num, x, y, and children:

interface BoxProps {
num: number;
x?: number;
y?: number;
children?: any | any[];
}

const Box = (props: BoxProps) => {
const numText = props.num.toString();
return (
<body type={BodyMoveType.Dynamic} scaleX={0} scaleY={0} x={props.x} y={props.y} tag={numText}>
<rect-fixture width={100} height={100}/>
<draw-node>
<rect-shape width={100} height={100} fillColor={0x8800ffff} borderWidth={1} borderColor={0xff00ffff}/>
</draw-node>
<label fontName='sarasa-mono-sc-regular' fontSize={40}>{numText}</label>
{props.children}
</body>
);
};

We use a React-like functional component approach

to define our box components, where:

  • body component’s tag attribute: stores the score of the box.
  • rect-fixture: defines the collision shape of the box.
  • draw-node: used to render the appearance of the box.
  • label: displays the score on the box.

3. Creating TSX-Instantiated Object References

Use useRef to create two reference variables for later use, one for the bird and one for the score label:

const bird = useRef<Body.Type>();
const score = useRef<Label.Type>();

4. Creating the Launch Line

The launch line is created by the line variable, and touch (or mouse click) event handling is added:

let start = Vec2.zero;
let delta = Vec2.zero;
const line = Line();

toNode(
<physics-world
onTapBegan={(touch) => {
start = touch.location;
line.clear();
}}
onTapMoved={(touch) => {
delta = delta.add(touch.delta);
line.set([start, start.add(delta)]);
}}
onTapEnded={() => {
if (!bird.current) return;
bird.current.velocity = delta.mul(Vec2(10, 10));
start = Vec2.zero;
delta = Vec2.zero;
line.clear();
}}
>
{/* ...create other game elements under the physics world... */}
</physics-world>
);
  • In the onTapBegan event, record the starting touch location and clear the launch line.
  • In the onTapMoved event, calculate the distance moved by the touch and update the launch line.
  • In the onTapEnded event, set the launch velocity of the bird based on the touch movement and clear the launch line.

5. Creating Other Game Elements

Next, we continue creating other elements in the game scene under the <physics-world> parent tag:

5.1 Ground

First, we use the body component to create the ground and set it as a static body:

<body type={BodyMoveType.Static}>
<rect-fixture centerY={-200} width={2000} height={10}/>
<draw-node>
<rect-shape centerY={-200} width={2000} height={10} fillColor={0xfffbc400}/>
</draw-node>
</body>
  • type={BodyMoveType.Static}: indicates this is a static body, unaffected by physics simulations.
  • rect-fixture: defines the ground’s collision shape as a rectangle.
  • draw-node: used to render the appearance of the ground.
  • rect-shape: draws a rectangle in yellow color.

5.2 Boxes

Next, we use the previously defined Box component to create 5 boxes with different initial positions and scores, and play their entrance animations upon creation:

{
[10, 20, 30, 40, 50].map((num, i) => (
<Box num={num} x={200} y={-150 + i * 100}>
<sequence>
<delay time={i * 0.2}/>
<scale time={0.3} start={0} stop={1}/>
</sequence>
</Box>
))
}
  • map function: used to iterate through an array of scores from 10 to 50, creating a box for each score that needs to be hit by the bird.
  • Box component: used to create boxes, with the following properties passed:
    • num={num}: the score of the box, corresponding to the number in the array.
    • x={200}: the initial x-axis position of the box, set at 200.
    • y={-150 + i * 100}: the initial y-axis position of the box, incrementally adjusted based on the creation index.
  • sequence component: used to create an animation sequence to be played on the parent node, including the following animations:
    • delay time={i * 0.2}: delays the animation playback, with the delay time incrementing based on the creation index.
    • scale time={0.3} start={0} stop={1}: scale animation, from not visible to fully visible, lasting 0.3 seconds.

5.3 Bird

Lastly, we use the body component to create the bird and set its collision shape, appearance, and score label:

<body ref={bird} type={BodyMoveType.Dynamic} x={-200} y={-150} onContactStart={(other) => {
if (other.tag !== '' && score.current) {
// accumulate score
const sc = parseFloat(score.current.text) + parseFloat(other.tag);
score.current.text = sc.toString();
// clear the score on the collided box
const label = tolua.cast(other.children?.last, TypeName.Label);
if (label) label.text = '';
other.tag = '';
// play the box collision animation
other.perform(Scale(0.2, 0.7, 1.0));
}
}}>
<disk-fixture radius={50}/>
<draw-node>
<dot-shape radius={50} color={0xffff0088}/>
</draw-node>
<label ref={score} fontName='sarasa-mono-sc-regular' fontSize={40}>0</label>
<scale time={0.4} start={0.3} stop{1.0} easing={Ease.OutBack}/>
</body>
  • ref={bird}: uses ref to create a reference variable for later manipulation of the bird.
  • type={BodyMoveType.Dynamic}: indicates this is a dynamic body, affected by physics simulations.
  • onContactStart={(other) => {}}: callback function triggered when the bird’s physics body contacts another object.
  • disk-fixture: defines the bird’s shape as a disk.
  • draw-node: used to render the bird’s appearance.
  • label: displays the bird’s accumulated score.
  • scale: plays the bird’s entrance animation.

6. Completing the Game Logic

With that, we have completed the core logic of our small game. You can further refine the game logic and add features based on your own ideas. The complete demo code can be seen at this link: Dora-SSR/Assets/Script/Test/Birdy.tsx. Below are some screenshots of the game in action.

Dragging the screen to launch the "Angry Birds

Dragging the screen to launch the "Angry Birds

Skilled moves earned me all the scores in one shot

Skilled moves earned me all the scores in one shot

4. A Little Reveal

1. Deer or Horse

In fact, the game code we wrote can ensure consistent performance across Linux, Android, iOS, macOS, and Windows thanks to the capabilities of the Dora SSR engine. However, to run this code, our Dora SSR engine doesn’t even support a JavaScript runtime environment... (What did you say?)

Yes, the underlying technology of Dora SSR is actually based on Lua and WASM virtual machines as the scripting language runtime. Support for TypeScript is provided through the integration of the TypeScriptToLua compiler https://github.com/TypeScriptToLua/TypeScriptToLua. TSTL has rewritten the backend of the TypeScript language compiler to compile TS and TSX code into equivalent Lua code, allowing TS code to run on Dora. The Dora Web IDE’s code editor helps with TS language checking, completion, and Dora built-in library API hints. In the end, whether it’s a deer or a horse, as long as the code passes the TS compilation check, it will run just the same.

2. Is There a Connection with React?

The answer to this question is currently: it could be (thus far, it hasn’t been). React’s most important capability is synchronizing the rendering of components and business data states through the Virtual DOM and Tree Diff process, which has not yet been implemented in Dora SSR. Currently, the code written in TSX for game rendering objects is only built once at runtime, and then the underlying C++ engine functionality continues to handle processing. Maybe one day we will provide a React-like mechanism for game UI development, executing Tree Diff to synchronize state, or a mechanism based on TSX like SolidJS for other rendering component state synchronizations. So here, we sincerely invite all frontend developers to join us, play with the Dora SSR project, and explore how to apply frontend development ideas to game development, bringing more convenient tools into the mix.

The Tale of Rewriting the Moonscript Compiler

· 4 min read
Li Jin
A Dora SSR developer.

tokyo moon

Moonscript: A Niche Language with a Twist

Moonscript is a fascinating programming language that compiles into Lua and runs on the Lua virtual machine. Its syntax and features draw inspiration from Coffeescript, offering a sweet spot between expressiveness and readability—minimizing code while maximizing clarity. It's particularly adept at handling frequently changing business logic, allowing developers to slash code volumes significantly when compared to native Lua—sometimes down to a third! This not only saves time but also reduces bugs and troubleshooting headaches. But perhaps one of its quirkiest features, as revealed by a seasoned developer in a Discord chat, is its dedicated global but modest-sized user base and its delightful Sailor Moon-themed aesthetic.

emotions embedded

Open Source and Free: A Challenging Sustainability

The creator of Moonscript has developed commercial sites like the indie game marketplace itch.io and the art-sharing platform streak.club using this language. To maintain stability, he paused the addition of new features and slowed down on fixing issues since 2017. Understandably, life's tough, and the creator has set up a GitHub sponsor page hoping for more support for his open-source efforts. It's unfair to expect continuous free contributions from anyone, after all.

Rewriting on My Own Terms

As a die-hard fan of Moonscript, I couldn't just stand by. The original Moonscript compiler was written in Moonscript itself, with a core parser built in C using a PEG grammar library to generate ASTs, which were then processed back in Lua. This was a resource-intensive process, particularly for large projects where dynamic loading of Moonscript code could cause noticeable lag. Additionally, the dynamic nature of Lua made it ill-suited for handling strict data types in ASTs—a typical weak point in dynamic language development.

So, instead of building on the existing codebase, I opted for a fresh start in my second favorite programming language, C++ (with Moonscript being the first, of course). This rewrite not only solved several unresolved issues but also reintroduced some long-missed programming features from other languages. Check out the new project here: Yuescript.

Transpilers for Lua and PEG Grammar

Nowadays, compilers that generate code in another programming language are more accurately called transpilers. Lua’s simple design allows for fast compilation with a one-pass recursive descent parser. With diverse programming preferences, many have ventured into developing transpilers from various languages like JavaScript, TypeScript, Lisp, C, Python, Go, and C# into Lua. This enhances Lua's capabilities, driven by aesthetic preferences, personalized needs, and advancing hardware that liberates computing power. Even Python’s creator once used a LL(1) grammar to ensure parser efficiency thirty years ago. With today's better hardware, more complex grammars like PEG that allow infinite backtracking for matches have become viable, improving parser flexibility and future language evolution.

The Advantages of C++ in Writing a Transpiler

Describing Moonscript as a macro system on Lua isn’t far from the truth, as many of its features are essentially syntactic sugar over Lua. The process involves three steps: parsing the code into a Moon AST, converting this AST into a Lua equivalent, and finally translating that into code. C++ shines in handling ASTs with its compile-time and runtime type checking, which minimizes errors significantly. Since C++17, the language has become even more powerful and expressive. For instance, the use of template metaprogramming allows us to ensure safety and efficiency:

// Checking if an AST node is either Exp or ExpList
if (item.is<Exp_t, ExpList_t>()) {
...
}

// Fetching the last matching node for a given AST structure
if (auto variable =
node->getByPath<ChainValue_t, Callable_t, Variable_t>()) {
auto varName = toString(variable->name);
...
}

// Handling different AST structures with a switch statement
switch (node->getId()) {
case id<While_t>(): {
auto while_ = static_cast<While_t*>(node);
...
break;
}
case id<For_t>(): {
auto for_ = static_cast<For_t*>(node);
...
break;
}
...
}

Yuescript in Action: More Than Just a Language

Initially, Yuescript was tied to an open-source game engine project, Dora SSR (https://dora-ssr.net ), aiming to elevate the capabilities of the Lua-supported engine with an advanced version of Moonscript. Along with the engine’s Web IDE, Yuescript also adds modest code completion and type inference features to enhance coding efficiency.

I particularly enjoy using Yuescript during Game Jams, brainstorming with teammates and then diving into coding without overthinking the design—a somewhat reckless yet fun approach to programming. Although we still integrate some programming design using Dora SSR’s messaging system combined with Yuescript’s functional style. You can see some of our frenzied Game Jam projects in Yuescript at Dora SSR's repository.

So, as a dialect of Lua's dialect Moonscript, Yuescript not only holds its ground in theory but has also been battle-tested in real applications within the Dora SSR project.

Cross-Platform Game Dev with Rust!

· 10 min read
Li Jin
A Dora SSR developer.

Introduction

Ever since I was captivated by the magic of Warcraft III MODs in my childhood, I've held a special fondness for game scripting languages. Reflecting back on those days, using Blizzard's JASS language to create levels in Warcraft III was quite basic by today's standards—being statically typed with no garbage collection—but it represented a bold experiment in the early days of game development standards.

Why Use Scripting Languages for Game Development?

The main purpose of incorporating scripting languages into game development is to enhance the convenience of development and testing. Using lower-level languages like C++ could mean waiting for lengthy recompilations with every single line of code changed. Scripting languages allow for hot-loading of gameplay code, significantly boosting development efficiency.

Over time, dynamic scripting languages like Lua and JavaScript have become regulars in game development. However, as programming languages have evolved, we have the opportunity to redefine the new standards for game scripting languages—a blend of retro and innovation, namely, the combination of Rust and WASM.

Rust + WASM + Dora SSR: Redefining Game Script Development

Combining Rust with WASM enables us to conduct game updates and testing on devices like Android or iOS without sacrificing performance and without relying on traditional app development toolchains. Moreover, with the help of the Dora SSR open-source game engine's Web IDE interface, games written in Rust can be compiled once and then tested and run on various gaming devices.

Why Choose Rust?

Rust offers unparalleled memory safety guarantees and operates without the need for a garbage collector, making it ideal for game development, especially in performance-sensitive scenarios. With WASM, Rust not only delivers high performance but also maintains consistency and security across platforms.

Quick Start Guide

Before diving into development, we need to install the Dora SSR game engine. This engine supports multiple platforms including Windows, Linux, macOS, iOS, and Android. For specific installation steps and requirements, please refer to the official Quick Start Guide: Dora SSR Quick Start.

Dora SSR v1.3.17 running on macOS

Dora SSR v1.3.17 running on macOS

Step One: Create a New Project

Once the Dora SSR engine is running, open the Dora SSR Web IDE in your browser, right-click on the left-side game resource tree, and choose 'New' to create a new folder named 'Hello'.

Accessing Dora SSR's Web IDE and creating a new folder in the browser

Accessing Dora SSR's Web IDE and creating a new folder in the browser

Step Two: Write the Game Code

Next, create a new Rust project from the command line:

rustup target add wasm32-wasi
cargo new hello-dora --name init
cd hello-dora
cargo add dora_ssr

Write the code in src/main.rs:

use dora_ssr::*;

fn main() {
let mut sprite = match Sprite::with_file("Image/logo.png") {
Some(sprite) => sprite,
None => return,
};
let mut sprite_clone = sprite.clone();
sprite.schedule(once(move |mut co| async move {
for i in (1..=3).rev() {
p!("{}", i);
sleep!(co, 1.0);
}
p!("Hello World");
sprite_clone.perform_def(ActionDef::sequence(&vec![
ActionDef::scale(0.1, 1.0, 0.5, EaseType::Linear),
ActionDef::scale(0.5, 0.5, 1.0, EaseType::OutBack),
]));
}));
}

Build the WASM file:

cargo build --release --target wasm32-wasi

Step Three: Upload and Run the Game

In the Dora SSR Web IDE, right-click the newly created 'Hello' folder, select 'Upload', and upload the compiled WASM file init.wasm.

Uploading files through the Web IDE

Uploading files through the Web IDE

Alternatively, use a helper script to upload the WASM file within the Rust project folder. Here’s the command, where the IP parameter should be the address shown in Dora SSR’s Web IDE after startup, and the last parameter is the relative path of the directory to upload:

python3 upload.py "192.168.3.1" "Hello"

Using a script for one-click compile, upload, and run

Using a script for one-click compile, upload, and run

Step Four: Publish the Game

In the editor's left-side game resource tree, right-click the newly created project folder and choose 'Download'.

Wait for the browser to prompt with a download notification for the packaged project files.

How It's Implemented

In Dora SSR, implementing support for Rust language development and embedding the WASM runtime was a new technical exploration and trial, involving three key steps:

1. Design of the Interface Definition Language (IDL)

To embed the WASM runtime in a C++-written game engine and support Rust, it was first necessary to design an Interface Definition Language (IDL) to facilitate communication and data exchange between different programming languages. Below is an example of a WASM IDL designed for Dora SSR, based on the native C++ programming interface with added annotations needed to transition to Rust interfaces, such as object, readonly, and optional. One of the challenges in cross-language interface mapping is the object-oriented interface design of C++, as Rust does not provide complete object-oriented capabilities, requiring additional code in Rust to simulate some object-oriented features. Fortunately, this language difference is not overly large or complex to manage.

object class EntityGroup @ Group
{
readonly common int count;
optional readonly common Entity* first;
optional Entity* find(function<bool(Entity* e)> func) const;
static EntityGroup* create(VecStr components);
};

Considering the differences between C++'s object-oriented features and Rust's design philosophy, we partially simulated object-oriented behavior in Rust, necessitating additional mechanisms in Rust to correspond to C++ classes and methods. Although this approach increased the development workload, it maintained the cleanliness of the interface and the maintainability of the system.

2. Generating Glue Code

The second step involved writing a program to generate the glue code that facilitates calls between C++, WASM, and Rust through the IDL. For this purpose, we chose to use Yuescript, a dynamic programming language based on Lua, developed as part of the Dora SSR project. Yuescript combines the flexibility and lightweight nature of Lua with the rich syntax and features necessary for complex code generation tasks, utilizing Lua's lpeg syntax parsing library to handle IDL parsing and glue code generation. Below is an excerpt from the IDL parser written using PEG grammar in Yuescript.

Param = P {
"Param"
Param: V"Func" * White * Name / mark"callback" + Type * White * Name / mark"variable"
Func: Ct P"function<" * White * Type * White * Ct P"(" * White * (V"Param" * (White * P"," * White * V"Param")^0 * White)^-1 * P")" * White * P">"
}

Method = Docs * Ct(White * MethodLabel) * White * Type * White * (C(P"operator==") + Name) * White * (P"@" * White * Name + Cc false) * White * Ct(P"(" * White * (Param * (White * P"," * White * Param)^0 * White)^-1 * P")") * White * C(P"const")^-1 * White * P";" / mark"method"

3. Embedding WASM Runtime and Code Integration

The final step was to embed the WASM runtime and the generated C++ glue code into the game engine, completing the code integration. For the WASM runtime, we chose WASM3, a high-performance, lightweight WebAssembly interpreter that supports multiple CPU architectures. This choice simplifies the complexity of the compilation chain and enhances cross-platform compatibility. By doing so, Dora SSR can support games developed in Rust running on hardware devices with various architectures, greatly enhancing the accessibility and flexibility of game projects.

During the integration process, we released a crate package for Rust developers, which includes all necessary interfaces and tools, enabling developers to easily develop and republish other game modules written in Rust based on the Dora SSR game engine.

Performance Comparison

Dora SSR supports Lua scripting as well, currently using the Lua 5.5 version virtual machine. Like WASM3, it does not perform JIT compilation of real-time machine code but interprets script codes within the virtual machine. This setting allows us to make some performance comparisons between these two scripting approaches.

Before delving into comparisons, it's evident that disregarding Lua's garbage collection time, the inherent dynamics of Lua mean that C++ mappings to Lua interfaces must perform runtime checks for input parameter types. Moreover, accessing Lua object properties requires runtime searches through a hash table structure—costs that Rust's static typing and WASM virtual machine either avoid or minimize. Here are some basic performance tests focusing on cross-language calling and parameter passing efficiency, specifically selecting interfaces that require minimal computational processing on the C++ side.

  • Rust Test Code
let mut root = Node::new();
let node = Node::new();

let start = App::get_elapsed_time();
for _ in 0..10000 {
root.set_transform_target(&node);
}
p!("object passing time: {} ms", (App::get_elapsed_time() - start) * 1000.0);

let start = App::get_elapsed_time();
for _ in 0..10000 {
root.set_x(0.0);
}
p!("number passing time: {} ms", (App::get_elapsed_time() - start) * 1000.0);

let start = App::get_elapsed_time();
for _ in 0..10000 {
root.set_tag("Tag name");
}
p!("string passing time: {} ms", (App::get_elapsed_time() - start) * 1000.0);
  • Lua Test Code
local root = Node()
local node = Node()

local start = App.elapsedTime
for i = 1, 10000 do
root.transformTarget = node
end
print("object passing time: " .. tostring((App.elapsedTime - start) * 1000) .. " ms")

start = App.elapsedTime
for i = 1, 10000 do
root.x = 0
end
print("number passing time: " .. tostring((App.elapsedTime - start) * 1000) .. " ms")

start = App.elapsedTime
for i = 1, 10000 do
root.tag = "Tag name"
end
print("string passing time: " .. tostring((App.elapsedTime - start) * 1000) .. " ms")

Performance Results

Rust + WASM:
object passing time: 0.6279945373535156 ms
number passing time: 0.5879402160644531 ms
string passing time: 3.543853759765625 ms

Lua:
object passing time: 6.7338943481445 ms
number passing time: 2.687931060791 ms
string passing time: 4.2259693145752 ms

As observed, aside from string type interface calling, Lua's cross-language calling performance in Dora SSR is almost an order of magnitude slower than WASM's. The slight difference in string handling is likely due to the bulk of performance loss occurring during string object copying, a minor concern compared to cross-language calling overheads.

User Experience Discussion

Introducing Rust into game development has offered a distinct boost in productivity compared to traditional approaches, especially when integrating with large language models like ChatGPT for code generation assistance. Unlike C or C++—or even many dynamic languages—where generated code might compile but often contains hidden runtime errors and defects such as memory leaks or misuse of pointers and references, Rust's strict compiler environment provides a more stable and secure coding environment for game development.

Rust's ownership and borrowing mechanisms, along with its design for type and memory safety, allow many potential issues to be caught and corrected during compilation. By supporting Rust in the Dora SSR game engine, I've found that scripting for games is not only safer but also more efficient, transforming game development from a process of debugging to one focused more on creation and realization.

Conclusion

Opting for Dora SSR + Rust as a game development toolkit is not just about being on the cutting edge of technology—it's a new exploration of the game development process itself. I warmly invite every game development enthusiast to join our community and embark on this exciting technological journey. Visit our GitHub repository for more information and to get involved. Let's start a new era of game development together!

From Compiler, Game Engine to Handheld Console: My Journey in Indie Game Development

· 5 min read
Li Jin
A Dora SSR developer.

Introduction

Developing my own games has been a dream since childhood, particularly fueled by my extensive use of the Warcraft 3 World Editor. This sparked a fascination with game engines and development tools. As a student, I delved into programming and soon felt the urge to expand beyond just using various programming languages for development. I started maintaining a programming language called Yuescript, tailored for writing game logic. My learning journey in graphics led me to rewrite the Cocos2d-x as a learning project, which eventually evolved into the Dora SSR game engine. Later, as my love for handheld gaming consoles grew, I began collaborating on an open, programmable gaming device called the "Auspice Gear", aiming to achieve the ultimate digital freedom in gaming.

The Fun and Challenges of Game Scripting Languages

Multilingual Playground!

Multilingual Playground!

Programming in various languages is exhilarating, as each language offers unique programming philosophies and design principles. For scripting complex and dynamic game mechanics, I prefer using languages that are succinct and expressive. Yuescript, translatable to Lua, fulfills this need beautifully. Over time, as I developed more with my Dora SSR engine, I integrated languages like Teal (which adds static typing to Lua), TypeScript (for enhanced code hints and checks), JSX, and XML (for descriptive, componentized development). Each scripting language shines in specific game development contexts and seamlessly inter-operates through translation to Lua. Beyond Lua-based extensions, the Dora SSR engine also experiments with supporting diverse scripting languages via the WASM virtual machine, such as Rust and upcoming support for C++ and Go, balancing performance with runtime expansibility.

Innovating with Game Engines

Game creation at your fingertips!

Game creation at your fingertips!

While high-performance graphic rendering and complex scene construction are typically associated with game engines, as an indie developer and enthusiast, I believe many 2D games or those blending 2D and 3D effects can also offer highly creative and unique experiences. Ideally, devices for developing and running games should be unrestricted. Thus, Dora SSR was envisioned to provide an accessible and user-friendly environment, or even a full-fledged game development IDE, on as many devices as possible. Game development has become a part of my daily routine, allowing me to enjoy coding and debugging game features leisurely and sporadically, using whatever devices are at hand.

Dora SSR features a built-in Web IDE server within the game engine runtime, enabling code writing, running, and debugging directly on any terminal device via a web browser. This integration provides visual hints and access to various game development and resource management tools. Presently, Dora SSR supports game development on platforms like Windows, macOS, iOS, Android, and several Linux distributions.

Pursuing the Dream of a Free and Open Gaming Handheld

Open source everything?

Open source everything? Want it for both software and hardware!

Despite the progress, the pursuit of an unrestricted and open gaming development experience is far from over. As a veteran handheld gaming enthusiast dissatisfied with many commercial open-source handhelds, I envisioned a device not just for playing games but also for freely developing, running, and even distributing homemade games. Many manufacturers restrict programmability for profit, so with like-minded hardware enthusiasts, we developed the fully open "Auspice Gear", offering modular customization of its core components and design.

Auspice Gear + Dora SSR

Auspice Gear + Dora SSR

Returning to the Essence of Game Creation

An open-source indie game project

An open-source indie game project made by the community called 'Luv Sense Digital'

So, did I eventually make my game? Yes, though it's not entirely complete yet. Before the generative AI boom of 2020, we envisioned a future where AI played a central role in games—where humans, having their material needs fully met, engage in games to provide creative and intelligent data for AI training. This data, assessed by futuristic banks, determines an individual's monetary worth. The AI trained with this data helps with all aspects of material production, individual nurturing, and social management. This narrative reflects our ongoing quest to define ourselves through our creations rather than being defined by circumstances into which we were born.

If you're interested in our work on programming languages, game engines, gaming handhelds, or our game project, feel free to star our repositories or join our discussion groups. Although our projects are still in their early stages, they are continuously integrated and iterated upon, offering a glimpse into our progress and processes.

We warmly invite everyone passionate about game development to join us. Whether contributing code, providing feedback, or sharing our projects, your efforts help us collectively realize the dream of freely developing games.

🌈 Dora SSR - A Magical Journey from "The Wizard of Oz" to the World of Gaming

· 2 min read
Li Jin
A Dora SSR developer.

🌟


Behind every great creation lies a story filled with magic. The inspiration for Dora SSR springs from one of my most cherished childhood tales - "The Wizard of Oz." In this classic story, Dorothy, along with her little dog Toto and new friends - the Tin Man lacking a heart, the Scarecrow without a brain, and the Cowardly Lion, embark on an adventure filled with challenges and wonders.


Just as Dorothy's journey in "The Wizard of Oz" was one of exploration and discovery, the Dora SSR engine represents a similar voyage. It's more than just a technological product; it's a platform that sparks creativity and realizes dreams. We aspire for every developer using Dora SSR to pursue their dreams with courage, overcome obstacles, and discover themselves, just like Dorothy and her companions.

🚀


In the world of Dora SSR, we encourage developers to seek wisdom like the Scarecrow, search for heart like the Tin Man, and find courage like the Lion. Each game represents a new adventure, every idea an exploration of the unknown. We believe that through this platform, everyone can find their "Emerald City" - the realization of their dreams.

🌍


The strength of Dora SSR, much like Dorothy and her friends, comes from its community - a place brimming with creativity, support, and collaboration. Our community is our "Oz," where everyone can find their voice and place.

🔥


Our journey has just begun. Dora SSR will continue to grow and evolve, constantly learning, advancing, and surpassing, just like the characters in "The Wizard of Oz." We look forward to witnessing more creativity and miracles born on this platform.

🤝


So, let's move forward together on this enchanting journey with Dora SSR, creating our own "Wizard of Oz" story! In this journey, everyone can be Dorothy, and every idea has the potential to become the next wonder!