SMILE 2.0Learn & build
Language guide

MAKE IT FEEL LIKE A GAME

Graphics, input & sound

Turn variables into a playable scene. Start with a moving circle, then add pictures, sound, and a score that survives the next launch.

Your canvas is a coordinate grid

Game Window "My Game" Size 640 By 360 creates a graphical program with a logical canvas. X increases rightward and Y increases downward. Window scaling does not change those logical positions.

The SMILE logical canvasOrigin at top left, x increases to the right, y increases down. A rectangle at x 120 y 80 has width 200 and height 120. A circle is positioned by its center.(0, 0)X grows right →Y grows down ↓(120, 80)Width: 200Height: 120Circle: center + radiusCoordinates stay logical even when the window is scaled.
The top-left corner is your starting point. Shapes use coordinates on a logical canvas.

Run the motion lab

This complete program needs no images, audio, or library imports. The arrow keys move a circle. Clicking inside the canvas increments a counter.

Option Explicit

Dim PlayerX As Number
Dim PlayerY As Number
Dim Clicks As Number
Dim Key As Number

PlayerX = 320
PlayerY = 180

Game Window "SMILE Motion Lab" Size 640 By 360

Do
    Get Key Key

    If Key_Held(KEY_LEFT) Then
        PlayerX = Max(20, PlayerX - 4)
    End If
    If Key_Held(KEY_RIGHT) Then
        PlayerX = Min(620, PlayerX + 4)
    End If
    If Key_Held(KEY_UP) Then
        PlayerY = Max(20, PlayerY - 4)
    End If
    If Key_Held(KEY_DOWN) Then
        PlayerY = Min(340, PlayerY + 4)
    End If
    If Pointer_Inside() And Pointer_Pressed(POINTER_PRIMARY) Then
        Clicks = Clicks + 1
    End If

    Clear Rgb(10, 18, 36)
    Fill Rectangle 20, 70, 600, 250, Rgb(17, 39, 60)
    Fill Circle PlayerX, PlayerY, 16, CYAN
    Draw Circle PlayerX, PlayerY, 20, WHITE
    Draw Text "Arrow Keys Move - Click Counts - Escape Exits" At 320, 20 Size 18 Color WHITE Centered
    Draw Text "Clicks:" At 24, 45 Size 16 Color YELLOW
    Draw Number Clicks At 95, 45 Size 16 Color YELLOW
    Show Screen
    Wait 16 Milliseconds

Loop Until Game_Closed() Or Key = KEY_ESCAPE

End Program

Download the complete motion lab. The Min/Max calls keep the circle inside the canvas. This first lesson uses a simple four-pixels-per-loop speed; a steady-speed game should scale movement by elapsed time or use a fixed-step update.

Build one complete frame

Draw in order, then presentClear background, draw world, draw player, draw interface, then Show Screen. Later drawing covers earlier drawing.1 · Clearbackground2 · Drawworld3 · Drawplayer4 · Drawscore / UI5 · ShowScreenEach later layer can cover pixels drawn earlier.
SMILE draws immediately in source order. Present the completed frame once.

Each pass through the loop reads input, updates state, redraws the scene, and presents it. Show Screen also ends the pointer-input frame. Read pressed/released buttons and movement deltas before that call. Wait 16 Milliseconds adds a short pause; rendering work also takes time, so it does not guarantee exactly 60 frames per second.

Draw with shapes and text

The following commands go after Game Window. Positions, sizes, radii, and colors are Number expressions. Draw outlines a shape; Fill paints its interior.

Clear Rgb(10, 18, 36)
Fill Rectangle 40, 60, 180, 90, DARK_BLUE
Draw Rectangle 40, 60, 180, 90, LIGHT_BLUE
Fill Rounded Rectangle 260, 60, 180, 90, 18, DARK_GREEN
Draw Rounded Rectangle 260, 60, 180, 90, 18, LIGHT_GREEN
Fill Circle 500, 105, 35, CYAN
Draw Circle 500, 105, 42, WHITE
Draw Line 40, 190, 580, 190, ORANGE
Draw Arc 500, 265, 40, 0, 270, YELLOW
Fill Quadrilateral 40, 230, 180, 245, 150, 315, 60, 300, MAGENTA
Draw Text "Level 1" At 320, 20 Size 24 Color WHITE Centered
Draw Number 100 At 40, 330 Size 18 Color YELLOW
Show Screen
ShapeArguments
RectangleX, Y, Width, Height, Color
Rounded RectangleX, Y, Width, Height, Radius, Color
CircleCenterX, CenterY, Radius, Color
LineX1, Y1, X2, Y2, Color
ArcCenterX, CenterY, Radius, StartAngle, SweepAngle, Color
QuadrilateralX1, Y1, X2, Y2, X3, Y3, X4, Y4, Color

Arc angles use integer degrees: 0 points right and 90 points down. Positive sweep is clockwise; negative sweep is counterclockwise. Draw Arc draws only the curve. There is no Fill Arc statement.

For a HUD label, Text_Width("Level 1", 24) and Text_Height("Level 1", 24) measure the drawn text. Measurement needs a Game Window and can vary slightly between drawing backends.

Pressed once or held down?

You want…UseExample
One action from a queued key pressGet Key PressedKeyStart, pause, or choose a menu item; no queued key gives KEY_NONE.
Continuous movementKey_Held(KEY_RIGHT)Keep moving while Right is held.
Modifiers at the moment of a queued key eventKey_Event_Held(KEY_CONTROL)Read immediately after Get Key to preserve a quick Control+Arrow press.
One click in the current framePointer_Pressed(POINTER_PRIMARY)Place a marker or select a button.
Dragging or wheel inputPointer_Held(...), Pointer_Delta_X(), Pointer_Wheel_Delta()Move a map view or adjust zoom.

Pointer X/Y coordinates use the same canvas as drawing. Check Pointer_Inside() before treating a location as a canvas click. Show Screen clears frame deltas and pressed/released transitions, while held state remains.

Load a picture once, draw it many times

Declare an Image, load it before the game loop, and check Image_Loaded. Draw it inside the loop. Unload it when its owner no longer needs it.

Dim HeroImage As Image
Load Image HeroImage From "Assets/Hero.png"

If Image_Loaded(HeroImage) Then
    Draw Image HeroImage At 200, 120 Size 96 By 96 Filter Pixel
End If

Show Screen
Unload Image HeroImage

This is a lifecycle fragment: add a Game Window, provide the PNG, and place the drawing in your loop. PNG transparency is preserved. Filter Pixel gives crisp pixel art; Filter Smooth suits paintings and high-resolution illustrations. Assignment shares the decoded image resource safely; clearing one Image variable does not unload another variable's retained image.

A sprite sheet cropSelect a 32 by 32 source area at x 32 y 0 from the second sprite, then draw it at x 200 y 120 with a size of 96 by 96.Source image: Sheet0123From 32, 0Size 32 By 321Destination on canvasAt 200, 120Size 96 By 96Source pixels and destination pixels are independent.
A sprite sheet stores frames side by side. Choose a source rectangle, then a destination rectangle.
Draw Image Sheet From 32, 0 Size 32 By 32 At 200, 120 Size 96 By 96 Filter Pixel
Draw Image Sheet From 32, 0 Size 32 By 32 At 300, 210 Size 96 By 96 Anchor 48, 96 Opacity 80 Filter Pixel Flip Horizontal

Anchor 48, 96 puts the destination image's bottom center at the requested X/Y point. Opacity runs from 0 to 100. Flipping preserves the anchor. Image rotation is not part of this 2D Draw Image syntax.

Keep drawing inside a panel

Clip Rectangle 40, 80, 240, 160
    Draw Image HeroImage At 0, 0 Size 480 By 480
End Clip

Nested clips intersect. Leaving a clip scope restores the previous clipping region, including when a Return or loop exit leaves the block.

Tell the project which assets it owns

Keep asset paths relative to your project, with consistent letter case. Add files to the application's project asset list so native and Web builds can publish them beside the program.

<ItemGroup>
    <Asset Include="Assets/Hero.png" />
    <Asset Include="Assets/Collect.wav" />
    <Asset Include="Assets/Level.mp3" />
</ItemGroup>

Use those same logical paths in SMILE code. Absolute paths, URLs, paths that escape the project, and undeclared project assets are rejected. Libraries supply code; applications supply assets. Loose-file compilation has no project asset manifest, so you must place the assets beside the generated executable yourself.

Sound effects and music have different jobs

Play Sound "Assets/Collect.wav" On Channel 1
Play Sound "Assets/Impact.wav" On Channel 2
Stop Sound On Channel 1

Play Music "Assets/Level.mp3" Loop
Music Volume 50
Pause Music
Resume Music
Stop Music
Stop Sound

These are separate command examples, not a sequence to run all at once. Start music when active play starts, keep it looping during that play session, and stop it when returning to the title or exiting. Play effects when events happen, such as collecting a coin.

There are 16 effect channels, numbered 0–15. Bare Play Sound uses channel 0; another sound on the same channel replaces the old sound. Different channels overlap. Bare Stop Sound stops all effects. Music Volume uses 0–100.

Native focus handling automatically silences game audio while inactive and stops effects. A manually paused music track remains paused. Browser audio may require a player interaction before playback; Web focus behavior pauses requested music while the page is hidden and restores it when appropriate.

Save a score, then graduate to structured data

For one whole-number value, a named save key is enough. The key belongs to the application's persistent storage; it is not an asset filename.

Option Explicit
Dim Best As Number
Dim Score As Number
Score = 250

Load Best From "HighScore" Default 0
If Score > Best Then
    Best = Score
    Save Best To "HighScore"
End If
Print "Best: "; Best

For a custom save layout, store bytes in a fixed Number array. Always inspect Status before announcing that data was saved.

Option Explicit
Dim Bytes[8] As Number
Dim ByteCount As Number
Dim SaveStatus As Number

Bytes[0] = 3
Bytes[1] = 25
Save Data Bytes Count 2 To "PlayerProfile" Status SaveStatus

If SaveStatus = DATA_STATUS_OK Then
    Print "Saved"
End If

Load Data "PlayerProfile" Into Bytes Count ByteCount Status SaveStatus
If SaveStatus = DATA_STATUS_OK Or SaveStatus = DATA_STATUS_RECOVERED Then
    Print "Loaded bytes: "; ByteCount
End If

Each byte must be 0–255; the count must fit the array and the 1 MiB data-block limit. The status distinguishes a missing save, invalid data, corruption, unavailable storage, recovery, and excess size. Native storage is application-owned; Web storage is isolated by application identity and can be removed by browser storage controls. Use Smile.RPG.SaveGames for that library's structured RPG progress.

Read packaged text; export player-chosen text

Dim FileBytes[8192] As Number
Dim FileByteCount As Number
Load Text File "Maps/level.map" Into FileBytes Count FileByteCount

Load Text File gives you UTF-8 bytes, not a Text value or a parsed map. It skips an optional UTF-8 BOM, zero-fills the array, and returns zero count for a missing/unreadable file. Use Smile.Game.TileMap when you want the built-in package's map format.

Dim Exported As Boolean
Dim Imported As Text
Exported = File_Export("my-notes.txt", "My game idea")
Imported = File_Import()

Call file-transfer functions in response to an explicit player action such as a menu choice. Import cancellation and an empty file both return empty Text. These functions transfer user-chosen UTF-8 files; they do not modify your Save Data automatically.

Keep platform differences in view

FeaturePractical boundary
2D graphicsShared logical coordinates and syntax; actual text measurements can differ between native and browser drawing engines.
3D renderingNative DirectX and WebGL2 provide true 3D. GDI is a wireframe/2D fallback. The newest arena/VFX lessons document native behavior; their browser adoption is not claimed here.
InputBrowser keyboard input belongs to the focused canvas. Native KEY_PLUS, KEY_MINUS, and KEY_C additions are not claimed as adopted in Web.
Window helpersWindow_Activate() and Window_CloseRequested() return False on Web; the browser owns focus and tab-close confirmation.
PersistenceNative application data and browser local storage are separate stores. Saving on one target does not synchronize the other.

Make it yours

  1. Change the motion lab's colors and circle radius.
  2. Add a target square and increment a score when the circle reaches it.
  3. Play a WAV effect only when the score changes.
  4. Save the best score when the round ends.

Next: reuse movement, UI, and game-system libraries, or build a 3D arena with elemental effects.

Sources & version notes

Checked against the local SMILE 2.0 source on September 25, 2026. Examples target the native Windows toolchain unless stated otherwise. The linked repository may continue to evolve.