<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Carrots</title><description>Carrots are good for your health.</description><link>https://carrots.sgenoud.com/</link><item><title>Small web apps are perfect for (tabletop gaming) tools</title><link>https://carrots.sgenoud.com/small-web-apps-for-tabletop-gaming/</link><guid isPermaLink="true">https://carrots.sgenoud.com/small-web-apps-for-tabletop-gaming/</guid><description>In the last few months, I have created two web apps, mostly for my own needs. These are tiny tools, they did not take a lot of time to build</description><pubDate>Fri, 12 Jun 2026 13:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the last few months, I have created two web apps, mostly for my own needs.
These are tiny tools, they did not take a lot of time to build and polish, but
I get a lot of value out of them. I guess they can benefit anyone who plays
tabletop games regularly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/moimoimoi.CBHYnAzt.png&quot; alt=&quot;MoiMoiMoi Screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;First, I made &lt;a href=&quot;https://moimoimoi.sgenoud.com&quot;&gt;MoiMoiMoi&lt;/a&gt;. I never use the “last
player to have seen an elephant starts” rules. I always find them a bit silly.
MoiMoiMoi solves that problem. The gist is that each player puts
a finger on the screen, and the app chooses one randomly. Note that this is
a &lt;a href=&quot;https://apps.apple.com/us/app/chwazi-finger-chooser/id689674978&quot;&gt;Chwazi&lt;/a&gt;
clone. The original was not working on my phone, although it looks like they
recently released a new version that might fix it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/scores.DuwTRym1.png&quot; alt=&quot;Scores Screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then I needed a score tracker, &lt;a href=&quot;https://scores.sgenoud.com/&quot;&gt;Scores&lt;/a&gt;. I really
like &lt;a href=&quot;https://apps.apple.com/us/app/scorekeeper-xl/id463243024&quot;&gt;Scorekeeper
XL&lt;/a&gt;. I valued its
simplicity and fun UI, but I had a couple of issues with it. First, there was
no way to switch between groups of people. I have different gaming groups (not
that many!) but having to re-enter everyone’s names is a bit annoying. Also,
some games, like &lt;a href=&quot;https://flip-7.com/&quot;&gt;Flip 7&lt;/a&gt;, need you to add tens of points
at once, which Scorekeeper is not great at either.&lt;/p&gt;
&lt;p&gt;These tools do not need accounts, and they do not need much data. In the case
of Scores, there is a little bit of data: the groups, as well as the current
sheet. The tradeoff is clear to me: either build a full account system, with
logins, passwords, sync, complexity, and cost, or ask people to recreate a tiny
bit of data on another device. For this kind of tool, I much prefer the second
option.&lt;/p&gt;
&lt;p&gt;Keeping everything local also means they can work completely offline. If you
add them as web apps (still weirdly difficult to find on iOS) they can work
fully offline.&lt;/p&gt;
&lt;p&gt;I have iterated on them to make the experience feel as smooth as possible. They
are definitely not native apps, but using them should feel like using an
application, not a clunky web thing. Here again, the platforms do not always
make it easy, but it can be done. For instance, Scores can keep the screen on
while you use it.&lt;/p&gt;
&lt;p&gt;The web has other great benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It is cross-platform: you can use web apps on iOS, Android, or anything that
can run a browser.&lt;/li&gt;
&lt;li&gt;There is no gatekeeper: no need to have someone review your app before it is
available, easy updates, and no need to create special assets for a store.&lt;/li&gt;
&lt;li&gt;They are cheap to host. These are static web apps: they consist of a small
HTML and JavaScript bundle that can be served for almost nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have a small itch to scratch, just build it as a web app, polish it
until you are happy with the result, and publish it. It costs almost nothing,
and it may help people around you. There is no need to build a business (or
try to monetize it). Just share!&lt;/p&gt;</content:encoded></item><item><title>The current landscape of 2D CAD libraries</title><link>https://carrots.sgenoud.com/2d-cad-libraries/</link><guid isPermaLink="true">https://carrots.sgenoud.com/2d-cad-libraries/</guid><description>I built the general workflow of replicad to be similar to a standard CAD workflow: draw in 2D, sketch this in a plane in 3D, and then give i</description><pubDate>Thu, 09 Mar 2023 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I built the general workflow of &lt;a href=&quot;https://replicad.xyz&quot;&gt;replicad&lt;/a&gt; to be similar to a standard CAD
workflow: draw in 2D, sketch this in a plane in 3D, and then give it some
thickness (extrude, revolve or sweep).&lt;/p&gt;
&lt;p&gt;Unfortunately, there is no support for some basic 2D CAD operations in &lt;a href=&quot;https://www.opencascade.com/&quot;&gt;open
cascade&lt;/a&gt;. For instance, there is no &lt;strong&gt;2D boolean operations&lt;/strong&gt;: fusing shapes
together, cutting one with another.&lt;/p&gt;
&lt;p&gt;I found multiple libraries to do 2D operations, but they all failed to be the
CAD library I expected. Let’s see what they lack (in my opinion, of course),
and build my &lt;a href=&quot;#tldr-my-list-of-features&quot;&gt;list of requirements&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/replicad-workbench-2d.CS4nH1rS.png&quot; alt=&quot;Showing off replicad 2D operations&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;solvespace-and-offsets&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#solvespace-and-offsets&quot;&gt;#&lt;/a&gt;Solvespace and offsets&lt;/h2&gt;
&lt;p&gt;We can start with the other open source CAD kernel, &lt;a href=&quot;https://solvespace.com/&quot;&gt;solvespace&lt;/a&gt;. It is a full
featured kernel, but lack an important feature for 2D CAD, &lt;strong&gt;offsets&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Offsets can be understood as &lt;a href=&quot;https://en.wikipedia.org/wiki/Parallel_curve&quot;&gt;parallel curves&lt;/a&gt;. They tend to be very useful to
transform a line into a 2D shape (by giving it some kind of stroke width). CAM
tools also use these to draw tool paths.&lt;/p&gt;
&lt;h2 id=&quot;clipper-and-polygons&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#clipper-and-polygons&quot;&gt;#&lt;/a&gt;Clipper and polygons&lt;/h2&gt;
&lt;p&gt;Then let’s have a look at &lt;a href=&quot;https://github.com/AngusJohnson/Clipper2&quot;&gt;Clipper&lt;/a&gt;. This is a very performant library
that does boolean operation (i.e. what they call clipping) and offsetting.
Unfortunately, it &lt;strong&gt;only works with polygons&lt;/strong&gt; (i.e. shapes built with straight
lines).&lt;/p&gt;
&lt;p&gt;What is this issue with polygons? Depending on your use case polygons are
great. You can approximate any curve by a set of lines, and then use clipper to
do your operations on it. This is what this &lt;a href=&quot;http://hessmer.org/gears/InvoluteSpurGearBuilder.html&quot;&gt;great gear generator
&lt;/a&gt; does.&lt;/p&gt;
&lt;p&gt;This is the analogous of a mesh for 3D objects. The trade off is also the same
– you gain some simplicity of computation (and performance), but lose
information about the shape itself (the topology). It becomes more difficult to
select an &lt;em&gt;edge&lt;/em&gt; of your shape (what is an edge then?).&lt;/p&gt;
&lt;p&gt;Note that many other libraries that deal with 2D geometries have the same
issue. I could find &lt;a href=&quot;https://shapely.readthedocs.io/&quot;&gt;shapely&lt;/a&gt; for instance.&lt;/p&gt;
&lt;h2 id=&quot;cavalier-contours-and-a-cad-data-structure&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#cavalier-contours-and-a-cad-data-structure&quot;&gt;#&lt;/a&gt;Cavalier contours and a CAD data structure&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jbuckmccready/cavalier_contours&quot;&gt;Cavalier contours&lt;/a&gt; is a rust library for offsets and
boolean operations that supports arcs of circle in addition to straight lines.
It seems that it is based on well researched algorithms, is fast and has some
nice webassembly builds.&lt;/p&gt;
&lt;p&gt;The issue I have with it, is its data model. As a very well focussed library
and offers a simple API for defining poly lines. But it stops at that point
– its data structure does not support anything like translations or rotations.
There is no concept of holes within closed poly lines and ways to understand
the inclusion logic.&lt;/p&gt;
&lt;p&gt;I am looking for a &lt;strong&gt;full CAD library&lt;/strong&gt;. Cavalier contours is not that. It is
good at some singular operations - but I would need to be extended a lot to
become a proper CAD library.&lt;/p&gt;
&lt;h2 id=&quot;flatten-makerjs-and-bézier-curves&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#flatten-makerjs-and-bézier-curves&quot;&gt;#&lt;/a&gt;Flatten, maker.js and Bézier curves&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/alexbol99/flatten-js&quot;&gt;Flatten&lt;/a&gt; offers all the functionality that clippers and cavalier
contours are missing. It supports arcs, is meant as a CAD library, with a data
model for “islands” and “holes” and APIs around inclusion of shapes within
other shapes.&lt;/p&gt;
&lt;p&gt;But arcs are not enough – if you want to draw shapes that are slightly organic
or need to be smooth, it becomes useful to offer &lt;a href=&quot;https://pomax.github.io/bezierinfo/&quot;&gt;Bézier curves&lt;/a&gt;. For
instance fonts for text rendering are represented as sets of &lt;strong&gt;Bézier curves&lt;/strong&gt;.
This is also a significant part of paths in SVG (or vector graphics in
general).&lt;/p&gt;
&lt;p&gt;It is possible to approximate Bézier curves with arcs - but we get the same
issue that we had with polygons. You loose the semantic relation between what
an edge is and how you represent it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://maker.js.org/&quot;&gt;maker.js&lt;/a&gt; (that I used to build the paper models in &lt;a href=&quot;https://deckinabox.sgenoud.com/&quot;&gt;deckinabox&lt;/a&gt;)
has the same issue. It is a full CAD library, it let you define Bézier curves,
but they are just arcs in disguise.&lt;/p&gt;
&lt;p&gt;Note that &lt;a href=&quot;https://github.com/jbuckmccready/cavalier_contours&quot;&gt;cavalier contours&lt;/a&gt; does not support Bézier
either.&lt;/p&gt;
&lt;h2 id=&quot;additional-considerations&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#additional-considerations&quot;&gt;#&lt;/a&gt;Additional considerations&lt;/h2&gt;
&lt;p&gt;There are some other typical features of 2D CAD software that I did not
mention. For instance, &lt;strong&gt;performance&lt;/strong&gt; is not my main concern now - I am more
looking for functionality first (and then, potentially, performance).&lt;/p&gt;
&lt;p&gt;Then, &lt;a href=&quot;https://solvespace.com/&quot;&gt;solvespace&lt;/a&gt;, while it does not have offsets, offers a &lt;strong&gt;constraints
solver&lt;/strong&gt;. This is very powerful for visual CAD (where these are more intuitive
than raw numbers). I have focussed on the &lt;em&gt;code CAD&lt;/em&gt; aspects of a 2D library
– and I don’t think that constraints are great for code. Note that &lt;a href=&quot;https://www.opencascade.com/&quot;&gt;open cascade&lt;/a&gt;
also has a constraints solver.&lt;/p&gt;
&lt;h2 id=&quot;what-did-i-choose-for-replicad&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#what-did-i-choose-for-replicad&quot;&gt;#&lt;/a&gt;What did I choose for replicad?&lt;/h2&gt;
&lt;p&gt;Within &lt;a href=&quot;https://replicad.xyz&quot;&gt;replicad&lt;/a&gt; I use &lt;a href=&quot;https://www.opencascade.com/&quot;&gt;open cascade&lt;/a&gt; as the kernel. As I mentioned earlier 2D
support within open cascade is sparse.&lt;/p&gt;
&lt;p&gt;While it does not offer the CAD operations themselves in 2D (not 2D booleans or
offsets), it gives the primitives needed (intersections and offsets of
a single curve). So I built the complex curves data structures, boolean
operations and offsets on top of the open cascade primitives.&lt;/p&gt;
&lt;p&gt;This is still not great. A big drawback is that you need to pull a lot of
things from open cascade and deal with garbage collection yourself. It is
also far from perfect in many ways. For instance offsets of Béziers tend to
fail a lot.&lt;/p&gt;
&lt;p&gt;But it has other advantages that none of the other libraries provide. Open
cascade has an &lt;strong&gt;arc of ellipses&lt;/strong&gt; type of curve, it provides ways to work with
&lt;strong&gt;BSplines&lt;/strong&gt; (even better than Béziers!), it supports &lt;strong&gt;stretching and
shearing&lt;/strong&gt; transformations and it has built-in &lt;strong&gt;approximation routines&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;tldr-my-list-of-features&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#tldr-my-list-of-features&quot;&gt;#&lt;/a&gt;TL;DR: my list of features&lt;/h2&gt;
&lt;p&gt;So what do I want from a 2D CAD library:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;basic geometric transformations (translations, rotations)&lt;/li&gt;
&lt;li&gt;boolean operations&lt;/li&gt;
&lt;li&gt;offsets of chains of curves&lt;/li&gt;
&lt;li&gt;complex types of curves (arcs, ellipses, Béziers)&lt;/li&gt;
&lt;li&gt;data structures thought for CAD with ways to express containment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And there are some other aspects that would be nice to have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;performance&lt;/li&gt;
&lt;li&gt;approximation routines&lt;/li&gt;
&lt;li&gt;a constraints solver&lt;/li&gt;
&lt;li&gt;all affine transformations&lt;/li&gt;
&lt;li&gt;BSplines as a type of curve&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even with my minimal requirements I could not find any library that fit the
bill. Within &lt;a href=&quot;https://replicad.xyz&quot;&gt;replicad&lt;/a&gt;, the best I could achieve was to extend &lt;a href=&quot;https://www.opencascade.com/&quot;&gt;open cascade&lt;/a&gt;
so that it worked with its basic 2D primitives.&lt;/p&gt;
&lt;p&gt;You can discuss this post &lt;a href=&quot;https://toot.cafe/@stevegenoud/109993643765595619&quot;&gt;on Mastondon&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Bling My Thing - decorate your 3D models</title><link>https://carrots.sgenoud.com/decorate-3d-models-with-pimpmything/</link><guid isPermaLink="true">https://carrots.sgenoud.com/decorate-3d-models-with-pimpmything/</guid><description>Deckinabox received some feedback asking for ways to decorate easily the boxes. Typically adding a logo, or a little bit of text. I like the</description><pubDate>Fri, 01 Apr 2022 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://deckinabox.sgenoud.com&quot;&gt;Deckinabox&lt;/a&gt; received some feedback asking for
ways to decorate easily the boxes. Typically adding a logo, or a little bit of
text. I like the Unix philosophy of small tools with a single purpose - making
simple boxes is the purpose of that tool, not decoration.&lt;/p&gt;
&lt;p&gt;So I created another tool! &lt;a href=&quot;https://blingmything.sgenoud.com&quot;&gt;Bling My Thing&lt;/a&gt; is
a web application that lets you decorate 3D models. It takes a STEP file (there
is also some STL support) and allows you to select faces and apply decorations.&lt;/p&gt;
&lt;p&gt;You can add text, make honeycomb or grid pattern and also apply SVGs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/showcase.BenVEdr9.png&quot; alt=&quot;Showcase of different types of decoration&quot;&gt;&lt;/p&gt;
&lt;p&gt;With the help of &lt;a href=&quot;https://replicad.xyz&quot;&gt;replicad&lt;/a&gt; creating such single purpose
web apps for 3D modelling becomes easy. I have open sourced &lt;a href=&quot;https://github.com/sgenoud/blingmything&quot;&gt;the
code&lt;/a&gt;, so that anyone can copy the
structure of the app and create their own tool.&lt;/p&gt;
&lt;p&gt;You can discuss it &lt;a href=&quot;https://toot.cafe/@stevegenoud/108056861702625739&quot;&gt;on
Mastodon&lt;/a&gt; or &lt;a href=&quot;https://twitter.com/stevegenoud/status/1509874313306034209&quot;&gt;Twitter&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Make custom storage solutions with deckinabox</title><link>https://carrots.sgenoud.com/make-custom-storage-with-deckinabox/</link><guid isPermaLink="true">https://carrots.sgenoud.com/make-custom-storage-with-deckinabox/</guid><description>Two years ago I bought myself a Silhouette Cameo. I built some nice papercraft statues with it and then went to my old love. Boxes. So I cre</description><pubDate>Thu, 17 Feb 2022 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Two years ago I bought myself a Silhouette Cameo. I built some nice &lt;a href=&quot;/how-to-create-a-papercraft-statue&quot;&gt;papercraft
statues&lt;/a&gt; with it and then went to my old love. &lt;strong&gt;Boxes&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So I created &lt;a href=&quot;https://deckinabox.sgenoud.com&quot;&gt;deckinabox&lt;/a&gt;, an online tool to
create boxes and trays.&lt;/p&gt;
&lt;h2 id=&quot;models-for-folding-paper-or-cardstock&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#models-for-folding-paper-or-cardstock&quot;&gt;#&lt;/a&gt;Models for folding paper or cardstock&lt;/h2&gt;
&lt;p&gt;Originally it could only generate boxes for card decks, but
I fairly quickly extended it to support token trays. With it I make storage
solutions for many of my board games, for instance
&lt;a href=&quot;https://boardgamegeek.com/thread/2401581/article/34459094#34459094&quot;&gt;Agricola&lt;/a&gt;,
&lt;a href=&quot;https://boardgamegeek.com/thread/2384863/article/34236253#34236253&quot;&gt;7 Wonders
Duel&lt;/a&gt; or
&lt;a href=&quot;https://boardgamegeek.com/thread/2410358/cardstock-custom-instert&quot;&gt;Paper
Tales&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/deckinabox-token-tray.Jp0DPmaE.jpeg&quot; alt=&quot;A paper token tray made with deckinabox&quot;&gt;&lt;/p&gt;
&lt;p&gt;No need to draw, align or think about the maths to build your box. You specify
its size, some additional configuration (what kind of lock mechanism do you
want?). That’s it.&lt;/p&gt;
&lt;p&gt;If you are building a tray, it exposes a simple interface to choose where your
separators go. And then it exports multiple formats that makes it available to
people with different machines, or even to cut by hand.&lt;/p&gt;
&lt;p&gt;The trays and boxes made with cardboard are sturdy (sturdier than what
I expected to be honest). They are easy to build, even if for complex trays it
can be relatively time intensive.&lt;/p&gt;
&lt;h2 id=&quot;models-for-3d-printing&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#models-for-3d-printing&quot;&gt;#&lt;/a&gt;Models for 3D printing&lt;/h2&gt;
&lt;p&gt;I wanted to expand this approach of offering a similar tool for models for 3D
printing. Usually STL models are built for one purpose only (with small
variations). Or can be parametrised with numeral, or if you can, changes in the
code.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/deckinabox-sample.CUxINkJ5.png&quot; alt=&quot;Deckinabox UI&quot;&gt;&lt;/p&gt;
&lt;p&gt;But I wanted to offer a way to create a model with a custom interface and
complex options. I needed to learn a lot of things about 3D modelling and how
to build 3D modelling software, but now deckinabox can also generate &lt;em&gt;quick
draw&lt;/em&gt; decks and token trays models for 3D printing.&lt;/p&gt;
&lt;p&gt;It uses the same type of interface as the models for folding paper. Standard
card sizes options for decks and separators for the token tray generator.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/3d-printed-deck-box.BJNlU1YL.jpeg&quot; alt=&quot;3D printed deck box&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;codecad-is-great&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#codecad-is-great&quot;&gt;#&lt;/a&gt;CodeCAD is great&lt;/h2&gt;
&lt;p&gt;I am quite proud to be able to offer a solution that allow someone who is not
interested in 3D modelling a way to &lt;strong&gt;create personalised models&lt;/strong&gt; for their
need.&lt;/p&gt;
&lt;p&gt;I could build this tool around a community of people working on &lt;a href=&quot;https://learn.cadhub.xyz/blog/curated-code-cad/&quot;&gt;codeCAD&lt;/a&gt;
tools. CodeCAD is this (small?) movement around using code to draw.&lt;/p&gt;
&lt;p&gt;If you are interested, have a look at &lt;a href=&quot;https://maker.js.org/&quot;&gt;maker.js&lt;/a&gt; (that I use for the 2D paper
models) and my own &lt;a href=&quot;https://replicad.xyz&quot;&gt;replicad&lt;/a&gt; for everything 3D!&lt;/p&gt;
&lt;p&gt;You can discuss this &lt;a href=&quot;https://toot.cafe/@stevegenoud/107812886259899021&quot;&gt;on
Mastodon&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Stack homemade cardboard boxes</title><link>https://carrots.sgenoud.com/stack-homemade-cardboard-boxes/</link><guid isPermaLink="true">https://carrots.sgenoud.com/stack-homemade-cardboard-boxes/</guid><description>There is a shelf at my place that is not very practical to store anything but big items. I wanted to create a storage solution to keep my sm</description><pubDate>Wed, 14 Jul 2021 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There is a shelf at my place that is not very practical to store anything but
big items. I wanted to create a storage solution to keep my small(-ish) craft
tools.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/stacked-boxes.DCtK-84F.jpeg&quot; alt=&quot;Stacked cardboard boxes&quot;&gt;&lt;/p&gt;
&lt;p&gt;First I needed to create the boxes themselves. This is fairly easy using this
&lt;a href=&quot;https://www.youtube.com/watch?v=hCJGcJFoSXY&amp;#x26;t=2918s&quot;&gt;nice tutorial video&lt;/a&gt; (the
third method, starting around minute 48).&lt;/p&gt;
&lt;p&gt;This methods requires to cut the bevels at 45 degrees. The good news is that
someone already designed the tool for that purpose (and you can download it
&lt;a href=&quot;https://www.thingiverse.com/thing:4665245&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Unfortunately cardboard boxes are not that easy to stack, especially because
I was not that precise measuring and cutting them. So I designed small corners
to be able to stack them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/box-corner.DtgSaLcp.jpeg&quot; alt=&quot;Box corner&quot;&gt;&lt;/p&gt;
&lt;p&gt;These print quickly, with my standard 0.2mm layer height it is about 15 minutes
a piece. It should also work without issue for higher height and faster prints.&lt;/p&gt;
&lt;p&gt;Here you can configure and download the files for your own builds.&lt;/p&gt;
&lt;iframe allow=&quot;fullscreen&quot; src=&quot;https://cadeau.sgenoud.com/boxCorner&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;I made this an editable model, where you can customise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the cardboard thickness (&lt;code&gt;cardboardThickness&lt;/code&gt;). You might add half
a millimeter to allow for a bit of tolerance.&lt;/li&gt;
&lt;li&gt;the size of the corner (&lt;code&gt;length&lt;/code&gt;). This value will be used in both direction&lt;/li&gt;
&lt;li&gt;how tall the corner will be (&lt;code&gt;height&lt;/code&gt;). Note that the total height will be
twice this parameter plus a &lt;code&gt;wallThickness&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;how much material you will use to build the structure (&lt;code&gt;wallThickness&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While tweaking the parameters, you might see a blob appear - it means that your
configuration made something break.&lt;/p&gt;
&lt;p&gt;You can export your file as STL and use a standard configuration for your
slicer. The corners are designed to be printed without any support. I print
them in groups of 4, with a small brim (5 lines) to avoid them falling over.&lt;/p&gt;
&lt;p&gt;You can discuss this &lt;a href=&quot;https://toot.cafe/@stevegenoud/106579290767087776&quot;&gt;on
Mastodon&lt;/a&gt; or &lt;a href=&quot;https://www.reddit.com/r/functionalprint/comments/ok4wy4/simple_corner_to_easily_stack_cardboard_boxes/&quot;&gt;on Reddit&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>3D printed parts for a baby gym arch</title><link>https://carrots.sgenoud.com/3d-print-a-baby-gym-arch/</link><guid isPermaLink="true">https://carrots.sgenoud.com/3d-print-a-baby-gym-arch/</guid><description>Somehow a baby appeared in my life. I wanted to build him one of these arches where you can suspend toys for him to play with. I think it is</description><pubDate>Thu, 24 Jun 2021 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Somehow a baby appeared in my life. I wanted to build him one of these arches
where you can suspend toys for him to play with. I think it is called a baby
arch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/arch-side.BE_XspWJ.jpeg&quot; alt=&quot;the baby arch from the side&quot;&gt;&lt;/p&gt;
&lt;p&gt;This arch is built of 4 legs made of rectangular lumber, a wooden rod for the
arch itself, and some 3D printed parts for the feet and to connect everything
together (I call them the heads).&lt;/p&gt;
&lt;p&gt;Here you can configure and download the files to 3D print.&lt;/p&gt;
&lt;iframe allow=&quot;fullscreen&quot; src=&quot;https://cadeau.sgenoud.com/babyGym&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;I made this an editable model, where you can customise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the shape of the (rectangular) legs (&lt;code&gt;legsWidth&lt;/code&gt;, &lt;code&gt;legsDepth&lt;/code&gt;), as well as
how they related to each other (&lt;code&gt;legsAngle&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;the radius of the rod (&lt;code&gt;rodRadius&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;how much of the legs is covered by the 3D printed piece (&lt;code&gt;footHoleLength&lt;/code&gt; and &lt;code&gt;headHoleLength&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;more technical parameters (&lt;code&gt;wallThickness&lt;/code&gt; and &lt;code&gt;tolerance&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While tweaking the parameters, you might see a blob appear - it means that your
configuration made something break.&lt;/p&gt;
&lt;p&gt;You can export your file as STL and use a standard configuration for your
slicer. Personally I printed them on the flat side, I did not use any support,
with layers at 0.2 (and in PLA). I had to clean a bit the legs holes because of
an imperfect bridge - but your printer is probably better configured than mine!&lt;/p&gt;
&lt;p&gt;You can discuss this &lt;a href=&quot;https://toot.cafe/@stevegenoud/106466324373248333&quot;&gt;on
Mastodon&lt;/a&gt; or &lt;a href=&quot;https://www.reddit.com/r/functionalprint/comments/o72wqb/a_baby_gym_arch_made_with_3d_printed_parts_and/&quot;&gt;on Reddit&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>How I create papercraft statues (using my Silhouette Cameo)</title><link>https://carrots.sgenoud.com/how-to-create-a-papercraft-statue/</link><guid isPermaLink="true">https://carrots.sgenoud.com/how-to-create-a-papercraft-statue/</guid><description>You might have seen these papercarfts, low poly, statues or animals floating around the web. I actually bought a nice giraffe trophy, and th</description><pubDate>Thu, 20 Feb 2020 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You might have seen these papercarfts, low poly, statues or animals floating
around the web. I actually bought a nice giraffe trophy, and then wondered if
I could do it myself.&lt;/p&gt;
&lt;p&gt;This baby yoda is my first project made by myself, and it is fairly easy to do
(if you buy the right tools).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/paper-baby-yoda.B6SRhG8Z.jpeg&quot; alt=&quot;baby yoda in papercraft&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;first-step-the-3d-model&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#first-step-the-3d-model&quot;&gt;#&lt;/a&gt;First step: the 3D model&lt;/h2&gt;
&lt;p&gt;You need to start with a 3D model, there are three different ways to can create
one (that I have looked into):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;find a low poly statue&lt;/li&gt;
&lt;li&gt;find a high poly statue and lower the resolution&lt;/li&gt;
&lt;li&gt;scan an object in the world and lower the resolution&lt;/li&gt;
&lt;li&gt;build yourself a 3D model&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For all the methods you will need a editor for 3D objects. Personally I played
with &lt;a href=&quot;https://www.blender.org/&quot;&gt;Blender&lt;/a&gt;, as it is good (and free).&lt;/p&gt;
&lt;h6 id=&quot;finding-a-low-poly-statue&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#finding-a-low-poly-statue&quot;&gt;#&lt;/a&gt;Finding a low poly statue&lt;/h6&gt;
&lt;p&gt;Online you can find free (or paying) 3D models. I go on the
&lt;a href=&quot;https://www.thingiverse.com/&quot;&gt;thingiverse&lt;/a&gt; or &lt;a href=&quot;http://www.cadnav.com/&quot;&gt;cadnav&lt;/a&gt;
for instance. You can find there some low poly models.&lt;/p&gt;
&lt;p&gt;For the next step you will need to have them in &lt;code&gt;.obj&lt;/code&gt; format. You can use
Blender to do the conversion. The steps are the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;open a new project&lt;/li&gt;
&lt;li&gt;remove the default cube (select it and then press &lt;code&gt;X&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;import from &lt;code&gt;.stl&lt;/code&gt; (which is the standard format for the objects I found so
far&lt;/li&gt;
&lt;li&gt;export as &lt;code&gt;.obj&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h6 id=&quot;lowering-the-resolution-of-a-high-poly-statue&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#lowering-the-resolution-of-a-high-poly-statue&quot;&gt;#&lt;/a&gt;Lowering the resolution of a high poly statue&lt;/h6&gt;
&lt;p&gt;For high poly statues the steps are very similar than for low poly, you will
need to lower the resolution. For which Blender has the right tool as well.&lt;/p&gt;
&lt;p&gt;Once your model is loaded into your scene in Blender, select all the points and
use the decimate function. Lower the ratio until you reach a number of polygons
that seem good for you. This
&lt;a href=&quot;https://blender.stackexchange.com/questions/78499/how-to-decrease-the-polygon-count-on-my-mesh/78505&quot;&gt;answer&lt;/a&gt;
can help you as well.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/blender-decimate.DoiDEtE0.png&quot; alt=&quot;Decimate bunnies&quot;&gt;&lt;/p&gt;
&lt;h6 id=&quot;scanning-a-real-world-object&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#scanning-a-real-world-object&quot;&gt;#&lt;/a&gt;Scanning a real world object&lt;/h6&gt;
&lt;p&gt;This is something that I have not tried (yet). But I figured out that with
recent phones it should be possible to scan a real world object. For instance
&lt;a href=&quot;https://apps.apple.com/us/app/capture-3d-scan-anything/id1444183458&quot;&gt;this app&lt;/a&gt; for iOS seems nice.&lt;/p&gt;
&lt;h6 id=&quot;buiding-the-model-yourself-from-scratch&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#buiding-the-model-yourself-from-scratch&quot;&gt;#&lt;/a&gt;Buiding the model yourself from scratch&lt;/h6&gt;
&lt;p&gt;Finally you can go deep with Blender and learn to build yourself a 3D model.
Obviously this is a world into itself and you will need to learn how to use
these tools. As I said, I personally played with Blender and there are lots of
&lt;a href=&quot;https://www.youtube.com/watch?v=7MRonzqYJgw&quot;&gt;nice tutorials out there&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;second-step-making-it-flat&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#second-step-making-it-flat&quot;&gt;#&lt;/a&gt;Second Step: Making it flat&lt;/h2&gt;
&lt;p&gt;Once we have a 3D object, we need to flatten it. This part will need you to buy
a little bit of software. There is a functionality withing Blender to do it
– but I was not convinced by it.&lt;/p&gt;
&lt;p&gt;As I am a Mac user, I tried (and then bought)
&lt;a href=&quot;https://www.unfolder.app&quot;&gt;Unfolder&lt;/a&gt;. In this app you can load an &lt;code&gt;.obj&lt;/code&gt; file
and it will make chunks that are flat. You can then modify them, cut in some
places and group others.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/unfolder.CgSrvbFj.png&quot; alt=&quot;Using unfolder&quot;&gt;&lt;/p&gt;
&lt;p&gt;I advice you to spend quite some time in there to think of how the different
tricky parts will be separated. I am not great at it yet, and figuring out ways
to make my life easier afterwards. Typically it seems to be better to have cuts
along long edges - it makes the pasting better.&lt;/p&gt;
&lt;p&gt;You can also look at the 3D render to separate the pieces with different colors
(and use multiple papers of different color).&lt;/p&gt;
&lt;p&gt;Do not forget to enable numbers for flap, use the auto functionality to
optimise the flap sizes and organise the different parts.&lt;/p&gt;
&lt;p&gt;To prepare for the next step we will export into 2 formats: &lt;code&gt;.dxf&lt;/code&gt; for the cuts
and &lt;code&gt;.png&lt;/code&gt; for the print. You can also export a &lt;code&gt;.pdf&lt;/code&gt; if you want to do the
cutting by hand.&lt;/p&gt;
&lt;p&gt;Note that there is an equivalent software for Windows (that seems uglier but
with more features, &lt;a href=&quot;https://tamasoft.co.jp/pepakura-en/&quot;&gt;pepakura&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;third-step-cutting&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#third-step-cutting&quot;&gt;#&lt;/a&gt;Third Step: cutting&lt;/h2&gt;
&lt;p&gt;First, if you do not have a cutting machine and do not want to invest more
money in this project you can print the pdf and then cut by hand. Depending on
the project there can be lots of cuts to make.&lt;/p&gt;
&lt;p&gt;I bought myself a &lt;a href=&quot;https://www.silhouetteamerica.com/shop/cameo&quot;&gt;Silhouette Cameo 4&lt;/a&gt;.
This will make this step way faster.&lt;/p&gt;
&lt;p&gt;In the silhouette studio software import the &lt;code&gt;.png&lt;/code&gt; file (it contains all the
numbers, as well as the marks for folding. You can now import the &lt;code&gt;.dxf&lt;/code&gt; file
and make sure both overlay perfectly.&lt;/p&gt;
&lt;p&gt;Add the alignment marks and then print on the paper of the color you are
interested in. I used 160mg paper - it worked fine for my projects. Note that
with dark color papers you might want to strengthen the black alignment marks
with a marker.&lt;/p&gt;
&lt;p&gt;Once you have the paper printed, we can actually use the silhouette machine. In
the send menu you will select the different lines. Do a first pass for the
scoring marks. You will select only the (blue and green I think) lines for
a first pass as scoring - it should not go though the paper, only make it
easier to fold in the right place.&lt;/p&gt;
&lt;p&gt;Then cut the pieces (the red lines).&lt;/p&gt;
&lt;h2 id=&quot;fourth-step-folding-and-pasting&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#fourth-step-folding-and-pasting&quot;&gt;#&lt;/a&gt;Fourth Step: folding and pasting&lt;/h2&gt;
&lt;p&gt;You now have a bunch of paper cuts. Go though them and fold according to the
lines. Note that for the ‘valley’ folds, start folding them the other way and
then the right way, it will be easier.&lt;/p&gt;
&lt;p&gt;The whole pasting can take time, but I really enjoy the activity, it feels
quite zen.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://carrots.sgenoud.com/_astro/paper-bunnies.BmXEIFqg.jpg&quot; alt=&quot;Paper bunnies&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can discuss this &lt;a href=&quot;https://toot.cafe/@stevegenoud/103690334133991304&quot;&gt;on Mastodon&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>My wishlist for the web</title><link>https://carrots.sgenoud.com/my-wishlist-for-the-web/</link><guid isPermaLink="true">https://carrots.sgenoud.com/my-wishlist-for-the-web/</guid><description>The web is amazing. But it could be better. To put a context, I currently would like to see the web as a full software platform, that compet</description><pubDate>Thu, 25 Apr 2019 06:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The web is amazing. But it could be better.&lt;/p&gt;
&lt;p&gt;To put a context, I currently would like to see the web as a full software
platform, that competes with Windows or iOS in terms of what you could do with
the technologies of the web. So what do I want?&lt;/p&gt;
&lt;h4 id=&quot;more-stylable-builtin-components&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#more-stylable-builtin-components&quot;&gt;#&lt;/a&gt;More stylable builtin components&lt;/h4&gt;
&lt;p&gt;Let’s start with something small.&lt;/p&gt;
&lt;p&gt;Right now, it is not possible to style the checkmark part of a checkbox on the
web. You can create your own and hack something together, sure. But you have to
be very careful not to break things. This should not be the case. There should
be a supported way to do it.&lt;/p&gt;
&lt;p&gt;More importantly, while selects (and datalists) can be styled, the menu that
shows when you open it cannot. There are great alternatives to the native
components (for instance &lt;a href=&quot;https://react-select.com/&quot;&gt;react-select&lt;/a&gt;), but they
cannot be as good a native one for all the cases (and require an important open
source effort to maintain).&lt;/p&gt;
&lt;p&gt;So let us use the builtins by giving us more access to what they look.&lt;/p&gt;
&lt;h4 id=&quot;a-standardised-popperjs&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#a-standardised-popperjs&quot;&gt;#&lt;/a&gt;A standardised Popper.js&lt;/h4&gt;
&lt;p&gt;I really like &lt;a href=&quot;https://popper.js.org/&quot;&gt;popper.js&lt;/a&gt;. It allows me to build
tooltips and other menus without sweating too much. This is something that
should also be part of the platform. Placing an object in relationship to
another is a common interface use case. By offering a native solution we could
have this work better and faster across the web.&lt;/p&gt;
&lt;h4 id=&quot;native-virtual-lists-think-infinite-scroll&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#native-virtual-lists-think-infinite-scroll&quot;&gt;#&lt;/a&gt;Native virtual lists (think infinite scroll)&lt;/h4&gt;
&lt;p&gt;Long lists of items, loaded dynamically. This is the core of most mobile apps.
But we need to reinvent them all the time on the web. And this is far from
something obvious to implement with many edge cases (and also, difficult to
make performant).&lt;/p&gt;
&lt;h4 id=&quot;operator-overloading-for-javascript&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#operator-overloading-for-javascript&quot;&gt;#&lt;/a&gt;Operator overloading for JavaScript&lt;/h4&gt;
&lt;p&gt;Now this is a bit different, a pure javascript need. Operator overloading is
the language feature in javascript that I miss the most from python. Why?.
Guido wrote an &lt;a href=&quot;https://neopythonic.blogspot.com/2019/03/why-operators-are-useful.html&quot;&gt;great
article&lt;/a&gt;
about why operators are important.&lt;/p&gt;
&lt;p&gt;I would add that this feature is what is missing for a good scientific
community on javascript. This is what is missing for a nodejs sqlalchemy.&lt;/p&gt;
&lt;p&gt;People are already &lt;a href=&quot;https://github.com/littledan/proposal-operator-overloading&quot;&gt;working on
it&lt;/a&gt;, cannot wait to
be able to use it!&lt;/p&gt;
&lt;h4 id=&quot;a-bigger-sandbox-for-your-web-apps&quot;&gt;&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#a-bigger-sandbox-for-your-web-apps&quot;&gt;#&lt;/a&gt;A bigger sandbox for your web apps&lt;/h4&gt;
&lt;p&gt;Last (but not least), I would like to be able to build any type of app on the
web. Why is it not possible now?&lt;/p&gt;
&lt;p&gt;First, there is no way to save data on the disk. Yes, IndexedDb is a thing, but
it is not access to a disk in a POSIX way. I would love to be able to compile
SQLite to webassembly and make it run for my app. I would like to have the same
freedom to same bytes with random access on a disk so I can build my own file
format for an audio editing app.
&lt;a href=&quot;https://github.com/WICG/native-file-system&quot;&gt;This&lt;/a&gt; is a nice step in the right
direction.&lt;/p&gt;
&lt;p&gt;Same with network access. Imagine I would like to build a email PWA. Why is it
not possible? Because you cannot have IMAP (or POP) in your browser, because
you cannot access TCP sockets.&lt;/p&gt;
&lt;p&gt;Perhaps when
&lt;a href=&quot;https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/&quot;&gt;WASI&lt;/a&gt;
becomes standard and available on all platform we will start to be there?&lt;/p&gt;
&lt;p&gt;Discuss this post on &lt;a href=&quot;https://toot.cafe/@stevegenoud/101985322842576183&quot;&gt;Mastodon&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Integrate Popper.js in React</title><link>https://carrots.sgenoud.com/use-popper.js-in-react/</link><guid isPermaLink="true">https://carrots.sgenoud.com/use-popper.js-in-react/</guid><description>Edit: You might want to use Floating UI now, the modern successor to PopperJS (by the same team) Until recently I used the library reactpopp</description><pubDate>Mon, 25 Feb 2019 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt;: You might want to use &lt;a href=&quot;https://floating-ui.com&quot;&gt;Floating UI&lt;/a&gt; now, the
modern successor to PopperJS (by the same team)&lt;/p&gt;
&lt;p&gt;Until recently I used the library
&lt;a href=&quot;https://github.com/FezVrasta/react-popper&quot;&gt;react-popper&lt;/a&gt; to add poppers (i.e.
floating elements, anchored to a target) in my pages using
&lt;a href=&quot;https://popper.js.org/&quot;&gt;Popper.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hooks makes it easy to do it yourself directly. With this article you should be
able to take a scaffold of a basic &lt;code&gt;usePopper&lt;/code&gt; hook and modify it for your
specific needs. We follow an approach inspired by react-popper.&lt;/p&gt;
&lt;p&gt;We have a menu component that we want to display next to a target. Because we
can, we introduce an arrow as well. Assuming that we have the components
already built, we need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;initialise Popper.js with references&lt;/li&gt;
&lt;li&gt;retrieve the changed style that it computes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So this is what how our API will look like as well&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PopperComponent&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;targetNode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setTargetNode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;menuNode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setMenuNode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;arrowNode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setArrowNode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;styles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;placement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;arrowStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; usePopper&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    referrenceNode: targetNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    popperNode: menuNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    arrowNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Target&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{setTargetNode}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Portal&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Popper&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{setMenuNode} &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{styles} &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;data-placement&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{placement}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Menu&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Arrow&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{setArrowNode} &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{arrowStyles} /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Popper&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Portal&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that we use &lt;code&gt;useState&lt;/code&gt; and not &lt;code&gt;useRef&lt;/code&gt; to get to the reference of the DOM
node, why?. With &lt;code&gt;useRef&lt;/code&gt; we would not refresh our popper on the change of node
(which would be an issue). Here we actually use a simple version of this
example from the &lt;a href=&quot;https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node&quot;&gt;React
FAQ&lt;/a&gt;,
where the ref function is just a &lt;code&gt;setState&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that I like to use &lt;a href=&quot;https://github.com/tajo/react-portal&quot;&gt;react-portal&lt;/a&gt; to
create a Portal element – it makes sure whatever is in the popper is not
influenced by the styling from parent elements. But this is not strickly
necessary.&lt;/p&gt;
&lt;p&gt;So what does &lt;code&gt;usePopper&lt;/code&gt; look like? If we go with the most simple configuration
we have the following hook.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; usePopper&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  referrenceNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  popperNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  arrowNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  placement,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;popperStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;updatePopperState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; usePopperState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(placement);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; popperInstance&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useRef&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // manage the popper instance lifecycle&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;      // We refresh the popper instance on every config change&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (popperInstance.current) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        popperInstance.current.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;destroy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        popperInstance.current &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;referrenceNode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;popperNode) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      popperInstance.current &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PopperJS&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        referrenceNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        popperNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          placement,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          modifiers: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            arrow: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              enabled: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;arrowNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              element: arrowNode,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            applyStyle: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;              // we manage to apply the styles ourselves&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              enabled: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            updateStateModifier: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              enabled: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              order: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;900&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;              fn: updatePopperState,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;          },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      popperInstance.current.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;enableEventListeners&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        popperInstance.current.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;destroy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        popperInstance.current &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [ arrowNode, referrenceNode, popperNode, placement ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (popperInstance.current) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      popperInstance.current.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;scheduleUpdate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; popperStyles;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What do we do? We have a popper instance that generates a style configuration
on each refresh. This style configuration is part of the state. On every change
of the styles a render will be triggered.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;useEffect&lt;/code&gt; we refresh the configuration of the popper. This means that
poppers will always take into account the latest configuration (or latest
targets if they change).&lt;/p&gt;
&lt;p&gt;Finally we make sure the popper position is always scheduled when the component
is re rendered.&lt;/p&gt;
&lt;p&gt;What does &lt;code&gt;usePopperState&lt;/code&gt; do? It is a simple mapper between what popper.js
returns and what we want to export as the &lt;code&gt;usePopper&lt;/code&gt; API.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; usePopperState&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; placement&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;currentStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useDiffedState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    position: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;absolute&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    top: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    left: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    opacity: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    pointerEvents: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;none&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;currentArrowStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setArrowStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useDiffedState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;currentOutOfBoundaries&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setOutOfBoundaries&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;currentPlacement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setPlacement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(placement);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; updatePopperState&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; updatedData&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      styles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      arrowStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      hide&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;      placement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;updatedPlacement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; updatedData;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    setStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(styles);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    setArrowStyles&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(arrowStyles);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    setPlacement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(updatedPlacement);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    setOutOfBoundaries&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(hide);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; updatedData;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; popperStyles&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    styles: currentStyles,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    placement: currentPlacement,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    outOfBoundaries: currentOutOfBoundaries,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    arrowStyles: currentArrowStyles,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [popperStyles, updatePopperState];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could modify it to allow for a more detailed management of the default
values for both the default style of the popper or the arrow.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;useDiffedState&lt;/code&gt; is a helper hook that allows us to refresh our state only when
necessary (it might be premature optimisation, but hey it was fun). This
exposes the API from &lt;code&gt;useState&lt;/code&gt;, but refreshes objects only if their value is
different.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { useState } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; isEqual &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;lodash/isEqual&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; isFunction &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;lodash/isFunction&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useDiffedState&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; initVal&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;storedValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setStoredValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(initVal);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setValue&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; valueToStore&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; isFunction&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(value) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(storedValue) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    setStoredValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;prevState&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;isEqual&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(prevState, valueToStore)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; prevState;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; valueToStore;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [storedValue, setValue];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is just a start, because Popper.js allows you to configure a lot what
you might want to do. For instance, you might want to configure if the
position is fixed, or work with modifiers.&lt;/p&gt;
&lt;p&gt;You can find a more complete example &lt;a href=&quot;https://github.com/sgenoud/quarolib/blob/master/hooks/usePopper.js&quot;&gt;published
here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Discuss it on &lt;a href=&quot;https://toot.cafe/@stevegenoud/101653871047531737&quot;&gt;Mastodon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt; March 22, 2019: Put the DOM node as state instead of ref, as it can
change. Thanks to &lt;a href=&quot;https://github.com/FezVrasta/react-popper/issues/241#issuecomment-475595288&quot;&gt;this
comment&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Groups of people on the fediverse</title><link>https://carrots.sgenoud.com/federa-groups-for-fediverse/</link><guid isPermaLink="true">https://carrots.sgenoud.com/federa-groups-for-fediverse/</guid><description>Edit: While the code is still on GitHub, Federa is not up anymore. You can play with Guppe that has the same philosophy. People around me us</description><pubDate>Mon, 28 Jan 2019 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; While the code is still &lt;a href=&quot;https://github.com/sgenoud/federa&quot;&gt;on
GitHub&lt;/a&gt;, Federa is not up anymore. You can play
with &lt;a href=&quot;https://a.gup.pe/&quot;&gt;Guppe&lt;/a&gt; that has the same philosophy.&lt;/p&gt;
&lt;p&gt;People around me use &lt;strong&gt;Facebook groups&lt;/strong&gt; a lot. They get lot of value out of them. These groups are used for vague communities organisation. You want to share information about flats to rent in your city? There is a group for that. Try to give out furnitures? Same, a group for that. Exchange tips on how to repair your car? You know where I am going.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mailing lists&lt;/strong&gt; used to fill that need. Why not anymore? It is more difficult to join one, mailing lists tend to have crummy interfaces. An email you receive feels more personal (even when it is not). Generally there is less a sense of community in a mailing list than on Facebook.&lt;/p&gt;
&lt;p&gt;What about &lt;strong&gt;forums&lt;/strong&gt;? The old &lt;a href=&quot;https://www.phpbb.com&quot;&gt;phpBB&lt;/a&gt;. They also tend to be replaced by Facebook groups. Convenience won here mostly. How many people know how to run and update a server to run a Discourse or a phpBB? How many want to pay for it?&lt;/p&gt;
&lt;p&gt;And in both case, the &lt;strong&gt;discovery&lt;/strong&gt; factor is quite important. It is easy to find out about a group a friend shares to (it appears in your timeline) – how would you discover a mailing list a friend is part of? No serendipity in finding a forum either, you need to search for it.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;fediverse&lt;/strong&gt; offers a new possibility to create a tool that is as good as Facebook groups – Mastodon is a social inbox with a familiar interface. We just need to have a concept of group.&lt;/p&gt;
&lt;p&gt;Isn’t there one with (hash)&lt;strong&gt;tags&lt;/strong&gt;? Kind of. But tags are completely informal, they do not appear in your timeline / inbox and, are not federated (as far as I know).&lt;/p&gt;
&lt;p&gt;What about instances as communities? I feel ambivalent about the &lt;strong&gt;local feed&lt;/strong&gt;. In a way it is a great tool to discover new people on my instance. But on the other hand it forces me to be careful about what I share. I want to avoid polluting the feed with things that are not relevant to the community of my instance. Should I create a new identity for each topic I might be interested in?&lt;/p&gt;
&lt;p&gt;So I went and created &lt;strong&gt;something new&lt;/strong&gt; – I called it &lt;a href=&quot;https://federa.site&quot;&gt;Federa groups&lt;/a&gt;. For now it is fairly simple. You log in with your Mastodon identity. Then create a group, let’s call it &lt;em&gt;starwars&lt;/em&gt; for the sake of the example. You (or anyone) just needs to follow this new group within Mastodon then at &lt;em&gt;@&lt;a href=&quot;mailto:starwars@group.federa.site&quot;&gt;starwars@group.federa.site&lt;/a&gt;&lt;/em&gt;. If you mention the group in a toot it will be boosted to all the people following this group.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Federa groups&lt;/strong&gt; is a very simple service for now. There is UX as well as security work to be done for sure. And I can think of many additional feature to add (private groups, search,…).
But first I want to see if the idea has legs. Contact me if you have any feedback on these groups! Tell me why I should keep investing some time in it! Or even better, &lt;a href=&quot;https://github.com/sgenoud/federa&quot;&gt;help me&lt;/a&gt; build it!&lt;/p&gt;
&lt;p&gt;Discuss this &lt;a href=&quot;https://toot.cafe/@stevegenoud/101494848350604036&quot;&gt;on Mastodon&lt;/a&gt;&lt;/p&gt;</content:encoded></item></channel></rss>