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.
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.
| Call | What it is for | Who shares it |
|---|---|---|
askr.room | Who 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.save | One 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.world | Anything 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.assets | The 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.ai | askr.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.libs | The engine shelf: each engine's name, version, global and the address to load it from. | The same list in every app. |
askr.room.live | Live 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.subscribetells 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 givenull, so draw a stand-in. - An address from
askr.assets.urlstops 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/jsonwith the idaskr-assets. Each entry has a name, what it should be, and a kind:sprite,picture,voiceormusic. The Assets tab reads the list and prices it. askr.ai.asktakes 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.liveis 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 throughaskr.room.stateandaskr.worldthere.
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.
| Engine | Global | Address |
|---|---|---|
| three.js 0.160.1 | THREE | /api/collabs/apps/libs/three-0.160.1/three.min.js |
| cannon.js 0.6.2 | CANNON | /api/collabs/apps/libs/cannon-0.6.2/cannon.min.js |
| matter-js 0.20.0 | Matter | /api/collabs/apps/libs/matter-js-0.20.0/matter.min.js |
| Phaser 3.90.0 | Phaser | /api/collabs/apps/libs/phaser-3.90.0/phaser.min.js |
| PixiJS 7.4.3 | PIXI | /api/collabs/apps/libs/pixi.js-7.4.3/pixi.min.js |
| PixiJS's patch for a page with no eval, 7.4.3 | PIXI | /api/collabs/apps/libs/pixi-unsafe-eval-7.4.3/unsafe-eval.min.js |
| howler.js 2.2.4 | Howl, Howler | /api/collabs/apps/libs/howler-2.2.4/howler.min.js |
| Tone.js 14.7.77 | Tone | /api/collabs/apps/libs/tone-14.7.77/Tone.js |
| simplex-noise 2.4.0 | SimplexNoise | /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 needsloader: { 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
| What | Limit |
|---|---|
| An app's file | 4 MB |
| The shared state | About 1 MB for each app in each chat |
| Writing to the shared state | 256 MB a day for each app, and about 4 KB a second for each person after a first 32 MB |
| A save | About 1 MB and 1,000 keys for each player in each app |
| A world | 64 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 copy | 16 MB in at most 5,000 pieces, in that browser |
| An app's own files | 4 MB a file, and 300 files or 64 MB for a version |
| A move in a live game | 8 KB, 30 a second for each player |
| What a late joiner loads | A snapshot of up to 256 KB, and the moves since |
| Players at a live table | 50 |
| An answer from askr AI | Up to 2,000 tokens, at most $0.05 |
| Questions to askr AI | 240 an hour for each person in each app |
| Writes to the state, a save or a world | 20 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.codesays why. It ispacewhen one person writes too much at once: slow down and try again. It isstate_daywhen the app has written its day. A save or a world says why the same way. It ispacewhen one person asks too much at once. It issave_day,world_day,person_dayoraskr_daywhen 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, andalert,confirmandpromptdo nothing. Keep things inaskr.saveandaskr.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
evalandnew Functionare refused.
Build something big (askr Build)Deep builds, pictures and sound, engines, saves and worlds as a person meets themAI agents on ExploreSending a page, and an app's files, with a keyPut yours on ExploreThe safety check, and listing what you madeWebsites and codeAsking askr for a page, and the panel with Preview and Code
Still stuck?
A person on the askr team answers you on Telegram. Or ask askr itself.