uxml-preview 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/LICENSE +201 -0
- package/README.md +400 -0
- package/THIRD-PARTY-NOTICES.md +55 -0
- package/dist/controls/registry.d.ts +10 -0
- package/dist/index.d.ts +110 -0
- package/dist/index.js +1292 -0
- package/dist/layout/yoga.d.ts +63 -0
- package/dist/model/types.d.ts +288 -0
- package/dist/parser/uss.d.ts +33 -0
- package/dist/parser/uxml.d.ts +12 -0
- package/dist/render/css-map.d.ts +16 -0
- package/dist/render/measure.d.ts +9 -0
- package/dist/render/paint.d.ts +19 -0
- package/dist/render/values.d.ts +50 -0
- package/dist/serializer/uss.d.ts +6 -0
- package/dist/serializer/uxml.d.ts +8 -0
- package/dist/style/properties.d.ts +20 -0
- package/dist/style/resolve.d.ts +42 -0
- package/dist/style/selector.d.ts +21 -0
- package/dist/style/specificity.d.ts +6 -0
- package/package.json +59 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — unreleased
|
|
4
|
+
|
|
5
|
+
First release. Parses Unity UI Toolkit `.uxml` and `.uss`, lays them out through
|
|
6
|
+
the same Yoga engine UI Toolkit uses, paints to the DOM, and writes the files
|
|
7
|
+
back unchanged.
|
|
8
|
+
|
|
9
|
+
### Verified
|
|
10
|
+
|
|
11
|
+
Measured against **Unity 6000.0.40f1** across 18 layout cases and 61 elements:
|
|
12
|
+
**242 of 244 element coordinates identical** (0.5px tolerance; the matching 17
|
|
13
|
+
cases agree exactly, not merely within tolerance). Procedure and per-case
|
|
14
|
+
figures in [`docs/accuracy.en.md`](docs/accuracy.en.md).
|
|
15
|
+
|
|
16
|
+
Round-trip is byte-exact on all 15 fixtures — comments, attribute order,
|
|
17
|
+
entity encodings, CRLF line endings, mixed indentation, unsupported controls.
|
|
18
|
+
|
|
19
|
+
### Supported
|
|
20
|
+
|
|
21
|
+
- Controls: `VisualElement`, `Label`, `Button`
|
|
22
|
+
- Selectors: type, class, `#name`, descendant, child, compound, universal,
|
|
23
|
+
pseudo-classes, `@import`
|
|
24
|
+
- Cascade: specificity, source order, inheritance, inline styles, `var()`
|
|
25
|
+
custom properties, shorthand expansion
|
|
26
|
+
- Layout: the flex family, sizing, box model, positioning
|
|
27
|
+
- Full matrix: [`docs/supported.en.md`](docs/supported.en.md)
|
|
28
|
+
|
|
29
|
+
### Known limitations
|
|
30
|
+
|
|
31
|
+
- **Only geometry was compared to Unity, and only as far as Yoga.** The figure
|
|
32
|
+
is measured at the layout engine's output; the painted DOM is checked against
|
|
33
|
+
it by an invariant of our own, not against Unity. Colours, borders, corner
|
|
34
|
+
radii and fonts render but were never measured at all.
|
|
35
|
+
- **Text measurement was not compared.** Unity uses its own font asset; the
|
|
36
|
+
line-height factor is an estimate.
|
|
37
|
+
- **`Button` has no golden case.** It renders through the `Label` path.
|
|
38
|
+
- One measured divergence: a percentage against a parent with no explicit size.
|
|
39
|
+
`yoga-layout` 3.2.1 resolves the main axis where UI Toolkit's Yoga does not.
|
|
40
|
+
Recorded in `KNOWN_DIVERGENCES` rather than smoothed over.
|
|
41
|
+
- `-unity-slice-*`, `-unity-background-image-tint-color` and `transition` are
|
|
42
|
+
parsed and preserved but not drawn.
|
|
43
|
+
- Editing a single attribute regenerates that tag's other attributes, so a
|
|
44
|
+
multi-line attribute list collapses onto one line.
|
|
45
|
+
- Changing an element's child list drops comments that sat between children.
|
|
46
|
+
|
|
47
|
+
### API
|
|
48
|
+
|
|
49
|
+
`loadLayoutEngine`, `parse`, `serialize`, `render`, `resolveStyles`,
|
|
50
|
+
`explainProperty`. See the README.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# uxml-preview
|
|
2
|
+
|
|
3
|
+
**Render and edit Unity UI Toolkit UXML/USS in the browser — no Unity Editor required.**
|
|
4
|
+
|
|
5
|
+
**유니티 에디터 없이, 브라우저에서 UXML/USS를 렌더링하고 편집합니다.**
|
|
6
|
+
|
|
7
|
+
### ▶ [Try it in your browser](https://reuhomi.github.io/uxml-preview/) · [한국어](#한국어)
|
|
8
|
+
|
|
9
|
+
Paste your own `.uxml` and `.uss`, or open one of the examples. Nothing is
|
|
10
|
+
uploaded — it all runs locally in the page.
|
|
11
|
+
|
|
12
|
+
[](https://reuhomi.github.io/uxml-preview/)
|
|
13
|
+
|
|
14
|
+
<sub>Deleting one line rotates the layout ninety degrees — `flex-direction`
|
|
15
|
+
defaults to `column` in USS and `row` in CSS. It is the most common way a ported
|
|
16
|
+
stylesheet comes out wrong.</sub>
|
|
17
|
+
|
|
18
|
+
[](https://github.com/ReuHomi/uxml-preview/actions/workflows/ci.yml)
|
|
19
|
+
[](https://github.com/ReuHomi/uxml-preview/actions/workflows/pages.yml)
|
|
20
|
+
[](LICENSE)
|
|
21
|
+
|
|
22
|
+
[English](#english) · [한국어](#한국어)
|
|
23
|
+
|
|
24
|
+
> ⚠️ **Status: pre-alpha.** Under active development. Not yet published to npm.
|
|
25
|
+
> 현재 개발 초기 단계입니다. 아직 npm에 배포되지 않았습니다.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
<a name="english"></a>
|
|
30
|
+
## English
|
|
31
|
+
|
|
32
|
+
### What it does
|
|
33
|
+
|
|
34
|
+
`uxml-preview` parses Unity UI Toolkit `.uxml` and `.uss` files and renders them
|
|
35
|
+
directly in a web browser. It uses **Yoga** — the same layout engine Unity UI Toolkit
|
|
36
|
+
itself uses — compiled to WebAssembly, so results match the Unity Editor rather than
|
|
37
|
+
approximating it.
|
|
38
|
+
|
|
39
|
+
Measured against Unity 6000.0.40f1: **242 of 244 element coordinates identical**
|
|
40
|
+
across 18 layout cases. The two that differ are named and explained in
|
|
41
|
+
[`docs/accuracy.en.md`](docs/accuracy.en.md).
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
.uxml + .uss → parse → style resolve → Yoga layout → DOM paint
|
|
45
|
+
↓
|
|
46
|
+
edit in browser
|
|
47
|
+
↓
|
|
48
|
+
serialize back to .uxml/.uss
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Why
|
|
52
|
+
|
|
53
|
+
Designing Unity UI Toolkit interfaces today means a slow round trip: mock it up
|
|
54
|
+
somewhere, hand-translate to UXML, open the Unity Editor, check, repeat. Web-based
|
|
55
|
+
design tools and AI coding agents can write UXML, but neither can *see* the result.
|
|
56
|
+
That broken feedback loop is what this library fixes.
|
|
57
|
+
|
|
58
|
+
**Use cases**
|
|
59
|
+
- Preview UXML layouts without launching Unity
|
|
60
|
+
- Give AI agents a visual feedback loop when authoring UI Toolkit interfaces
|
|
61
|
+
- Embed a UXML preview in your own tooling (editor extensions, internal tools)
|
|
62
|
+
- Share UI mockups with people who don't have Unity installed
|
|
63
|
+
|
|
64
|
+
### Design principles
|
|
65
|
+
|
|
66
|
+
1. **Never reimplement layout.** Unity UI Toolkit delegates layout to Yoga. So do we.
|
|
67
|
+
Reimplementing it guarantees drift.
|
|
68
|
+
2. **Round-trip fidelity is non-negotiable.** Parse → serialize must preserve comments,
|
|
69
|
+
attribute order, and formatting. If opening and saving a file produces a noisy
|
|
70
|
+
git diff, it's unusable in practice.
|
|
71
|
+
3. **USS is not CSS.** Different box model, different defaults, no `z-index`,
|
|
72
|
+
no `@keyframes`. [**USS is not CSS**](docs/uss-vs-css.md) walks through the
|
|
73
|
+
differences with a live example for each.
|
|
74
|
+
4. **Honest support matrix.** Unsupported properties produce warnings, not silent
|
|
75
|
+
wrong output. See [`docs/supported.en.md`](docs/supported.en.md).
|
|
76
|
+
|
|
77
|
+
### Status & roadmap
|
|
78
|
+
|
|
79
|
+
| Phase | Scope | Status |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| 0 | Repo scaffold + playground | ✅ |
|
|
82
|
+
| 1 | Data model | ✅ |
|
|
83
|
+
| 2 | Parser + serializer (round-trip) | ✅ |
|
|
84
|
+
| 3 | USS style resolver | ✅ |
|
|
85
|
+
| 4 | Yoga layout + DOM painting | ✅ |
|
|
86
|
+
| 5 | Golden tests against Unity | ✅ |
|
|
87
|
+
| 6 | **v0.1 release** | 🔨 |
|
|
88
|
+
| 7+ | More controls, editing layer, tool integration | ⬜ |
|
|
89
|
+
|
|
90
|
+
Full plan: [`docs/ROADMAP.md`](docs/ROADMAP.md)
|
|
91
|
+
|
|
92
|
+
### What is not verified yet
|
|
93
|
+
|
|
94
|
+
The support matrix is deliberately conservative — see
|
|
95
|
+
[`docs/supported.en.md`](docs/supported.en.md) for the full table.
|
|
96
|
+
|
|
97
|
+
- **Only geometry was compared, and only as far as Yoga.** The figure above is
|
|
98
|
+
measured at the coordinates the layout engine produces. Whether the painted
|
|
99
|
+
DOM reproduces them is checked by an invariant of our own rather than against
|
|
100
|
+
Unity. Colours, borders, corner radii and fonts are implemented but were not
|
|
101
|
+
measured at all; coordinates say nothing about them.
|
|
102
|
+
- **Text measurement was not compared.** Unity renders text with its own font
|
|
103
|
+
asset. Layout that is driven by measured text will not match exactly, and the
|
|
104
|
+
line-height factor is still an estimate.
|
|
105
|
+
- **`Button` has no golden case.** It renders through the same path as `Label`,
|
|
106
|
+
but "same path" is not a measurement.
|
|
107
|
+
- `-unity-slice-*`, `-unity-background-image-tint-color` and `transition` are
|
|
108
|
+
parsed and preserved, but not drawn.
|
|
109
|
+
|
|
110
|
+
### API
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { loadLayoutEngine, parse, render, serialize } from 'uxml-preview';
|
|
114
|
+
|
|
115
|
+
// Yoga is WebAssembly, so it loads once, up front. `render` stays synchronous.
|
|
116
|
+
await loadLayoutEngine();
|
|
117
|
+
|
|
118
|
+
// text → model
|
|
119
|
+
const doc = parse(uxmlText, ussText);
|
|
120
|
+
|
|
121
|
+
// model → screen
|
|
122
|
+
const view = render(doc, document.getElementById('preview'), {
|
|
123
|
+
resolveAsset: (path) => myAssetUrlFor(path),
|
|
124
|
+
});
|
|
125
|
+
console.log(view.warnings);
|
|
126
|
+
|
|
127
|
+
// Yoga nodes are WASM handles and are not garbage collected.
|
|
128
|
+
view.dispose();
|
|
129
|
+
|
|
130
|
+
// model → text
|
|
131
|
+
const { uxml, uss } = serialize(doc);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Playground
|
|
135
|
+
|
|
136
|
+
**[reuhomi.github.io/uxml-preview](https://reuhomi.github.io/uxml-preview/)** —
|
|
137
|
+
or run it locally:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
pnpm install
|
|
141
|
+
pnpm dev
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Edit UXML and USS on the left, see the result on the right. The panel size is
|
|
145
|
+
set explicitly rather than following the window, because USS percentages and
|
|
146
|
+
stretching resolve against the panel — a preview that resizes with the browser
|
|
147
|
+
cannot answer "how does this look at 1920×1080".
|
|
148
|
+
|
|
149
|
+
The corner reads `round-trip: exact` whenever serializing the document back out
|
|
150
|
+
reproduces what you typed, byte for byte. It is the round-trip guarantee checked
|
|
151
|
+
live, on your own file — and it holds for text that does not parse, too, since
|
|
152
|
+
untouched input is copied out of the original rather than regenerated. Half a
|
|
153
|
+
tag, no root element, an empty file: still exact. `DIFFERS` would mean a bug
|
|
154
|
+
here, not in your document.
|
|
155
|
+
|
|
156
|
+

|
|
157
|
+
|
|
158
|
+
The panel size is chosen rather than inherited from the window, so a layout can
|
|
159
|
+
be checked at the resolution it will actually ship at.
|
|
160
|
+
|
|
161
|
+

|
|
162
|
+
|
|
163
|
+
The examples are chosen to show the traps: `flex-direction` defaulting to
|
|
164
|
+
`column`, overlap ordered by markup rather than `z-index`, and unsupported
|
|
165
|
+
controls surviving a round trip while being reported rather than drawn.
|
|
166
|
+
|
|
167
|
+
### Development
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
pnpm test # everything
|
|
171
|
+
pnpm test:roundtrip # parse -> serialize is byte-identical
|
|
172
|
+
pnpm test:golden # regression snapshots + comparison against Unity
|
|
173
|
+
pnpm golden:emit # write the golden cases out for loading into Unity
|
|
174
|
+
pnpm build
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Reproducing the accuracy numbers needs a Unity install; the procedure is in
|
|
178
|
+
[`docs/accuracy.en.md`](docs/accuracy.en.md).
|
|
179
|
+
|
|
180
|
+
### Accuracy
|
|
181
|
+
|
|
182
|
+
Checked by comparing element geometry against the Unity Editor, case by case.
|
|
183
|
+
Geometry rather than pixels: Unity draws text with its own font asset and a
|
|
184
|
+
browser does not, so a pixel diff would measure the font more than the layout.
|
|
185
|
+
|
|
186
|
+
Measured against Unity on 2026-08-02, over 18 cases and 61 elements:
|
|
187
|
+
|
|
188
|
+
| | |
|
|
189
|
+
|---|---|
|
|
190
|
+
| Cases matching exactly | **17 / 18** |
|
|
191
|
+
| Values within 0.5px | **242 / 244 (99.2%)** |
|
|
192
|
+
|
|
193
|
+
The one divergence is a percentage sized against a parent that has no explicit
|
|
194
|
+
size, where `yoga-layout` resolves the main axis and the Yoga inside UI Toolkit
|
|
195
|
+
does not. It is recorded rather than smoothed over — see
|
|
196
|
+
[`docs/accuracy.en.md`](docs/accuracy.en.md) for the numbers, the failed attempts to
|
|
197
|
+
configure around it, and how to reproduce the measurement.
|
|
198
|
+
|
|
199
|
+
### Questions this answers
|
|
200
|
+
|
|
201
|
+
**Can I preview a UXML file without opening the Unity Editor?**
|
|
202
|
+
Yes. Paste `.uxml` and `.uss` into the [playground](https://reuhomi.github.io/uxml-preview/),
|
|
203
|
+
or call `parse()` and `render()` from the library. Nothing is uploaded and Unity
|
|
204
|
+
is never launched.
|
|
205
|
+
|
|
206
|
+
**Why does my CSS layout come out wrong in UI Toolkit?**
|
|
207
|
+
Most often because `flex-direction` defaults to `column` in USS and `row` in CSS,
|
|
208
|
+
so every container without an explicit direction is rotated ninety degrees. The
|
|
209
|
+
other four common causes — no `z-index`, forced `border-box`, no bare text nodes,
|
|
210
|
+
no margin collapsing — are in [USS is not CSS](docs/uss-vs-css.md), each with a
|
|
211
|
+
live example.
|
|
212
|
+
|
|
213
|
+
**Does USS support `z-index`, CSS Grid, or `calc()`?**
|
|
214
|
+
No, none of the three. Overlap follows markup order, grid layouts must be rebuilt
|
|
215
|
+
as nested flex, and computed values have to be resolved to fixed numbers or
|
|
216
|
+
calculated in C#.
|
|
217
|
+
|
|
218
|
+
**How close is the output to Unity?**
|
|
219
|
+
242 of 244 element coordinates identical against Unity 6000.0.40f1, across 18
|
|
220
|
+
layout cases. Geometry is compared rather than screenshots, because Unity draws
|
|
221
|
+
text with its own font asset. The single divergence and the numbers behind this
|
|
222
|
+
are in [`docs/accuracy.en.md`](docs/accuracy.en.md).
|
|
223
|
+
|
|
224
|
+
**Will it damage my files if I edit them?**
|
|
225
|
+
Editing goes through a model that keeps the original text. An unedited document
|
|
226
|
+
serializes back byte-for-byte — comments, attribute order, entity encodings and
|
|
227
|
+
CRLF endings included — and an edit rewrites only the region it touched. The
|
|
228
|
+
playground shows this live as `round-trip: exact`.
|
|
229
|
+
|
|
230
|
+
**What happens to controls it does not support?**
|
|
231
|
+
They are kept in the tree, reported as a warning, excluded from rendering, and
|
|
232
|
+
written back out unchanged. One unsupported control never takes down the rest of
|
|
233
|
+
the screen, and nothing is silently dropped.
|
|
234
|
+
|
|
235
|
+
### License
|
|
236
|
+
|
|
237
|
+
Apache-2.0
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
<a name="한국어"></a>
|
|
242
|
+
## 한국어
|
|
243
|
+
|
|
244
|
+
### 무엇을 하는가
|
|
245
|
+
|
|
246
|
+
`uxml-preview`는 Unity UI Toolkit의 `.uxml`, `.uss` 파일을 파싱해서 웹 브라우저에
|
|
247
|
+
직접 렌더링하는 라이브러리입니다. Unity UI Toolkit이 실제로 사용하는 레이아웃 엔진인
|
|
248
|
+
**Yoga**를 WebAssembly로 그대로 사용하기 때문에, 결과를 "비슷하게 흉내내는" 것이 아니라
|
|
249
|
+
유니티 에디터와 일치시킵니다.
|
|
250
|
+
|
|
251
|
+
Unity 6000.0.40f1과 대조한 결과, 레이아웃 케이스 18개에서
|
|
252
|
+
**요소 좌표 244개 중 242개가 완전히 일치**합니다. 어긋난 2개는
|
|
253
|
+
[`docs/accuracy.md`](docs/accuracy.md)에 사유까지 적어뒀습니다.
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
.uxml + .uss → 파싱 → 스타일 계산 → Yoga 레이아웃 → DOM 페인팅
|
|
257
|
+
↓
|
|
258
|
+
브라우저에서 편집
|
|
259
|
+
↓
|
|
260
|
+
.uxml/.uss로 다시 저장
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 왜 만드는가
|
|
264
|
+
|
|
265
|
+
지금 UI Toolkit으로 UI를 만들려면 왕복이 깁니다. 어딘가에 시안을 만들고 → 손으로 UXML로
|
|
266
|
+
옮기고 → 유니티를 켜서 확인하고 → 안 맞으면 되돌아갑니다. 웹 기반 디자인 도구나 AI 코딩
|
|
267
|
+
에이전트가 UXML을 쓸 수는 있지만, 둘 다 그 결과를 **볼 수 없습니다.** 이 끊긴 피드백
|
|
268
|
+
루프를 잇는 것이 이 라이브러리의 목적입니다.
|
|
269
|
+
|
|
270
|
+
**활용**
|
|
271
|
+
- 유니티를 켜지 않고 UXML 레이아웃 확인
|
|
272
|
+
- AI 에이전트가 UI Toolkit UI를 만들 때 시각적 피드백 루프 제공
|
|
273
|
+
- 자체 도구(에디터 확장, 사내 툴)에 UXML 프리뷰 내장
|
|
274
|
+
- 유니티가 없는 사람과 UI 시안 공유
|
|
275
|
+
|
|
276
|
+
### 설계 원칙
|
|
277
|
+
|
|
278
|
+
1. **레이아웃을 직접 구현하지 않는다.** UI Toolkit은 레이아웃을 Yoga에 위임합니다.
|
|
279
|
+
우리도 그렇게 합니다. 직접 구현하면 반드시 어긋납니다.
|
|
280
|
+
2. **왕복 보존은 타협 대상이 아니다.** 파싱 → 직렬화 시 주석, 속성 순서, 서식이
|
|
281
|
+
유지되어야 합니다. 열었다 저장했을 때 git diff가 지저분해지면 실무에서 못 씁니다.
|
|
282
|
+
3. **USS는 CSS가 아니다.** 박스 모델이 다르고, 기본값이 다르고, `z-index`가 없고,
|
|
283
|
+
`@keyframes`가 없습니다. [**USS는 CSS가 아니다**](docs/uss-vs-css.ko.md)에
|
|
284
|
+
차이점마다 직접 해볼 수 있는 예제 링크와 함께 정리해뒀습니다.
|
|
285
|
+
4. **지원 범위를 정직하게 밝힌다.** 미지원 속성은 조용히 틀린 결과를 내는 대신
|
|
286
|
+
경고를 남깁니다. [`docs/supported.md`](docs/supported.md) 참조.
|
|
287
|
+
|
|
288
|
+
### 진행 상황
|
|
289
|
+
|
|
290
|
+
| 단계 | 범위 | 상태 |
|
|
291
|
+
|---|---|---|
|
|
292
|
+
| 0 | 저장소 뼈대 + 놀이터 | ✅ |
|
|
293
|
+
| 1 | 데이터 모델 | ✅ |
|
|
294
|
+
| 2 | 파서 + 직렬화 (왕복 검증) | ✅ |
|
|
295
|
+
| 3 | USS 스타일 리졸버 | ✅ |
|
|
296
|
+
| 4 | Yoga 레이아웃 + DOM 페인팅 | ✅ |
|
|
297
|
+
| 5 | 유니티 대조 골든 테스트 | ✅ |
|
|
298
|
+
| 6 | **v0.1 공개** | 🔨 |
|
|
299
|
+
| 7+ | 컨트롤 확장, 편집 레이어, 도구 통합 | ⬜ |
|
|
300
|
+
|
|
301
|
+
전체 계획: [`docs/ROADMAP.md`](docs/ROADMAP.md)
|
|
302
|
+
|
|
303
|
+
### 아직 검증되지 않은 것
|
|
304
|
+
|
|
305
|
+
지원 범위는 일부러 보수적으로 적었습니다. 전체 표는
|
|
306
|
+
[`docs/supported.md`](docs/supported.md)에 있습니다.
|
|
307
|
+
|
|
308
|
+
- **좌표만, 그것도 Yoga 층까지만 비교했습니다.** 위 수치는 레이아웃 엔진이 낸
|
|
309
|
+
좌표를 잰 것입니다. 그려진 DOM이 그 좌표를 재현하는지는 유니티가 아니라 자체
|
|
310
|
+
불변식 검사로 봅니다. 색·테두리·모서리·폰트는 구현돼 있지만 아예 측정하지
|
|
311
|
+
않았습니다 — 좌표로는 알 수 없는 것들입니다
|
|
312
|
+
- **텍스트 측정은 대조하지 않았습니다.** 유니티는 자기 폰트 에셋으로 글자를
|
|
313
|
+
그립니다. 측정된 텍스트가 좌우하는 레이아웃은 정확히 맞지 않고, 행 높이
|
|
314
|
+
계수도 아직 추정치입니다
|
|
315
|
+
- **`Button`은 골든 케이스가 없습니다.** `Label`과 같은 경로로 그려지지만,
|
|
316
|
+
"같은 경로"는 측정이 아닙니다
|
|
317
|
+
- `-unity-slice-*`, `-unity-background-image-tint-color`, `transition`은
|
|
318
|
+
파싱·보존은 되지만 그려지지 않습니다
|
|
319
|
+
|
|
320
|
+
### 놀이터
|
|
321
|
+
|
|
322
|
+
**[reuhomi.github.io/uxml-preview](https://reuhomi.github.io/uxml-preview/)** —
|
|
323
|
+
또는 로컬에서:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
pnpm install
|
|
327
|
+
pnpm dev
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
왼쪽에서 UXML과 USS를 고치면 오른쪽에 바로 반영됩니다. **패널 크기는 창을 따라가지
|
|
331
|
+
않고 직접 지정합니다** — USS의 `%`와 stretch가 전부 패널 크기에 걸려 있어서,
|
|
332
|
+
창 크기를 따라가는 프리뷰로는 "1920×1080에서 어떻게 보이나"에 답할 수 없기 때문입니다.
|
|
333
|
+
|
|
334
|
+
우상단의 `round-trip: exact`는 **지금 입력한 내용을 다시 저장했을 때 바이트 단위로
|
|
335
|
+
같다**는 뜻입니다. 왕복 보존이라는 약속을 사용자 파일로 실시간 검사하는 것이고,
|
|
336
|
+
**파싱되지 않는 텍스트에도 성립합니다** — 건드리지 않은 입력은 재생성하지 않고
|
|
337
|
+
원본에서 그대로 복사하기 때문입니다. 태그를 반쯤 지우든, 루트가 없든, 파일을
|
|
338
|
+
비우든 `exact`입니다. `DIFFERS`가 뜬다면 그건 문서가 아니라 **이 라이브러리의
|
|
339
|
+
버그**라는 뜻입니다.
|
|
340
|
+
|
|
341
|
+
예제는 예쁜 것보다 **함정을 보여주는 것**으로 골랐습니다 — `flex-direction`의 기본값이
|
|
342
|
+
`column`이라는 것, 겹침 순서가 `z-index`가 아니라 마크업 순서로 정해진다는 것,
|
|
343
|
+
미지원 컨트롤이 그려지지는 않지만 경고와 함께 왕복에서 살아남는다는 것.
|
|
344
|
+
|
|
345
|
+
### 개발
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
pnpm test # 전체
|
|
349
|
+
pnpm test:roundtrip # 파싱 -> 직렬화 바이트 일치
|
|
350
|
+
pnpm test:golden # 회귀 스냅샷 + 유니티 대조
|
|
351
|
+
pnpm golden:emit # 골든 케이스를 유니티용 파일로 출력
|
|
352
|
+
pnpm build
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
정확도 수치를 재현하려면 유니티가 필요합니다. 절차는
|
|
356
|
+
[`docs/accuracy.md`](docs/accuracy.md)에 있습니다.
|
|
357
|
+
|
|
358
|
+
### 이런 질문에 답합니다
|
|
359
|
+
|
|
360
|
+
**유니티를 켜지 않고 UXML을 미리 볼 수 있나요?**
|
|
361
|
+
됩니다. [놀이터](https://reuhomi.github.io/uxml-preview/)에 `.uxml`과 `.uss`를
|
|
362
|
+
붙여넣거나, 라이브러리의 `parse()`·`render()`를 호출하면 됩니다. 아무것도
|
|
363
|
+
업로드되지 않고 유니티도 실행되지 않습니다.
|
|
364
|
+
|
|
365
|
+
**CSS 레이아웃을 옮겼는데 UI Toolkit에서 왜 어긋나나요?**
|
|
366
|
+
대개 `flex-direction` 기본값 때문입니다. USS는 `column`, CSS는 `row`라서
|
|
367
|
+
방향을 명시하지 않은 모든 컨테이너가 90도 틀어집니다. 나머지 네 가지 흔한
|
|
368
|
+
원인(`z-index` 없음, `border-box` 강제, 맨몸 텍스트 노드 없음, margin 상쇄 없음)은
|
|
369
|
+
[USS는 CSS가 아니다](docs/uss-vs-css.ko.md)에 직접 해볼 수 있는 예제와 함께 있습니다.
|
|
370
|
+
|
|
371
|
+
**USS에 `z-index`나 CSS Grid, `calc()`가 있나요?**
|
|
372
|
+
셋 다 없습니다. 겹침은 마크업 순서로 정해지고, 그리드는 중첩 flex로 다시 짜야 하며,
|
|
373
|
+
계산이 필요한 값은 고정값으로 풀거나 C#에서 계산해야 합니다.
|
|
374
|
+
|
|
375
|
+
**유니티와 얼마나 같나요?**
|
|
376
|
+
Unity 6000.0.40f1 기준, 레이아웃 케이스 18개에서 **요소 좌표 244개 중 242개 일치**
|
|
377
|
+
입니다. 스크린샷이 아니라 좌표를 비교하는데, 유니티가 자기 폰트 에셋으로 글자를
|
|
378
|
+
그리기 때문입니다. 유일한 불일치와 근거 수치는
|
|
379
|
+
[`docs/accuracy.md`](docs/accuracy.md)에 있습니다.
|
|
380
|
+
|
|
381
|
+
**편집하면 파일이 망가지지 않나요?**
|
|
382
|
+
편집은 원본 텍스트를 그대로 들고 있는 모델을 거칩니다. 고치지 않은 문서는 주석·속성
|
|
383
|
+
순서·엔티티 표기·CRLF까지 **바이트 단위로 같게** 저장되고, 고친 경우에도 건드린
|
|
384
|
+
영역만 바뀝니다. 놀이터의 `round-trip: exact` 표시가 이걸 실시간으로 보여줍니다.
|
|
385
|
+
|
|
386
|
+
**지원하지 않는 컨트롤은 어떻게 되나요?**
|
|
387
|
+
트리에 유지되고, 경고로 보고되고, 렌더링에서만 빠지고, 저장하면 그대로 다시
|
|
388
|
+
나옵니다. 미지원 컨트롤 하나 때문에 화면 전체가 죽지 않고, 조용히 사라지는 것도
|
|
389
|
+
없습니다.
|
|
390
|
+
|
|
391
|
+
### 라이선스
|
|
392
|
+
|
|
393
|
+
Apache-2.0
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
### Keywords
|
|
398
|
+
|
|
399
|
+
Unity, Unity3D, UI Toolkit, UITK, UXML, USS, renderer, preview, browser,
|
|
400
|
+
Yoga layout, WebAssembly, TypeScript, game UI, editor tooling
|