0:29:26 Got it.
0:29:27 So given that Kinopio is not just like a
more traditional web app where you have
0:29:33 tons of forms and like pages and routes,
et cetera, but it's a spatial canvas.
0:29:39 This seems to be a more common
way now, how software is laid out.
0:29:44 I've never built a canvas-based
app myself, but I'm very interested
0:29:48 in learning more about it.
0:29:49 So I'm curious whether you can
share some of your learnings.
0:29:53 about building a canvas-based tool?
0:29:56 Fundamentally, there are two
main different approaches
0:29:59 when you build a canvas.
0:30:00 So the first approach is you can
build it sort of like a website where
0:30:05 each card is a dom node and you know,
absolutely positioned and you just
0:30:09 kind of move it around with transforms.
0:30:11 Um, the upside of that is it's really fast
and you know, like it'll work everywhere.
0:30:15 The downside is there's a lot of like
interactions you do on a canvas, like
0:30:20 pinch zooming and things like that.
0:30:22 are not really handled well by all
browsers out of the gate, especially
0:30:27 iOS Safari and, and Android Chrome,
for that matter, does a really
0:30:30 poor job in some of these things.
0:30:32 So for example, like I have a UI on my, on
my page and I, but I also have my canvas.
0:30:37 If I pinch zoom the phone, I'm zooming in
the whole thing, including the UI, which
0:30:41 makes the buttons look wild and crazy.
0:30:43 And I don't want to do that.
0:30:44 I can also like add like special touch
handlers to only zoom in that part of
0:30:49 the canvas, but it's really hard to do
it in a way Where it doesn't just crash
0:30:53 the browser because the transformed
texture of the page gets gets too big.
0:30:57 So a Kinopio document can be like tens of
thousands of pixels wide or deep, right?
0:31:01 So it's really hard to design around that.
0:31:03 The second approach, which is by far the
more popular approach, is to recreate
0:31:08 the whole canvas in the HTML canvas
element or some some similar type of
0:31:14 rendering that you control and you
have really fine grained thing over.
0:31:18 And so the upside of that is you have
full control over pinching and zooming.
0:31:22 You can tell things to, to leave space.
0:31:25 The viewport like intersection observer
equivalent, um, is a lot more reliable.
0:31:31 So browsers don't always report their
positions, especially on mobile,
0:31:34 accurately to web apps, as I've found.
0:31:37 And so, being able to control
every part of the rendering
0:31:40 process means you control it.
0:31:42 You can make things appear
precisely how you want to.
0:31:46 The downside is you have to, you lose all
the things you get for free on the web.
0:31:50 You lose accessibility, you lose speed.
0:31:53 You lose like, you know, like special
touch handling and other things like that.
0:31:56 And you have to build it in yourself,
or more likely you don't really.
0:32:00 And you kind of have a canvas
that works great on like desktop
0:32:03 computers, but not so much elsewhere.
0:32:05 And so because of that, Kinopio uses
the first approach, which is fast, but.
0:32:10 It requires a lot of work to not be janky
and I, I do my best, I'll say that much.
0:32:15 Any particular patterns that
you figured out for that first
0:32:19 approach that you laid out?
0:32:20 Yeah, so there's a thing that
I do called counterscaling.
0:32:24 So essentially when you pinch the
screen on mobile, the whole page
0:32:28 will zoom up, including the UI.
0:32:30 But what I do with the UI is I
tell it to scale itself down.
0:32:34 So if let's say you pinched in and
the page is now 2x, I tell the UI.
0:32:38 Hey, it looks like the page is 2x.
0:32:40 Maybe zoom yourself down,
scale yourself down to 0.
0:32:42 5x.
0:32:43 And so it kind of like net makes
the UI look the correct size.
0:32:47 So I'm basically like making the UI
smaller so that it appears regular
0:32:51 size while you're doing this.
0:32:52 What I found though is that
browsers, mobile browsers don't send
0:32:56 resized data and pinch zoom data
as quickly as you interact with it.
0:32:59 A lot of events happen in the
browser that just aren't reported.
0:33:02 To the browser, because they
don't want to like, you know, blow
0:33:05 up the JavaScript or whatever.
0:33:06 There's like little tricks that
you do to kind of work around that.
0:33:09 So like, I will fade in the UI during
like touch events so that you don't
0:33:13 see things like jitter around as
they're, they're struggling to resize.
0:33:17 So yeah, I've learned a lot
about how mobile browsers operate
0:33:20 differently than desktop ones.
0:33:21 And, uh, it's, it's a lot.
0:33:23 Would you still choose approach
number one, as opposed to
0:33:27 the canvas-based approach?
0:33:28 I think I would, because I've tried like.
0:33:30 a couple times to, to redo
Kanopio with different approaches.
0:33:34 The other big downside of the
canvas-based approach is it
0:33:37 also makes iteration way harder.
0:33:40 Like adding new features when you have to
also render them or like, you know, like,
0:33:44 like at a lower level and figure out how
to just work around that sort of stuff.
0:33:48 And you don't have like, you
know, the normal flex box type
0:33:52 positioning flow and things like that.
0:33:53 It's a, it's a lot more tricky.
0:33:55 And so I think it's kind of
like I've chosen the net best
0:33:58 approach, at least for Kinopio.
0:34:00 And the one that I've kind of embraced
because one of the other advantages
0:34:03 of doing a full canvas rendering
is you can scroll in 360 degrees.
0:34:08 And with Kinopio, you can only scroll
down and to the right as much as you want.
0:34:11 But because of that constraint,
You always know where the
0:34:14 beginning of the document is.
0:34:16 It's always in the top left for the
most part, as opposed to other canvas
0:34:20 tools where it can be like in the
center of the page, which might not
0:34:23 be visible depending on the size of
your device and you've got to kind of
0:34:26 scroll around to figure things out.
0:34:28 That's super cool.
0:34:29 In regards to the real time collaboration,
so you can share boards with other people
0:34:35 and like work on them at the same time.
0:34:37 Are you going even further to have like
a sense of presence across collaborators?
0:34:42 You can do see other people's
cursors or how did you think about
0:34:46 designing those interactions?
0:34:47 So, Kinopio has this kind of unique
feature called Paint Select or Magic
0:34:51 Paint and basically it lets you select
multiple cards to do bulk actions, like
0:34:55 move them all together, but it lets
you paint over them to select them.
0:34:59 So instead of drawing a box, you can
kind of like make more kind of unique
0:35:04 selections by painting over and it was
kind of also a way to like bridge this
0:35:07 gap between the right side of your
brain and the left side of your brain.
0:35:11 And so the paint stroke kind of disappears
as you're paint selecting, there's like
0:35:14 a exponential decay function there.
0:35:17 And so I also I show those same paint
strokes for other people looking at
0:35:21 your space or interacting with it.
0:35:23 So as you're moving around, you see
their paint strokes kind of moving
0:35:26 around and fading in the background.
0:35:28 You also see their user icons
kind of floating around.
0:35:30 So it kind of creates more than
just like the cursor plus user icon.
0:35:34 It kind of creates more of like a feeling
of like, Oh, like these people are
0:35:38 like, or someone's really interacting
with the space or maybe somebody is
0:35:40 just noodling around in the space.
0:35:41 I can just see their paint strokes and
they're trying to spell out words or
0:35:44 draw things before the paint fades away.
0:35:47 That is super cool.
0:35:48 Yeah.
0:35:48 This is, I think goes back to the design
principles that did you laid out initially
0:35:53 and how you're not directly imitating
paper, but you figure out like what is
0:35:58 the best mechanism here for, for this
medium and the goals you're going for.
0:36:02 So going back to the canvas, I recently
read that I think Obsidian has launched
0:36:08 an initiative called JSON Canvas.
0:36:11 Um, if I remember correctly, and I
think there, do you have some plans
0:36:15 to, to also like integrate with that?
0:36:18 Funny you should mention, I literally,
um, just yesterday launched, uh, Kinopio
0:36:22 support for full import and export, uh,
you know, um, exporting with that, with
0:36:27 that file format, the canvas file format.
0:36:30 So they launched it yesterday.
0:36:31 I really quickly added it yesterday.
0:36:33 So can you share a little bit more about
why that would be useful for, for people?
0:36:37 Sure.
0:36:38 Yeah.
0:36:38 So for the longest time there hasn't been
like a great interop document format.
0:36:43 So of course, each different app has
its own JSON representation of nodes
0:36:48 or cards and edges or connection lines.
0:36:51 But they're not, they're all app specific.
0:36:53 So, you know, it's kind of tough
if you're trying to, you know,
0:36:55 Migrate from one tool or another
or test out one tool or another.
0:36:59 And so the closest equivalent we
had before, just for a little bit of
0:37:01 historical context was OPML, which is also
like kind of a, an off requested feature,
0:37:06 an OPML was kind of made for outliners.
0:37:09 So like collapsible nested tree and you
know, structures I can indent now dent.
0:37:14 The problem with OPML is it doesn't handle
what happens if you have multiple trees
0:37:19 that aren't connected to each other,
or you have multiple trees that might
0:37:22 have child node that they both share.
0:37:24 You know, like you can, you can
create structures that are way
0:37:26 more complex than OPML can capture.
0:37:29 And so I just couldn't figure
out how to do it with OPML.
0:37:32 So I followed the spec for a while and,
and when Capano and Obsidian launched
0:37:36 it, I, I was already kind of in a rework
of the importing and exporting system.
0:37:41 So it's a very simple spec.
0:37:42 It doesn't cover every feature
that either app has, I'm sure.
0:37:46 But the advantage of that is
it's also very easy to implement.
0:37:48 So, you know, it's different.
0:37:49 Transforming from one JSON
object to another, essentially.
0:37:53 Got it.
0:37:53 And I suppose that while the spec
is like very open ended in some
0:37:58 way, maybe that converges to,
towards some more details over time.
0:38:03 And the idea would be that I can
bring some data from one tool,
0:38:07 for example, Obsidian into Kinopio
or the other way around or future
0:38:12 tools that might, might exist.
0:38:14 Yeah.
0:38:15 It's, but there are wrinkles because.
0:38:17 Of how different these tools
are, or at least how different
0:38:19 Kinopio is from all of them.
0:38:21 So there are assumptions and I've,
I've left like feedback about these
0:38:24 things in, in GitHub issues for the
spec, but there are like assumptions
0:38:28 that they make like, um, the node
has to define like how wide it is
0:38:32 explicitly, or what type of node is it?
0:38:35 Is it a file node?
0:38:36 Is there a, you know, like
a website node or whatever.
0:38:39 So problems with both of these is that
like the width, Of one app's node for the
0:38:45 same amount of text might be different for
another app because they're all rendering
0:38:49 it differently in Kinopio's case.
0:38:51 There's also this.
0:38:52 It's also mobile compatible.
0:38:53 So there's a bit extra of padding
and sizing for touch friendliness.
0:38:57 So those numbers don't really translate.
0:39:00 And so it's kind of weird that
they're required in the spec
0:39:02 as opposed to being optional.
0:39:03 Second issue was the node type.
0:39:05 So I can mention a long time ago.
0:39:07 Or earlier in this chat, you know, a
lot of apps make you choose, like, Hey,
0:39:10 are you going to insert a web page?
0:39:11 Are you going to sort of whatever?
0:39:12 On Kinopio, they're all the same type.
0:39:14 They're all just, there's only one
type of card, a text card, and whatever
0:39:17 type of content you put in that,
whether it's a link or a website or
0:39:20 whatever, is what that card transforms
into using the power of regexes.
0:39:24 And so that part of the whole
spec is basically, like, not
0:39:28 necessarily relevant to Kinopio.
0:39:30 Didn't really connect because
It's making the assumption
0:39:33 that that isn't really shared.
0:39:34 So in some ways I think it's too
specific in some ways it's, and I'm sure
0:39:38 a lot and a lot of people's complaint
is that it's not specific enough.
0:39:42 So it's weird because like
it's really hard to make a
0:39:45 spec for wildly different apps.
0:39:47 But I think currently I'm actually
pretty happy with the spec because it
0:39:50 captures like the most important part,
which is the representation of cards
0:39:55 and nodes in a way that doesn't require
them to have this strict tree structure.
0:40:00 Yeah.
0:40:00 That makes a lot of sense.
0:40:01 And yeah, I mean, the devil's always in
the detail and you built Kinopio really
0:40:06 to enable the sort of interactions and
details that you uniquely thought about.
0:40:11 And you might not have that entropy
available in Obsidian and vice versa.
0:40:17 And then it's also, how do
you preserve that intent and
0:40:20 that information across apps?
0:40:22 That's, that's a very tricky problem,
but I, I applaud the initiative to take
0:40:27 some first steps there to at least bring
some data across one app to another.
0:40:32 So that sort of cross app collaboration,
I think that is certainly a goal that I'm
0:40:37 rooting for, but that we still have like
many chapters still ahead of us there.
0:40:42 So the way I've built Kenopio, it's super
impressive, both in terms of like how
0:40:48 the product feels and works and looks,
but also like, given that you've been
0:40:54 on this journey for, for such a long
time, uh, by, by yourself, I'm curious
0:40:59 which corners you might've already cut
along the way that you regret looking
0:41:04 back where you wish you would have like
spent up front or vice versa where you
0:41:10 thought something might be a problem
and it never actually became a problem.
0:41:13 Oh, wow.
0:41:14 Yeah.
0:41:14 There's, there's
definitely a lot of those.
0:41:16 So like, there's like a lot of code kind
of like with the syncing engine, uh, and
0:41:21 the way I merge, um, different changes
to make smaller change sets that get
0:41:25 sent to the server, but I feel like.
0:41:27 are a little hard to work around now
in just in terms of like just how gross
0:41:32 that code is or how like abstractive
and I wish I did a better job writing
0:41:36 it like it's not it's not something
that's painted me into too harsh a
0:41:39 corner it's just something I'm like
oh I'm scared to touch this part of
0:41:42 the app but one day I'll just you know
buckle down and and really get to it.
0:41:47 So I actually think the app is in a
pretty good place just because um I
0:41:52 guess the other thing is like I prefer
to like write code that's like, not
0:41:57 necessarily for me to understand now,
but for me to understand in like two
0:42:00 months or three months or five years from
now, where I forget what the S variable
0:42:05 or the A variable is referring to.
0:42:07 So I, I, I was like kind of influenced
by, by some short time, like,
0:42:13 Coding for Apple platforms where
they're very verbose with variables.
0:42:16 I kind of took some of that
Coco convention into my own
0:42:20 kind of code writing style.
0:42:22 Yeah, I think that's very wise.
0:42:23 Uh, I've made the same observation
about myself since in reality, even
0:42:28 if you just work by yourself, you
still collaborate with yourself.
0:42:32 Over time more instances of you over
time the future you, the past you.
0:42:34 who do not the same
context right in your brain
0:42:42 So just like leaving notes for yourself
of like, why did you do a certain
0:42:48 thing has, I, I've had to learn that
lesson painfully and I'm treating my
0:42:53 future self better or I'm trying to,
so, uh, it looks like you've learned
0:42:59 quite a couple of similar lessons, but
0:43:01 Yeah, I think we all kind of learn that,
but we all have to, like, burn ourselves
0:43:04 a little bit before we truly learn it.
0:43:06 Because it's not, like, an
intuitive thing to know.
0:43:09 And it is, like, in an industry that's
always trying to, like, move fast and
0:43:12 ship fast and whatever, it's a little,
it's mildly antithetical to that.
0:43:16 But it is one of those things where,
take a little extra time to write