Installation
Varse is a single executable with no external dependencies. Build from source with NASM and GoLink:
git clone https://github.com/varse-lang/varse
cd varse
nasm -f win64 varse.asm -o varse.obj
golink /entry:main /console varse.obj kernel32.dll user32.dll gdi32.dll gdiplus.dll wininet.dll
Cloning gets you the interpreter source, the build script, the assembler and linker in tools/, and the examples. The interactive console and every GUI widget live in the kernel32, user32, gdi32, gdiplus and wininet libraries, so there is nothing else to install.
Hello World
Create a file called hello.var:
fn main() {
print(42);
}
Running Code
Every Varse program must have a fn main() function. The interpreter parses all definitions first, then finds and executes main.
varse hello.var
Standalone executables
Pass --build and Varse copies the interpreter, appends the source to it, and writes the result out. The .exe that comes out carries its own source, so it runs on its own with nothing else installed:
varse --build hello.var -o hello.exe
hello.exe
The built program reads the source from its own tail at startup, so it keeps running the code exactly as it was when you built it — rebuild after editing the .var.
Built-ins Quick Reference
The entire language is 7 built-in functions and 26 statement keywords, plus 2 command line forms. That is the whole surface — anything else is defined by your own program. Both tables below link to the section that documents each one.
Built-in functions (7) — the only names always in scope
These seven are resolved before any of your own definitions, so they cannot be shadowed. Write one bare (netlength()) or as part of a larger expression (setnum status netstatus();). print() looks like a call too but starts a statement, so it is listed below.
| Function | Returns | More |
|---|---|---|
netstatus() | HTTP status code of the last request (200, 404, 0 on failure) | netstatus() |
netlength() | Size of the stored response body in bytes | netlength() |
cssbg() | Page background color as a number | cssbg() |
cssfg() | Page text color as a number, 0 if the page sets none | cssfg() |
htmlblocks() | How many blocks the stored page has | htmlblocks() |
blocklen(i) | Characters in block i | blocklen() |
blocktag(i) | Element kind of block i (1–6 heading, 7 li, 8 pre, 9 quote, 10 table, 0 other) | blocktag() |
Statements (26 keywords, plus assignment) — used on their own line
Each of these starts a statement. The first seven are the core language; the rest are the GUI, networking and page readers. Assignment (name = expr;) is not a keyword — a bare name followed by = updates an existing variable.
| Statement | What it does | More |
|---|---|---|
print(expr); | Writes a number to the console | print() |
let name = expr; | Declares a variable | Variables |
name = expr; | Assigns to an existing variable | Variables |
def name: value; | Declares an immutable constant | Constants |
fn name(params) { } | Defines a function | Functions |
return expr; | Returns from a function | Return Values |
if (cond) { } else { } | Conditional execution | If / Else |
prints "text"; | Writes a string to the console | prints |
window "t" w h bg=#HEX; | Creates the window | window |
button name x y w h "t" ...; | Creates a clickable button | button |
label name x y w h "t" ...; | Creates a text label | label |
input name x y w h "t" ...; | Creates an editable text field | input |
panel name x y w h ...; | Creates a filled surface | panel |
onclick name { }; | Runs a block when a button is clicked | onclick |
show; | Enters the message loop | show |
settext w "text"; | Replaces a widget's text with a string | settext |
setnum w expr; | Replaces a widget's text with a number | setnum |
setcolor w expr; | Changes a widget's color | setcolor |
sethide w expr; | Hides or shows a widget | sethide |
resetui n; | Drops widgets past n before rebuilding a layout | resetui |
httpget "url"; | HTTP GET a URL or an input widget's text | httpget |
netprint; | Writes the stored body to the console | netprint |
netsave "path"; | Writes the stored body to a file | netsave |
nettext w; | Puts the stored body into a widget | nettext |
htmlstrip w; | Puts the page's readable text into a label | htmlstrip |
htmltitle w; | Puts the page's title into a label | htmltitle |
htmlblock w i; | Puts block i of the page into a label | htmlblock |
Command line (2)
| Command | What it does | More |
|---|---|---|
varse file.var | Runs a program | Running Code |
varse --build file.var -o out.exe | Writes a standalone exe with the source embedded | Standalone executables |
Not in the language at all
| Missing | What to do instead |
|---|---|
Loops (while, for) | Recursion, or unroll by hand — No loops |
| Strings as values | Use the engine's readers — Strings are not values |
| Arrays / lists | Not available |
| Modulo, bit shifts, logic operators | Only + - * / and the comparisons exist — Operators |
| HTTP POST, headers, JSON | httpget is GET only; parse the body yourself as text |
| Fonts, sizes, scrolling | Not available — headings differ by color and spacing only — Notes & Limits |
Variables
Variables store values that can be changed. Declared with let.
let name = expression;
fn main() {
let x = 10;
let y = x + 5;
print(y);
x = 20;
print(x);
}
Constants
Constants are immutable values declared with def. They are resolved at the start of execution.
def name: value;
def pi: 314;
def max_retries: 3;
fn main() {
print(pi);
}
Functions
Functions are declared with fn and contain a block of statements. Functions can be nested.
fn name(params) {
statements
}
fn add(a + b) {
return a + b;
}
fn main() {
print(add(10 + 20));
}
Parameters
Parameters are separated by + (or ,) in both the definition and the call. When calling a function, + acts as the argument separator. To pass an arithmetic expression as a single argument, wrap it in parentheses.
| Syntax | Description |
|---|---|
fn(a + b) | Two parameters |
fn(x) | One parameter |
fn() | No parameters |
add(10 + 20) | Call with 2 arguments (10 and 20) |
add((x + y)) | Call with 1 argument (the expression x + y) |
Return Values
Use return to send a value back from a function.
fn fib(n) {
if (n <= 1) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
fn main() {
print(fib(10));
}
Operators
Arithmetic
| Op | Description | Example |
|---|---|---|
+ | Addition / parameter separator | x + y |
- | Subtraction / unary negation | x - y, -x |
* | Multiplication | x * y |
/ | Integer division | x / y |
Comparison
| Op | Description |
|---|---|
== | Equal to |
!= | Not equal to |
< | Less than |
> | Greater than |
<= | Less than or equal |
>= | Greater than or equal |
Precedence (high to low)
| Level | Operators |
|---|---|
| 1 | Unary - |
| 2 | *, / |
| 3 | +, - |
| 4 | <, >, <=, >=, ==, != |
Comments
// This is a single-line comment
/*
This is a
block comment
*/
If / Else
Conditional execution with if, else if, and else. The condition is always wrapped in its own parentheses, even when it is a bare comparison.
fn classify(n) {
if (n < 10) {
return 1;
} else if (n < 100) {
return 2;
} else {
return 3;
}
}
fn main() {
print(classify(4));
print(classify(42));
print(classify(999));
}
Blocks & Scope
Variables declared inside a function are scoped to that function. Nested functions can access variables from enclosing scopes.
def base: 10;
fn main() {
fn add(x + y) {
return x + y;
}
let sum = add(base + 2);
print(sum);
}
print()
Built-in function that outputs a number to the console.
| Parameter | Type | Description |
|---|---|---|
| expression | number | The value to output. Any expression that evaluates to a number. |
Multiple print() calls concatenate on the same line with no separator.
fn main() {
print(197);
print(12345);
}
prints
Like print(), but writes a string literal instead of a number. Escape sequences are processed inside the literal.
prints "text";
| Escape | Output |
|---|---|
| \n | Newline |
| \t | Tab |
| \\ | Backslash |
| \" | Double quote |
fn main() {
prints "hello ";
print(42);
prints "\n";
}
GUI Framework
Varse includes a built-in GUI system for creating native Windows applications with styled widgets, rounded corners, and click handlers. The GUI uses Win32 API and GDI under the hood.
A GUI program defines widgets, registers click handlers, then calls show to enter the message loop.
Geometry
Every widget takes x, y, width and height, and each of the four is a full expression evaluated as the widget is created. That is what makes a flow layout possible: a widget can sit at a running y variable, and the next one below it at y + height.
let y = 120;
label row1 24 y 600 30 "first";
y = y + 38;
label row2 24 y 600 30 "second";
A name followed directly by ( is read as a call, so write a parenthesised expression with no space before the bracket, and keep a leading bracket away from a variable: x (w - 8) would parse as a call to x.
Colors & options
Every widget accepts the same optional trailing options, written after the text and in any order.
| Option | Value | Applies to |
|---|---|---|
color= | A #RRGGBB literal, or any expression that returns a color such as cssbg() | button and input and panel fill, label text |
radius= | Corner radius in pixels. Has to be a literal number; an expression here is a syntax error | button, input, panel |
bg= | Window background color, same form as color= | window only |
Defaults are per widget: a button is #CC4422 with radius 8, an input is #303033 with radius 6, a panel is white and unrounded, a label's text is black, and a window's background is white.
button go 752 20 130 42 "Go" radius=8 color=#2864C7;
label content 44 144 972 90 "" color=cssfg(); // colour from an expression
A color is an ordinary number, so it can be held in a variable and passed to setcolor like any other value. An option the engine does not recognise is parsed and skipped, so a misspelt option name fails quietly instead of pointing at the mistake.
window
Creates the application window. Must be the first GUI statement.
window "title" width height bg=#HEX;
| Parameter | Type | Description |
|---|---|---|
| title | string | Window title bar text |
| width | number | Width in pixels |
| height | number | Height in pixels |
| bg | color | Background color #RRGGBB or an expression (optional, default #FFFFFF) |
window "My App" 800 600 bg=#121212;
button
Creates a clickable button with optional rounded corners and color.
button name x y w h "text" radius=N color=#HEX;
| Parameter | Type | Description |
|---|---|---|
| name | identifier | Unique name for onclick |
| x, y | number | Position from top-left |
| w, h | number | Width and height in pixels |
| text | string | Label text, centered |
| radius | number | Corner radius, default 8 (optional) |
| color | color | Fill color #RRGGBB or an expression (optional, default #CC4422) |
Visual defaults for the widget, on the dark theme the examples use:
button go 20 20 120 40 "Go"; // #CC4422, radius 8
button go 20 20 120 40 "Go" radius=0 color=#2864C7; // square and blue
label
Creates a text label. Not clickable.
label name x y w h "text" color=#HEX;
| Parameter | Type | Description |
|---|---|---|
| name | identifier | Unique name |
| x, y | number | Position from top-left |
| w, h | number | Text bounding box |
| text | string | Text to display |
| color | hex | Text color #RRGGBB (optional, default #000000) |
input
Creates a single-line text field. Clicking it gives it keyboard focus; typed characters are appended to its text. Its contents can be read by httpget and written with settext.
input name x y w h "default" radius=N color=#HEX;
| Parameter | Type | Description |
|---|---|---|
| name | identifier | Unique name |
| x, y | number | Position from top-left |
| w, h | number | Width and height in pixels |
| default | string | Initial contents (optional) |
| radius | number | Corner radius, default 6 (optional) |
| color | color | Fill color #RRGGBB or an expression (optional, default #303033) |
input address 20 20 700 42 "https://example.com" radius=8 color=#26262B;
panel
Creates a filled rectangle used as a surface behind other widgets — a page area, a card, or a colored strip. Panels are not clickable and draw no text.
panel name x y w h radius=N color=#HEX;
| Parameter | Type | Description |
|---|---|---|
| name | identifier | Unique name |
| x, y | number | Position from top-left |
| w, h | number | Width and height in pixels |
| radius | number | Corner radius, default 0 (optional) |
| color | color | Fill color #RRGGBB or an expression (optional, default #FFFFFF) |
panel page 20 78 1020 600 radius=6 color=#FFFFFF;
Widgets are drawn in declaration order, so a panel declared before a label sits behind it. Labels wrap text to their width and honour newlines.
show
Creates the window and enters the message loop. Blocks until the window is closed.
show;
onclick
Registers a callback that runs when a button is clicked.
onclick button_name {
statements
};
window "Clicker" 400 200 bg=#222222;
button btn1 20 20 160 50 "Print 42" radius=25 color=#1DB954;
onclick btn1 {
print(42);
};
show;
A handler is a normal block, so variables declared with let in main stay visible inside it and can be mutated. Pair that with the widget update statements below to make an interactive program.
Widget Updates
Widgets are addressed by the name they were created with. These statements can appear anywhere, including inside an onclick handler. Each one repaints the window right away.
settext
Replaces the text of a button, label or input with a string literal.
settext widget "text";
| Parameter | Type | Description |
|---|---|---|
| widget | identifier | The name the widget was created with |
| text | string | New text. Has to be a literal — a string cannot be held in a variable |
settext status "Saved";
setnum
Replaces the text of a button, label or input with the result of a numeric expression. Numbers are turned into decimal text for you, so this is the usual way to show a value that changes.
setnum widget expression;
| Parameter | Type | Description |
|---|---|---|
| widget | identifier | The name the widget was created with |
| expression | number | Any numeric expression, including function and built-in calls |
setnum score netstatus();
setcolor
Changes a widget's color. On a button, input or panel it is the fill color; on a label it is the text color.
setcolor widget expression;
| Parameter | Type | Description |
|---|---|---|
| widget | identifier | The name the widget was created with |
| expression | color | A #RRGGBB literal or anything that returns a color, such as cssbg() |
setcolor row #3C7A3C;
setcolor page cssbg();
sethide
Shows or hides a widget. Any non zero value hides it, 0 shows it. Hidden widgets are skipped when drawing and when testing clicks, so they cannot be clicked, and hiding a widget is how you drop a widget you have no data for instead of rebuilding the layout.
sethide widget expression;
| Parameter | Type | Description |
|---|---|---|
| widget | identifier | The name the widget was created with |
| expression | number | Non zero hides, 0 shows |
fn taghide(i) {
if (blocktag(i) == 7) { // a list item
return 0; // keep the bullet
}
return 1; // hide it everywhere else
}
sethide bullet taghide(3);
Widget statements can appear anywhere a statement can, including inside an onclick handler, and each one repaints the window immediately.
let n = 0;
onclick inc {
n = n + 1;
setnum value n;
if (n >= 10) {
settext value "max";
setcolor value #CC4422;
}
};
Networking
Varse makes HTTP requests through the WinINet API. The response body is kept in a buffer that stays readable until the next request.
httpget
Performs an HTTP GET request and stores the response body. The body stays in the buffer until the next request, so read it before you fetch anything else.
httpget "https://example.com";
httpget address;
| Parameter | Type | Description |
|---|---|---|
| url | string or identifier | A URL literal, or the name of an input widget — the widget's current text is then used as the URL, which is how an address bar is wired up |
httpget "https://example.com";
print(netstatus()); // 200
print(netlength()); // 559
netprint
Writes the stored response body to the console, unchanged and without a trailing newline. Handy for looking at what a page actually returned when a renderer shows nothing.
netprint;
| Parameter | Type | Description |
|---|---|---|
| — | — | Takes no arguments; it always prints the current buffer |
httpget address;
netprint;
prints "\n";
netsave
Writes the stored response body to a file, overwriting it if it already exists. The path is relative to the directory the program was started in.
netsave "out.html";
| Parameter | Type | Description |
|---|---|---|
| path | string | File to write, created or replaced |
httpget "https://example.com";
netsave "page.html";
nettext
Sets the text of a button or label to the stored response body, which puts a result straight into the UI without going through the console. The body arrives as it was sent, tags and all — use htmlstrip or htmlblock for a page.
nettext widget;
| Parameter | Type | Description |
|---|---|---|
| widget | identifier | Label or button to receive the body |
httpget "https://example.com";
nettext raw; // raw is a label
netstatus()
Built-in function that returns the HTTP status code of the last request. It is filled in by httpget, so read it after the request returns. On a failed request it is 0.
netstatus()
| Returns | Type | Description |
|---|---|---|
| code | number | 200 on success, 404 for a missing page, 0 when the request never completed |
setnum status netstatus();
if (netstatus() == 0) {
settext status "request failed";
}
netlength()
Built-in function that returns the number of bytes in the stored response body — the size the server sent, useful as a sanity check that something arrived.
netlength()
| Returns | Type | Description |
|---|---|---|
| bytes | number | Body size in bytes, 0 when the buffer is empty |
prints "loaded ";
print(netlength());
prints " bytes\n";
fn main() {
httpget "https://example.com";
print(netstatus());
prints " ";
print(netlength());
netsave "page.html";
}
HTML & CSS
Fetched pages can be turned into plain text and their stylesheet colors extracted. Both readers work on the body stored by the last httpget.
htmlstrip
Extracts the readable text of the stored page into a label, dropping script and style blocks, unescaping entities such as & and , collapsing runs of spaces, and inserting newlines at block boundaries. Labels wrap text to their width, so the result renders as a paragraph.
htmlstrip widget;
| Parameter | Type | Description |
|---|---|---|
| widget | identifier | Label to write the extracted text into |
For a page of <h1>Example Domain</h1><p>This domain is for use in examples.</p> the label ends up holding two lines:
Example Domain
This domain is for use in examples.
htmltitle
Copies the contents of the page's <title> element into a label. The label is left untouched if the page has no title.
htmltitle widget;
| Parameter | Type | Description |
|---|---|---|
| widget | identifier | Label to write the title into |
httpget "https://example.com";
htmltitle title; // title now reads "Example Domain"
cssbg()
Returns the background color the page sets, as a color value usable by setcolor. It recognises both background and background-color, named colors, and three and six digit hex shorthand, so example.com's body{background:#eee} yields #EEEEEE.
cssbg()
| Returns | Type | Description |
|---|---|---|
| color | number | The page's background color, or white when no rule is found |
setcolor page cssbg();
cssfg()
Returns the page's text color, taken from the first color rule in the page's stylesheet. Unlike cssbg() there is no sensible fallback, so a page that sets no color gives 0 and the caller picks its own default.
cssfg()
| Returns | Type | Description |
|---|---|---|
| color | number | The page's first color rule as a color value, or 0 when the page sets none |
if (cssfg() != 0) {
setcolor content cssfg();
}
Putting it together
httpget "https://example.com";
htmltitle title;
htmlstrip content;
setcolor page cssbg();
setcolor content cssfg();
htmlblock
Halfway between a text dump and a layout engine: copies a single top level block of the stored page into a label. Blocks are split at block level elements — div, p, h1–h6, ul, ol, li, pre, blockquote, table, tr, td, header, footer, section, article, nav, form and hr. Inline markup such as <a>, <b> or <span> stays inside its block, and <script>, <style>, <head>, <svg>, <iframe> and <template> are skipped entirely. Entities are unescaped and runs of whitespace collapse, exactly as in htmlstrip.
htmlblock widget index;
| Parameter | Type | Description |
|---|---|---|
| widget | identifier | Label to write the block's text into |
| index | expression | Zero based block number. An index past the end clears the widget |
htmlblocks()
Returns how many blocks the stored page has, so a layout can stop at the last one.
htmlblocks()
| Returns | Type | Description |
|---|---|---|
| count | number | Number of top level blocks, 0 when nothing has been fetched |
let n = htmlblocks(); // 3 for example.com
blocklen()
Returns the number of characters in a block. Since a label wraps its text, this is what tells the layout how many lines a block will need and therefore how tall to make it.
blocklen(index)
| Parameter | Type | Description |
|---|---|---|
| index | number | Zero based block number |
| Returns | Type | Description |
|---|---|---|
| length | number | Characters in the block, 0 when the index is out of range |
let lines = blocklen(0) / 120 + 1;
let height = lines * 17 + 14;
blocktag()
Returns a number for the element that opened the block, which is how a rendered page knows a heading from a paragraph from a list item:
| Value | Element |
|---|---|
| 1 – 6 | h1 – h6 |
| 7 | li |
| 8 | pre |
| 9 | blockquote |
| 10 | table, tr, td, th |
| 0 | Everything else, including plain text |
if (blocktag(3) == 7) {
setcolor row #3C7A3C;
}
resetui
Forgets every widget past the first n and starts the list over. A page that rebuilds its own layout — a browser navigating to a new page — calls this first, otherwise every render would stack another copy of the page on top of the last, until the widget limit is hit.
Keep the widgets that are not part of the rebuilt layout. A window plus an address bar, a Go button and a page label is resetui 4;: the rendered page goes, the chrome stays. Keeping the chrome matters for input — rebuilding a widget resets it to its declared default text, so an address bar recreated on every navigation would always hold the URL it was declared with. With no count at all, everything except the window goes.
resetui n;
| Parameter | Type | Description |
|---|---|---|
| n | expression | How many widgets to keep, counted from the window. Optional, defaults to 1 |
Rendering a page
A renderer unrolls a pool of slots and guards each one with the block count, because widget geometry is fixed when the widget is created. Each slot measures its block, creates the label, asks the engine for the text, then moves the cursor down:
resetui 4; // window, address, go, page - keep the chrome
let y = 148;
let n = htmlblocks();
let h = 0;
if (n > 0) {
h = blkh(0);
label t0 24 y 1034 h "" color=#B9B9BD;
htmlblock t0 0;
setcolor t0 blkcol(0);
y = y + h;
}
if (n > 1) {
h = blkh(1);
label t1 24 y 1034 h "" color=#B9B9BD;
htmlblock t1 1;
setcolor t1 blkcol(1);
y = y + h;
}
Each height comes from a helper that reads the block length and tag:
fn blkh(i) {
let t = blocktag(i);
let l = blocklen(i);
let lines = l / 120 + 1;
if (t > 0) {
if (t < 7) {
return 32;
}
}
let h = lines * 17 + 14;
if (h < 28) {
h = 28;
}
return h;
}
Notes & Limits
Varse is small on purpose. A few things are worth knowing before you lean on it.
No loops
There is no while or for. Repetition is either written out or done with recursion — fib calls itself. That is also why a layout needing one widget per item, such as the browser's page slots, is unrolled by hand rather than generated in a loop.
Strings are not values
A string literal is only ever handed to a statement — a widget's text, settext, prints, httpget, netsave. It cannot be stored in a variable, joined with another, or compared, so anything text shaped has to come through the engine's readers: htmlstrip, htmlblock, htmltitle and the block accessors. That boundary is why the browser is a layout engine for text the engine already knows how to find, rather than a parser written in Varse.
Numbers
Arithmetic is integer arithmetic and division truncates, so l / 120 + 1 is how a block length becomes a line count. Colors are numbers as well, written #RRGGBB, and print() prints numbers.
Widget budget
A program can hold 128 widgets, and creating one past that limit is fatal rather than silently ignored. The browser is nowhere near it: it spends 10 on its chrome and two per rendered block (a bullet and a line of text), so 40 slots come to 90.
What actually stops the browser at 40 blocks is its own guard, not the widget cap. Each slot checks the block count and, once the running y passes the bottom of the page surface, sets a flag that switches off every later slot — so a long page is cut off rather than scrolled, and the page never overflows into the chrome below it. Raising the slot count means adding another guarded block to the source, which is why it is unrolled by hand instead of generated.
Example: Browser Engine
An address bar, a Go button, and a page surface. The initial page loads on startup; Go re-reads the address field, so anything you type is fetched and rendered. The listing below is the minimal version — one label holding the whole stripped page.
fn main() {
window "Varse Browser" 1060 760 bg=#17171B;
input address 20 20 716 42 "https://example.com" radius=8 color=#26262B;
button go 752 20 130 42 "Go" radius=8 color=#2864C7;
panel page 20 78 1020 600 radius=6 color=#FFFFFF;
label title 44 100 972 34 "" color=#111111;
label content 44 144 972 518 "" color=#222222;
label status 20 692 1020 26 "Type a URL and press Go" color=#8A8A93;
httpget "https://example.com";
htmltitle title;
htmlstrip content;
setcolor page cssbg();
setcolor title cssfg();
setcolor content cssfg();
setnum status netstatus();
onclick go {
httpget address;
htmltitle title;
htmlstrip content;
setcolor page cssbg();
setcolor title cssfg();
setcolor content cssfg();
setnum status netstatus();
};
show;
}
Clicking the address field focuses it and clears the default text on the first keystroke.
The shipped examples/bengine.var goes further and lays the page out the way a browser does. The window, address bar and buttons are declared once in main; render() then rebuilds only the page, which is why resetui keeps the chrome and drops the old page. Inside it, htmlblocks() gives the number of blocks, each one is measured with blocklen() and styled from blocktag(), and htmlblock fills the slot. Headings come out black on a light page and white on a dark one, list items get an indent and a bullet, and the page's own stylesheet colours the surface and the text through cssbg() and cssfg(). Clicking Go re-reads the address bar, so a URL you type is the URL that loads.
Example: Fibonacci
fn fib(n) {
if (n <= 1) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}
fn classify(n) {
if (n < 10) { return 1; }
else if (n < 100) { return 2; }
else { return 3; }
}
fn main() {
let z = fib(10);
print(z);
print(classify(4));
print(classify(10));
print(classify(99));
}
Example: GUI App
window "Varse GUI" 600 400 bg=#222222;
label title 20 20 300 40 "Hello from Varse!" color=#FFFFFF;
button btn1 20 130 180 50 "Print Number" radius=10 color=#CC4422;
button btn2 220 130 180 50 "Say Hello" radius=10 color=#226644;
button btn3 20 200 180 50 "Big Radius" radius=25 color=#4444CC;
onclick btn1 { print(42); };
onclick btn2 { print(100); };
onclick btn3 { print(999); };
show;
Example: Counter
A complete interactive app. The handler mutates n, then pushes the new value and a new color into the label.
fn main() {
window "Counter" 520 320 bg=#111111;
label heading 30 25 460 40 "Counter" color=#FFFFFF;
label value 30 80 460 60 "0" color=#1DB954;
button inc 30 170 150 50 "Add One" radius=10 color=#2864C7;
button dec 190 170 150 50 "Minus One" radius=10 color=#444444;
button reset 350 170 150 50 "Reset" radius=10 color=#774422;
let n = 0;
onclick inc {
n = n + 1;
setnum value n;
};
onclick dec {
n = n - 1;
setnum value n;
setcolor value #CC4444;
};
onclick reset {
n = 0;
setnum value n;
setcolor value #1DB954;
};
show;
}
Example: HTTP Fetch
fn main() {
httpget "https://example.com";
prints "status ";
print(netstatus());
prints " / ";
print(netlength());
prints " bytes\n";
netsave "page.html";
}