Attach a script to what happens when the player interacts with a hotspot or combines an item — the same place you'd give an item or set a flag.
Scripting reference
The .j17 language
A safe scripting language embedded in the June 17 game maker. It adds what point-and-click rules can’t say on their own — scoped variables, arithmetic, branching, loops, real-time elapsed tracking, and sprite graphics with time-based animation — while staying impossible to misuse: a fixed vocabulary, no access to the page, and a hard step budget so every script is guaranteed to finish.
01What it is
Most of a June 17 game is built from declarative rules you set in the editor — “this hotspot gives that item”, “this exit needs that flag”. .j17 is the small escape hatch for the handful of moments those rules can’t reach: keeping a count, doing arithmetic, choosing between outcomes, or repeating an action a set number of times.
It is deliberately not general-purpose JavaScript. There is a fixed set of words, no way to touch the page, the file system, or the network, and a hard limit on how long a script may run. That makes any .j17 script safe to share inside a published game.
02Where scripts run
A script is a script effect — one of the actions you can attach to an interaction. It fires when the player triggers that interaction: examining or using a hotspot, or reaching a line or choice in a conversation. The script runs once, top to bottom, then control returns to the game.
A conversation line or a player choice can carry a script, so a single answer can update several things at once.
Three verbs hand off and stop
goto, win, and minigame transfer control to the engine. Any statements after them in the same run are not executed — put them before the hand-off, or inside the branch that shouldn’t hand off.
03Syntax basics
One statement per line — or separate several with a semicolon. Text is written in double quotes. Anything after # on a line is a comment. Keywords are lowercase.
# a comment runs to the end of the line
set tries = tries + 1 # one statement per line
give coin; sfx coin # …or several, split by ;
say "Text always uses double quotes."Names vs. text
Item, room, flag, sound and mini-game names may be written bare (coin) or quoted ("blue key" — quote it when the name has a space). The words after say are spoken text and must always be quoted.
04Statements
The complete vocabulary — the verbs that change the game’s state, speak, play a sound, or move the story on.
Store a number or string in a variable. Unset variables read as 0. Saved to the player’s game the moment it changes.
set gold = gold + 5Add an item to the player's inventory.
give braceletRemove an item from the inventory.
take kiteSet a story flag on. Flags are the same ones the rest of the game reads — use them to unlock exits or reveal hotspots gated with showWhen.
flag met_miaTurn a story flag back off.
unflag door_openThe character the player is interacting with speaks a line. Any text expression — join in live values with + and str().
say "You have " + str(gold) + " gold."Move, fade, scale, spin, show or hide a sprite in the current scene — instantly or animated over time. Its own section covers it in full.
sprite "ghost" fade 1 over 5Play a built-in sound effect by name (for example coin).
sfx coinReport a number to this game’s June 17 leaderboard — the player’s best is kept. Enable the leaderboard first on the game’s manage page. See Scores & achievements.
score goldUnlock a creator-defined achievement by its key (define the key on the manage page). Unlocking is idempotent — safe to call again.
achievement "first_win"Travel the player to a room, then end the script and hand control to the engine.
goto cellarLaunch a mini-game, then end the script.
minigame reelsTrigger the game's ending / win screen, then end the script.
win05Control flow
Two structures: a conditional and a counted loop. Both close with end.
Run the first block when the expression is true (any non-zero number). The else block is optional.
if has(ticket) and gold >= 10 then
take ticket
goto fairground
else
say "Not yet — you need a ticket and ten gold."
endRepeat the block a set number of times (the count is rounded down to a whole number and capped at 10,000). It runs to completion instantly, so it's for repeating state changes — not for animating over time.
repeat 3
give coin
end06Expressions
Expressions produce a number or a string. They power set and the condition in if and repeat. There are three built-in queries and the usual arithmetic, comparison, and logic operators.
1 if the item is in the inventory, else 0.
if has(map) then say "You know the way." end1 if the story flag is set, else 0. (As a query it takes a name in parentheses; as a statement, flag sets one.)
if flag(rescued_dog) then win endThe id of the currently active party character (a string). Compare it to branch on who's in control.
if char == "lac" then say "I remember this." endNumbers (5, 2.5), quoted "strings", and true / false (which are just 1 and 0). A bare word is a variable; unset ones are 0.
set ready = true
set who = "stranger"floor · round · abs · sqrt · sin · cos (radians) · min(a,b) · max(a,b) · random() (0–1). Enough to shape a curve or a wave.
set y = 200 + sin(t) * 40str(x) turns a number into text; + joins text (so say can show live values). now() and timeset(v) read the clock — see Time.
say "Score: " + str(score)Logic: or, then and, then not. Comparison: == != < > <= >=. Arithmetic: + -, then * / %. When either side of + is text it joins instead of adding. Use ( ) to group and -x to negate. Dividing by zero yields 0.
set score = (base + bonus) * 2 - penalty
if not flag(warned) and tries > 2 then … end07Variables & scope
A variable’s name says where it lives and how long it lasts. Three scopes cover everything from a one-scene counter to a value that follows the player across saves.
Global & permanent. Readable and writable from any scene, saved with the player’s game, and reset only when they start a New Game from the menu. Every change also records when it happened (see Time). A bare name is the same as game. — this is the default.
set game.day = game.day + 1Global but temporary. Shared across scenes for the length of a session, but never written to the save — it starts empty each time the player opens the game. Good for “what happened a moment ago”.
set temp.last_room = "forest"Scene-local. Belongs to the current room and is cleared the moment the player leaves it. Perfect for a per-puzzle counter you don’t want leaking elsewhere.
set local.tries = local.tries + 1Everything is shared with the game world
Flags and inventory a script touches are the same ones your hotspots and exits read — set a flag here, gate a door with it elsewhere.
08Time & elapsed
Every global (saved) variable remembers the moment it was last changed. Combined with the current time, that lets you tell the player how long it’s been — “123 days since you arrived on the island”.
The current time, in seconds. Anchored to an authoritative server time when the game starts and advanced by a monotonic clock — so a player can’t fast-forward it by changing their device clock.
The time a global variable was last set (0 if it never was). Subtract it from now() to get elapsed seconds.
Set a marker global once (that stamps the time), then compute the difference whenever you need it — 86,400 seconds to a day.
# the moment they arrive, once:
set game.arrived = 1
# anywhere later:
set days = floor((now() - timeset(game.arrived)) / 86400)
say "It's been " + str(days) + " days since you arrived."09Sprites & animation
A script can take any named sprite in the current scene and change how it looks — position, transparency, size, rotation — either instantly or animated over a span of seconds. The shape is always the same:
sprite "name" action args [over seconds] [after seconds]Leave off over and the change is instant. Add over 3 and it eases smoothly to the target across three seconds; add after 1 to hold for a second first. Several animations on the same sprite run together, so moving and fading at once reads as one motion.
Place the sprite (its position in scene coordinates). Animate it to glide.
sprite "crow" move 480 120 over 2Opacity from 0 (invisible) to 1 (solid).
sprite "ghost" fade 0.4 over 3Size, where 1 is the sprite’s normal size.
sprite "balloon" scale 1.5 over 4Rotation in degrees, around the sprite's centre.
sprite "key" spin 360 over 1Reveal or remove a sprite. With over, they fade in or out instead of popping.
sprite "door" hide over 0.5over N sets the duration; after N delays the start — chain a few with different after values to sequence a little scene.
“Can I pick a sprite and make it move on a sine-wave path while its transparency changes — like a ghost drifting out of the forest and slowly becoming visible?”
✓ Yes — that’s exactly what this is for.
# the ghost starts hidden, deep in the trees
sprite "ghost" fade 0
sprite "ghost" move 120 300
# over 5s it drifts forward and materialises — both at once
sprite "ghost" move 300 240 over 5
sprite "ghost" fade 1 over 5For a true wave you can drive a position from sin() — set up a marker and nudge it, or compute a y from a rising counter. A single tween eases in a graceful arc on its own; sin() gives you a full ripple when you want one.
10Safety & limits
The language is sandboxed on purpose, so a script inside a shared game can never do harm or hang.
Every run has a step budget. Loops that would run away simply stop — a script can't freeze the game.
A repeat count above 10,000 is capped, and negative counts run zero times.
No page, file system, network, or arbitrary code — only the fixed set of verbs on this page.
The editor validates the script and reports the first syntax error, so a broken script never ships.
11Examples
Whole scripts, the way you’d attach them to a hotspot or a line of dialogue.
# attached to "use the rusty lock"
set tries = tries + 1
if tries >= 3 then
sfx coin
say "The lock finally gives."
goto cellar
else
say "Stuck. Maybe once or twice more."
endif has(kite) then
take kite
give bracelet
sfx coin
say "A fair trade."
else
say "Bring me the kite first."
end# repeat is for repeating an action, not animating
repeat 5
give coin
end
say "Five coins for the road."if char == "lac" then
flag lac_remembered
say "You've stood here before."
else
say "It means nothing to you — yet."
end12Boundaries
.j17 reaches a lot further than it used to, but it’s still a scripting layer over the game — not a drawing engine. The honest edges:
You animate sprites you've placed in the scene in the editor — a script can't conjure a brand-new image out of nothing. A hidden, pre-placed sprite is the usual starting point.
sprite acts on the room the player is in. It can’t reach into another room’s sprites.
A sprite's position, fade and spin are live visual state — they reset when the player leaves the room or reloads. Persist the story with variables and flags; re-run the animation on the way back in.
No arbitrary shapes, pixels, or filters, and sound is limited to the game’s built-in effects via sfx. And, as always: no page, files, or network.
← Developer · The embedded logic language of the June 17 game maker. Reference generated from the engine’s own source.