Alph Simple Selectors
Draft P3N
The Alph Hypertext System Project: <http://alph.io>
This document indexed at: <http://alph.io/index.html>
©2025 Adam C. Moore (LÆMEUR) <mailto:adam@laemeur.com>
In Alph we use some simple numeric fragment selectors for addressing, linking, and transclusion of "flat" media — text, images, audio, and video streams.
A great mess of heterogeneous fragment selectors/schemes already exist for a variety of media types[1], but rather than try to implement a motley rabble of nominal "standards", we designed the Alph Simple Selectors to be terse, easy to parse, and to provide a baseline addressing capability for common media types.
There are three fragment types: POINT, RANGE, and and AREA; and each fragment type has two selectors: INTEGER, and FLOAT[2]. Here's the whole list, with examples of what they look like:
POINT Selectors
Form: #index
-
intPoint — ex.: http://host/path/file#123
-
floatPoint — ex.: http://host/path/file#123.456
RANGE Selectors
Form: #origin-extent
-
intRange — ex.: http://host/path/file#12-34
-
floatRange — ex.: http://host/path/file#12.34-56.78
AREA Selectors
Form: #originX,originY[,originZ][...]-extentX,extentY[,extentZ][...]
-
intArea — ex.: http://host/path/file#12,34-56,78
-
floatArea — ex.: http://host/path/file#12.34,56.78-91.23,456.78
These selectors all dereference easily from a URL, and can be identified by a regular expression match:
- intPoint test:
/\d+/
- floatPoint test:
/\d+\.\d+/
- intRange test:
/\d+-\d+/
- floatRange test:
/\d+\.\d+-\d+\.\d+/
- intArea test:
/(\d+,)+\d+-(\d+,)+\d+/
- floatArea test:
/(\d+\.\d+,)+\d+\.\d+-(\d+\.\d+,)+\d+\.\d+/
These tests are STRICT. Ints and floats are not to be mixed in the same selector. For example, these are valid selectors:
#123-456 intRange
#123.0-456.0 floatRange
But this is not:
#123.0-456
On The POINT Selectors (intPoint, floatPoint)
POINT selectors are the simplest of the Simple Selectors and are, as you might have inferred already, for numerically referencing an individual point or segment in a stream or collection of media.
As point selectors are zero-length and do not refer to a fragment of media, they may be used to represent a bookmark, play position, cursor location, insertion point, etc..
On The RANGE Selectors (intRange, floatRange)
RANGE selectors are for referencing a contiguous portion of media with a numeric point-to-point range. This may represent a word, sentence, or paragraph in a plain text, or a clip from an audiovisual recording, &c..
To be clear, the length of the resulting media fragment will be equal to the origin point subtracted from the extent. For example:
http://host/path/file#5-10
Applied to the following text:
This is a test string.
Refers to the five characters between index 5 and index 10:
0 5 10
| |---------|
.T.h.i.s. .i.s. .a. .t.e.s.t.
On The AREA Selectors (intArea, floatArea)
AREA selectors are for referencing a rectangular, cubic, or n-dimensional section of a media resource. As with the POINT and RANGE selectors, the indices in the selector are zero-based. The most obvious application for an AREA selector is for specifying a rectangular section of an image.
But WHAT ARE THE UNITS?!
Yes, the numbers in a selector will represent different things when applied to different media types. The prescribed media-specific UNITS follow.
For text/* media types:
intPoint
— The intPoint represents a zero-based index into the Unicode CODEPOINTS of the text – not the bytes. Legacy/regional text encodings aren't supported at the moment, but they should be treated in the same way — i.e., codepoints are what matter here, regardless of the number of bits required to encode each one.
floatPoint
— n/a
intRange
— The intRange represents the string between two zero-based indices into the Unicode CODEPOINTS of a text.
floatRange
— n/a
intArea
— n/a
floatArea
— n/a
For image/* media types:
intPoint
— The intPoint represents a zero-based index into the PAGES of a multi-page image, or the LAYERS of a single-page, multi-layer image.[3]
floatPoint
— n/a
intRange
— The intRange represents the PAGES between two zero-based indices into a multi-page image, or the LAYERS of a single-page multi-layer image.
floatRange
— n/a
intArea
— A two-dimensional intArea represents a rectangular section of the image. The format for this is [X origin],[Y origin]-[X extent],[Y extent], where each of those values represents a zero-based index into the CSS PIXELS of the image. Yes, that's right, CSS pixels, which are locked at 96ppi. If the source image has a native resolution greater or lesser than 96ppi, the client should be making the calculations to either crop the source appropriately, or verify that a fragment sent by the server is matching-up with what's expected.[4]
floatArea
— TBD. I'm open to suggestions. A two-dimensional floatArea could be used to address an image rectangle in physical measurements like centimeters or inches, certainly.
For audio/* media types:
intPoint
— The intPoint represents a zero-based index into the SAMPLES of a PCM audio stream.
floatPoint
— The floatPoint represents a zero-based index into the SECONDS of the audio recording.
intRange
— The intRange represents the audio between two zero-based indices into the SAMPLES of a PCM audio stream.
floatRange
— The floatRange represents the audio between two zero-based indices into the SECONDS of the audio stream.
intArea
— TBD. One possibility is that one dimension of the area could specify duration in PCM samples, while a second dimension could specify the channel of a multi-channel audio stream; ...
floatArea
— TBD. Could be anything, but does it need to be?
For video/* media types:
intPoint
— The intPoint represents a zero-based index into the FRAMES of a video stream.
floatPoint
— The floatPoint represents a zero-based index into the SECONDS of the audio recording.
intRange
— The intRange represents the video between two zero-based indices into the FRAMES of a video stream.
floatRange
— The floatRange represents the video between two zero-based indices into the SECONDS of the video streams.
intArea
— TBD. One possibility is that a three-dimensional intArea could be used to specify a duration (in frames) as well as a cropping rectangle in native pixels.
floatArea
— TBD. Suggest something!
Footnotes
1. At an earlier stage in this project I was interested in adopting the W3C's Web Annotation Data Model as my linking model, which has an interesting selection of well-documented selectors (for just the selectors, see the Selectors and States reference note: <https://www.w3.org/TR/selectors-states/>). However, these selectors are nice in a JSON-LD context but they don't stringify to a human-readable one-line IRI very well, which is one of my key design criteria.
1a. Since the previous draft of this document, Chrome introduced the Text Fragment selector scheme in Chrome 80, which is similar to the Text Quote selector in the aforementioned W3C reference note, and which has widespread browser support now. It's pretty handy when dealing with Web pages, but it's not xanalogical and I won't be adding any support for it.
2. The *Normal selectors from draft J86 of this document are all DEPRECATED.
Because resources may GROW (for example, text resources are appended-to all of the time), the *Normal selectors, which are proportional to the content size, are not reliable selectors. The media that a *Normal selector points-at one day may not be the same media the next. That's contrary to the entire rationale of this system.
3. Not really any use-cases for image/* intPoint or intRange, I know. Multi-page TIFF images are supported in Safari and nowhere else, and while these integers could refer to the frames in a GIF, AVIP, WEBP, or APNG ... is there much of a use-case for that? Perhaps. And as far as multi-LAYER images with browser support go...
4. IMPLEMENTATION NOTE/admission of guilt: I am not currently doing this properly in the Docuplextron. Alph.py IS reporting pixelDensity for images on the server, so the pieces are in place for doing this right, I just have to code it.