Edition 1.0-draft. This is a living document; the edition stamp identifies the vocabulary and fixture set that the Agent Skill [AGENT-SKILLS] and the conformance suite refer to.
1. Introduction
This section is informative.
A JAI document is an image compressed into words: a natural-language description and, optionally, a few rendering parameters, from which a generative model reconstructs the picture. The description is the code; the model is the decoder. Two decoders produce different pixels, but the same image in meaning and appearance, in the way two JPEG decoders produce slightly different pixels from the same file, only much further along the same curve.
The simplest JAI document is a sentence:
Parameters follow the description, separated by semicolons:
The same document has a JSON form and a compressed file form, and all three are the same document:
jai:A magical castle;model=flux;style=animeJSON form:
File form: the JSON above as a single gzip member, in a file named{ "jai" : 1 , "prompt" : "A magical castle" , "model" : "flux" , "style" : "anime" }
castle.jai, served as image/jai, or embedded as data:image/jai;base64,….
1.1. Motivation
This section is informative.
1.1.1. A description is compression
Every image format trades bits for distortion. JPEG discards detail the eye will not miss; JAI keeps only what a person would say about the picture and discards the rest. In the terms of rate–distortion theory it sits at the far low-rate end of the same curve: a typical document is 50 to 500 bytes for an image of any resolution, against tens of kilobytes to megabytes for a raster, and its distortion is measured in meaning and appearance (does the result show the same things, arranged and lit the same way) rather than in pixel error.
This works because the decoder carries a prior. A generative model has learned what harbours, castles and dusk light look like, so the code only has to say which ones, where and how. Speech coding has relied on the same idea for decades: a vocoder transmits the parameters of a model of the voice instead of the waveform, and a CELP encoder finds those parameters by running the decoder inside the encoder and keeping what sounds closest. JAI encoding is the same analysis by synthesis (§ 10 Encoding images): an image encoder describes an image, renders the description with the target models, compares the renders with the original, and revises the description until they match as closely as time and budget allow. A document can carry a core description shared by all models plus small per-model refinements, so that each decoder in its preference list reconstructs the image as well as it can.
The rate–distortion trade-off is the author’s to choose: a sentence for a decorative image, a few precise paragraphs for one whose look matters.
1.1.2. Where it matters
JAI is designed for a world where generating an image is cheap and local, and moving one is not.
-
Links with little bandwidth and enough compute. Spacecraft and deep-space links, ships, aircraft, satellite connections with data caps, rural networks, disaster zones, and text-only channels such as SMS, packet radio and mesh networks can carry a sentence where they cannot carry a photograph. A receiver with a GPU reconstructs the picture.
-
Local generation. Image generation is moving onto commodity GPUs and phones, at well under a second per image. When decoding is local and free, a browser can choose the JAI source in a
<picture>element and never download the raster (§ 11.1 Carriers); pages get lighter with no change to their markup. -
An audience of one. Because the reader’s own decoder produces the pixels, the reader can ask for them differently: adapted to their culture, softened for sensitive content, adjusted for their eyesight, in the language of the text inside the image, or simply in a mood or style they enjoy, while the author’s description stays the same (§ 11.5.3 Personalisation).
-
Longevity and resolution independence. A description does not age with its codec and has no fixed resolution. Rendered next year by a better model, or at a higher resolution, the same document yields a better picture, much as vector graphics outlive the screens they were drawn for.
-
Text all the way down. A JAI image can be searched, translated, diffed in version control and edited with a text editor; it carries its own text alternative for screen readers and text-only browsers; and language models and agents can read and write images in the medium they already use.
-
Honest provenance. A JAI image is generated by construction, so it cannot be mistaken for a photograph of something that happened.
Today, rendering usually runs on hosted providers through an API key. That is the stage this edition is published in: good for demonstrations and for personal renders, and the reason the security section spends so much care on consent, budgets and what leaves the browser (§ 13 Security and privacy considerations). The format does not depend on it.
1.2. What JAI is and is not
This section is informative.
JAI describes visual intent, not pixels. It does not specify a neural network, a sampler, a provider, or exact output. A decoder produces an image consistent with the description, not the image; the encoder can only reduce the distortion, never remove it. Decoding is non-deterministic across decoders, versions, hardware and time. With hosted providers, as today, it may also take seconds, cost money, and be refused by a provider’s content policy, and it has side effects that no other image format has: it transmits the document, and possibly an input image, to a renderer, under the account of the person viewing it.
Every JAI document also has a textual rendering that is instant, free and
always available: its description, the prompt values joined with line
breaks. A user agent that will not render pixels presents that instead.
Where exact pixels matter more than size, such as evidence, medical images,
diagrams and screenshots of text, ship the raster. JAI can still travel
alongside it as the editable, searchable source: HTML’s <picture> element
carries both (§ 11.1 Carriers).
1.3. Audiences
This section is informative.
This specification is written for six audiences: people and AI agents who write JAI; authoring tools that convert images to JAI or validate it; library developers implementing parsers and serialisers; extension developers adding parameters or renderers; browser and extension developers implementing discovery, rendering and replacement; and renderer developers turning a JAI document into a picture. Sections § 5 Text form through § 7 File form, media type and decoding are the parts a library developer needs; § 8 Standard parameters and § 9 Rendering are for renderer developers; § 11 HTML and URL integration is for browser, extension and web developers; and § 15 Writing JAI by hand is a plain-language primer for authors.
2. Conformance
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. The same words in lower case have their ordinary English meaning.
Everything in this specification is normative except sections marked informative, examples, notes, and the appendices so marked.
2.1. Conformance classes
This specification defines requirements for the following classes. An implementation may belong to several.
- conforming document
-
A JAI document in any of its forms that satisfies every requirement placed on documents and authors (§ 4 Data model, § 5 Text form, § 6 JSON form, § 7 File form, media type and decoding, § 8 Standard parameters, § 11 HTML and URL integration).
- parser
-
Converts the text form to a document (§ 5.4 Parsing).
- JSON reader
-
Converts the JSON form to a document (§ 6.3 Reading).
- decoder
-
Converts the bytes of a
.jaifile, animage/jairesource, or the body of adata:image/jaiURL to a document (§ 7.4 Decoding). A decoder contains a parser and a JSON reader. - serialiser
-
Produces the canonical text form and the canonical JSON form of a document (§ 5.5 Canonical text serialisation, § 6.4 Canonical JSON).
- encoder
-
Produces the file form (§ 7.2 Encoding). An encoder contains a serialiser.
- validator
-
Reports advisory diagnostics about a document or its carrier (§ 14 Diagnostics).
- interpreter
-
Derives the interpreted parameters of a document from its values (§ 8.1 Interpretation). Every renderer and every viewer contains an interpreter.
- renderer
-
Produces an image from a document (§ 9 Rendering).
- viewer
-
Software acting for a user that discovers JAI documents in content, decides whether and when to render them, and presents the result: a browser, a browser extension, a chat client, an image viewer (§ 11 HTML and URL integration, § 11.5 Viewer requirements, § 13 Security and privacy considerations).
- authoring tool
-
Software that produces or edits JAI documents on behalf of an author.
2.2. Determinism
Parsing, reading and decoding are total and deterministic: for every input, including malformed input, a conforming implementation produces a document (possibly empty) and a set of diagnostics, and two conforming implementations produce the same document and the same parser-level diagnostics for the same input. Error recovery is therefore specified, not left to implementations. Nothing in this specification may throw, abort or produce a partial result on malformed input. The guarantee covers inputs within the minimum bounds of § 13.1 Untrusted input and bounds; beyond them, an implementation that applies its bound yields the empty document with the diagnostic named there.
2.3. Conformance test suite
The repository at github.com/gnistai/jai
holds machine-readable fixtures under tests/ (§ 14.1 Conformance fixtures). The fixtures
are normative: where the fixtures and the prose of this specification
disagree, the fixtures are correct and the prose has a bug. An implementation
may claim conformance for a class when it passes every fixture of that class
("JAI 1.0-draft conforming parser").
| Conformance class | Fixture classes it must pass |
|---|---|
| parser | parse (documents and diagnostics)
|
| JSON reader | json
|
| decoder | parse, json, decode, and the url cases of kind data
|
| serialiser | serialize (text, bare, json, identity), and roundtrip except the file form
|
| encoder | as serialiser, plus serialize url and the file form of roundtrip
|
| interpreter | interpret
|
| viewer | html, url (all kinds), and everything required of a decoder and an interpreter
|
| validator | the advisories and no_advisories of every case
|
Renderers, authoring tools and conforming documents have no fixtures in this edition.
3. Terminology
- document
-
An instance of the data model (§ 4 Data model): a map from keys to lists of values, describing one image.
- key
-
The name of a parameter: an ASCII string matching the key grammar.
- value
-
One string assigned to a key. A key may have several values, in order.
- parameter
-
A key together with its values.
- standard key
-
One of the eleven keys defined in § 8 Standard parameters.
- prompt
-
The values of the key
prompt: the description of the image. - description
-
The textual rendering of a document: its prompt values joined with U+000A LINE FEED, in order.
- text form
-
The human-readable serialisation of a document (§ 5 Text form):
jai:A magical castle;style=anime. - JSON form
-
The JSON serialisation of a document (§ 6 JSON form).
- file form
-
The gzip-compressed JSON form (§ 7 File form, media type and decoding); the content of a
.jaifile. - canonical form
-
The unique text form or JSON form a serialiser produces for a document (§ 5.5 Canonical text serialisation, § 6.4 Canonical JSON).
- identity
-
The SHA-256 digest of a document’s canonical JSON form (§ 6.5 Identity).
- JAI whitespace
-
Exactly the 25 code points that have the Unicode
White_Spaceproperty: U+0009 TAB, U+000A LF, U+000B VT, U+000C FF, U+000D CR, U+0020 SPACE, U+0085 NEL, U+00A0 NO-BREAK SPACE, U+1680 OGHAM SPACE MARK, U+2000 to U+200A inclusive, U+2028 LINE SEPARATOR, U+2029 PARAGRAPH SEPARATOR, U+202F NARROW NO-BREAK SPACE, U+205F MEDIUM MATHEMATICAL SPACE and U+3000 IDEOGRAPHIC SPACE. No other code point is whitespace for the purposes of this specification. U+FEFF is not whitespace. - trim
-
To remove every leading and trailing JAI whitespace code point from a string.
String.prototype.trim(JavaScript),str.strip()(Python),String.trim()(Java) and the regular-expression class\seach remove a different set of code points, and none of them removes exactly this set; Go’sstrings.TrimSpacehappens to match. Implementations use the list. - ASCII lowercase
-
The string with every code point in the range U+0041 (A) to U+005A (Z) replaced by the code point 32 greater, and no other change [INFRA].
- ASCII case-insensitive
-
Two strings match ASCII case-insensitively when their ASCII lowercase forms are identical [INFRA]. Implementations MUST NOT use locale-sensitive case mapping or Unicode case folding anywhere in this specification: under those, U+0130 (İ), U+0131 (ı) and U+212A (KELVIN SIGN) would match ASCII letters.
- scalar value string
-
A string of Unicode scalar values, that is, a string containing no surrogate code points [INFRA].
- author
-
Whoever wrote a document.
- publisher
-
The site or channel that delivers a document to a user. On a site that accepts user content the author and the publisher are different parties.
- user
-
The person on whose behalf a viewer renders a document, and under whose renderer account the pixels are produced.
- original image
-
Pixels that accompany a document in its carrier: the
<img>element’s own image in HTML, or the image named by thesourcekey (§ 8.1.7 source). - carrier
-
A place in a host format where a document is found (§ 11.1 Carriers).
- JAI context
-
The content of a
.jaifile, of a resource served asimage/jaior referenced from a carrier, or the body of adata:image/jaiURL. Attribute carriers are not JAI contexts: they always hold the text form. - provider
-
A service that runs a model for a renderer.
- layout box
-
The box HTML lays out for an element, from its attributes and CSS.
- advisory
-
Of a parameter: a preference the author expresses, which a renderer or viewer honours when it can and ignores, with a diagnostic, when it cannot; an advisory value never selects anything the user has not configured and never overrides a user setting.
4. Data model
A document is an ordered map from keys to lists of one or more values. The order of values within a key is significant; the relative order of distinct keys is not significant and carries no meaning.
A document describes exactly one image.
4.1. Keys
The key grammar is, in ABNF [RFC5234]:
key = name [ "/" target ] name = segment * ( "." segment ) target = segment segment = ALPHANUM * ( ALPHANUM / "_" / "-" ) ALPHANUM = %x61-7A / DIGIT ; a-z, 0-9
A key is a name, a non-empty sequence of segments separated by single full
stops, optionally followed by / and a target, one segment. Each segment
starts with a lowercase ASCII letter or digit and continues with lowercase
ASCII letters, digits, _ and -. A key with a target, such as
prompt/flux, is a qualified key: it holds refinements for
the models that target names (§ 8.3 Per-model refinements). Only the names
prompt, style and avoid take a target in this edition; parsers and
serialisers keep other qualified keys unchanged, and validators report them
with invalid-qualifier.
Keys are compared for equality after ASCII lowercase conversion: readers convert every key they receive to ASCII lowercase before anything else, so a document never contains two keys that differ only in case.
Keys without a . are reserved for this specification (§ 12 Extensibility).
The key jai is reserved and is never a parameter: in the JSON form the
member named jai identifies the object as a JAI document (§ 6.2 The jai marker);
in the text form an assignment to jai is dropped (§ 5.4 Parsing).
constructor is a valid key, and __proto__, while
not a valid key, is a valid JSON member name.
4.2. Values
A value is a non-empty scalar value string that does not begin or end with JAI whitespace and does not contain U+000D CARRIAGE RETURN or U+0000 NULL.
Every reader of every form applies the following value normalisation to each candidate value before it enters the document, in this order:
-
Replace every surrogate code point with U+FFFD REPLACEMENT CHARACTER.
-
Replace every U+000D U+000A pair, and then every remaining U+000D, with U+000A.
-
Replace every U+0000 with U+FFFD. (Other control characters are kept as content; validators report them, see § 14 Diagnostics. Byte inputs never reach this step with U+0000: § 7.4 Decoding rejects the byte 00.)
-
Trim the string.
-
If the result is empty, discard the candidate and emit the diagnostic
empty-value; otherwise the result is the value.
Values are strings and only strings. Numbers, booleans and structured data
exist only as their spelling (strength=0.6, animate=true); this is what
makes the text form able to represent every document.
No Unicode normalisation is applied anywhere in this specification. Two
strings are the same value if and only if they consist of the same sequence
of code points; canonically equivalent texts (for example NFC and NFD
spellings of the same word, or U+037E GREEK QUESTION MARK and ;) are
different values and yield different identities. Parsers MUST NOT
normalise their input.
4.3. Standard keys and repetition
A document may assign any number of values to any key; the data model does not
know which keys are single-valued. The standard keys aspect, mode,
strength, seed, source, preview and animate are single-valued at
interpretation: an interpreter uses the last value and reports
repeated-single (§ 8.1 Interpretation). Parsers and serialisers
keep every value; identity and round-tripping depend on all of them.
5. Text form
The text form is a string. It is used wherever a string fits: HTML
attributes, the body of a data:image/jai URL, chat messages, clipboards and
documentation.
5.1. Grammar
*This grammar is informative; the algorithm in § 5.4 Parsing is normative.*
jai-text = OWS [ prefix ] [ text-segment * ( ";" text-segment ) ] [ ";" ] prefix = %s"jai:" OWS ; "jai:" is ASCII case-insensitive text-segment = assignment / prose assignment = OWS key-ci OWS "=" value ; key-ci: the key grammar, ASCII case-insensitive prose = value value = * ( escape / vchar ) escape = "\" ( ";" / "=" / "\" ) vchar = <any scalar value except ";" and "\" >/ "\" <not followed by ";" ,"=" or "\" >OWS = * ( <JAI whitespace >)
A segment is an assignment if it matches assignment; otherwise it is prose.
A \ that does not begin an escape is an ordinary character.
5.2. Structure
-
The optional prefix
jai:marks a string as JAI. It is required where the context does not already establish JAI (analtattribute, a chat message); it is optional where the context does (adata-jaiattribute, the body of adata:image/jaiURL, a.jaifile). -
Segments are separated by unescaped
;. A segment whose text before its first unescaped=is, after trimming, a key is an assignment of the rest of the segment to that key. Every other segment is prose. -
The first prose segment is the prompt. Any later prose segment is a continuation: it belongs to the most recently assigned value, with the
;that preceded it restored. This is what lets ordinary semicolons appear in descriptions without escaping. -
Empty segments and segments consisting only of JAI whitespace are ignored, so a trailing
;and a doubled;;are harmless. -
Three escape sequences exist:
\;is a literal semicolon,\=a literal equals sign,\\a literal backslash. A backslash before any other character is itself literal, soC:\Usersneeds no escaping. -
Keys are ASCII case-insensitive;
Style=animeandstyle=animeare the same assignment. Values are never case-converted. -
Whitespace around keys, around
=and at the ends of values is ignored; whitespace inside values is preserved.
| Input | Document |
|---|---|
A magical castle
| prompt = A magical castle
|
jai:A magical castle;style=anime;model=flux;model=sdxl
| prompt = A magical castle; style = anime; model = flux, sdxl
|
prompt=A magical castle
| prompt = A magical castle
|
model=flux;prompt=A magical castle
| model = flux; prompt = A magical castle
|
A wizard stands in a doorway; behind him, a dragon sleeps;model=flux
| prompt = A wizard stands in a doorway; behind him, a dragon sleeps; model = flux
|
A castle ; style = anime ;
| prompt = A castle; style = anime
|
source=data:image/webp;base64,UklGRkI=;style=anime
| source = data:image/webp;base64,UklGRkI=; style = anime (base64,… is not an assignment)
|
; my key=value
| prompt = my key=value (my key contains a space and is not a key; the leading ; yields empty-segment)
|
http://example.org/?a=b
| prompt = http://example.org/?a=b (: and / are not key characters)
|
Draw a graph\; y=2x
| prompt = Draw a graph; y=2x
|
E\=mc2 explained
| prompt = E=mc2 explained
|
5.2.1. Sharp edges
This section is informative.
The assignment rule is deliberately simple, and five consequences are worth knowing. Validators report each of them (§ 14 Diagnostics).
-
A description that begins with a word, an equals sign and more text is an assignment:
E=mc2 explainedassignsmc2 explainedto the keye. Writeprompt=E=mc2 explainedorE\=mc2 explained. -
Prose after an assignment continues that assignment, not the prompt:
style=anime;A castlehas no prompt and the styleanime;A castle. Write the description first, or introduce it withprompt=. A new line does not start a parameter either; one-parameter-per-line layouts need;at the line ends. -
Whitespace is allowed around
=, soA chalkboard; e = mc2 written on itassigns toe. Writee \= mc2. -
A
data:URL whose media type carries parameters (;charset=utf-8,;name=a.png) contains;key=and is split there. Escape those semicolons (data:image/svg+xml\;charset=utf-8,…); the canonical serialiser does so. A plaindata:…;base64,URL needs nothing, becausebase64,…is not an assignment. -
A word,
/, a word and=after a semicolon is a qualified key:A ratio; a/b=cassignsctoa/b. Writea/b\=cto keep it as text.
5.3. Escaping arbitrary text
An authoring tool or template that places text it did not write into a
document MUST protect it. The function escape-prose(s) replaces
every \ with \\, then every ; with \; and every = with \=. For any
string s whose value normalisation is s itself, the segment
prompt=escape-prose(s) parses as exactly one prompt value equal to s, and
key=escape-prose(s) as one value of key.
The prompt= is part of the recipe: a bare first segment that begins with
jai: would lose those characters to prefix removal.
data-jai="prompt=Red mug\; model\=XZ-200\; colour\=red;style=product photo"parses to prompt =
Red mug; model=XZ-200; colour=red and style =
product photo. Without escaping, model and colour would have become
parameters and the prompt would have been cut short.
5.4. Parsing
The text parsing algorithm takes a string input and returns a document and a list of diagnostics. Transport decoding (percent-decoding, HTML attribute decoding) has already happened (§ 11.2 Transport decoding); the algorithm never decodes anything.
-
Let diagnostics be an empty list and doc an empty document.
-
Replace every surrogate code point in input with U+FFFD.
-
While input begins with U+FEFF, remove it.
-
Replace every U+000D U+000A pair in input, then every remaining U+000D, with U+000A.
-
Skip leading JAI whitespace: let i be the index of the first code point of input that is not JAI whitespace, or the length of input.
-
If input from i begins with the four code points
jai:compared ASCII case-insensitively, advance i past them. -
Split input from i into raw segments: scan left to right; a
\followed by any code point consumes both code points as part of the current raw segment; an unescaped;ends the current raw segment and starts a new one; the end of the input ends the last raw segment. Raw segments keep their escape sequences and their whitespace. -
Let pending be an empty list of (key, raw text) pairs and let current be null.
-
For each raw segment raw, in order:
-
If raw is empty or consists only of JAI whitespace: unless raw is the last raw segment, append
empty-segmentto diagnostics; in either case continue with the next raw segment. (A trailing delimiter is allowed and not diagnosed; an interior empty segment is ignored with a diagnostic.) -
Let eq be the index of the first
=in raw that is not preceded by a\that is part of an escape sequence, determined by the same left-to-right scan as step 7. -
If eq exists and the trimmed text of raw before eq matches the key grammar after ASCII lowercase conversion:
-
Let key be that ASCII-lowercased text and rest the text of raw after eq.
-
If key is
jai: appendreserved-keyto diagnostics; set current to a discarded pair that is not in pending; continue. -
Append the pair (key, rest) to pending and set current to it.
-
-
Otherwise, if current is null: append the pair (
prompt, raw) to pending and set current to it. -
Otherwise: append
;followed by raw to the raw text of current. (If current is the discarded pair, the text is dropped with it.)
-
-
For each pair (key, text) in pending, in order:
-
Let unescaped be text with every escape sequence
\;,\=,\\replaced by its second character, scanning left to right so that\\;(two backslashes, then a semicolon) yields\followed by an unescaped;. -
Apply value normalisation to unescaped. If it yields a value, append that value to the list for key in doc; otherwise the diagnostic
empty-valuehas been emitted.
-
-
Return doc and diagnostics.
Trimming happens once, in step 10, so interior spacing around restored
semicolons is preserved exactly as typed (A wizard ; behind stays
A wizard ; behind), except that an ignored empty or whitespace-only segment
disappears together with one delimiter (A; ;b becomes A;b; write
A\; \;b to keep it).
The result is deterministic for every input and the algorithm runs in time linear in the length of the input.
| Input | Document | Diagnostics |
|---|---|---|
jai:
| empty | |
;;
| empty | empty-segment ×2
|
A castle;style=
| prompt = A castle
| empty-value
|
k=;a
| k = ;a (the empty assignment was continued)
| |
jai:jai=1;prompt=x
| prompt = x
| reserved-key
|
jai:A castle;jai=2;more
| prompt = A castle (more continued the dropped assignment)
| reserved-key
|
jai:A castle
| prompt = A castle
| |
jai: jai:A castle
| prompt = jai:A castle (the prefix is removed once)
| |
JAİ:A castle (U+0130)
| prompt = JAİ:A castle (not the prefix)
| |
a\=b
| prompt = a=b
| |
A; ;b
| prompt = A;b
| empty-segment
|
a\\;style=x
| prompt = a\; style = x
| |
a\;style=x
| prompt = a;style=x
| |
mode=transform;style=anime
| mode = transform; style = anime (a document without a prompt is valid)
|
5.5. Canonical text serialisation
A serialiser takes a document whose keys and values satisfy § 4 Data model and produces one string. Serialisers MUST reject or normalise input that does not satisfy the data model (keys not lowercase, values not normalised).
-
Let out be
jai:. -
Let segments be an empty list.
-
For each value v of the key
prompt, in order: if it is the first prompt value and v does not match the assignment pattern (optional JAI whitespace, a key, optional JAI whitespace,=, matched ASCII case-insensitively at the start of v), append escape-value(v) to segments; otherwise appendprompt=followed by escape-value(v). -
For each qualified key whose name is
prompt, in ascending order of key by code point, for each of its values v in order: append the key,=, and escape-value(v) to segments. -
For each remaining key, in ascending order of key by code point, for each of its values v in order: append the key,
=, and escape-value(v) to segments. -
Join segments with
;, append the result to out, and return out.
escape-value(v) is one left-to-right pass over v that inserts a
\ before:
-
a
\that is immediately followed by;,=or\, or that is the last code point of v (the serialiser, or a later concatenation, will place a delimiter after it); -
a
;that is the first code point of v, or that is followed by optional JAI whitespace and then either the end of v, another;, or a key followed by optional JAI whitespace and=.
Each decision looks at the original v, never at text already escaped. As an
ECMAScript regular expression, with WS standing for the JAI whitespace
class and KEY for the key grammar (case-insensitively):
v. replace( /\\(?=[;=\\]|$)|^;|;(?=WS*(?:$|;|KEY WS*=))/gi , m=> '\\' + m)
WS and KEY are placeholders for the class and the pattern to substitute.
Implementations that escape in two passes MUST escape backslashes first. =
is never escaped by the serialiser; the prompt= form protects the one place
where it matters.
This escaping is deterministic and regular; it escapes a superset of the characters that would be significant and is not the shortest possible encoding. The canonical form of ordinary prose stays readable:
| Document | Canonical text |
|---|---|
prompt = A wizard stands; behind him, a dragon; model = flux
| jai:A wizard stands; behind him, a dragon;model=flux
|
prompt = E=mc2 explained
| jai:prompt=E=mc2 explained
|
prompt = ;-) a smiley
| jai:\;-) a smiley
|
prompt = ends with backslash\; style = x
| jai:ends with backslash\\;style=x
|
prompt = a;;b
| jai:a\;;b
|
prompt = A list; item=1
| jai:A list\; item=1
|
prompt = C:\Users\me
| jai:C:\Users\me
|
style = anime; prompt = A castle; model = flux, sdxl
| jai:A castle;model=flux;model=sdxl;style=anime
|
Parsing the canonical text of a document yields that document, and serialising the result yields the same text (the canonical form is a fixed point). The conformance suite checks both properties.
5.5.1. Bare serialisation
The bare serialisation is the canonical text without the jai:
prefix, for contexts that establish JAI and are not displayed as text (the
body of a data:image/jai URL, a data-jai attribute). It is produced by the
same algorithm with one more case in step 3: the first prompt value is also
written as prompt=… when it begins with jai: (ASCII case-insensitively),
with U+FEFF, or with {.
{ rule keeps the body of a data:image/jai URL from being mistaken for
the JSON form by a decoder (§ 7.4 Decoding).
5.6. Bidirectional text
This section is informative.
The structure of the text form is left-to-right: keys and delimiters are
ASCII. A canonical string always starts with jai:, which pins the base
direction of the whole string under first-strong detection; an
Arabic or Hebrew prompt therefore displays correctly in a plain text field.
The bare form, used only in attributes and URL bodies, is not displayed as
text. Authoring tools that show a document should display the canonical
string in a left-to-right container and each value with dir="auto" or
unicode-bidi: isolate. Trailing punctuation of a right-to-left prompt may
display beside the following ;key=; parsing is unaffected. Validators report
explicit bidirectional controls and invisible formatting characters inside
values (§ 14 Diagnostics).
6. JSON form
The JSON form is a JSON object [RFC8259].
6.1. Shape
-
The object MUST contain a member named
jaiwhose value is the JSON number1(§ 6.2 The jai marker). -
Every other member maps a key to either a JSON string (one value) or a JSON array of JSON strings (one or more values, in order). A string is equivalent to a one-element array.
-
Member names MUST be valid keys (lowercase). A conforming document contains no two members whose names are equal after ASCII lowercasing.
-
Member values are subject to value normalisation when read, so a conforming document contains no empty strings, no empty arrays and no strings that begin or end with JAI whitespace.
-
An empty array contributes no values and is not diagnosed by readers; validators MAY report it.
-
A member whose value is an object, or an array containing anything other than strings, is reserved for future revisions of this specification (§ 12 Extensibility). Conforming documents of this edition contain none.
6.2. The jai marker
The member jai identifies a JSON object as a JAI document and gives the
file form its decompressed signature: the bytes {"jai":1 followed by , or
} (§ 6.4 Canonical JSON).
Its value is the JSON number 1 (so 1.0 is accepted, because it is the same
number).
This specification does not expect to assign another value to the marker: revisions add keys and reserved member shapes, and never change the meaning of existing ones. An incompatible future format would use a different member name or media type.
Readers behave as follows:
-
value 1: proceed;
-
member absent: in a JAI context, proceed with the diagnostic
missing-marker; in any other context the reader returns the empty document with no diagnostics (the object is not a JAI document); -
any other integer (including 0 and negative integers): proceed best-effort with the diagnostic
unsupported-version; a viewer MUST NOT render such a document automatically; -
any other value (
"1",true,null,1.5): proceed as for 1 with the diagnosticinvalid-marker.
The text form carries no marker; its prefix plays that role.
6.3. Reading
The JSON reading algorithm takes a JSON text and a flag in JAI context and returns a document and diagnostics.
-
Parse the text as JSON [RFC8259]. Texts that are not valid RFC 8259 JSON (including
NaN,Infinity, comments and trailing commas), and texts containing a number whose value, rounded to the nearest IEEE 754 binary64 value, is infinite (for example1e400) wherever it occurs, thejaimember included, yield the empty document with the diagnosticinvalid-json. If the top-level value is not an object, yield the empty document withinvalid-json. If arrays and objects are nested more than 32 deep anywhere in the text (the top-level object has depth 1), yield the empty document withinvalid-json. Implementations whose JSON parser recurses check this with a scan before parsing, skipping the contents of strings, so that no input exhausts the stack. -
Read the members into an insertion-ordered map keyed by the exact member name. A member name that repeats an earlier one replaces that member’s value in place and keeps the earlier position (this is what ECMAScript
JSON.parseand Pythonjson.loadsdo). Readers do not diagnose an exact repetition; validators MAY report it asduplicate-member. -
Handle the marker as in § 6.2 The jai marker, then remove it from the map. If the marker is absent and in JAI context is false, return the empty document and no diagnostics.
-
For each remaining member, in map order:
-
Let name be the ASCII lowercase of the member name. If name does not match the key grammar, emit
invalid-keyand skip the member. If name isjai, emitduplicate-memberand skip it. -
Let items be the member value if it is an array, otherwise a one-element list containing the value.
-
For each item: a string is a candidate value; a number is converted to a candidate value by the ECMAScript
Number::toStringalgorithm applied to its IEEE 754 binary64 value, as RFC 8785 §3.2.2.3 specifies ([RFC8785]), with the diagnosticnumber-value;trueandfalsebecome the candidatestrueandfalsewithnumber-value;nullis skipped withempty-value; an object or an array is skipped withunsupported-member. -
Apply value normalisation to each candidate and append the resulting values, in order, to the list for name. If a member earlier in the map has a different name that also lowercases to name, emit
duplicate-keyfor name, once for this member, whether or not either member contributed values. The values of all such members are concatenated in map order.
-
-
Return the document and diagnostics.
"strength": 0.6 is forgiven, and so that it is the same in every language:
1.0 → 1, 1E2 → 100, 0.60 → 0.6, -0 → 0, 1e21 → 1e+21,
5e-324 → 5e-324. Integers beyond 253 lose precision in this
conversion; authors write such values as JSON strings (§ 8.1.6 seed
requires it). Python readers need parse_constant to reject NaN and Infinity
and a short emulation of Number::toString; the conformance suite pins the
cases.
| JSON | Document | Diagnostics |
|---|---|---|
{"jai":1,"prompt":" A castle "}
| prompt = A castle
| |
{"jai":1,"prompt":"a\r\nb"}
| prompt = a U+000A b
| |
{"jai":1,"Prompt":"a","prompt":"b"}
| prompt = a, b
| duplicate-key
|
{"jai":1,"strength":0.60,"animate":true}
| strength = 0.6; animate = true
| number-value ×2
|
{"jai":1,"seed":12345678901234567890}
| seed = 12345678901234567000
| number-value (precision lost)
|
{"jai":1,"prompt":["a",null,"",["b"],{"x":1}," c "]}
| prompt = a, c
| empty-value ×2, unsupported-member ×2
|
{"jai":"1","prompt":"x"}
| prompt = x
| invalid-marker
|
{"jai":2,"prompt":"x"}
| prompt = x
| unsupported-version
|
{"prompt":"x"} in a .jai file
| prompt = x
| missing-marker
|
{"jai":1,"__proto__":"x","prompt":"x"}
| prompt = x
| invalid-key
|
6.4. Canonical JSON
The canonical JSON form of a document is the following byte sequence, and every serialiser produces exactly it:
-
UTF-8 without a byte order mark; no whitespace outside strings.
-
Members in this order:
jai, thenpromptif present, then the qualified keys whose name ispromptin ascending code point order, then every other key in ascending code point order of the key. -
The value of
jaiis1. Every other member’s value is a JSON string when the key has one value and a JSON array of strings when it has several. -
Strings are serialised exactly as RFC 8785 §3.2.2.2 [RFC8785] specifies:
"as\",\as\\, U+0008, U+0009, U+000A, U+000C and U+000D as\b,\t,\n,\fand\r, every other code point below U+0020 as\ufollowed by four lowercase hexadecimal digits, and every other code point, including U+007F, U+2028, U+2029 and all non-ASCII, literally.
Because values are scalar value strings, canonical JSON never contains surrogate escapes.
jai and prompt come first, so that every file begins with the
bytes {"jai":1 followed by , or } after decompression and a reader can
see the description first. An implementation can run a JCS library and move those two members to
the front; the string and number rules are identical. In JavaScript the
canonical form is JSON.stringify of an object built in this member order;
in Python, json.dumps(obj, ensure_ascii=False, separators=(',', ':')) with
members inserted in order; Go callers need SetEscapeHTML(false).
anime; prompt = A castle, with a moat; model = flux.
{ "jai" : 1 , "prompt" :[ "A castle" , "with a moat" ], "model" : "flux" , "style" : "anime" }
6.5. Identity
The identity of a document is the SHA-256 digest of its canonical JSON form, written as 64 lowercase hexadecimal digits.
Identity is syntactic: two documents are the same document if and only if
their canonical JSON forms are byte-identical. Documents that differ in any
member, including preview, vendor keys, or the spelling 16x9 versus
16:9, are different documents. Identity is the same whichever form or
carrier delivered the document, and whatever whitespace, key case or key
order the author used.
Identity names a document, not a render. A render cache key MUST include,
besides the identity, the renderer and its configuration, and the identity of
every image input the render used (an explicit source or the carrier’s
original image). See also § 13.7 Caches.
Identity is public information and MUST NOT be used as a capability or as a key into an allow- or deny-list.
7. File form, media type and decoding
7.1. File form
The file form of a document is exactly one gzip member [RFC1952] with
compression method 8 (deflate), followed by nothing, whose decompressed
content is the canonical JSON form. A .jai file contains the file form.
Decoders MUST reject, as described in § 7.4 Decoding:
-
a member whose reserved FLG bits are set;
-
a CRC32 or ISIZE that does not match the decompressed content;
-
any bytes after the end of the member, including a second member;
-
decompressed output exceeding the decoder’s bound (§ 13.1 Untrusted input and bounds), which is enforced on the decompressed byte count during inflation and never read from ISIZE;
-
decompressed content that is not a JSON object (including content that is itself gzip);
-
a header with FLG.FHCRC set whose two header-CRC bytes are not the two least significant bytes of the CRC32 of all header bytes before them;
-
a deflate stream [RFC1951] that is invalid: a block of type 3; a stored block whose LEN is not the ones' complement of NLEN; more than 286 literal/length codes or more than 30 distance codes (HLIT + 257 > 286 or HDIST + 1 > 30); a code-length code that is over-subscribed or incomplete; a literal/length or distance code that is over-subscribed, or that is incomplete unless it consists of exactly one code of length 1 (a distance code with no codes at all is accepted); a literal/length code with no code for symbol 256; a repeat code 16 with no previous length, or code lengths that run past the HLIT + 257 + HDIST + 1 lengths announced; a code in the compressed data that is assigned no symbol, a length symbol 286 or 287, or a distance symbol 30 or 31; a distance greater than the number of bytes output so far; or a stream that ends before its final block ends. These are exactly the streams zlib’s inflate rejects, so
DecompressionStream, Node’szliband Python’szlibcan be used unmodified.
The header fields FEXTRA, FNAME, FCOMMENT, MTIME, XFL and OS are read and
ignored; FNAME is never used as a file name. Byte equality of two .jai
files is not a conformance notion: the canonical form is defined at the JSON
level.
7.2. Encoding
An encoder produces the file form from a document. Encoders MUST write the canonical JSON form as the member content. Encoders SHOULD write MTIME as 0 and SHOULD NOT write FNAME or FCOMMENT, so that files carry no timestamps or file names and tests are reproducible.
gzip -n and the default settings of most library encoders already satisfy
this. A file produced by gzip -c castle.json > castle.jai from canonical
JSON is a conforming file whatever its header fields.
DecompressionStream), runtime, language
and CDN decodes natively; it undoes almost all of the base64 inflation of an
embedded preview; and it gives the format one encoding rule instead of
"compress when large". Contexts where the twenty extra bytes matter use the
text form in a data: URL instead (§ 7.5 data: URLs).
7.3. Media type and file extension
The media type of a JAI document in any of its three serialisations is
image/jai. The file extension is .jai. The type attribute
value image/jai (§ 11.1 Carriers) is matched by its essence, ASCII case-insensitively, ignoring parameters. A charset parameter has no
meaning: the text and JSON forms are always UTF-8.
image/jai is used unregistered, as image/webp was for a decade before
RFC 9649. Appendix Appendix A. Media type registration template carries the registration template; registration
in the standards tree requires an IETF or SDO process that the project intends
to pursue once the format is stable. Should the type be registered under a
different name, viewers will match both. JAI is unrelated to JPEG AI
(ISO/IEC 6048), whose registered types are image/jaii and image/jais.
Servers SHOULD send Content-Type: image/jai for .jai resources, and, as
for web fonts, SHOULD send Access-Control-Allow-Origin: * so that scripts on
other origins can read them; a .jai resource contains no user data. Servers
need not apply Content-Encoding: gzip; if they do, fetch() removes it and
the decoder sees JSON. Decoders apply § 7.4 Decoding to the bytes of any
resource referenced from a JAI carrier regardless of the served
Content-Type, because static hosts commonly serve unknown extensions as
application/octet-stream.
7.4. Decoding
The decoding algorithm takes a byte sequence bytes and a flag in JAI context (true in a JAI context) and returns a document and diagnostics. It never falls back from one serialisation to another; each layer either succeeds or yields the empty document.
-
If bytes begins with
1F 8B:-
Decode exactly one gzip member under the output bound. If the member is malformed in any way listed in § 7.1 File form, if bytes follow it, or if the bound is exceeded, return the empty document with
malformed-container, discarding any partial output. -
Let bytes be the decompressed content, and let from gzip be true.
-
-
If from gzip is false and bytes is longer than the decoder’s text bound (§ 13.1 Untrusted input and bounds), return the empty document with
undecodable. -
Decode bytes as UTF-8. If the bytes are not well-formed UTF-8 [ENCODING] or contain the byte 00, return the empty document with
malformed-containerif from gzip is true and withundecodableotherwise. There is no autodetection of UTF-16 or other encodings and nocharsethandling. (The byte 00 never occurs in text a person or tool writes; rejecting it keeps binary data, such as UTF-16 without a byte order mark, from becoming a prompt.) -
Remove every leading U+FEFF.
-
Let i be the index of the first code point that is not JSON whitespace (U+0009, U+000A, U+000D, U+0020). If the code point at i is
{and the next code point after i that is not JSON whitespace is"or}, the input is in the JSON form: run the JSON reading algorithm on the text with in JAI context. A JSON failure is final: do not try the text form. -
Otherwise, if from gzip is true, return the empty document with
malformed-container(a gzip member must contain JSON). -
Otherwise, the input is in the text form: run the text parsing algorithm on the text.
A .jai file whose bytes are not gzip is accepted by this algorithm but is
not a conforming file; validators report non-canonical-encoding.
1F 8B, { followed by " or }, or anything else. A text
description that begins with { but is not followed by a quote, for example
{masterpiece}, a castle, is text. The bare serialisation writes a
{-initial prompt as prompt=… so that canonical output never meets the
JSON test.
| Bytes | Result |
|---|---|
gzip member containing {"jai":1,"prompt":"A castle"}
| prompt = A castle
|
| the same followed by a second gzip member | empty, malformed-container
|
gzip member containing jai:A castle
| empty, malformed-container
|
{"jai":1,"prompt":"A castle"} (uncompressed)
| prompt = A castle; validator: non-canonical-encoding
|
{masterpiece}, a castle
| prompt = {masterpiece}, a castle
|
{"quoted"} prose
| empty, invalid-json
|
FF FE 6A 00 … (UTF-16)
| empty, undecodable
|
| the bytes of a PNG file | empty, undecodable
|
jai:A castle
| prompt = A castle
|
7.5. data: URLs
A document may be embedded in a data: URL [RFC2397] with the media type
image/jai, in any of the three serialisations:
data:image/jai,A%20magical%20castle;style=anime data:image/jai;base64,H4sIAAAAAAACA6tWykrMVLIy1FEqKMrPLShRslJyVMhNTM9MTsxRSE4sLslJVdJRKi6pBNJWSol5mbmpSrUAq6nXdjUAAAA=Both URLs carry the same document.
The body of the URL, after the data: URL processor of the Fetch Standard has
percent-decoded or base64-decoded it [FETCH], is decoded with
§ 7.4 Decoding with in JAI context true (the body is a JAI context). The non-base64 text form is the
most compact and the only human-readable option; the base64 file form is
permitted and never required. Media-type parameters other than base64 are
ignored.
If the data: URL processor returns failure (no ,, or a ;base64 body that
forgiving-base64 rejects), or the essence of its MIME type is not image/jai,
the URL carries no document. The MIME type is parsed, as Fetch does, from the
serialised URL, in which the URL parser has percent-encoded non-ASCII and
control code points, so data:image/jai followed by U+00A0 is not
image/jai.
When a serialiser or encoder writes the text form or the JSON form into the body of a
data:image/jai, URL it MUST percent-encode every byte of the UTF-8 encoding
that is a C0 control, U+007F, an ASCII whitespace character (U+0020 as %20,
U+000A as %0A, U+0009 as %09), % (as %25), # (as %23), " (as %22), ' (as %27), < (as %3C),
> (as %3E), and a ,
that would be the last byte of the URL (as %2C); a body beginning with /
is written with %2F. Every other byte, including ;, =, ,, {, }, ?, /,
&, + and non-ASCII, MAY remain literal. The
canonical URL form of a document is data:image/jai, followed by
its bare serialisation so encoded, so that the canonical URL form can be
placed in any quoted HTML attribute without further escaping.
srcset attribute silently discards the candidate;
an unencoded # ends the URL, so everything after it is lost; a literal %
followed by two hexadecimal digits is decoded as a byte. Line breaks have to be
%0A: every URL parser deletes raw tabs and line feeds. Percent-decoding is
a transport step performed once by the URL processor; %3B and %3D become
; and = and then parse as delimiters, exactly as if typed. Only \; and
\= protect prose (§ 5.3 Escaping arbitrary text).
8. Standard parameters
This edition defines eleven standard keys. Each has a meaning a renderer can act on without knowing anything about a particular model. All of them are advisory in the sense of § 3 Terminology: a renderer honours what it can and reports what it cannot (§ 9.4 Renderer diagnostics); none of them can select, fetch or configure anything the user has not configured.
| Key | Values | Form | Meaning |
|---|---|---|---|
prompt
| many | text | What the image shows. The description is the values joined with U+000A, in order. |
style
| many | text | Visual treatment: anime, watercolor, 35mm film photo. All values apply.
|
avoid
| many | text | Things or qualities the image should not contain, one per value, stated positively (people, not no people).
|
model
| many | identifier | Ordered preference list of models or rendering packages. A selector, never a locator. |
aspect
| one | W:H, WxH, decimal, square, landscape, portrait
| Preferred aspect ratio. |
mode
| one | generate, transform, keep
| How the description relates to an original image. Default generate.
|
strength
| one | decimal 0 to 1, or percentage | In transform, how far the result may depart from the source: 0 unchanged, 1 unconstrained.
|
seed
| one | integer | Reproducibility hint, passed through when the model accepts one. |
source
| one | URL or data: URL of a raster image
| The image to transform. Takes precedence over the carrier’s own image. |
preview
| one | data: URL of a tiny raster image
| Placeholder shown while rendering. Never an input to generation. |
animate
| one | boolean | Requests a looping animated image where supported; otherwise a still frame. |
8.1. Interpretation
An interpreter derives the interpreted parameters of a
document from its values. Interpretation never modifies the document: the
serialiser writes values as the author wrote them, and 16x9 and 16:9
remain different documents with the same interpretation.
For each single-valued standard key (aspect, mode, strength, seed,
source, preview, animate) that is present:
-
If the key has several values, let v be the last value and emit
repeated-singlefor the key; otherwise let v be its value. Appending a parameter to a shared default string is how an author overrides a single-valued key. This does not work forprompt,style,avoidandmodel, whose values accumulate; this edition has no way to clear an inherited value (;style=is dropped withempty-value), so keep those keys out of shared prefixes. -
If v begins and ends with the same ASCII quotation mark (
"or') and is at least two code points long, remove both and trim the result (validators reportquoted-value). Then, if v ends with., remove it. -
Match v against the key’s value grammar below, ASCII case-insensitively where keywords are involved. On failure emit
invalid-valuefor the key (forsource,invalid-image; forpreview,unsupported-preview), treat the key as absent, and, where the grammar suggests one, offer the corrected spelling in the diagnostic.
The values of prompt, style, avoid and model are used exactly as they
appear in the document: no quotation mark or full stop is removed, and
§ 8.2 Model matching receives the document’s values.
Interpreters MUST NOT use lenient or locale-aware number parsers; the
grammars below are ASCII and exact. Non-ASCII digits, full-width characters
and the decimal comma are invalid (an authoring tool offers 0,6 → 0.6,
16:9 → 16:9).
8.1.1. prompt, style, avoid
Any value is valid. The interpreted prompt is the description: the values
joined with a single U+000A in order. prompt=a;prompt=b renders as the same
input as a single value a U+000A b but is a different document. Renderers
MAY normalise whitespace for their model.
style values are combined; all apply. avoid values are independent
items; avoid=text;avoid=people and avoid=text, people reach a negative
prompt identically but are different documents. Validators report an avoid
value that begins with no, not, without or never followed by
whitespace (negated-avoid), because negation inside a negative prompt
inverts the author’s intent on most models.
8.1.2. model
Any value is valid. Values are matched against the renderers the user has
configured as described in § 8.2 Model matching. A value promises nothing: the
same model value may select different models on different days or at
different providers, and a value the user has not configured selects
nothing.
Values are opaque identifiers. Validators MAY warn when a value looks like a
URL or a file path (model-looks-like-locator), because such values are
never fetched (§ 13.3 Selectors, never locators).
8.1.3. aspect
aspect = ratio / number / "square" / "landscape" / "portrait" ratio = number OWS ( ":" / "x" / %x00D7 / "/" ) OWS number ; ABNF strings are case-insensitive number = 1* DIGIT [ "." * DIGIT ] / "." 1* DIGIT
A ratio denotes width divided by height; 1920x1080 and 16:9 denote the
same ratio, 16/9. A bare number denotes the ratio itself (1.5). Both
numbers of a ratio MUST be greater than zero. A ratio whose quotient W/H, or a
bare number, is greater than 100 or less than 0.01 is invalid. square is 1:1. landscape and
portrait express intent (wider than tall, taller than wide) without a
number; renderers SHOULD treat them as 4:3 and 3:4 unless they have a
different default for the model. W:H with integers is the canonical
spelling for authoring tools to suggest.
Renderers use the nearest ratio they support and report adjusted-value
when the result differs materially from the request. The relationship between
aspect and an original image is defined in § 9.3 Size and aspect.
8.1.4. mode
One of generate, transform, keep, matched ASCII case-insensitively.
Semantics in § 9.1 Modes and the original image. Absent or invalid: generate.
8.1.5. strength
strength = number [ OWS "%" ]
A number from 0 to 1 inclusive, or a percentage from 0% to 100% which is
divided by 100 (60% is 0.6). A value outside the range is clamped to it
with adjusted-value. 0 means the source is unchanged, 1 means the source
constrains nothing. Renderers map this linearly onto the model’s own control;
a control that measures image influence rather than departure takes
1 − strength. strength has an effect only in transform mode; validators
report strength-without-transform otherwise.
8.1.6. seed
One to twenty ASCII digits. Renderers pass the value through when it lies
within the model’s accepted range and otherwise reduce it deterministically
(for example modulo the range) with adjusted-value. A seed promises
nothing across renderers, model versions or hardware; a renderer that cannot
honour it reports unsupported-parameter, and one that runs a
non-deterministic mode reports seed-nondeterministic. Authors MUST write
seeds above 253 as strings in the JSON form (§ 6.3 Reading).
8.1.7. source
A URL, absolute or relative to the carrier’s base URL, or a data: URL,
resolving to a raster image of type image/png, image/jpeg, image/webp,
image/gif or image/avif. Other types, including SVG, HTML and
image/jai, are invalid (invalid-image): a document never contains another
document as an input.
An interpreter checks a source value without fetching it. A data: value
is invalid when the data: URL processor returns failure or the essence of its
MIME type is not one of the types above. Any other value that begins with a URL
scheme (an ASCII letter followed by ASCII letters, digits, +, - or .,
then :) is invalid unless the scheme is http or https, ASCII
case-insensitively. An invalid source is reported with invalid-image and
treated as absent, so it never also yields ignored-value. A valid value’s
type is known only when it is fetched; one that cannot be fetched, or does not
decode as one of these types, is not readable (§ 13.2 Permitted inputs).
A valid source is used only in transform mode (otherwise ignored-value). When
present it takes precedence over the carrier’s original image. A source
URL is fetched only with the privileges of the document that carries it, and
only after the consent that the render itself requires (§ 13.2 Permitted inputs).
Documents intended for text channels SHOULD reference a URL rather than embed
bytes.
8.1.8. preview
A data: URL of a raster image of one of the types listed for source,
RECOMMENDED at most 64 pixels on the long side and at most 1 KiB. A viewer
shows it, scaled to the layout box, while a render is pending or when no
original image exists. It is never an input to generation and never fetched
from a network. Other values are ignored with unsupported-preview.
data: URL, and shows the image’s colour layout. Hash-based
placeholders such as ThumbHash [THUMBHASH] and BlurHash [BLURHASH] are
three to four times smaller but need decoder code; a later edition might admit
them as prefixed values without affecting this edition’s viewers.
8.1.9. animate
true, yes, 1, on (true) or false, no, 0, off (false), matched
ASCII case-insensitively. True requests a looping animated image resource
(GIF, APNG, animated WebP or animated AVIF) of renderer-chosen length that is
displayable wherever a still image is; video containers are not JAI render
results. A renderer that cannot produce one renders a still frame and reports
unsupported-parameter. Viewer obligations for motion are in
§ 11.5.2 Accessibility.
8.2. Model matching
A renderer, or a viewer choosing among configured renderers, resolves the
model values as follows. Only models the user has configured and enabled take
part (§ 13.3 Selectors, never locators).
-
For each
modelvalue v in document order:-
If v matches, ASCII case-insensitively, the identifier or an alias of an eligible model, select that model.
-
Otherwise, unless the renderer pins versions: if the last
/-separated segment of v contains:or@after its first code point, let v′ be v with the text from the last such:or@to the end removed. If v′ matches as in step 1.1, select that model and reportversion-ignored. -
Otherwise, let the words of a string be its maximal runs of ASCII letters and digits, ASCII-lowercased. A known family occurs in a list of words when the words of its name, or of one of its spellings, appear there as a contiguous run, and it has at least one eligible model. Search the words of the last
/-separated segment of v; if no family occurs there, search the words of the whole of v. If several families occur in the same search, choose the one whose run starts earliest; at the same start, the one with the longer run; then the one the renderer lists first. Select that family’s default model and reportsubstituted-model.
-
-
If no value selected a model, including when the document has no
modelvalue, use the user’s default model and reportno-matching-model. -
A model is eligible if it is configured and enabled and, in
transformmode with an input image, accepts an image input. Step 2 uses the user’s default model even when it is not eligible; intransformmode with an input image it is then rendered asgeneratewithmode-degraded(§ 9.1 Modes and the original image).
The known families are the families the renderer lists, in its order,
followed by the family of every configured model not already listed, in
configuration order; a family’s name is always one of its spellings. The
default model of a family is the user’s default model if it is eligible and
belongs to that family, and otherwise the first eligible configured model of
that family.
flux (spellings flux) and sdxl (sdxl, stable diffusion xl): black-forest-labs/FLUX.1-dev → the words of the last segment are
flux, 1, dev → family flux. stable-diffusion-xl-base-1.0 → stable,
diffusion, xl, … → family sdxl. https://example.org/flux-schnell → last
segment flux-schnell → flux (and a validator warns that the value looks like
a URL). stability-ai/sdxl:7762fd07 → no exact match; without the version
:7762fd07 it is the exact id stability-ai/sdxl (version-ignored).
replicate:stability-ai/sdxl:7762fd07 → no exact match with or without the
version; the words of the last segment, sdxl and 7762fd07, give family
sdxl (substituted-model). replicate:flux → the segment replicate:flux
without :flux matches nothing, so nothing is removed; the words replicate,
flux give family flux.
Appendix Appendix B. Model family names lists family names informatively. There is no registry of models: a renderer advertises what it knows, and the user configures what the renderer may use.
8.3. Per-model refinements
A document can carry a core description that every model receives, plus refinements for particular models in qualified keys:
jai:A girl holding a red balloon in a park at dusk;prompt/flux=The balloon floats high above her;prompt/imagen=The balloon is glossy;model=flux;model=imagen
The selected model is the model that § 8.2 Model matching selects,
or the model the user chose when a viewer lets the user override the
document’s preference. Once a model is selected, an interpreter forms the
values it uses for prompt, style and avoid: the core values of the key,
followed by the values of every qualified key with that name whose target
matches the selected model, in ascending code point order of the key. A target
matches when it equals, ASCII case-insensitively, the model’s family name,
its identifier or one of its aliases. The description given to the model is
formed from these values.
Qualified keys never select a model: model remains the ordered preference
list, like a font stack, and the core values are the fallback that every model
receives. Qualified keys whose target does not match the selected model are unused,
without a diagnostic.
Because refinements follow the core, a model that reads only the start of its input, such as one with a 77-token text encoder, may never see them. Authors who refine for such a model keep the core short, with the essentials first.
An image encoder typically evolves the core first and then adds refinements for the models in its preference list.
8.4. Never document intent
The following are settings of the user’s renderer, never parameters of a document, and renderers MUST NOT let any key, standard or vendor, set them: output format, number of candidates, quality or speed tier, resolution beyond the layout box, safety and moderation settings, provider endpoint, credentials, and anything that affects billing. See § 13.4 Parameter forwarding.
9. Rendering
A renderer turns a document into an image. This section defines what every renderer MUST do with the interpreted parameters and what it MUST report; how it produces pixels is outside this specification.
Renderer checklist (informative):
-
compute the interpreted parameters (§ 8.1 Interpretation);
-
select the model (§ 8.2 Model matching);
-
resolve the mode and the input image (§ 9.1 Modes and the original image, § 13.2 Permitted inputs);
-
assemble the model input (§ 9.2 Assembling the model input);
-
forward vendor keys only through the mapping (§ 13.4 Parameter forwarding);
-
size the output (§ 9.3 Size and aspect);
-
report every interpreter and renderer code (§ 9.4 Renderer diagnostics);
-
handle failure (§ 9.5 Failure).
9.1. Modes and the original image
The original image is the carrier’s own image (an <img> element’s
currentSrc at render time) or, when present, the image named by source.
mode states how the document relates to it; a viewer’s settings always take
precedence over mode (§ 11.5 Viewer requirements).
generate(default)-
Render from the description alone. A viewer shows the original image, or the
preview, until the render is ready, then replaces it, and falls back to the original on failure. transform-
As
generate, but the original image is an input to generation, governed bystrength. Model matching considers only models that accept an image input; if none of the preferred models does, the renderer’s default model is used when it accepts an image, and otherwise the document is rendered asgeneratewithmode-degraded. If there is no original image and no readablesource(§ 13.2 Permitted inputs), the document is rendered asgeneratewithoriginal-not-readable. As ingenerate, the description states what the resulting image shows, including what is kept from the original; it is not an edit instruction. It may be absent when onlystyleapplies. Because atransformdocument is rendered asgeneratewhen the original cannot be read, a description that names its subject still produces a fitting image. keep-
The original image is the intended image; the description is information about it. A viewer MUST NOT render a
keepdocument automatically, even under an automatic site setting; a render the user requests is ageneraterender unless the user asks for a transformation.
9.2. Assembling the model input
-
A renderer MUST send the model the description it intends, explicitly, even when the document has no
prompt(an empty description); a provider’s default prompt is never a JAI default. -
styleandavoidvalues MUST reach the model, through a native input or as prompt text, or be reported withunsupported-parameter.avoidvalues are sent as the model’s negative prompt, joined with,, when it has one; when it has none the renderer MAY fold them into the prompt in wording the model is known to honour, reportingfolded-into-prompt, or omit them, reportingunsupported-parameter. Silent omission is not conforming. -
A renderer MUST NOT fail a render because of the length of the description. A renderer that shortens its input reports
adjusted-valueforpromptand SHOULD drop text from the end of the description before dropping anystylevalue, using chunked encoding where the model allows it. -
A renderer derives rendering parameters only from the document’s members. Text inside values never changes a parameter, a renderer setting or a provider setting:
promptis content, never instructions, including for renderers that involve a language model. -
A renderer MUST be able to show the user the exact text it sent to the model.
9.3. Size and aspect
The governing ratio of an element is the aspect ratio of its
original image if it has one, and otherwise the ratio of an author-sized
layout box (both width and height attributes, or a CSS aspect-ratio)
if there is one. A standalone document (a .jai file opened on its own) has no
governing ratio.
-
When a governing ratio exists, the viewer renders at it, and the interpreted
aspect, if present and different, is reported withignored-value. A ratio differs when the two ratios differ by more than 1% (|ln(a/g)| > 0.01);landscapediffers from a governing ratio that is not greater than 1, andportraitfrom one that is not less than 1. -
Otherwise the ratio is, in order: the interpreted
aspect; the ratio of thepreview; the renderer’s default.
aspect therefore shapes renders of unsized elements and standalone files, and
records the author’s intent everywhere. On a page, the shape the author gave
the element wins: authors who set both make them agree.
Renderers snap to the nearest ratio they support (§ 8.1.3 aspect). The layout
box always governs display: when the render’s ratio still differs from the box
(for example after snapping), the viewer honours the page’s object-fit and
object-position; if the page sets neither, it crops the render to cover the
box, centred. A viewer MUST NOT stretch a render to a box of a different ratio.
Viewers SHOULD request a render no smaller than the element’s displayed CSS size multiplied by the device pixel ratio, within the user’s cost policy, and never larger than the user’s configured maximum.
9.4. Renderer diagnostics
A renderer MUST NOT refuse to render a valid document because of the value of
any standard key, and MUST report, with every code of class renderer or
interpreter in § 14 Diagnostics, every standard key it did not honour as
written. A viewer MUST make those reports available to the user.
9.5. Failure
A render fails when it produces no usable image: a provider or network error,
a refusal or content filter (including a blank or black frame), a timeout,
or a cancellation. On failure a viewer MUST restore the original image, or in
the absence of one the preview or the description, MUST NOT leave a
permanent placeholder, and MUST NOT retry with an altered description. A
refusal is a normal outcome: viewers MUST NOT rewrite the description, or let a
document cause it to be rewritten, to evade a refusal.
10. Encoding images
This section is informative.
An image encoder produces a document from an existing image. It is a tool, not a conformance class: its output is an ordinary document, and the encoder class above only concerns the file form. Nothing here constrains how an image encoder works; the section describes the approach that the compression view in § 1.1.1 A description is compression suggests, and the conventions that make encoded documents easy to recognise and reuse.
10.1. Analysis by synthesis
An image encoder searches for the description whose renders look most like the original, using the target models themselves as the decoder:
-
Describe. A vision-capable model writes a first description of the original, following § 15 Writing JAI by hand: medium first, subject and counts, composition, light and colour, literal text in quotes.
-
Render. Each candidate description is rendered with every target model, with fixed seeds so that differences between candidates come from the text, not from noise.
-
Compare. Each render is scored against the original. Useful measures are semantic (cosine similarity of image embeddings such as CLIP), perceptual (colour and layout distance between small thumbnails), and a vision model’s list of the visible differences. The fitness of a candidate is its mean score across the target models.
-
Revise. The best candidates are kept, and new ones are written from them by addressing the listed differences, while keeping what already matches.
-
Refine per model. Once the core description stops improving, the encoder looks at models that lag behind and tries short per-model refinements for them, keeping a refinement only when it raises that model’s score.
-
Stop. On a budget, a time limit, or when scores reach a plateau, the encoder returns the best document found so far.
This is the loop a CELP speech coder runs, with a description in place of codebook indices and a generative model in place of the synthesis filter. The result is a code tuned to the decoders the author chose. Other models still receive the core description, which remains a faithful general description of the image.
The quality of an encoded document is bounded by its decoders: a model that cannot draw hands, legible text or exact counts will not do so because the description is better. Scores measure resemblance, not truth; an encoder that optimises an embedding score alone can drift towards text that games the metric, which is why the comparison step also uses a reader of the images.
10.2. Output conventions
An image encoder is expected to produce a document that a person could have written by hand, so that it stays portable and editable:
-
promptholds the core description, complete enough for any model;prompt/<target>(and, rarely,style/<target>oravoid/<target>) holds the per-model refinements, with the target set to the model’s family name when only one target model is in that family, else to its alias or identifier. -
modellists the target models, best-scoring first, so that viewers that have several of them prefer the one that reproduced the image best. -
aspectis the ratio of the original’s pixel dimensions, reduced to small whole numbers when that changes the ratio by less than 1%. -
seedis left out unless the author wants exact reproduction with one model: a description tuned on one seed is still meant to work on any. -
preview, when wanted, is a tiny placeholder derived from the original, within the bounds of § 13.1 Untrusted input and bounds. -
Scores and the encoder’s settings, when recorded at all, go in the tool’s own vendor keys. Because vendor keys are part of the identity and add bytes, published documents usually leave them out and keep the report beside the document instead.
-
The original image is not embedded. An encoded document describes the original; it is not a copy of it, and it does not carry the original’s provenance or rights information (§ 13.10 Provenance).
11. HTML and URL integration
11.1. Carriers
A document reaches an <img> element through one of four carriers. A
viewer examines them in the order below and takes the first one found; the
same order is the recommended order for authors.
- carrier 1:
<picture>with<source type="image/jai"> -
This is HTML’s own format negotiation: a browser that does not support< picture > < source type = "image/jai" srcset = "castle.jai" > < img src = "castle.png" alt = "A magical castle at dusk" > </ picture > image/jaiskips the<source>without fetching it and shows the raster [HTML].srcandaltstay untouched, the.jaiis fetched only when a viewer wants to render, and a browser that one day decodesimage/jainatively needs no markup change. Thesrcsetmay name a.jairesource or hold adata:image/jaiURL. - carrier 2: the
data-jaiattribute -
The attribute holds the text form; the< img src = "castle.png" alt = "A magical castle at dusk" data-jai = "A magical castle at dusk;style=anime" > jai:prefix is optional. It is never read as the JSON form: a JSON object indata-jaiis prose. This is the inline form for markup that cannot be restructured.HTML intendsdata-*attributes for a page’s own scripts and recommends type negotiation for extensions shared across tools, which is why carrier 1 is preferred. Carrier 2 is kept because it survives most sanitisers and needs no extra element. - carrier 3:
srcis adata:image/jaiURL -
The pure form: the image is the description and there are no fallback pixels. In every current browser this is an unavailable image whose< img src = "data:image/jai,A%20magical%20castle%20at%20dusk;style=anime" alt = "A magical castle at dusk" width = "800" height = "600" > alttext is what the reader sees; see § 11.1.2 Requirements for carrier 3. - carrier 4:
altbeginning withjai:(deprecated) -
Deprecated. The accessible name of the image becomes the syntax, which assistive technology announces, and every parameter is read aloud. Documents SHOULD NOT use this carrier where any other is available; validators report< img src = "castle.png" alt = "jai:A magical castle at dusk;style=anime" > alt-carrier. It is recognised because it is the only carrier that Markdown and strict sanitisers let through, and in those contexts a document should be the prefix and a short description with few or no parameters. A document MUST NOT place adata:URL (preview,sourceor any other value) in analtcarrier (alt-carrier-payload). A viewer MUST NOT render automatically from this carrier; it MAY offer rendering on explicit per-image request.
Carriers 1 and 3 are HTML’s own extension points and are the only carriers a
user agent that decodes image/jai natively implements. Carriers 2 and 4 are
defined for scripts and extensions acting for a user on a page that opted in;
a native user agent ignores them unless the user enables such a viewer.
An alt attribute that does not begin, after leading JAI whitespace, with
jai: is never a JAI document. A jai: string in any URL slot (src,
href, srcset, CSS url()) is not a carrier: jai: is a text prefix and
this specification defines no jai: URL scheme (jai-scheme-url).
11.1.1. Discovery
A viewer runs discovery over the <img> elements of a document in
tree order, descending into open shadow roots and skipping closed ones, and
re-runs it on the mutations HTML considers relevant for source selection
(changes to src, srcset, sizes, media, type, and to the children of
a <picture>), as well as on data-jai and alt changes. Discovery MUST NOT
depend on the image having been fetched or having failed: lazily loaded
images fire no events until they approach the viewport.
For an <img> element:
-
If the element’s parent is a
<picture>: consider each<source>that precedes the<img>among the parent’s children, in tree order, whosetypeattribute has the essenceimage/jaiand whosemediaattribute is absent or matches the environment. Parse itssrcsetwith HTML’s parse a srcset attribute algorithm [HTML]; a candidate whose descriptors are invalid is dropped exactly as HTML drops it. If no candidate remains, skip the<source>(validators reportsrcset-unparseable). Otherwise let url be the first candidate’s URL; descriptors play no further part. If url is adata:URL and the data: URL processor [FETCH] returns failure, or returns a MIME type whose essence is notimage/jai, skip the<source>. Otherwise the document is the resource at url, resolved against the element’s base URL, and no later<source>is examined.widthandheighton the<source>are layout hints. An implementation that cannot evaluate media queries treats everymediavalue as matching. -
Otherwise, for a script or extension viewer: if the element has a
data-jaiattribute, the document is its value parsed with the text parsing algorithm. -
Otherwise, if the element’s
srcattribute, parsed against the base URL, is adata:URL that the data: URL processor accepts and whose MIME type essence isimage/jai: the document is its body (§ 7.5 data: URLs). -
Otherwise, for a script or extension viewer: if the element’s
altattribute begins, after JAI whitespace, withjai:ASCII case-insensitively, the document is the attribute value parsed with the text parsing algorithm (carrier 4). -
Otherwise the element carries no document.
If the element’s currentSrc is the URL selected in step 1 and the element
is complete with a natural width greater than zero, the user agent decodes
image/jai natively and the viewer stands down.
A <source> without a type attribute is selected by the browser and
yields a broken image; validators report source-missing-type. A <source>
after the <img> is ignored by HTML (source-after-img). A JAI URL MUST NOT
appear in the <img>’s own srcset. Authors place the image/jai source
before raster sources when JAI-capable user agents should prefer it; an
extension’s discovery does not depend on the order. A <source type="image/jai"> for a document with mode=keep is unusual, since a native
decoder would then never show the raster (keep-in-source).
image/jai natively would select the JAI source
and never load the raster original; mode then applies only with an
explicit source. HTML never re-selects a source after a decode fails, so
native support will need a rule that a declined or failed render re-selects
the next candidate; the editors intend to raise this with the HTML
Standard’s maintainers when a native implementation exists.
11.1.2. Requirements for carrier 3
An <img> whose src is a data:image/jai URL:
-
MUST have a non-empty
altthat is prose (the description or a human summary); in every current browser thealtis what the reader gets; -
SHOULD have
widthandheightattributes or a CSSaspect-ratio, since it has no intrinsic size until a render arrives; -
MUST NOT have a
srcset; -
SHOULD NOT be the
<img>of a<picture>that also carries a JAI<source>.
Authors are warned that pages without a JAI viewer show an unavailable
image; that onerror handlers and lazy-loading libraries rewrite a broken
image’s src (viewers capture the carrier at discovery); that a Content
Security Policy must list data: in img-src; and that carrier 1 is
preferred whenever fallback pixels exist. The inline pure form with a
fallback is carrier 1 with a data: URL in srcset:
< picture > < source type = "image/jai" srcset = "data:image/jai,A%20magical%20castle;style=anime" > < img src = "castle.png" alt = "A magical castle" > </ picture >
11.1.3. Serving .jai resources
This section is informative. See § 7.3 Media type and file extension for the server
requirements. A script on another origin can read a .jai resource only when
it is served with CORS headers; browser extensions with host permissions
fetch it from their privileged context but are still bound by
§ 13.2 Permitted inputs for any image input. Appendix Appendix D. Serving .jai files gives server mappings.
11.2. Transport decoding
Exactly one transport decoding is applied per carrier, before the decoding algorithm or the text parsing algorithm runs:
-
data:URL (carrier 1 with adata:URL insrcset, carrier 3): parse the attribute value against the document’s base URL and run the data: URL processor of the Fetch Standard [FETCH]. The fragment is excluded; the percent-decoding is the URL Standard’s byte-level percent-decode [URL], which leaves a%not followed by two hexadecimal digits in place and never fails. Decode the resulting bytes with § 7.4 Decoding. -
http(s) URL (carrier 1 with a resource URL): the response body, decoded with § 7.4 Decoding regardless of the served
Content-Type. -
data-jaiandaltattributes (carriers 2 and 4): no transport decoding; the attribute value, as the HTML parser produced it, is the input. -
Query forms: § 11.3 Query forms.
No second percent-decoding is ever applied. Implementations MUST NOT use
decoders that throw on malformed input (decodeURIComponent) in a transport
step. Transport decoding never changes JAI syntax: %3B and %3D become ;
and = and parse as delimiters.
src attribute and reading the element’s src property give
the same data: body by construction, because the data: URL processor
starts from the parsed URL either way.
11.3. Query forms
Two conventions carry a document in a URL’s query, for playgrounds, gateways and links in text channels.
- whole-query form
-
https://example.org/play?prompt=A%20magical%20castle;style=animeParse the URL with the URL parser [URL]. If its query is null, the URL carries no document. Otherwise percent-decode the query once as in § 11.2 Transport decoding, decode the bytes with UTF-8 decode without BOM [ENCODING] (ill-formed sequences become U+FFFD), and run the text parsing algorithm on the result; an empty query is the empty document. The JSON test of § 7.4 Decoding does not apply.
+is a literal plus sign and&is ordinary text; the URL carries no other parameters. Generators MUST percent-encode space as%20(never+),%,#and ASCII whitespace, and MAY leave;,=,+,&,:,/and non-ASCII unencoded. Form serialisers and parsers (URLSearchParams,<form method=get>) MUST NOT be used to build or read this form. - parameter form
-
https://example.org/render?jai=A%20magical%20castle%3Bstyle%3Danime&w=800A query parameter named
jai, inapplication/x-www-form-urlencoded[URL], whose value is a text-form document. Parse the URL with the URL parser; if its query is null there is no document. Otherwise parse the query with theapplication/x-www-form-urlencodedparser; the value of the first pair namedjaiis run through the text parsing algorithm (an empty value is the empty document). With no such pair there is no document. Raw tabs and newlines have already been removed by the URL parser. It is read by any form parser, so+is a space and&separates parameters; generators encode;,=,&,+,#,%and whitespace in the value. This form coexists with other parameters and is the convention for a gateway: a server that renders a document to pixels so that<img src="https://gateway/…?jai=…">displays everywhere today. Hosting a gateway is outside this specification; a gateway that stores or publishes prompts or watermarks output must say so to its users. A JAI-aware viewer MAY, with the user’s consent, decode the parameter locally instead of fetching the gateway.
11.4. Other host formats
This section is informative.
-
Markdown. CommonMark image syntax exposes only
srcandalt, so the only Markdown carrier is carrier 4 (), or a gateway URL in the parameter form. Where a Markdown host allows raw HTML, carrier 1 is preferred. Bare spaces break Markdown destinations; use percent-encoding or angle brackets. -
CSS.
image-set(url("castle.jai") type("image/jai"), url("castle.png") type("image/png"))is the CSS twin of carrier 1; this edition does not require viewers to act on CSS images or on SVG<image>. -
**
<object type="image/jai" data="castle.jai">** renders its fallback content in current browsers but may download the resource and is governed byobject-src; it is not a carrier. -
Links. A link to a
.jaifile behaves like a link to any file the browser cannot display. There is no navigable JAI link form in this edition. -
Service workers. A site can serve
<img src="castle.jai">to its own visitors today by rendering in a service worker; this works over http(s) only and not on a first visit. -
Clipboard. The interoperable clipboard representation is
text/plaincontaining the canonical text form with itsjai:prefix.
11.4.1. Carriers by context
This section is informative. Sanitisers differ, and the carrier an author can use depends on the pipeline:
| Context | Usable carriers |
|---|---|
| HTML the author controls | all; prefer carrier 1 |
| User content through DOMPurify defaults | carriers 2 and 3, and carrier 1 with an http(s) or relative .jai URL (data: URLs in srcset are removed)
|
| User content through GitHub-style allow-list sanitisers | carrier 1 as raw HTML (<picture>, <source>, srcset, type survive; data-* and data: src do not), else carrier 4
|
| CommonMark image syntax | carrier 4 only, or a gateway URL |
| Chat, documentation, email text | the text form with its prefix |
11.5. Viewer requirements
A viewer decides whether, when and how documents are rendered. The user
always wins: user settings (never render, ask, render on request, render
automatically for a site) override mode and every other author preference,
except that keep is never rendered without a user request
(§ 9.1 Modes and the original image), and the consent, budget and disclosure requirements of
§ 13.5 Consent, budgets and cancellation apply to every render.
A viewer MUST NOT present a render as saving data or bandwidth when the original image was fetched, and SHOULD NOT state any saving unless it avoided fetching the original.
11.5.1. Replacement
A viewer that replaces an image with a render:
-
MUST make the replacement effective under HTML’s image source selection and MUST verify it (the
loadevent andcurrentSrc). Settingsrcalone is a no-op when the element has asrcsetor a preceding matching<source>. RECOMMENDED: inside a<picture>, insert a viewer-owned<source>whosesrcsetis the rendered image as the first child and remove it to restore; otherwise set the element’ssrcset, recording the previous value. -
MUST keep the layout box: the element’s
widthandheightor CSSaspect-ratio, else the original’s ratio. -
MUST NOT alter
id,class, event listeners, or link ancestors, and MUST keep the element in place where possible; a replacement element carriesrole="img"and the same accessible name and description. -
MUST record every state it changes and restore all of it on request and on failure, and MUST let the user compare the original and the render.
-
MUST NOT replace the same element more than once per identity per page load, and MUST NOT re-render on resize or scroll. If the page changes
src,srcsetor the<picture>children of a replaced element, the viewer treats the element as new and releases its saved state. -
SHOULD NOT, under an automatic setting, start rendering before the user agent would fetch the image (for
loading=lazy, not before it is near the viewport), and MUST NOT render elements that are not displayed. -
MUST obtain the rendered bytes itself and insert them from local data; it MUST NOT point a page element at a provider URL (which would leak the page through
Refererand reveal the provider). -
MUST confirm that a replacement loaded (
load, natural width greater than zero) and MUST NOT retry the same URL. Depending on the engine and on how the viewer is implemented, replacement loads may be governed by the page’s Content Security Policy [CSP3], under which'self'never matchesblob:and*never matchesdata:. (Chrome currently exempts loads initiated by an extension’s content script from the page’s policy; other engines and page scripts are not exempt.) When a replacement does not load, the viewer either restores the original or presents the render without a page-initiated fetch (for example anImageBitmappainted into a canvas sized to the layout box withrole="img"and the original accessible name) or in viewer-owned UI. Viewers SHOULD prefer adata:URL of the rendered bytes over ablob:URL, which more policies permit. -
Viewer UI injected into a page is subject to the page’s
style-srcandscript-src; a shadow root with constructed stylesheets avoids both.
11.5.2. Accessibility
-
A viewer MUST keep a human-written
altunchanged, includingalt="". If thealtcarried the document (carrier 4) or is absent, the accessible name becomes the firstpromptvalue with control characters removed, truncated at a grapheme cluster boundary at about 250 code points, with the full text available in the viewer’s own UI; when the document has noprompt, a localised generic name. Keys, URLs anddata:payloads never appear in an accessible name. -
A viewer SHOULD expose to assistive technology what it shows sighted users about the image’s state: that it was rendered by an AI model from a description, that it may differ from the publisher’s image, and that the original is available.
aria-description(oraria-describedbyreferring to an element the viewer owns) carries this;titledoes not.aria-busyis set while a render is pending. -
Per-image controls MUST be keyboard-operable and named, never hover-only.
-
Under
prefers-reduced-motionthe swap SHOULD happen without transitions. Individual replacements are not announced to assistive technology by default. -
For
animate: underprefers-reduced-motiona viewer shows a still frame until the user starts the animation; it shows the first frame until the user starts playback unless the user has opted into autoplay for the site; it provides a keyboard-operable control to pause, stop or hide animation longer than five seconds [WCAG22]; renderers SHOULD instruct the model to avoid flashing; viewers MAY refuse to play animation they detect as flashing. -
The viewer’s own UI (consent, provider configuration, per-image controls, diagnostics) MUST be keyboard-operable and expose names, roles and states.
-
A JAI-aware user agent MAY, without rendering, expose the description as the original image’s accessible description; it MUST NOT replace a human-written
altwith it.
Generated imagery carries no authority: logos, text and interface elements inside a render are model output. Viewers mark rendered images as such in viewer-owned UI and always offer the original.
The page’s own accessibility conformance is unaffected by what a user’s agent does at the user’s request; a conforming viewer is a user agent in the sense of the User Agent Accessibility Guidelines.
11.5.3. Personalisation
At the user’s request, a viewer MAY render a document with transformations the user chose: for example a preferred style, a sensitivity or accessibility adjustment, the text inside the image translated into the user’s language, or a mood. A personalised render:
-
MUST be marked as personalised, in viewer-owned UI and to assistive technology, alongside the AI-rendered state (§ 11.5.2 Accessibility);
-
MUST leave the document unchanged, and the viewer MUST keep a render without personalisation available to the user;
-
is reported like any render: the text sent to the model includes the personalisation (§ 9.2 Assembling the model input).
Personalisation is a user setting. A document or a page MUST NOT be able to request or trigger it, and a viewer MUST NOT add a personalisation in order to get past a refusal (§ 9.5 Failure).
12. Extensibility
-
Keys without a
.are reserved for this specification and are only assigned by a revision of it. Validators report unassigned undotted keys (unknown-key). -
Anyone may define keys of the form
vendor.name, wherevendoris a segment they control (comfy.sampler,acme.lighting). Serialisers preserve them; renderers that do not understand them ignore them; renderers that do understand them honour them only through the mapping rules of § 13.4 Parameter forwarding. -
The segment
dcis reserved for Dublin Core terms:dc.title,dc.creator,dc.description,dc.created,dc.language(a BCP 47 tag for the language of the document’s text),dc.rights,dc.license. A viewer that writes document text into a page MAY setlangfromdc.language. -
Members of the JSON form whose value is an object, or an array containing non-strings, are reserved for future revisions (§ 6.1 Shape). Future revisions will add keys and member shapes and will never remove a key or change the meaning of an existing one; a key may be deprecated with a diagnostic. Sequences, variants and multi-image documents, if ever defined, will use such members or a distinct media type, never additional gzip members.
-
There is no registry: this specification is the registry of undotted keys, and each vendor owns its segment. Appendix Appendix B. Model family names and the Dublin Core list above are informative.
13. Security and privacy considerations
Decoding a JAI document has side effects that no other image format has: it transmits the document, and possibly an input image, to a renderer; the render is performed under the user’s provider account and is attributable to the user; and it usually costs money. Every requirement in this section follows from that.
13.1. Untrusted input and bounds
All JAI input is untrusted. Parsing, reading and decoding are total (§ 2.2 Determinism): no input causes an exception, a crash, a hang, or unbounded resource use.
-
Decoders MUST bound the decompressed size of a gzip member, enforced during inflation, and the size of any text or JSON input that did not come from gzip. The bounds MUST be at least 16 MiB and 1 MiB respectively; those values are RECOMMENDED. Exceeding the decompression bound yields the empty document with
malformed-container; exceeding the text bound yields the empty document withundecodable. Viewers MAY apply the text bound to attribute carriers. -
Viewers SHOULD decode a document only when the element is displayed and a render may follow, and SHOULD cap the length of values they transmit to a renderer, reporting
value-truncated. -
Viewers SHOULD bound the dimensions of any image they decode as an input or preview (RECOMMENDED 16 megapixels) and MUST re-encode input images before transmission, which also strips their metadata.
-
A viewer never interprets a value inside a document as another document, never runs discovery on elements it inserted or modified itself, and displays a
previewonly through an image decoder, never as markup.
13.2. Permitted inputs
A viewer MUST NOT use as an input to rendering any image data that the
embedding document could not itself read. In a browser that is exactly the
data that would not taint a canvas: same-origin images, data: images and
blob: images of the page’s origin, and cross-origin images loaded with CORS
that succeeded for the document’s origin. Input pixels are obtained with the
document’s own privileges (a content script’s canvas, or a fetch applying
the document’s CORS and credential rules), never from a privileged context
that carries the user’s cookies. When the implicit original is not readable,
transform behaves as generate with original-not-readable unless a
readable source is present. Publishers who want transform on cross-origin
originals serve them with CORS headers and crossorigin="anonymous".
A source URL is fetched only with the carrier document’s privileges and
only after the consent the render requires. Renders that transmit an input
image SHOULD require a per-image confirmation that shows the image and names
its origin.
13.3. Selectors, never locators
model is a selector: a viewer matches its values only against renderers
and models the user has configured and enabled. A viewer MUST NOT dispatch to
a model, package, endpoint or workflow because a document names it, even
inside a configured provider’s namespace, and MUST NOT download, install,
load or execute any artefact in response to a model value or to any other
key, standard or vendor, that names weights, LoRAs, workflows, graphs or
packages. Unmatched values use the user’s default renderer with
no-matching-model and are shown to the user as text, never as a link.
Viewers SHOULD let the user mark a renderer as available only on explicit
request.
13.4. Parameter forwarding
A document, through any standard or vendor key, MUST NOT be able to cause a viewer or renderer to fetch a URL, load weights, workflows or code, select or alter the endpoint, credentials, headers, webhooks or callbacks, change safety or moderation settings, or exceed the user’s configured cost policy (candidate count, steps, resolution, duration).
A renderer MUST forward document parameters to a provider only through a
mapping it controls: standard keys through its own semantics, and vendor keys only
into the provider’s model-input namespace, after validating each value
against the provider’s published input schema and the user’s limits, and only
when the key is not on the renderer’s per-provider deny-list of inputs that
name artefacts, carry credentials, or affect safety, output count or billing.
A renderer MUST ignore a key it will not forward and report
parameter-not-allowed.
"Preserved when serialising" (§ 12 Extensibility) binds serialisers, not
renderers.
13.5. Consent, budgets and cancellation
-
A render is requested by the user’s agent under the user’s provider account. Viewers MUST make this visible.
-
A viewer MUST NOT render automatically on a top-level site the user has not enabled; the default for every site is "ask" or "on request". Third-party frames are enabled separately. "Always render" is an explicit per-site setting with a spending or concurrency bound.
-
Automatic rendering MUST be bounded per page and per time window and run with bounded concurrency; limits are visible to the user and reaching one stops rendering. Elements not displayed to the user MUST NOT be rendered.
-
Consent and per-image actions are taken in viewer-owned UI from trusted user events and show the site, the full
prompt,avoidandstyletext, any input image and its origin, and the configured renderer that matched. -
The user MUST be able to cancel a render; a viewer SHOULD cancel the provider job and set provider-side time limits where the API offers them, and cancels on navigation.
-
A viewer MUST NOT render automatically from carrier 4 or from a document with
unsupported-version. -
A viewer SHOULD keep a local, clearable, unsynchronised record of renders: it is a browsing history.
-
A viewer SHOULD NOT render automatically in private browsing and MUST NOT persist records from it.
13.6. What leaves the browser
A viewer sends a provider only the parameters its renderer maps and the input
image bytes it decoded and re-encoded locally. It MUST NOT send the page URL,
title, referrer, cookies, identity or other page content, and SHOULD send
image bytes rather than URLs. The viewer’s disclosure names the provider and
links its retention terms. Any in-page UI, replacement or .jai fetch
reveals to the page that the user runs a viewer.
Credentials of the reference viewer are stored extension-locally, used only from its background context, never exposed to pages or content scripts, requested only in viewer UI, sent only to the configured endpoint, and redacted from logs; the background context accepts a provider endpoint, allow-listed parameters and image bytes, never arbitrary URLs.
13.7. Caches
A render cache keyed by identity is a cross-site history oracle. A cached render is subject to the same per-site consent and the same user action as an uncached one, and viewers SHOULD prevent documents from distinguishing cross-site cache hits, by keying the cache on (identity, renderer configuration, top-level site) or by applying comparable delay.
13.8. Viewer UI hygiene
Viewer UI MUST render every document value as text, never as markup; SHOULD
isolate bidirectional text (unicode-bidi: plaintext or <bdi>); MUST NOT
silently truncate (prompt, avoid, style and model are fully
available); SHOULD visualise or warn on control and invisible formatting
characters; MUST show the top-level site; and MUST display the configured
renderer that matched, never the document’s model string, as the thing that
will run. The same rules
apply to playgrounds and validators, which are cross-site scripting surfaces
for preview values and generated HTML snippets.
13.9. Guidance for publishers
Sites that accept user markup and do not intend to publish JAI SHOULD strip
data-jai, alt values beginning with jai: in any case, data:image/jai
URLs in src and srcset, and <source type="image/jai">. DOMPurify’s
defaults keep all of them; strict allow-list sanitisers remove all but alt.
A .jai referenced by URL is fetched per viewer at render time and may change
after review; publishers who need stability inline the document or record its
identity. Injection through templated prose (§ 5.3 Escaping arbitrary text) can truncate
or override a document but, because of the rest of this section, can neither
select a renderer nor spend beyond the user’s limits.
13.10. Provenance
Renderers that write files SHOULD set the IPTC digitalSourceType to
trainedAlgorithmicMedia (compositeWithTrainedAlgorithmicMedia for
transform) [IPTC-PHOTOMETADATA] and MUST NOT strip provider-applied
provenance such as C2PA manifests [C2PA] or watermarks when re-encoding.
Viewers mark rendered images as generated (§ 11.5.2 Accessibility).
14. Diagnostics
A diagnostic is a code from the table below, optionally with the key it concerns, and with any human-readable message the implementation chooses. Codes are stable identifiers; messages are not.
-
Parser codes are emitted by parsers, JSON readers and decoders. They are normative: a conforming implementation emits exactly these codes for the conditions described, and the conformance fixtures assert them.
-
Validator codes are advisory. A validator SHOULD emit them for the conditions described and MAY define additional codes.
-
Interpreter codes are emitted by interpreters, including model matching. They are normative: for the conditions described, a conforming interpreter emits exactly these codes, and the
interpretfixtures compare the interpreter codes it emits as an exact multiset, ignoring any other codes. An interpreter that also validates MAY emit validator codes alongside them. -
Renderer codes are emitted by renderers; a renderer MUST emit them when the condition occurs (§ 9.4 Renderer diagnostics).
-
Viewer codes are emitted by viewers.
The Key column names the key a diagnostic concerns. When it names one, an
implementation MUST attach it to the diagnostic. Fixtures write a diagnostic as
code or code:key; a fixture that writes code alone does not constrain the
key.
| Code | Class | Key | Condition |
|---|---|---|---|
empty-segment
| parser | none | An interior empty or whitespace-only segment was ignored. |
empty-value
| parser | the key of the assignment or member (ASCII-lowercased; prompt for prose)
| A value was empty after normalisation and was dropped. |
reserved-key
| parser | jai
| An assignment to the reserved key jai was dropped.
|
invalid-key
| parser | none (MAY carry the member name as written) | A JSON member name is not a valid key; the member was dropped. |
missing-marker
| parser | none | JSON object without a jai member, read in JAI context.
|
unsupported-version
| parser | none | The jai member is an integer other than 1.
|
invalid-marker
| parser | none | The jai member is not an integer.
|
number-value
| parser | the key of the assignment or member (ASCII-lowercased; prompt for prose)
| A JSON number or boolean was converted to a string. |
duplicate-member
| parser | jai
| A member name other than jai lowercases to jai; the member was dropped. (Validators MAY also report an exact repetition of a member name with this code.)
|
duplicate-key
| parser | the key of the assignment or member (ASCII-lowercased; prompt for prose)
| Two JSON member names collided after ASCII lowercasing; values were concatenated. |
unsupported-member
| parser | the key of the assignment or member (ASCII-lowercased; prompt for prose)
| A JSON object or nested array was dropped (reserved for future revisions). |
invalid-json
| parser | none | The JSON form could not be parsed; the document is empty. |
malformed-container
| parser | none | The gzip member was malformed, followed by bytes, over the bound, or did not contain JSON; the document is empty. |
undecodable
| parser | none | The bytes are not well-formed UTF-8 or exceed the text bound; the document is empty. |
first-segment-assignment
| validator | the key concerned | The first segment was an assignment to an unknown key and the document has no prompt. |
invalid-qualifier
| validator | the key concerned | A qualified key whose name is not prompt, style or avoid.
|
unknown-key
| validator | the key concerned | An undotted key that this specification does not define. |
continuation-into-single-valued-key
| validator | the key concerned | Prose continued the value of aspect, mode, strength, seed or animate (not source or preview, whose data: URLs contain semicolons; see split-data-uri).
|
no-prompt
| validator | none | No prompt, and the interpreted mode is generate.
|
bare-key
| validator | the key concerned | A prose segment is exactly a standard key; key=true was probably intended.
|
newline-assignment
| validator | the key concerned | A value contains a line break followed by key=.
|
prefix-in-prompt
| validator | the key concerned | A prompt value still begins with jai:.
|
stray-wrapper
| validator | none | The whole document is wrapped in quotes, brackets or a Markdown fence. |
split-data-uri
| validator | the key concerned | An unknown key such as charset or name follows a source or preview value: an unescaped ; inside a data URL.
|
url-split
| validator | the key concerned | A URL-like value was followed by an unknown-key assignment. |
confusable-delimiter
| validator | none | A full-width or Arabic semicolon is followed by what looks like key=.
|
confusable-equals
| validator | the key concerned | A full-width equals sign follows a key. |
foreign-syntax
| validator | none | The text looks like another prompt dialect (--ar 16:9, Negative prompt:, <lora:…>).
|
colon-assignment
| validator | the key concerned | key: value was written where key=value was probably intended.
|
quoted-value
| validator | the key concerned | A value was wrapped in quotation marks. |
percent-encoded-text
| validator | the key concerned | A non-URL value contains %XX sequences and no %25.
|
control-character
| validator | the key concerned | A value contains a control character other than TAB and LF. |
invisible-char
| validator | the key concerned | A value contains U+200B to U+200D, U+2060 or a non-initial U+FEFF. |
bidi-control
| validator | the key concerned | A value contains U+202A to U+202E or U+2066 to U+2069. |
nonstandard-value
| validator | the key concerned | A valid value in a non-canonical spelling (16x9); the canonical spelling is offered.
|
invalid-value
| validator, interpreter, renderer | the key concerned | A standard key’s value does not match its grammar and was ignored. |
negated-avoid
| validator | the key concerned | An avoid value begins with a negation.
|
strength-without-transform
| validator | the key concerned | strength without mode=transform.
|
repeated-single
| validator, interpreter, renderer | the key concerned | A single-valued key had several values; the last was used. |
model-looks-like-locator
| validator | the key concerned | A model value looks like a URL or a path.
|
large-payload
| validator | the key concerned (none for the document-size condition) | A value exceeds 8 KiB or the document exceeds 64 KiB. |
non-canonical-encoding
| validator | none | A .jai file, or an image/jai resource fetched by URL (not a data: URL), is not in the file form.
|
unencoded-url-text
| validator | none | A URL-slot value contains whitespace, # or a bare %.
|
srcset-unparseable
| validator | none | The srcset of a <source type="image/jai"> yields no candidate under HTML’s srcset parsing (for example because of an unencoded space).
|
jai-scheme-url
| validator | none | A jai: string in a URL slot.
|
alt-carrier
| validator | none | Carrier 4 is used. |
alt-carrier-payload
| validator | none | A data: URL inside an alt carrier.
|
missing-size
| validator | none | A carrier-3 image without width/height or aspect-ratio.
|
attribute-split
| validator | none | An element carrying a JAI carrier has an attribute whose name contains ", ', ; or =: an unescaped quote probably ended the carrier attribute early.
|
data-url-missing-comma
| validator | none | A data:image/jai URL in a carrier has no ,.
|
data-url-parameter
| validator | none | A data:image/jai URL has a media-type parameter other than base64 or charset.
|
source-missing-type
| validator | none | A <source> naming a .jai or data:image/jai URL has no type.
|
source-after-img
| validator | none | A JAI <source> follows the <img>.
|
keep-in-source
| validator | none | A <source type="image/jai"> carries a mode=keep document.
|
no-matching-model
| interpreter, renderer | model
| No model value selected a model (or the document has none); the default was used.
|
substituted-model
| interpreter, renderer | model
| A family match selected a model the author did not name exactly. |
version-ignored
| interpreter, renderer | model
| A version suffix of a model value was ignored.
|
mode-degraded
| interpreter, renderer | mode
| transform with an input image was rendered as generate because the selected model accepts no image.
|
original-not-readable
| renderer | mode
| transform had no readable input image. Decided when inputs are fetched; interpreters do not emit it.
|
unsupported-parameter
| renderer | the standard key concerned | A standard key could not be honoured by the model and was omitted. |
folded-into-prompt
| renderer | avoid
| avoid values were folded into the prompt text.
|
adjusted-value
| interpreter, renderer | the standard key concerned | A value was clamped, snapped, reduced or shortened. |
ignored-value
| interpreter, renderer | the standard key concerned | A value had no effect in this context (aspect with an original, source outside transform).
|
seed-nondeterministic
| renderer | seed
| The seed was passed but the mode is not deterministic. |
parameter-not-allowed
| renderer | the vendor key refused | A vendor key was refused by the forwarding rules. |
value-truncated
| viewer | the standard key concerned | A value was shortened before transmission. |
unsupported-preview
| interpreter, renderer | preview
| A preview value is not an allowed raster data: URL.
|
invalid-image
| interpreter, renderer | source
| A source value is not an allowed raster image.
|
14.1. Conformance fixtures
Fixtures live under tests/<class>/<class>.json in the specification
repository. Each file is a JSON object with class, edition and cases.
Every case has id (unique across the suite), since and rationale. A
document is an object mapping each key to an array of strings. A diagnostic is
written code or code:key (§ 14 Diagnostics). diagnostics is compared as
an exact multiset. advisories lists validator codes that an implementation
with a validator MUST emit; other codes are allowed. no_advisories lists
validator codes that it MUST NOT emit.
parse-
input(string) →document,diagnostics; optionaladvisories,no_advisories. serialize-
document→text(canonical text),json(canonical JSON),identity(lowercase hex SHA-256); optionalbare(bare serialisation) andurl(canonical URL form, § 7.5 data: URLs); each field is compared when present. roundtrip-
document→ the document survives, and serialisation is a fixed point of, each of: the canonical text parsed with the text parsing algorithm; the bare serialisation and the canonical URL form decoded with § 7.4 Decoding in a JAI context; the canonical JSON read with the JSON reading algorithm; the file form decoded with § 7.4 Decoding. json-
input(JSON text) andcontext(boolean, defaulttrue: whether the text is in a JAI context) →document,diagnostics. decode-
bytes(base64) and optionalbound(the decompression bound in bytes, default 16 MiB) →document,diagnostics; optionaladvisories,no_advisories. url-
url(string) andkind→documentanddiagnostics, ordiscovered: falsewhen the URL carries no document.kinddataapplies § 7.5 data: URLs;queryandparamapply the two forms of § 11.3 Query forms. html-
html(a fragment parsed as HTML’s fragment parsing algorithm does, with declarative shadow roots attached; base URLhttps://example.test/page/; everymediavalue matches) →discovered, one entry per<img>that carries a document, in the order of § 11.1.1 Discovery:carrier(1 to 4), and eitherdocumentanddiagnostics, orurl, the candidate URL as written insrcset, compared after resolving it against the base URL. Optionaladvisoriesandno_advisoriesapply to all carriers in the fragment. interpret-
document; optionalcatalog, the configured models in configuration order, each{id, aliases, family, image_input, default}(familymay be null;default: truemarks the user’s default model, otherwise the first entry is the default); optionalfamilies, the renderer’s family list, mapping each family name to its spellings in order; optionalhas_original(boolean, defaultfalse: whether the carrier offers an original image); optionalgoverning_ratio(number: the element’s governing ratio, absent for none); optionalselected(theidof a catalog entry the user chose, which is then the selected model instead of the result of § 8.2 Model matching) →interpretedanddiagnostics.interpretedis compared only for the members present:description(string, after § 8.3 Per-model refinements);styleandavoid(arrays of strings, after § 8.3 Per-model refinements);aspect(W/H as a number,squareas 1, or the stringlandscapeorportrait);mode(string, the interpreted value of themodekey);strength(number);seed,source,preview(string);animate(boolean);model(theidof the selected catalog entry);ratio(the ratio to render at under § 9.3 Size and aspect, W/H as a number;nullwhen thepreviewor the renderer’s default decides).nullmeans absent or invalid.diagnosticsis the exact multiset of interpreter codes.
Fixtures are append-only from the first tagged edition: a changed expectation is a new case id with an erratum, never a silent edit.
15. Writing JAI by hand
This section is informative.
-
Write the description first, as you would describe the picture to someone on the phone: what is in it, how it is arranged, the light, the colours, the medium. Ordinary punctuation, including semicolons, is fine.
-
Add settings after a semicolon, each as
name=value:;style=anime,;aspect=16:9,;avoid=text. Repeatstyleandavoidfor several items rather than listing them in one value. -
Put
jai:in front when the place you are writing in does not already say it is JAI (a chat message, a document). On a web page, put the text in adata-jaiattribute (no prefix needed) or use the<picture>form; avoidalt, which screen readers read aloud. -
If your description itself starts with a word followed by
=, start withprompt=instead. If you need a literal;right before something that looks likename=, write\;. -
For an existing photo you want restyled, add
;mode=transformand;strength=0.6. Describe the finished picture, including what stays the same, not the change. -
Name a model only if you care:
;model=flux. It is a preference, not a command; the reader’s own setup decides. -
Check it in the playground: it shows what a reader’s software will see and offers the canonical spelling to copy.
16. Examples
This section is informative.
A red bicycle leaning against a whitewashed wall, afternoon sun
jai:A lighthouse on a cliff in a storm;style=watercolor jai:A lighthouse on a cliff in a storm;style=anime jai:A lighthouse on a cliff in a storm;style=35mm film photo;style=grainy
jai:A still life of pears on pewter, Dutch golden age;model=flux;model=sdxl;aspect=4:3
< picture > < source type = "image/jai" srcset = "data:image/jai,Fishing%20boats%20in%20a%20harbour%20at%20dawn,%20as%20a%20loose%20pencil%20sketch;mode=transform;strength=0.7" > < img src = "harbour.jpg" alt = "Fishing boats in a harbour at dawn" crossorigin = "anonymous" width = "1200" height = "800" > </ picture >
< img src = "team.jpg" alt = "The four founders in front of the office" data-jai = "Four people in casual clothes standing in front of a brick office building, overcast daylight;mode=keep" >
.jai file’s content, decompressed:
{ "jai" : 1 , "prompt" :[ "A magical castle on a hill at dusk, lanterns in the windows" , "Mist in the valley below" ], "aspect" : "16:9" , "avoid" :[ "people" , "text" ], "model" : "flux" , "style" : "storybook illustration" }
jai:A brass astrolabe on velvet;comfy.sampler=euler;dc.title=Astrolabe study
Appendix A. Media type registration template
This appendix is informative until registration is pursued. It follows the form of RFC 6838 §5.6 [RFC6838].
- Type name
-
image
- Subtype name
-
jai
- Required parameters
-
none
- Optional parameters
-
none (
charsethas no meaning; content is always UTF-8) - Encoding considerations
-
binary. The file form is a gzip member; the text and JSON forms are UTF-8.
- Security considerations
-
See § 13 Security and privacy considerations. Decoding transmits content to a renderer and is performed under the viewer’s account; decoders bound decompression; model references are selectors and are never fetched; documents are untrusted input and parsing is total.
- Interoperability considerations
-
Three serialisations are distinguished by their leading bytes (§ 7.4 Decoding). Renderers produce different pixels for the same document by design.
- Published specification
-
This document.
- Applications that use this media type
-
Browsers and browser extensions, image generation tools, authoring tools, AI agents.
- Fragment identifier considerations
-
none
- Additional information
-
Deprecated alias: none. Magic numbers:
1F 8B(gzip), then{"jai":1followed by,or}after decompression; or{for the uncompressed JSON form. File extension:.jai. Macintosh file type code: none. - Person and email address to contact for further information
-
The editors, via the specification repository.
- Intended usage
-
COMMON
- Restrictions on usage
-
none
- Author
-
The editors.
- Change controller
-
The specification repository.
Appendix B. Model family names
This appendix is informative. Family names and spellings a renderer may
recognise in model values. The list implies nothing about availability.
| Family | Spellings |
|---|---|
| flux | flux, flux-schnell, flux-dev, flux-pro, kontext
|
| sdxl | sdxl, stable diffusion xl, stable-diffusion-xl
|
| sd3 | sd3, stable diffusion 3
|
| ideogram | ideogram
|
| recraft | recraft
|
| dall-e | dall-e, dalle
|
| gpt-image | gpt image, gpt-image
|
| imagen | imagen
|
| midjourney | midjourney, mj
|
Appendix C. Relationship to existing formats
This appendix is informative.
Prompt metadata in rasters. Tools such as AUTOMATIC1111 and ComfyUI write
their prompt and settings into PNG text chunks. An importer maps them as
follows: the positive prompt → prompt; "Negative prompt" → one avoid
value per comma-separated item; "Seed" → seed; "Model" or ckpt_name →
model; "Denoising strength" → strength with mode=transform; "Size" →
aspect (lossily). Sampler, steps, CFG scale and other internals go to
a1111.* or comfy.* vendor keys or are dropped. Weighting syntax such as
(word:1.3) passes through uninterpreted.
JAI inside raster files. A raster that was rendered from, or described
by, a JAI document may carry the canonical JSON form in a PNG iTXt chunk
with keyword jai, an empty language tag and an empty translated keyword
(compressed or not), or in XMP as the simple property jai:document in the
namespace https://jai.gnist.ai/ns/xmp/1.0/ (preferred prefix jai). This lets the editable source travel with the
pixels.
Placeholders. BlurHash and ThumbHash serve the same purpose as preview
with smaller payloads; see § 8.1.8 preview.
Provenance. IPTC digital source types and C2PA manifests describe how an image was made; JAI describes what it should show. A renderer that writes files sets the former (§ 13.10 Provenance).
Other dialects. --ar 16:9 → aspect=16:9; --no text → avoid=text;
--seed N → seed=N; --niji → style=anime; --style raw → dropped.
Appendix D. Serving .jai files
This appendix is informative.
Apache (.htaccess):
AddType image/jai .jai
<FilesMatch "\.jai$">
Header set Access-Control-Allow-Origin "*"
</FilesMatch>
nginx:
types { image/jai jai; }
location ~ \.jai$ { add_header Access-Control-Allow-Origin "*"; }
GitHub Pages serves .jai as application/octet-stream; decoders inspect
the bytes regardless (§ 7.3 Media type and file extension).
Appendix E. Stability and change policy
This appendix is informative.
-
Frozen in this edition: the data model, the text grammar and parsing algorithm, the canonical forms, the JSON shape and the file form.
-
Extensible: the key vocabulary (keys are added by revision and never removed; a key may be deprecated with a diagnostic), the reserved member shapes, the diagnostics registry.
-
Informative and expected to change: model families, the carrier-by-context matrix, server mappings.
-
The
jaimarker stays 1 across editions. Parsers accept every document of any 1.x edition. Fixtures are append-only after the first tagged edition. -
The Agent Skill states the edition it teaches.
-
Everything in the specification repository is released under CC0-1.0.
Acknowledgements
The first edition was shaped by an adversarial review of the design across grammar, authoring, web platform, security, rendering, file format, agent authoring, accessibility and prior-art lenses, whose findings are recorded in the repository’s design record.