Changelog
All notable changes to @ivkit/core, @ivkit/player and @ivkit/react are documented here. The packages are versioned together.
The format is based on Keep a Changelog, and this project follows Semantic Versioning. Until 1.0.0, minor versions may include breaking changes, which are always listed under Changed or Removed.
Unreleased
Added
@ivkit/react: a new package with anIvkitPlayerReact component for React 18 and 19. It setsstory,renderHotspotandpluginsas properties, takescontrols,autoplayandmutedas boolean props, turns each event into a typed callback such asonAnswer, renders children into the player's slots and forwards its ref to the element. It's a client component, so server components can render it.
0.2.0 - 2026-10-29
Variables and conditions, multiple-answer and timed questions, cues and player plugins, jumping to any scene, and recovery from videos that fail. Both packages are now licensed under Apache 2.0.
Added
@ivkit/core:answerRange(question, offered), the fewest and most options an answer takes. The engine,validateStoryand the player now share it.@ivkit/core:StoryEngine.goTo(sceneId, time?), which enters any scene from any state, dismissing the question on screen, and plays it fromtime, asking its questions from there on. It works beforestart(), e.g. to resume a saved story. Thesceneevent now carries thattime, andMediaControllerstarts the video there.@ivkit/core:StoryEngine.seek(time), which resumes the current scene fromtimelike aseekin the story.@ivkit/core:StoryEngine.destroy(), which cancels a question's timeout and removes every listener, andpauseTimeout()andresumeTimeout(), which stop and go on with a question's countdown.@ivkit/player:goTo(sceneId, time?)on<ivkit-player>, which jumps to a scene and plays it. Use it to branch on a score, resume where the viewer left off or build chapter menus.@ivkit/core: anerrorevent onMediaControllerwhen a scene's video can't be loaded or played, andretry(), which loads it again from where it failed. A failed preload is no longer stuck: it's loaded again when its scene comes.@ivkit/player: an error screen with anerrorslot, aniv-errorevent andretry(), so a missing or unplayable video no longer leaves the player frozen without notice.@ivkit/player: removing the player from the page pauses a question's timeout until it's back, and keeps a scene that finishes loading meanwhile from playing. Setting another story destroys the previous engine.@ivkit/core:pauseon hotspots, which pauses the video when the hotspot appears until it's activated. The engine emits a newpauseevent, andMediaControllerpauses on the hotspot's first frame and resumes when it's activated without agoto.@ivkit/core: variables and conditions in the story format.Story.varsdeclares variables,setchanges them on choices, hotspots and scenes,branchespick a scene by condition before falling back togotoornext, andifoffers a choice or shows a hotspot only while it holds.validateStoryreports undeclared variables with the newmissing_variablecode.@ivkit/core:StoryEngine.vars,StoryEngine.setVar()and avarsevent. Theinteractionevent now includes theoptionsoffered, andanswerandhotspotinclude the scene they branch to asgoto.@ivkit/player: questions show only the options whoseifholds, andiv-interaction,iv-answerandiv-hotspotcarry the same new fields as the engine's events.@ivkit/core:correcton choices, reported in theanswerevent to score quizzes.@ivkit/core:seekon choices and hotspots, which resumes the current scene from another second when they don't branch, asking the questions from there on again.MediaControllernow seeks onresumewhen itstimeisn't the current one.@ivkit/player:hrefon hotspots, which openshttp:andhttps:links in a new tab when activated.@ivkit/core: multiple-answer questions.multiple: truetakes several options, bounded byminandmax, and applies each one'sset. Questions also takegoto,branchesandseek, which decide formultiplequestions and act as a fallback for single ones.StoryEngine.answer()takes a list of ids, and theanswerevent addschoicesandcorrect, true when exactly the options markedcorrectwere picked.@ivkit/player:multiplequestions show toggle options and a Confirm button, exposed as::part(submit).@ivkit/core:timeoutanddefaulton questions. When nobody answers in time, the engine emits a newtimeoutevent and answers withdefault, or else lets the question'sbranches,gotoandseekdecide.@ivkit/player: a countdown bar for questions withtimeout, exposed as::part(timer), and aniv-timeoutevent. The player now ignores events from an engine it has replaced.@ivkit/core:cueevents in the story format, which mark a span of a scene for plugins and apps, picked bykind. The engine emits a newcuesevent with the active ones and exposes them asStoryEngine.activeCues.@ivkit/core:dataon the story, scenes, events and options, free-form JSON that IVKit carries but never reads.validateStorychecks that it's a JSON object.@ivkit/core:validateStory(story, { cues })runs a plugin's checks on cues of its kind, reporting with the newinvalid_cuecode.@ivkit/player: plugins throughplayer.use(plugin). A plugin runs for each story with the engine, the media controller, its own layer over the video and anon()that unsubscribes by itself, and may return a cleanup. The player also dispatchesiv-cues.@ivkit/core: atimeevent onMediaController, with each playback time it reports to the engine.<ivkit-player>now moves animated hotspots on it instead of keeping its own frame callbacks.
Changed
- The license is now the Apache License 2.0 instead of MIT, for both packages.
- Size budgets: the standalone player now stays under 9.5 KiB gzip (was 8 KiB), and all of
@ivkit/coreunder 6 KiB (was 4 KiB), to fit variables, conditions, multiple-answer questions and timeouts. @ivkit/player: its CSS is now minified at build time, which takes about 500 B off the standalone player.@ivkit/core:MediaControlleremitsblockedonly when the autoplay policy rejectsplay()(aNotAllowedError). Aplay()interrupted by a pause or a new source no longer shows the player's Play button over a scene that's playing.@ivkit/core:MediaController.play()does nothing while the next scene loads, so the previous scene can't play, heard but hidden, behind it.@ivkit/player: settingstoryto one whosestartisn't a scene throws without resetting the player, instead of leaving it half reset.@ivkit/core: a listener that moves the story, withgoTo(),start()orseek(), wins over what the engine was doing. Before, agoTo()from ananswer,hotspotortimeoutlistener was overridden by the answer's own branch or followed by a staleresume.@ivkit/core: a listener that throws no longer stops the other listeners or leaves the engine halfway through a transition. Its error is still reported.@ivkit/player: a plugin that throws, when it runs or cleans up, no longer stops the player or the plugins after it.@ivkit/player:restart(), and so the Replay button, sets the variables back to their initial values. Before, a replay kept the previous run's scores and counters.@ivkit/player: hotspots that stay on screen keep their buttons when others appear or go, so keyboard focus,renderHotspotchanges and animations aren't lost.renderHotspotruns once per hotspot while it stays on screen.
0.1.1 - 2026-10-27
The first release of @ivkit/player, which wasn't published as 0.1.0.
Fixed
@ivkit/core:VERSIONreported0.0.0instead of the package's version. It's now read frompackage.jsonat build time.
0.1.0 - 2026-10-27
The first release of @ivkit/core.
Added
@ivkit/core
- Story format: scenes with a video, a
nextscene, questions and hotspots. StoryEngine, a DOM-free state machine that drives a story from playback time, with events for scenes, questions, answers, hotspots and the end of the story.- Questions that pause on their exact frame and branch, resume or continue to the next scene. They fire once per visit, and seeking past several asks only the earliest.
- Hotspots shaped as rectangles, ellipses or polygons, animated through keyframes with
linear,ease-in-outorstepeasing, morphing between shapes. MediaController, which plays a story on two stacked media elements: it preloads the likely next scene and swaps only once its first frame can be drawn, so there's no black frame between scenes. It follows playback withrequestVideoFrameCallback, falling back totimeupdate.validateStory, which reports every problem in untrusted story data with a JSON Pointer and an error code.hotspotGeometryAt,boundsOfandisAnimated, for drawing hotspots in custom players.
@ivkit/player
- The
<ivkit-player>Web Component, withcontrols,autoplayandmutedattributes. - A control bar with play/pause, seeking within the scene, volume and fullscreen, plus keyboard shortcuts.
- Fullscreen for the whole player, including questions and hotspots, with a viewport-covering fallback on iPhone.
- Hotspot variants
outline,pulse,labelandhidden, custom variants styled through::part(hotspot-<variant>), andrenderHotspotfor custom content. - Theming through
--iv-*custom properties,::part()for every element, andstartandendslots. iv-scene,iv-interaction,iv-answer,iv-hotspotandiv-endevents, typed throughHTMLElementEventMap.@ivkit/player/element, which exports the element class anddefineIvkitPlayer()without registering anything.- Safe to import during server-side rendering. React Server Components, Cloudflare Workers and Vercel Edge get a server build without DOM code.
- A standalone build,
ivkit-player.min.js, that includes core and loads straight from a CDN, under an 8 KiB gzip budget.