github nyblnet/bento v1.2.0
bento/slides v1.2.0

7 hours ago

Download the single file below and open it in any modern browser — it's the document, the viewer and the editor in one. Shipped files self-update through the signed release channel.

  • A deck opens inside Teams and SharePoint again. Their viewer refuses
    the way 1.1.0's file started itself (a script loaded from a blob: URL).
    The file now starts the way nothing refuses: the runtime is inserted as an
    inline script first, and only if a policy turns that down does it fall
    back to new Function, then to the blob import — measured in Teams with
    seven variants. Inside such a viewer the frame has no storage, so
    autosave and preferences do not persist there, and its policy blocks every
    connection — so inside an embedded view the app makes no request at all:
    no update check at launch, no language-pack listing, no live-session
    socket; the About dialog says so. The deck itself opens, presents and
    saves.
  • Maths is Bento's own now, and it reads Typst. Formulas in text used to
    go through Temml, a 64 KB library that every saved deck carried. A small
    engine of our own (slides/src/maths, about 8 KB) renders them instead, so
    every file you save is about 78 KB smaller, and nothing in the file changes:
    a formula is still the $…$ source you typed. Measured against Temml on 91
    formulas, from our own decks and from Temml's own list of supported
    functions: 97.8% render pixel-identical, and the rest are places where
    Temml drew nothing on Chrome — \overline and \underline now draw their
    rule. New: Typst maths, asked for by thimotedupuch (#358) — write
    $typst: a/b$ (or $$typst: …$$) and the formula is read as Typst:
    sqrt(x), sum_(i=1)^n, mat(a, b; c, d), cases(…), "if" x. A plain
    $…$ is LaTeX as before. Not covered, for now: \substack, \xrightarrow,
    chemistry (\ce), \tag and \hline; a formula using them shows as
    typed, the way any TeX Temml refused always has.
  • Slides export as images. Save ▾ Export slides as images… writes
    this slide, or every slide in the show, as PNG or JPEG at 1× or 2× — one
    file per page, named after the deck (My_Deck-page-01.png), hidden slides
    and interactive states left out the way a PDF leaves them out. Chromium
    asks for a folder and writes the pages into it; other browsers get one
    download per page; Safari can export the current slide. The picture is the
    deck's own render — its fonts, gradients and shapes — with charts and media
    as stills and web-linked images blank, since a file cannot fetch. No ZIP,
    no second renderer: about four kilobytes of runtime. Asked for by den-sv
    (#243, #261); the shape follows lazyeo's #306, kept to the thin half —
    the heavier converter belongs to bento/convert.
  • A Layers list. The Slide panel now opens with Layers: every element
    on the slide, top of the stack first, with a glyph and a short label (the
    text's first words, or the kind). Click a row to select, shift-click to add,
    drag a row to move it up or down the stack, or use ⌘↑ and ⌘↓ with the list
    focused. With an element selected the same list closes its panel, so the
    highlighted row is never far. Nothing new in the file: the list is a view
    onto the order the four Order buttons (front, forward, backward, back) have
    moved elements through since 1.0, and a row dropped somewhere lands exactly
    where those buttons would put it. Asked for by Li Wei in discussion #371.
  • A deck can be written the short way. An AI agent writing a deck used
    to spend most of its output on fields nobody chose — rotation 0, opacity 1,
    the font stack, weight 400, centre, middle, line height 1.25, on every
    element. A document marked "compact": true may leave all of that out and
    gets it back on load, filled from the same defaults the editor uses when
    you insert an element; elements may nest arrays, and an element without
    an id gets one minted from its slide and position, the same every time.
    Save ▾ Copy compact JSON (for agents) and window.bento.compact() hand
    a deck back in that shape; Replace from JSON… and loadDoc take it. The
    saved file is unchanged — always full, so nothing older is affected.
    Measured: 12–14% off a designed deck's JSON, about 3× off a deck written
    the compact way. Asked for, with a working proof of concept, by
    benedictjohannes (#411, #422); the nested arrays and the flattening come
    from that proof.
  • The short way, round two: text sizes itself, markdown is accepted, and
    a load says what it dropped.
    In a compact document a text element may
    leave h out (or say "auto"): the box is sized to its text on load,
    with the deck's real fonts — the same measurement as Fit height to text.
    A text element may carry md instead of html and it converts exactly as
    pasted markdown does (bold, italic, code, strike, bullets and sub-bullets,
    links). And window.bento.loadDoc now returns a report: every key the
    safety check discarded, with its path and the reason (/slides/0/elements/2/fontSze: unknown key), how many fields were filled in, and validate()'s findings
    — so an agent's loop is load, read, fix, load again, instead of guessing
    why a field vanished. Replace from JSON… summarises the same report in a
    toast and logs it. Three agent-written decks are checked in and load clean
    in CI.
  • An agent can place a slide by layout and role. In the compact form a
    slide may say "layout": "title-body" and its elements carry a role
    (title, body, subtitle, kicker, quote, attribution, image,
    card1…) instead of coordinates and typography: the layout's frames and
    type are used, the same way Apply layout fills a slide in the editor, and
    slides born from the same layout still morph their chrome. Several body
    paragraphs stack into the slot, each sized to its text; an element that
    carries its own x y w h is placed as given. Four new built-in layouts —
    Three cards, Quote, Image left, Image right — appear in the layout
    picker for everyone, next to the five that were there. The file on disk is
    unchanged: the layout is applied on load, and what is saved is the placed
    slide.
  • bento check: an agent can look at what it wrote. node scripts/bento-check.mjs deck.bento.html loads the deck in headless Chrome
    and prints what the editor would otherwise keep to itself — text that
    overflows its box (and by how many pixels), elements off the canvas, dead
    links, effects that can never run — by slide, with element ids; --png out/
    adds one PNG per slide through the same render path as Export slides as
    images
    , and a contact sheet of the whole deck in one picture; --json for
    scripts, --fail-on warning for a strict exit code. A document JSON works
    as input too, checked inside the built shell. The other half of the agent
    loop that AGENTS.md describes: write, check, fix, check again.
  • The format has a schema, and every file says where it is. A JSON
    Schema for the bento/slides document is generated from the same tables the
    app uses to check what it loads, so it cannot describe a deck the app would
    refuse. It is published at https://bento.page/schema/slides.json (and a
    version-pinned copy beside it), returned by window.bento.schema() in a
    running file, listed in https://bento.page/llms.txt for AI agents, and
    named in the Tooling comment at the top of every deck. A deck that carries
    "$schema" at the top validates in any schema-aware editor; the app ignores
    the key. Runtime cost: about 2.6 KB in the shell.
  • A saved deck names its schema. The first key of the saved JSON is now
    "$schema": "https://bento.page/schema/slides.json" — 50 bytes, so a
    reader with only the file in hand knows the format. Older versions keep the
    key and write it back unchanged; nothing fetches it.
  • Connectors for diagrams. Three asks from xairy, in one go. A
    Curved connector (#302): a curve that sticks to the elements at its ends
    and re-routes when they move, like the straight Connector, and carries a
    tip that points the way the curve arrives rather than along the chord; any
    open curved line can take tips now. Seven more tip styles (#303): open
    arrow, triangle, hollow triangle, diamond, hollow diamond, square, hollow
    circle — a hollow head stops the line at its back edge, so nothing shows
    through. A Double arrow shape (#304): the solid arrow with a head at both
    ends; and a line has always taken an arrowhead at each end through its
    start and end tips. Sticking (#301) has been in since 1.0.2. Old decks are
    untouched: the original tips keep their exact geometry. A deck that uses
    the new tips opens in 1.1.0 and older, but those shells draw a bar where a
    new tip should be; a double arrow shows there as a single one.
  • A picture can be moved and zoomed inside its frame. Double-click an
    image and the frame becomes a window onto the whole picture: drag to choose
    which part shows, scroll or pinch to zoom in, Enter to keep it, Esc to put
    it back. The Crop section of the image panel has the zoom as a number and a
    way back to the whole picture. The crop is one small optional field on the
    image; a deck opened in an older version shows the cover-fitted picture,
    never a blank frame. Canvas, thumbnails, the show, print and file-manager
    previews all show the same crop, and a morph between two cropped copies of
    a picture glides between them. Asked for in discussion #319 by morreau.
  • A pasted photo no longer costs megabytes. Insert or paste a picture
    and it is stored at slide resolution — the long edge capped at 2560 px,
    crisp on a 4K projector — and photos are re-encoded as JPEG, so a phone
    photo adds a few hundred KB to the file instead of three or four MB.
    Screenshots, logos, charts and anything with transparency are only
    downscaled, never made lossy, so text in them stays sharp; SVG and GIF are
    left alone; and when re-encoding would not save at least a fifth, the
    original bytes are kept. When the saving is worth mentioning a toast says
    so ("Photo stored at 2560 px — 3.8 MB → 410 KB"). The picture panel shows
    what is stored and offers Replace file (original size)… for the times
    you want every pixel; Shrink photos on insert in the About dialog turns
    it off for this browser. Nothing in an existing deck changes until you
    insert something new. The file itself is untouched: a picture is still a
    picture.
  • An image can drop its aspect ratio, and the properties panel stays
    where you left it.
    Contributed by 1eevy (#372). Images gain a Keep
    aspect ratio
    switch in the Fit & corners section, on by default: turn it
    off and width and height resize independently (the image stretches to
    fill); Shift is the one-drag exception in either direction, as it always
    was. Turning it back on keeps the shape the image has at that moment. And
    changing a control near the bottom of the properties panel no longer throws
    the panel back to the top. The same PR proposed editable template pages
    with locked furniture and a save-time asset compactor; the compactor's job
    landed as #447/#476, and locked furniture is a design question for a
    discussion rather than a change to how layouts work.
  • A date can pin its format, and fields are one click away. {{date}}
    and {{time}} have resolved in text since 0.9.12, but they followed the
    viewer's locale — an author could not say M/D/YY and have every viewer see
    it — and nothing in the editor said the tokens existed. Now
    {{date:M/D/YY}}, {{date:D MMMM YYYY}}, {{time:h:mm a}} pin the
    shape (YYYY YY MMMM MMM MM M DD D HH H hh h mm ss A a; a word in
    [brackets] stays literal; month names still come in the viewer's
    language), and the Text panel gains a Field picker that drops a page
    number, date, time, title or document property into the text — the date
    and time entries show today in each shape so the choice is made by eye.
    Bare {{date}} is unchanged. Asked for in discussion #381 by Jef Ducon.
  • Every file is about 38 KB smaller. The runtime's two compressed blocks
    used to be base64; they are now base86 — 86 printable characters chosen so
    the text can never close or comment out the block that carries it — which
    is 6.25% denser (4 bytes in 5 characters instead of 3 in 4). Measured on
    the release shell: 699,847 → 661,768 bytes. Older versions keep opening
    their own files; this one still reads theirs. The new decoder is also
    quicker than the old atob path (11 ms against 47 for the runtime).
  • A deck opened in a background tab is ready when you switch to it. The
    compressed file used to finish starting in a later task and hold its
    splash on a timer — in a tab that was not visible (or a viewer rendering
    the file off-screen for a preview card) timers are throttled and frames
    never come, so the editor sat behind the splash until the tab was looked
    at. The runtime now unpacks and starts inside the file's own script,
    before the page is even "loaded", and a hidden document drops the splash
    the moment the editor exists; visible, the brand moment is held for at
    most 0.8 s and never waits on its own fade.
  • A web link whose address contains a dollar sign works again. Since
    links arrived, an address like …/$a$b had its two dollars read as a
    formula and the link broke; formulas are now looked for in the text only,
    never inside a tag.
  • A pasted code snippet keeps its code. The table the app uses to know
    an element's fields had no entry for the code element, so a pasted or loaded
    code block kept its box but lost its content, grammar and theme — an empty
    snippet — and validate() did not know its fields. Found while building
    the schema from that table; fixed.
  • A plain Save drops unused images too. 1.1.0 promised that a save
    leaves out every image nothing in the deck refers to, and it did — on
    every path except the one most people use. ⌘S and the Save button write
    through a different route, and the clean-up never ran there, so a deleted
    screenshot stayed in the file. It runs on every way of saving now.
    Reported again, with a step-by-step, by charlycoste (#442, fixed in #476).
  • Every language pack is complete. The 22 downloadable packs had fallen
    to 91% of the interface — the formatting bar, the context menu, the canvas
    help, hidden slides, appearance, and the whole live-broadcast surface
    showed in English. All 22 carry every string again.
  • One brand yellow. Ten places in the editor chrome — the speaker view's
    timer, buttons and current thumbnail, the show's link, selection and
    progress colours, the follow chip, and the path editor's anchor dots —
    carried their own copy of the accent instead of reading the chrome's
    --accent token. They read the token now; nothing looks different. The
    slide-list highlight already did. The deck's own theme.accent is a
    separate thing and stays separate: chrome does not recolour per deck.

Don't miss a new bento release

NewReleases is sending notifications on new releases.