├── Makefile ├── Readme.md ├── track.html ├── track.lua ├── track_test.html └── track_test.js /Makefile: -------------------------------------------------------------------------------- 1 | # Given 'track.lua', prepend a header to create 'track_test.p8'. 2 | track_test.p8: track.lua 3 | @echo 'pico-8 cartridge // http://www.pico-8.com' > track_test.p8 4 | @echo 'version 16' >> track_test.p8 5 | @echo '__lua__' >> track_test.p8 6 | @cat track.lua >> track_test.p8 7 | 8 | # Remove generated files. 9 | clean: 10 | @rm track_test.p8 11 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # analytics-pico8 2 | 3 | 4 | 5 | Analytics for your PICO-8 game, powered by Segment. 6 | 7 | See a video demo of a fully-instrumented Jelpi demo: View Link 8 | 9 | > *Note:* I created this project for Segment Hack Week. Consider it alpha quality, since it doesn't support the functionality of [Segment's official sources](https://segment.com/docs/sources/). 10 | 11 |
12 | 13 | ## Wait, what? 14 | 15 | PICO-8 is a tool that you can use to create (and distribute) small, retro-style games. It's like Unity – the game engine – but with more design constraints to encourage you to keep your project scope small. Admittedly, it's kinda nerdy. 16 | 17 | Segment is an awesome analytics product that intends to be your **customer data infrastructure**. You can use Segment to track user events, send events out to hundreds of analytics tools automatically, and use these tools to derive insights from your data. Armed with these insights, you can find ways to improve your game's design. 18 | 19 |
20 | 21 | ## Awesome, how do I use it? 22 | 23 | ### Learn 24 | 25 | If you're new to PICO-8, I suggest skimming the [manual](https://www.lexaloffle.com/pico-8.php?page=manual) for an overview. 26 | 27 |
28 | 29 | ### Copy and paste 30 | 31 | Copy and paste [`track.lua`](./track.lua) into your PICO-8 game. 32 | 33 |
34 | 35 | ### API 36 | 37 | `track.lua` will expose a single function `track()` globally. To use: 38 | 39 | ```lua 40 | -- API: 41 | track(event, properties?) 42 | 43 | -- Example: 44 | track('Level Cleared', { 45 | level = 4, 46 | time = 39.2, 47 | found_secret_room = true, 48 | }) 49 | ``` 50 | 51 | You can track as many events and properties as you want, subject to PICO-8's char and token limits. `track.lua` serializes `track()` calls to PICO-8's [GPIO pins](http://pico-8.wikia.com/wiki/GPIO), so be aware that you have 128 bytes of info per `track()` call. 52 | 53 |
54 | 55 | ### Export, insert `track.html` and `analytics.js` 56 | 57 | In the PICO-8 console, export your game to HTML5: 58 | 59 | ```sh 60 | > EXPORT YOUR_GAME.HTML 61 | ``` 62 | 63 | Find your ` 67 | ``` 68 | 69 | Above it, insert the contents of [`track.html`](./track.html), then the `analytics.js` snippet ([view here](https://segment.com/docs/sources/website/analytics.js/quickstart/)). Verify that your Segment write key is present – check the setup instructions for details. 70 | 71 | You can reference [`track_test.html`](./track_test.html) as an example. 72 | 73 |
74 | 75 | ### Celebrate 76 | 77 | If all goes well, you should see events flowing through to Segment's Debugger: 78 | 79 | screen shot 2018-08-08 at 1 50 50 pm 80 | 81 | You now have the ability to understand how players interact with your game's design! Go forth and inform your designs with data. 82 | 83 |
84 | 85 | ## Feedback 86 | 87 | Please open an [issue](https://github.com/segmentio/analytics-pico8/issues/new). 88 | 89 |
90 | 91 | ## License 92 | 93 | `analytics-pico8` is released under the MIT License. 94 | 95 | Copyright © 2018 Segment.io, Inc. 96 | -------------------------------------------------------------------------------- /track.html: -------------------------------------------------------------------------------- 1 | 65 | -------------------------------------------------------------------------------- /track.lua: -------------------------------------------------------------------------------- 1 | do 2 | local chars = ' !"#%\'()*+,-./0123456789:;<=>?abcdefghijklmnopqrstuvwxyz[]^_{~}' 3 | 4 | -- generate char-to-num map. 5 | local charset = {} 6 | for i=1,#chars do 7 | charset[sub(chars,i,i)] = i 8 | end 9 | 10 | local start = 0x5f80 11 | local offset = 0 12 | 13 | local function check() 14 | if start+offset > 0x5fff then assert(false, 'event is too large.') end 15 | end 16 | 17 | local function write_char(ch) 18 | check() 19 | poke(start+offset, charset[ch]) 20 | offset += 1 21 | end 22 | 23 | local function write_bool(b) 24 | check() 25 | poke(start+offset, b and 1 or 0) 26 | offset += 1 27 | end 28 | 29 | local function write_uint8(n) 30 | check() 31 | poke(start+offset, n) 32 | offset += 1 33 | end 34 | 35 | local function flush() 36 | check() 37 | poke(start+offset, 255) 38 | offset = 0 39 | end 40 | 41 | local function write_str(s) 42 | write_uint8(#s) 43 | for i=1,#s do write_char(sub(s,i,i)) end 44 | end 45 | 46 | function track(event, properties) 47 | write_str(event) 48 | if properties == nil then 49 | flush() 50 | return 51 | end 52 | for k,v in pairs(properties) do 53 | write_str(k) 54 | if type(v) == 'boolean' then 55 | write_uint8(0) 56 | write_bool(v) 57 | elseif type(v) == 'number' then 58 | write_uint8(1) 59 | write_str(tostr(v)) 60 | elseif type(v) == 'string' then 61 | write_uint8(2) 62 | write_str(v) 63 | else 64 | assert(false, k .. ' must be a primitive.') 65 | end 66 | end 67 | flush() 68 | end 69 | end 70 | 71 | --[[ 72 | 73 | example: 74 | 75 | track('level completed', { 76 | level = 4, 77 | score = 9000, 78 | found_secret = true, 79 | }) 80 | 81 | --]] 82 | -------------------------------------------------------------------------------- /track_test.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | PICO-8 Cartridge 6 | 7 | 8 | 52 | 53 | 54 | 55 | 56 | 57 |


58 | 59 |
60 | 61 | 62 | 63 | 86 | 150 | 156 | 157 | 158 | 159 | 177 | 178 |
179 | 180 |
181 | 182 | Reset 183 | 184 | Reset
185 | 186 |
187 | 188 | Pause 189 | 190 | Pause
191 |
192 | Fullscreen 193 | 194 | Fullscreen
195 |
196 | Toggle Sound 197 | 198 | Sound
199 | 203 | 204 |
205 | 206 |
207 |

208 | 209 | 210 | 211 | 212 | --------------------------------------------------------------------------------