├── 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 |
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 |