Text hex logos with {hext}

hext
r
Author

Matt Dray

Published

February 15, 2026

  ________
 /        \
/   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:

pak::pak("matt-dray/hext")  # GitHub-only

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

  1. You know who you are, dear one-user-who-isn’t-me↩︎

  2. The irony being that the original iteration—called {hexbase}—was even simpler. Dependency-free, in fact.↩︎

  3. See-also the namesake YouTube channel for sports videos. And documentaries about the history of slipping on banana peels.↩︎

  4. 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.↩︎

  5. This works via nchar(x, type = "width") (or stringi::stri_width() if you have {stringi} installed), rather than the default nchar(x, type = "chars"). The smiley emoji has a width of 2, but is 1 character long, for example. Obviously this impacts the whitespace padding that hext() needs to apply. If this is bothersome, you can use the argument count_type in hext() to switch between these counting modes.↩︎

  6. ‘It may look ugly, especially on Windows’, to quote Yihui’s post. If your logo is borked somewhere then… c’est la vie.↩︎

Reuse