chore: release v0.24.0 - #139
Open
github-actions[bot] wants to merge 1 commit into
Open
Conversation
Contributor
Author
github-actions
Bot
force-pushed
the
tegami/version-packages
branch
from
September 4, 2026 17:05
5e06696 to
2f2f8f7
Compare
github-actions
Bot
force-pushed
the
tegami/version-packages
branch
from
September 6, 2026 00:16
2f2f8f7 to
3fe0bed
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
All bumped packages.
@reactunity/create0.23.20.24.0@reactunity/material0.23.20.24.0@reactunity/renderer0.23.20.24.0@reactunity/scripts0.23.20.24.0Changelogs
2026-09-03-1f9ad3.mdShow Bumped Packages (1)
npm:@reactunity/rendererTailwind's Preflight, rewritten for ReactUnity
@reactunity/renderer/tailwind.cssis what a ReactUnity app imports in place of Tailwind'sPreflight. Preflight resets what a browser does to a document, and here most of it names elements
ReactUnity has not got while the rules that do land —
*clearing every margin and padding — leaveReactUnity's own control styling half undone. This is the equivalent written for what ReactUnity
renders: the padding and the grey fill on a
button, aninputand atogglego, sop-*andbg-*are the only things that decide,appearancestays so they still behave as controls, and theroot gets a line height and the font family ReactUnity actually ships. It also carries the two theme
values whose defaults are stacks of web font names,
--font-sansand--font-mono.An app still writes the one line Tailwind's docs give it.
@reactunity/renderer/vitealiases abare
@import "tailwindcss"to this file, so nothing about the setup changes:Only the bare specifier is aliased —
tailwindcss/theme.cssand the rest keep resolving to thepackage, which is where this entry gets them from — and
reactUnity({ tailwind: false })turns thealias off. Either half can also be imported alone, as
@reactunity/renderer/tailwind/preflight.css— intolayer(base), since an unlayered rule beatsevery utility — and
@reactunity/renderer/tailwind/theme.css. The kitchen-sink sample now loadsTailwind once for every page, Preflight included and the control look written back into its own
baselayer through@apply, andUsing Tailwind CSS covers what does and does
not carry over.
2026-09-03-4ac1e7.mdShow Bumped Packages (1)
npm:@reactunity/rendererCSS logical properties
padding-inline,margin-block,inset-inline-startand the rest of the logical box propertiesnow work, as longhands, as the two-value shorthands, and under their camelCase names in an inline
style:
The inline axis is handed to Yoga's own start and end edges rather than resolved here, which is what
makes
directionmean something: it is inherited, so setting it once turns the inline axis aroundfor a whole subtree, and an element needs no
directionof its own to follow one set above it. Theblock axis is always vertical —
writing-modedoes not exist here, soblock-startis the top.An inline value takes precedence over the physical property covering the same edge whichever order
the two are declared in. CSS would let the later declaration win; that is the one place the two
disagree, and the reason not to set both on one edge. Under UIToolkit the inline axis is always the
physical one, since UIElements has no start and end edge and ignores
direction.padding-start,margin-endandborder-start-width— the React Native spellings that have beenin the property table all along — reach the same edges, and now do something for the first time:
nothing had been pushing them to Yoga.
The practical effect is that Tailwind's
px-*,py-*,mx-*,my-*,inset-x-*,border-x-*,ps-*,ms-*,start-*andspace-x-*all work. v4 writes every two-axis and start/end utilityas a logical property, so those had been quietly doing nothing.
2026-09-03-7b3e41.mdShow Bumped Packages (1)
npm:@reactunity/rendererA Vite preset for ReactUnity apps
@reactunity/renderer/viteconfigures Vite the way a ReactUnity app needs it, so a project's wholeconfig is:
Output goes into the Unity project. The preset walks up from the Vite root looking for an
Assetsfolder beside aProjectSettings/ProjectVersion.txt, testing each ancestor and one levelbelow it, and builds into that project's
Assets/Resources/react. Both layouts are found: the appinside the project, and the app beside it.
unityProjectandassetPathsay it outright when theguess is wrong, and it stays out of the way entirely if the config already sets
build.outDir.The output folder is cleaned, and the
.metafiles survive. Unity writes a.metabeside everyasset, and the GUID in it is what scenes and prefabs reference — so emptying the folder the way Vite
would means every rebuild mints new GUIDs and breaks whatever pointed at the old ones. The clean
deletes the output and leaves the metas, and once the build has written its files it drops only the
metas whose asset did not come back, along with any directory the build left empty. A build that
fails leaves the metas alone, so the next successful one restores the files under their original
GUIDs.
preserveexempts paths the build does not own, and the clean refuses outright to run on adirectory that is not plausibly build output — a package, a repository, an
Assetsfolder, oranything containing the Vite root.
For the same reason, output filenames carry no content hash by default: a hash renames the file on
every build, which costs it its meta.
hashFileNames: truerestores Vite's naming.Emitted assets carry their extension twice, so
index.cssis written asindex.css.css. Unityfinds a resource by its path minus the last extension, which makes
assets/index.jsandassets/index.cssthe same resource -- and asking for the script could hand back the stylesheet, tobe run as JavaScript. Doubling puts the type back into the name the lookup uses. Content hashes did
this by accident before; without them it has to be deliberate.
Assets are never inlined. Vite turns a file under 4 kB into a
data:URI, and Unity loads anasset URL through its own loaders — so a small image that got inlined stopped resolving. The limit
is 0, which is where
react-unity-scriptshad it too.CSS is emitted for an old browser. ReactUnity's CSS subset does not know
oklch(),color-mix()or nesting, and a stylesheet that uses them silently loses those declarations.
build.cssTargetdefaults to
chrome87, which is what makes Lightning CSS lower them on the way out — enough thatTailwind v4's palette arrives as hex.
Vite's devtools and the HMR error overlay are off. Neither has anywhere to draw in Unity, and an
overlay rendered into a page nobody is looking at only hides the console message.
Everything the config sets itself wins — the preset only fills in what was left out — and
react: falsedrops@vitejs/plugin-reactfor a project that wants to configure React itself.2026-09-05-9f2d4b.mdShow Bumped Packages (1)
npm:@reactunity/renderer@starting-style, light-dark(), color-scheme, place-* shorthands, math functions, :nth-child(of S), attr(), linear() and boolean hover/pointer queries
@starting-styleis the style an element has on the frame it appears, and the state atransitionstarts from. It used to collapse into the enclosing rule, so@starting-style { opacity: 0 }made the element invisible for good. Each rule in a block is now applied through:enter, which is the machinery ReactUnity already had for the first frame:.a { @starting-style { opacity: 0 } }is.a:enter { opacity: 0 }, and the top-level form works the same. The one visible deviation is that:enteradds pseudo-class specificity where the web adds none.light-dark(<light>, <dark>)picks one of two values, wherever a color goes. The newcolor-schemeproperty (normal,light,dark,light dark; inherited) decides: a single scheme settles it for the subtree, anything else defers to theprefers-color-schememedia feature, and a change to that feature restyles the tree.color-schemeon the root element also seedsprefers-color-scheme, so@media (prefers-color-scheme: dark)rules follow the page's declared scheme; a value set throughMediaProvider.SetValueis never seeded over, and withdrawing the declaration restores what the feature held.DefaultMediaProvider.SeedValueis the public shape of that.place-content,place-itemsandplace-selfset the align and justify pair in one declaration, which Tailwind emits constantly. Yoga has nojustify-itemsorjustify-self, so the last two set their align property and only check that a second value is a keyword. The align and justify longhands also take the web spellingsstart,end,self-start,self-end,left,rightandnormal.The math functions beyond
min()/max()/clamp():round()withnearest,up,downandto-zero,mod(),rem(),abs(),sign(),sin(),cos(),tan(),asin(),acos(),atan(),atan2(),pow(),sqrt(),hypot(),log()andexp(), plus the constantspi,e,infinity,-infinityandNaN. Operands are calc() expressions, so they nest in one another and incalc(), and takevar(); all-constant inputs fold at parse time. The property's own converter reads the operands, soround(1250ms, 1s)is a duration, and when it refuses one they are all read as plain numbers, which is whatcalc(mod(7, 3) * 1s)needs;round(1s, 1)mixes the two and is invalid. Trigonometric arguments are angles or radians, the inverse functions return degrees.calc()with a leading sign,calc(-1 * 10px), used to fail to parse and now works.:nth-child(An+B of S)and:nth-last-child(An+B of S)count only the siblings matchingS, a selector list of compound selectors; a branch with a combinator is dropped, since siblings are what is counted. The clause adds the specificity of its most specific branch, as on the web.attr()reads adata-*prop into any property:content: attr(data-label), with the prefix optional, a fallback as the second argument, and a unit after the name (attr(data-size px)) or a type for a typed value. A pseudo element reads the element it belongs to, and a number or boolean prop reads as its text.linear()joinssteps()andcubic-bezier()as an easing:linear(0, 0.25 40%, 1), with up to two positions per stop to hold a value, missing positions spread evenly, and extrapolation past the ends.The
hover,any-hover,pointerandany-pointermedia features are now always defined, so the boolean forms(hover)and(pointer)are the standard way to gate hover-only styling; a platform whose real value was the provider's default used to leave them undefined. Two provider bugs went with it: a mobile platform registered theconsolemedia type instead ofmobile, and the legacy Input path listed a touch screen as a fine pointer.TypeScript's
RenderStylegainscolorScheme,placeContent,placeItemsandplaceSelf, and the align and justify types take the new spellings.2026-09-05-b7e3a1.mdShow Bumped Packages (1)
npm:@reactunity/rendererAccept the CSS that Tailwind and the web actually emit
A stylesheet written for a browser, or generated by Tailwind v4, reaches ReactUnity full of spellings the engine parsed into nothing. Each one below was silently dropped before; each is now either honoured or mapped onto the nearest thing the renderer already had.
Names and keywords. Vendor prefixes are stripped, so
-webkit-line-clampismax-linesand-webkit-text-strokeistext-stroke(custom properties keep their--).text-decoration-linesets the same flags asfont-style.overflow: autoscrolls andoverflow: cliphides.font-variant: small-caps(and-caps,all-small-caps,petite-caps) is atext-transform.text-aligntakesjustify,startandend;text-overflowtakesclip.text-wrap: balance | pretty | stableparse as plain wrapping. Thedvh/svh/lvhfamily,dvw/svw/lvw, theirmin/maxforms andvi/vball resolve as viewport lengths.min(),max()andclamp(). Anywherecalc()works, with the same operand grammar, soclamp(1rem, 2vw + 0.5rem, 2rem)andmin(100%, var(--width))resolve against the same reference ascalc.noneis accepted for either bound ofclamp, and all-constant inputs fold at parse time.white-space.text-wrap: nowrapused to be the whole story;white-spacenow carriespre,pre-wrap,pre-lineandbreak-spaces, and TextMeshPro'stextWrappingModefollows it, preserving runs of spaces and newlines where the value asks for it. The renderer'swhiteSpacetyping grew the same values.text-shadow. Rendered through TMP's underlay, so the shader draws it and no second text object exists. Pixel offsets and blur are converted to the underlay's own units from the font asset's sampling point size and gradient scale, which is why1px 1px 2pxlooks the same at any font size. TMP has a single underlay, so only the first shadow of a list is drawn.overflow-xandoverflow-y.overflowis now a two-value shorthand over them. Yoga still has one overflow, so it gets the stronger of the two (scroll over hidden over visible), and the mask applies when either axis is hidden, because a rectangle mask cannot clip one axis alone. What the split does buy is scroll direction: a<scroll>withoverflow-x: hiddenscrolls vertically only, andoverflow-y: hiddenhorizontally only, unless thedirectionprop says otherwise.caret-colorand::selection. Both on<input>. The caret defaults tocurrentColoras the spec says.::selectionis a pseudo-element like::placeholder, and itsbackground-coloris the TMP_InputField's selection highlight, soinput:focus::selection { background-color: … }works too. That is the whole of what TextMeshPro can recolor: the selected glyphs keep their own color, and<text>has no selection at all.scrollbar-colorandscrollbar-width.scrollbar-color: <thumb> <track>andscrollbar-width: auto | thin | none | <length>on a<scroll>. They are implemented as custom properties the user-agent::scrollbarand::scrollbar-thumbrules read throughvar(), which gives the precedence the web has for free: a::scrollbarrule of your own still wins, andautofalls back to the defaults.noneis a zero-size scrollbar rather thandisplay: none, because the ScrollRect toggles the scrollbar object itself to auto-hide it. One deviation: both inherit, where the spec inherits only the color.Media queries.
prefers-color-schemeandprefers-reduced-motionexist as features. The default scheme follows the Editor skin in the Editor and islightin a player; reduced motion defaults tono-preference. Both are runtime values, set withDefaultMediaProvider.SetValuefrom whatever the game reads from the platform.Gradients.
linear-gradient(to right in oklab, …), and the same hint onradial-andconic-gradient, parse. The colour space itself is not honoured; interpolation stays in sRGB, which is what a browser does for the defaultin srgband is a close match for the short hues Tailwind emits.A regression test pins down that Tailwind's
filter: var(--tw-blur,) var(--tw-brightness,) …chains already worked: an emptyvar()fallback resolves to nothing and the remaining functions compose.2026-09-05-e4c1a7.mdShow Bumped Packages (1)
npm:@reactunity/rendererContainer queries, style queries and container units
container-type(normal,size,inline-size),container-nameand thecontainershorthand make an element a query container, and@containerrules read the nearest eligible ancestor:(min-width: 400px),(width > 400px),(400px <= width < 800px),aspect-ratio,orientation,and/or/not, an optional container name, and nesting inside style rules,@media,@supports,@layerand other@containerblocks. A length in a condition resolves against the container, so20emis its font size.style()queries compare a property of the container: a custom property as its declared text, withstyle(--theme)alone meaning it is set; a regular property as its computed value. Every element can answer one, whatever itscontainer-type.cqw,cqh,cqi,cqb,cqminandcqmaxmeasure the nearest size container's content box on each axis, and fall back to the viewport where there is none.A container is measured after layout, and one whose content box changed since a query or a unit last read it restyles its subtree and lays out again in the same frame, up to twice. There is no size containment, so a container whose size depends on what the query changes can oscillate, and stops where the second pass lands. UIToolkit, whose layout is the framework's, sees a resize a frame later. A change to a property a
style()query reads re-resolves the elements that read it, inherited or not.The bundled parser reads a
@containerprelude as written, since a container query is not a media query, and parses one nested in a style rule the way it parses a nested@media.TypeScript's
RenderStylegainscontainerTypeandcontainerName.2026-09-06-a4c7e2.mdShow Bumped Packages (1)
npm:@reactunity/rendererscrollbar-gutter, and scrollbar-size is gone
scrollbar-gutter: auto | stable | stable both-edgeson a<scroll>. ReactUnity's scrollbars are drawn over the content, so there was never layout shift to prevent; whatstablebuys here is that content is never covered. The viewport shrinks by the bar's thickness along the bar's edge, for each direction the view can scroll in, and Yoga loses the same width, so awidth: 100%child fits the visible area exactly and does not start a horizontal scroll of its own.both-edgesmirrors the gutter onto the opposite edge. The thickness comes from the bar's own computed size, soscrollbar-width: thinreserves 6px andnonereserves nothing. One limit: a percent padding on the scroll view cannot absorb the gutter, so the gutter is skipped there.scrollbar-size, an alias ofscrollbar-widththat never existed on the web, is removed from the property map and theRenderStyletyping.scrollbar-widthis the spelling.2026-09-06-d2e7b9.mdShow Bumped Packages (1)
npm:@reactunity/rendererlight-dark() reaches Unity as written from a Vite build
The Vite plugin names an old browser as the CSS target so Lightning CSS lowers oklch, color-mix and nesting, which ReactUnity does not read. That target also lowered
light-dark(), into two variables that only acolor-schemedeclaration in the same sheet defines, so an app's ownlight-dark()colors came out invalid unless a Tailwindscheme-*utility happened to sit next to them. The plugin now excludes that one feature from the lowering, since ReactUnity resolveslight-dark()itself; an app that setscss.lightningcss.excludekeeps its own value.Publish
The following packages will be published if merged:
@reactunity/create0.24.0npm@reactunity/material0.24.0npm@reactunity/renderer0.24.0npm@reactunity/scripts0.24.0npm