DOCUMENTATION / Start here
What is Ouragora?
A console on the internet where you can write little programs, build games and tools, and explore what other people have made.
Ouragora is the place. Ouro is the programming language. The console gives you a prompt, a text editor, a compiler, and a shared filesystem. You type commands to find files and run programs. You write Ouro to make something new.
You do not need to install anything or create an account. Programs run in your browser; the server stores the shared files and connects programs to each other.
Two ways to start
Just looking around? Open the console and type these commands, one line at a time:
cat /README
ls /
ls /bin
ls /lib
cat reads a file. ls lists a directory. The contents of /bin depend on what visitors have added. Read a program with cat /bin/name.ouro before running it with name.
Want to build something? Follow Your first program, then try drawing with gfx.
What can you build?
Text tools with the standard library, pixel art and games with gfx, textured graphics with gpu, connected programs with net, or tools that launch other tools with proc.
A shared space
Files you save are readable by other visitors. Your browser holds the key that lets you change files you created. Do not store passwords or private information here. See Files & ownership before leaving something behind.
DOCUMENTATION / Your first program
Write, save, run
Make a program that prints a message. This is the same workflow you will use for the package examples.
1. Open a file
In the console, type:
edit /bin/my-hello.ouro
Choose another name if that path already belongs to someone. .ouro is the file extension for Ouro source code.
2. Write your program
Paste this into the editor, not into the command prompt:
fn main(): i64 {
print("hello from ouragora\n");
return 0;
}
main is where execution begins. print writes text to the terminal; \n starts a new line. return 0; ends the program successfully.
3. Save and close
Press Ctrl+S (or ⌘S on Mac), wait for the saved message, then press Esc to return to the prompt. F1 opens the editor guide.
4. Run it
my-hello
You should see hello from ouragora. A bare command name looks for /bin/name.ouro. You can also use the full path:
run /bin/my-hello.ouro
Edit the message, save, and run again. The console compiles the saved source each time you run it. Press Ctrl+C to stop a running job.
DOCUMENTATION / Ouro basics
A little Ouro
Ouro is a statically typed language: variables and function arguments have types, and the compiler checks them before your program runs.
Variables, loops, and conditions
fn main(): i64 {
let count: i64 = 1;
while count <= 3 {
print_i64(count);
print("\n");
count = count + 1;
}
if count == 4 {
print("done\n");
}
return 0;
}
This prints 1, 2, 3, then “done”. let declares a variable; it can be reassigned. Statements end with semicolons. Conditions and loops use braces. Comments begin with //.
Types you will meet
i64 | Whole numbers, such as a score or pixel coordinate. |
f64 | Decimal numbers, such as 1.5. Used by math and gpu. |
bool | true or false. Use and, or, and not. |
string | Text in double quotes. |
*Arena | A pointer to a memory arena. Packages use this to allocate their data. |
Functions
fn double(n: i64): i64 {
return n * 2;
}
fn main(): i64 {
print_i64(double(6));
print("\n");
return 0;
}
The type after a function's closing parenthesis is its return type. Convert between numeric types explicitly, for example 12 as f64.
Imports and memory
The standard library is loaded automatically: print, print_i64, and arena_new need no import. Packages use import math; and qualified names such as math::sqrt(9.0).
arena_new(16777216) creates an arena with a 16 MiB capacity. A pointer type begins with *; null means no value was returned. The examples check for failed allocations. &e passes the address of a variable so a function can fill it in.
DOCUMENTATION / Console commands
Finding your way around
Type these at the console prompt. They are commands, not Ouro code.
| Command | What it does |
help | List the built-in commands. ? also works. |
ls /bin | List programs visitors have saved. |
cd /lib | Change your current directory. |
pwd | Print the current directory. |
cat /README | Read a text file. |
edit /bin/my-tool.ouro | Create or edit a file. write is an alias. |
cp /bin/tool.ouro /bin/my-tool.ouro | Make your own copy. |
rm /bin/my-tool.ouro | Delete a file you own. |
run /bin/my-tool.ouro | Compile and run saved source. |
whoami | Show your anonymous identity, not the secret key. |
clear | Clear the terminal output. |
Paths
A path starting with / is absolute. Otherwise it is relative to your current directory. After cd /lib, ls gfx lists /lib/gfx. Use cd / to return to the root.
Keyboard shortcuts
Ctrl+C stops a running job and its child programs. Ctrl+L clears terminal output. In the editor, Ctrl+S / ⌘S saves and Esc closes. If you have unsaved changes, the editor warns before discarding them.
DOCUMENTATION / Files & ownership
Your files in a shared world
Saving a file makes it available to everyone. Ownership controls who can change it, not who can read it.
Where things live
/README | The welcome file. |
/bin | Programs that can be run by name. |
/lib | Shared packages and their source. |
/sys/std | The built-in standard library source. |
Use ls / to discover other folders that visitors have created.
Making a copy
cp /bin/their-tool.ouro /bin/my-tool.ouro
edit /bin/my-tool.ouro
Replace the source name with a file that exists, and choose an unused destination. Copying gives you a separate file to edit; it does not change the original.
Your browser is your identity
The first browser to create a path owns it. Its anonymous key is stored in that browser. Clearing site data, switching browser profiles, or using another device can leave you unable to change your old files. whoami shows a short identifier; it is not a recovery key.
The server retains previous versions when files are overwritten or deleted, but the console has no built-in restore command. Keep your own copy of work you care about.
DOCUMENTATION / Package overview
Choose a package
Packages are reusable Ouro code. These five are bundled with the console; you do not need to install them.
| Package | Use it for |
| gfx | Pixel art, simple games, shapes, text, keyboard and mouse input. A good first graphics package. |
| gpu | Textured sprites, triangles, transparency, and depth with WebGL2. |
| math | Trigonometry, square roots, clamping, and interpolation. |
| net | Find open relay ports and connect programs inside one browser page. |
| proc | Launch other Ouro programs, capture output, and host child windows. |
How to use one
import math;
fn main(): i64 {
print_i64(math::sqrt(81.0) as i64);
print("\n");
return 0;
}
Save this in an .ouro file and run it. It prints 9. The import loads the package; :: selects a function inside it.
Read the source
ls /lib
ls /lib/math
cat /lib/math/ouro.json
cat /lib/math/math.ouro
ouro.json describes the package. Its .ouro files contain the implementation and API comments. Functions marked pub are available to callers. Shared package contents may change; their source is the reference for the version in your console.
DOCUMENTATION / gfx · pixels & input
Draw your first screen
Use gfx for a small pixel canvas, shapes, and a built-in bitmap font. Coordinates are whole numbers measured from the top-left corner.
Save this as /bin/my-picture.ouro, then run my-picture. It draws a green rectangle and a message. Press Esc to exit.
import gfx;
fn main(): i64 {
let a: *Arena = arena_new(16777216);
if a == null { return 1; }
let s: *gfx::Screen = gfx::open(a, 320, 200);
if s == null { return 1; }
let e: gfx::Event;
while true {
while gfx::poll(s, &e) {
if e.kind == gfx::KEY_DOWN and e.a == gfx::K_ESC {
gfx::close(s);
return 0;
}
}
gfx::clear(s, 0x101010);
gfx::rect(s, 40, 50, 100, 60, 0x66cc99);
gfx::text(s, 8, 8, "hello, pixels", 0xffffff);
gfx::present(s);
}
return 0;
}
The drawing loop
Poll input first, clear the old image, draw the new one, then call present to display it. Colours use 0xRRGGBB: 0xff0000 is red and 0xffffff is white.
Useful calls
gfx::pixel(s, x, y, color);
gfx::rect(s, x, y, width, height, color);
gfx::circle(s, center_x, center_y, radius, color);
gfx::line(s, x0, y0, x1, y1, color);
gfx::text(s, x, y, "text", color);
These are call patterns to use inside your program. After polling, gfx::key(s, gfx::K_LEFT) tells you whether the left arrow is held. s.mouse_x, s.mouse_y, and s.buttons[0] give mouse state.
Read more: cat /lib/gfx/gfx.ouro.
DOCUMENTATION / gpu · accelerated graphics
Draw with the GPU
Choose gpu for sprites, transparency, and larger scenes. It needs WebGL2 in your browser. Unlike gfx, drawing coordinates use decimal numbers.
Save as /bin/my-gpu.ouro and run my-gpu. This draws a blue rectangle. Press Esc to exit.
import gpu;
fn main(): i64 {
let a: *Arena = arena_new(16777216);
if a == null { return 1; }
let g: *gpu::Gpu = gpu::open(a, 640, 360);
if g == null { return 1; }
let e: gpu::Event;
while true {
while gpu::poll(g, &e) {
if e.kind == gpu::KEY_DOWN and e.a == gpu::K_ESC {
gpu::close(g);
return 0;
}
}
gpu::clear(g, 0x101010);
gpu::rect(g, 40.0, 60.0, 180.0, 100.0, 0x6699ff);
gpu::text(g, 16.0, 16.0, "hello, gpu", 0xffffff, 2.0);
gpu::present(g);
}
return 0;
}
Going further
gpu::texture(g, pixels, w, h) uploads a buffer of u32 pixels in 0xAARRGGBB format and returns a texture ID. Use that ID in gpu::sprite(g, id, x, y, w, h).
gpu::alpha(g, 128) applies roughly half opacity to subsequent drawing. gpu::depth(g, true) enables depth testing. gpu::tri draws a triangle; gpu::vertex supports textured vertices with depth.
Read the full signatures and texture setup in cat /lib/gpu/gpu.ouro.
DOCUMENTATION / math · numbers
Numbers, angles, and motion
Math helpers for movement, geometry, and calculations. Functions take and return f64 values.
import math;
fn main(): i64 {
let distance: f64 = math::sqrt(9.0 + 16.0);
print_i64(distance as i64);
print("\n");
return 0;
}
Save and run using the first-program workflow. The result is 5; the cast converts the result to an integer for print_i64.
| Call | Meaning |
|---|
math::clamp(x, lo, hi) | Keep a value between two bounds. |
math::lerp(a, b, t) | Interpolate: t = 0 gives a; t = 1 gives b. |
math::sin(angle), math::cos(angle) | Waves and circular motion. Angles are in radians. |
math::atan2(y, x) | Find the angle of a direction. |
math::sqrt(x), math::pow(x, y) | Square root and exponentiation. |
math::floor(x), math::ceil(x), math::round(x) | Round a value; the result is still f64. |
Also included: abs, min, max, tan, atan, exp, and log. Read cat /lib/math/math.ouro for implementation details.
DOCUMENTATION / net · connections
Connect running programs
Networking here connects Ouro programs through Ouragora. It does not fetch websites or connect to arbitrary internet servers.
See whether a port is open
import net;
fn main(): i64 {
let a: *Arena = arena_new(1048576);
if a == null { return 1; }
if net::open(a, 7777) {
print("someone is listening on 7777\n");
} else {
print("port 7777 is not open\n");
}
return 0;
}
Send a message between two tabs
Save the following as /bin/my-listener.ouro and run it in one console tab. It waits for a connection, sends a greeting, then exits. If port 7777 is taken, choose another port in both programs.
fn main(): i64 {
let listener: i64 = socket_listen(7777);
if listener < 0 { return 1; }
print("waiting on 7777\n");
let client: i64 = socket_accept(listener);
if client >= 0 {
fd_print(client, "hello from another program\n");
file_close(client);
}
file_close(listener);
return 0;
}
Save this as /bin/my-client.ouro and run it in a second console tab while the listener is waiting:
fn main(): i64 {
let a: *Arena = arena_new(1048576);
if a == null { return 1; }
let client: i64 = socket_connect("", 7777);
if client < 0 { print("no listener\n"); return 1; }
let line: string = "";
if fd_read_line(a, client, &line) {
print(line);
print("\n");
}
file_close(client);
return 0;
}
The socket and file functions are in the standard library, so these two programs need no import. An empty host string selects the relay. Reads can wait for data; fd_ready(fd) checks readiness without waiting.
What net adds
net::ports(a) lists open relay ports. net::listen_local(port) and net::connect_local(port) use private ports reachable only by programs in the same page. Ports close when their program ends.
Read cat /lib/net/net.ouro.
DOCUMENTATION / proc · child programs
Run one program from another
Use proc to combine tools or build a program that manages other programs in the same browser page.
First create /bin/my-hello.ouro from Your first program. Then save this as /bin/my-launcher.ouro and run my-launcher:
import proc;
fn main(): i64 {
let a: *Arena = arena_new(1048576);
if a == null { return 1; }
let child: *proc::Proc = proc::start(
a, "/bin/my-hello.ouro", null, proc::INHERIT
);
if child == null {
print("could not start the program\n");
return 1;
}
return proc::wait(child.pid);
}
You should see the child's greeting. null supplies no arguments. Waiting keeps the parent alive until the child finishes; ending a parent also ends its children.
Three launch modes
proc::INHERIT | The child prints to the terminal and receives no input. |
proc::PIPE | Read from child.stdout and write to child.stdin using file functions. |
proc::WINDOW | The parent receives the child's graphics and forwards input. It must display the frames itself. |
proc::status(pid) checks a process. proc::wait(pid) waits for its exit code. proc::start_window, proc::frame, and proc::send_event support window hosts.
Read cat /lib/proc/proc.ouro for signatures and pipe/window examples.
DOCUMENTATION / Troubleshooting
When something does not work
“Nothing here answers to that”
The command does not exist as a built-in or as /bin/name.ouro. Check the spelling with ls /bin, or use run /full/path.ouro.
My changes are not running
Save with Ctrl+S / ⌘S and check the editor's save message before pressing Esc. The compiler reads the saved file, not unsaved editor text.
I cannot save over a file
It may belong to another browser identity or be read-only system content. Copy it to an unused path. If you cleared your site data, your previous ownership key may be gone.
A compiler error
Start with the first reported file, line, and column. Check semicolons, braces, argument types, and imports. Use decimal values such as 10.0 for gpu and math arguments. Package names use ::, for example gfx::rect.
A blank graphics screen
Check that opening the screen did not return null and that your loop calls present. The gpu package also requires WebGL2. Try the gfx example to check basic drawing.
A program will not finish
Graphics loops deliberately stay open. Network reads and waits may also block. Use Ctrl+C to stop the job. Programs run in workers, but can still consume your browser's CPU and memory.
What can someone else's program access?
The browser runtime exposes shared files, graphics, input sent to the program, child programs, and the relay. It does not expose the page DOM, cookies, your computer's files, or arbitrary internet connections. Treat text you type into a stranger's program as information they may keep or share.