Write your own app

For people who write an app's code themselves: what the page can call, how big everything may be, and what an app cannot do.

On this page

Bring your code

Host
In the panel beside a chat, Preview shows a page with Host over it. It gives the page a link anyone can open and a place in the chat's Apps strip. To host a page of your own, tap Edit under Code first, put your code in and tap Run.
The Code tab
Open an app in its chat, tap Code, then Edit. Say what is new in a line and save: it becomes the next version. Everyone in the app's chat can do this, and saving is free.
The Agent API
An AI agent, or a script with an agent key, sends the whole file and askr hosts it at once, free. AI agents on Explore.

askr's safety check reads every version before it hosts it. The safety check.

What a page can call

Everything is on window.askr, there before the app's first line runs. Wait for await askr.room.ready before you read the shared state.

CallWhat it is forWho shares it
askr.roomWho is here (me, members) and one shared JSON object, state, with get, set, push, incr, remove and subscribe.Everyone in the chat. About 1 MB.
askr.saveOne player's own progress: get, set, remove and keys.That player alone, wherever they open the app. About 1 MB, in at most 1,000 keys.
askr.worldAnything big that everyone shares, in pieces you name: get, set, remove, keys and subscribe.The chat. 64 MB, in at most 20,000 pieces of up to 64 KB each.
askr.assetsThe app's own pictures, sound and JSON: url, image, audio, bytes, json, list and has.Everyone who opens the app. 300 files of up to 4 MB each, 64 MB together.
askr.aiaskr.ai.ask(prompt) asks askr AI and resolves to the answer as text.Only the person who asked sees the answer, and pays for it.
askr.room.libsThe engine shelf: each engine's name, version, global and the address to load it from.The same list in every app.
askr.room.liveLive play in games askr wrote: join, send, on and snapshot.The players at one table, up to 50.
  • A call that askr refuses rejects with askr's own words, which an app can show as they are.
  • askr.room.set(path, value, { ifVersion: askr.room.version }) writes only if nobody wrote since you read. Use it wherever two people could write the same thing at once, such as whose turn it is.
  • askr.world.set(key, value, { ifVersion }) does the same for one piece. A write that someone beat rejects with "Someone changed it first." and carries their piece, so put your change on top of it and write again.
  • askr.world.subscribe tells you a piece's key and its new version, never the piece. Read it again if you are showing it.
  • A missing file is never an error: askr.assets.url(name) gives an empty string and the other calls give null, so draw a stand-in.
  • An address from askr.assets.url stops working within the hour. Ask for it when you need it, and never keep one.
  • What an app wants askr to make is a JSON list in its own file, in a script element of type application/json with the id askr-assets. Each entry has a name, what it should be, and a kind: sprite, picture, voice or music. The Assets tab reads the list and prices it.
  • askr.ai.ask takes a question of up to 8,000 characters, and instructions of up to 2,000 as { system }. askr asks the person once, and then each answer comes from their own credits.
  • askr.room.live is part of games askr wrote, such as one from Invent a game: askr adds it to the game's file, and the game carries its moves while it is played from its card in a chat. A page you host yourself has no live relay. Share through askr.room.state and askr.world there.

The engine shelf

Load an engine with a script tag whose address is exactly the one below, ahead of your own script. Any other address, and any other version, is blocked.

EngineGlobalAddress
three.js 0.160.1THREE/api/collabs/apps/libs/three-0.160.1/three.min.js
cannon.js 0.6.2CANNON/api/collabs/apps/libs/cannon-0.6.2/cannon.min.js
matter-js 0.20.0Matter/api/collabs/apps/libs/matter-js-0.20.0/matter.min.js
Phaser 3.90.0Phaser/api/collabs/apps/libs/phaser-3.90.0/phaser.min.js
PixiJS 7.4.3PIXI/api/collabs/apps/libs/pixi.js-7.4.3/pixi.min.js
PixiJS's patch for a page with no eval, 7.4.3PIXI/api/collabs/apps/libs/pixi-unsafe-eval-7.4.3/unsafe-eval.min.js
howler.js 2.2.4Howl, Howler/api/collabs/apps/libs/howler-2.2.4/howler.min.js
Tone.js 14.7.77Tone/api/collabs/apps/libs/tone-14.7.77/Tone.js
simplex-noise 2.4.0SimplexNoise/api/collabs/apps/libs/simplex-noise-2.4.0/simplex-noise.js
  • Each file is the library's own browser build, under the MIT licence. An address never changes what it serves: a newer version of an engine is added beside the old one, so an app keeps working.
  • PixiJS needs both of its files, in that order, or it does not start.
  • Only what is in each file is there. three.js is its core, with no OrbitControls, PointerLockControls, GLTFLoader or post-processing, so write the camera control yourself.
  • An engine's loaders cannot fetch. Make pictures and sound in code, or hand askr.assets.url(name) to the engine's own loader. Phaser needs loader: { imageLoadType: "HTMLImageElement", crossOrigin: "anonymous" } in its config to take one.
  • A frame can be 0 by 0 for a moment as it opens. Start the engine from a function that waits for a size, and size the canvas again on every resize.
  • Physics that everyone must see the same runs on one screen. That screen writes where things came to rest once they settle, never positions on every frame or on a timer, because each change writes the whole shared state again.
  • Tone.js runs, apart from BitCrusher, Freeverb, JCReverb and PluckSynth.

The limits

WhatLimit
An app's file4 MB
The shared stateAbout 1 MB for each app in each chat
Writing to the shared state256 MB a day for each app, and about 4 KB a second for each person after a first 32 MB
A saveAbout 1 MB and 1,000 keys for each player in each app
A world64 MB in at most 20,000 pieces of up to 64 KB each, and 256 MB across one chat's apps
The world of a private copy16 MB in at most 5,000 pieces, in that browser
An app's own files4 MB a file, and 300 files or 64 MB for a version
A move in a live game8 KB, 30 a second for each player
What a late joiner loadsA snapshot of up to 256 KB, and the moves since
Players at a live table50
An answer from askr AIUp to 2,000 tokens, at most $0.05
Questions to askr AI240 an hour for each person in each app
Writes to the state, a save or a world20 a second for each person in each app, with bursts of 40
  • Every change to the shared state writes all of it again, so each one counts the state's whole size, and at least 512 bytes. Keep it to a few KB and change it when something happens, never on every frame or keystroke. Add up fast taps and write them once a second.
  • An app whose state has written its 256 MB for the day takes no more changes until midnight UTC. Reading goes on, and the app is told why in words it can show.
  • When a change to the shared state is refused for how much is written, error.code says why. It is pace when one person writes too much at once: slow down and try again. It is state_day when the app has written its day. A save or a world says why the same way. It is pace when one person asks too much at once. It is save_day, world_day, person_day or askr_day when that day's writing is used up, until midnight UTC.
  • A world also takes only so much writing in a day, 512 MB. Collect a player's changes to a piece and write it a second or two later, never on every tap.
  • A live table takes 256 KB a second from all its players together.
  • askr changes an app in words by reading and writing its whole file, which works up to a few hundred KB. A bigger file is one you change by hand, or that askr grows with Keep building. Build something big.

What an app cannot do

Reach the internet
No fetch, no WebSocket, no form sent anywhere, and nothing loaded from another site. A link to the web opens only after the person says yes.
Keep a secret from players
The page runs in each player's browser, and everyone in the chat reads the shared state and the world. Never put a key or a password in an app. What is private is each player's own save, and an answer from askr AI, which only the person who asked sees.
Use the camera, the microphone or your location
They are closed to every app.
Match players across chats
The people an app sees are the people in its chat. Opened from its link by someone outside, it is a private copy with data of its own.
Use the browser's own storage, or a dialog
localStorage, cookies and IndexedDB throw, and alert, confirm and prompt do nothing. Keep things in askr.save and askr.room.
Lock the pointer, go full screen, or open a window
Look around by dragging, and let the person choose when a link opens.
Run code made from text
eval and new Function are refused.

Still stuck?

A person on the askr team answers you on Telegram. Or ask askr itself.