How it worksDocsAboutLive demoStar on GitHub
About

Written by one person, in the open.

Virgil is a package that draws on top of someone else’s product and takes their users’ clicks for a moment. That is a lot to ask of a stranger’s dependency, so here is who is asking, and what it is written to.

The author

Simone Fratini

Builds product interfaces and the systems underneath them.

Virgil was built first as an internal companion for a real estate back office, then extracted and rewritten as a standalone package. It started where every product tour dies: more screens than anyone could document, a written walkthrough that was wrong within a month, and the same three questions arriving every week.

The fix people reach for is a scripted tour — a list of selectors and tooltips. It is a promise about an interface that nobody can keep: the first person to rename a button breaks it, silently, and the tour goes on confidently pointing at nothing.

So Virgil writes nothing down. It reads the screen that actually rendered, asks what the user should do next, and points. When the interface changes, there is nothing to update, because there was never a path to begin with.

The rules it is written to.

Every one of these cost something to hold to. They are here because they are the reasons to pick this over the alternative, and because a promise stated in public is one you can be held to.

01

The model can only name what is on screen

It answers with an id from the list the browser just sent, and there is no field for a selector or a label. It cannot point at a button that does not exist, because there is nothing else it is able to say.

02

What the app calls things, not what it shows

A field is reported as filled or empty; its value is not read. Inside a row, a cell, or anything marked data-virgil-data, the text is withheld too — those are described as “a cell in Supplier”. Authored labels do go, so a label that interpolates data is data: that is what redact is for.

03

No account, no telemetry, no vendor

It calls your model key from your own route handler. Nothing phones home — there is no home to phone. The package cannot tell how many people use it, and that is the intended design.

04

It works from the keyboard

The reticle follows focus as well as the pointer, the step is announced to a screen reader, and the panel is a real dialog. A guide that only works for people who can already use the interface is a guide for the wrong audience.

05

It never takes a click it was not given

Inspect mode is a mode, entered on purpose and left with Escape, the same button, or a click outside. It says loudly that it is on, because it is spending the app's own clicks while it is.

06

No dependency is added to be fashionable

No state library, no chat runtime, no icon set, no CSS framework: a state store that ships with React, four lines of getReader(), hand-drawn SVGs and six custom properties. Everything installed here has to earn the install.

It is MIT, and it has no account to sign up for.

Bring your own model key, keep your own data, remove it in an afternoon if it is not for you. If it turns out to be useful, a star is what puts it in front of the next person.