pak::pak("matt-dray/hext") # GitHub-only ________
/ \
/ he \
\ xt /
\________/
tl;dr
The {hext} R package helps you make text-based hex logos.
A simple mind
Call me a normie, but I am an R-hex-logo enjoyer.
I took a step further last year to create my own (limited) hex-making package, {gex}, which I’ve written about before1.
The goal of {gex} was to keep things simple: minimal dependencies, only grid graphics2.
But I was too short-sighted, too small-brained. I went simple, but not simple enough.
Do the simple things well
Yihui recently said ‘bye, hex stickers’.
In his post he discussed an entirely text-based hex logo for {litedown}. Charlie Gao’s {secretbase}3 has also joined the text revolution.
The spirit of these packages is minimalism. Their logos match this aesthetic.
Simplicity is a probably a good goal in general.
So, naturally, I have overengineered a simple thing to make it simple for you to not think about the complication behind such a simple thing.
Next: text hext
{hext} lets you write text-based logos.
You could install like:
There is only one function: hext(). Very simple, very demure.
Hex outputs have four lines4. You can add text and specify alignment for each of these.
hext::hext(
"keep", "it", "simple,", "silly",
"left", "centre", "right", "left"
) ________
/keep \
/ it \
\ simple,/
\silly___/
hext() handles character padding and line-length limits on your behalf. It tries its best with Unicode (like emoji)5, but rendering is hard6.
That’s it, really.
Hexagone
Think less, say less.
Environment
Session info
Last rendered: 2026-02-22 21:01:02 GMT
R version 4.5.1 (2025-06-13)
Platform: aarch64-apple-darwin20
Running under: macOS Sequoia 15.6.1
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: Europe/London
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
loaded via a namespace (and not attached):
[1] htmlwidgets_1.6.4 compiler_4.5.1 fastmap_1.2.0 cli_3.6.5
[5] tools_4.5.1 htmltools_0.5.8.1 yaml_2.3.10 stringi_1.8.7
[9] rmarkdown_2.29 knitr_1.50 jsonlite_2.0.0 xfun_0.52
[13] digest_0.6.37 rlang_1.1.6 hext_0.1.0 evaluate_1.0.4
Footnotes
You know who you are, dear one-user-who-isn’t-me↩︎
The irony being that the original iteration—called {hexbase}—was even simpler. Dependency-free, in fact.↩︎
See-also the namesake YouTube channel for sports videos. And documentaries about the history of slipping on banana peels.↩︎
The community seems divided on the number of characters per row. Like Charlie, I have opted for 8-10-10-8 top-to-bottom, which gives a little extra character space, even if makes the hexagon look a little more plump.↩︎
This works via
nchar(x, type = "width")(orstringi::stri_width()if you have {stringi} installed), rather than the defaultnchar(x, type = "chars"). The smiley emoji has a width of2, but is1character long, for example. Obviously this impacts the whitespace padding thathext()needs to apply. If this is bothersome, you can use the argumentcount_typeinhext()to switch between these counting modes.↩︎‘It may look ugly, especially on Windows’, to quote Yihui’s post. If your logo is borked somewhere then… c’est la vie.↩︎