uxml-preview 0.5.1 → 0.6.1
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 +181 -4
- package/README.ja.md +84 -0
- package/README.ko.md +84 -0
- package/README.md +46 -502
- package/README.zh-CN.md +84 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +1575 -1299
- package/dist/layout/yoga.d.ts +11 -0
- package/dist/model/types.d.ts +18 -4
- package/dist/render/css-map.d.ts +15 -0
- package/dist/render/fonts.d.ts +21 -0
- package/dist/render/measure.d.ts +9 -0
- package/dist/render/paint.d.ts +5 -0
- package/dist/render/values.d.ts +2 -0
- package/dist/render/visibility.d.ts +20 -0
- package/dist/style/registry.d.ts +5 -1
- package/dist/style/resolve.d.ts +9 -2
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,540 +1,84 @@
|
|
|
1
1
|
# uxml-preview
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
*English · [한국어](https://github.com/ReuHomi/uxml-preview/blob/main/README.ko.md) · [日本語](https://github.com/ReuHomi/uxml-preview/blob/main/README.ja.md) · [简体中文](https://github.com/ReuHomi/uxml-preview/blob/main/README.zh-CN.md)*
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Render Unity UI Toolkit UXML/USS in a browser, without the Unity Editor — laid
|
|
6
|
+
out by Yoga, the engine UI Toolkit itself uses, and measured against Unity.**
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
[](https://reuhomi.github.io/uxml-preview/)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
uploaded — it all runs locally in the page.
|
|
10
|
+
### ▶ [Open the playground](https://reuhomi.github.io/uxml-preview/)
|
|
11
11
|
|
|
12
|
-
|
|
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>
|
|
12
|
+
Paste your own `.uxml` and `.uss`, or open an example. Nothing is uploaded; it
|
|
13
|
+
all runs in the page.
|
|
17
14
|
|
|
18
15
|
[](https://github.com/ReuHomi/uxml-preview/actions/workflows/ci.yml)
|
|
19
16
|
[](https://github.com/ReuHomi/uxml-preview/actions/workflows/pages.yml)
|
|
20
|
-
[](LICENSE)
|
|
21
|
-
|
|
22
|
-
[English](#english) · [한국어](#한국어)
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
npm install uxml-preview
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
> **v0.5.1.** Five controls (`VisualElement`, `Label`, `Button`,
|
|
29
|
-
> `Image`, `ScrollView`), everything else drawn as a plain box with a warning,
|
|
30
|
-
> and a support matrix that says plainly what has not been measured.
|
|
31
|
-
> Read [what is not verified yet](#what-is-not-verified-yet) before relying on it.
|
|
32
|
-
>
|
|
33
|
-
> **v0.5.1.** 컨트롤 5종(`VisualElement`, `Label`, `Button`,
|
|
34
|
-
> `Image`, `ScrollView`)이고, 나머지는 경고와 함께 일반 박스로 그립니다.
|
|
35
|
-
> 검증되지 않은 부분은 지원 범위표에 그대로 적어뒀습니다. 쓰시기 전에
|
|
36
|
-
> [아직 검증되지 않은 것](#아직-검증되지-않은-것)을 먼저 봐주세요.
|
|
17
|
+
[](https://github.com/ReuHomi/uxml-preview/blob/main/LICENSE)
|
|
37
18
|
|
|
38
|
-
|
|
19
|
+
## How it is verified
|
|
39
20
|
|
|
40
|
-
|
|
41
|
-
|
|
21
|
+
- **Coordinates:** 660 / 676 element coordinate values identical to Unity 6000.0.40f1, over 40 layout cases including a complete screen. [Every difference, named →](https://github.com/ReuHomi/uxml-preview/blob/main/docs/accuracy.en.md) Re-dumped on Unity 6.3 (6000.3.25f1), every one of those cases laid out exactly as in a 6000.0.40f1 dump taken the same day. [The 6.3 re-measurement →](https://github.com/ReuHomi/uxml-preview/blob/main/docs/accuracy.en.md#unity-63-lts-re-measurement-2026-10-15)
|
|
22
|
+
- **Text:** drawn in a real browser and compared with Unity 6000.3.25f1 Label by Label — line count 92 / 92, height 84 / 92, width 92 / 92 within 1px or 1%. Every height that differs is Korean or mixed text set in Inter, a Latin font with no Hangul, which Unity draws with a fallback font; the preview warns about exactly that. [The text cohort →](https://github.com/ReuHomi/uxml-preview/blob/main/docs/accuracy.en.md#text-cohort-separate-set-measured-2026-10-16)
|
|
23
|
+
- **Unity version:** the reference is Unity 6.3 LTS. A property is USS if Unity's official property table lists it, up to 6.6; 6.7 is not supported until it is an LTS. [What is supported →](https://github.com/ReuHomi/uxml-preview/blob/main/docs/supported.en.md)
|
|
24
|
+
- **What does not match is reported, not glossed over.** An unsupported control, property or value comes back as a warning that says why, and — where it was measured — what Unity does instead. [Warnings →](https://github.com/ReuHomi/uxml-preview/blob/main/docs/api.en.md#warnings)
|
|
42
25
|
|
|
43
|
-
|
|
26
|
+
## Three ways to use it
|
|
44
27
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Measured against Unity 6000.0.40f1: **660 of 676 element coordinates identical**
|
|
51
|
-
across 40 layout cases, including a full working screen. Ten of the sixteen
|
|
52
|
-
differences are font metrics rather than layout — a browser cannot measure
|
|
53
|
-
Unity's font asset. All sixteen are named in
|
|
54
|
-
[`docs/accuracy.en.md`](docs/accuracy.en.md).
|
|
55
|
-
|
|
56
|
-
This changes what you can open: **you can now open real screens made by someone
|
|
57
|
-
else**, including screens assembled from reusable UXML parts rather than one
|
|
58
|
-
self-contained file. `<ui:Template>` declarations and `<ui:Instance>` elements
|
|
59
|
-
are expanded for rendering. The template cohort is measured separately:
|
|
60
|
-
**200 / 220 coordinate values across 55 elements and 11 rendered cases**; it is
|
|
61
|
-
not added to the base 660/676 figure. Cycles fail closed with a diagnostic, and
|
|
62
|
-
slots are measured as alive in Unity 6000.0.40f1 but remain out of scope and
|
|
63
|
-
report `template-slot-unsupported`.
|
|
28
|
+
| If you are | Use |
|
|
29
|
+
|---|---|
|
|
30
|
+
| **Designing a screen** | The [playground](https://reuhomi.github.io/uxml-preview/) in the browser, or [UXML Preview for VS Code](https://github.com/ReuHomi/vscode-uxml-preview) beside your project files |
|
|
31
|
+
| **Having an AI agent write UI** | [uxml-author](https://github.com/ReuHomi/uxml-author) — a skill that writes UXML/USS, renders it with this library and checks the result before handing it over |
|
|
32
|
+
| **Building a tool** | This library: `npm install uxml-preview`, then the [API](https://github.com/ReuHomi/uxml-preview/blob/main/docs/api.en.md) |
|
|
64
33
|
|
|
65
|
-
|
|
66
|
-
14** external documents uses `<ui:Template>`. The reported 31 → 0 improvement
|
|
67
|
-
there counts diagnostic lines (1 declaration + 15 instances + 15 overrides),
|
|
68
|
-
not 31 opened subtrees.
|
|
34
|
+
## Install
|
|
69
35
|
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
↓
|
|
73
|
-
edit in browser
|
|
74
|
-
↓
|
|
75
|
-
serialize back to .uxml/.uss
|
|
36
|
+
```bash
|
|
37
|
+
npm install uxml-preview
|
|
76
38
|
```
|
|
77
39
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
Designing Unity UI Toolkit interfaces today means a slow round trip: mock it up
|
|
81
|
-
somewhere, hand-translate to UXML, open the Unity Editor, check, repeat. Web-based
|
|
82
|
-
design tools and AI coding agents can write UXML, but neither can *see* the result.
|
|
83
|
-
That broken feedback loop is what this library fixes.
|
|
84
|
-
|
|
85
|
-
**Use cases**
|
|
86
|
-
- Preview UXML layouts without launching Unity
|
|
87
|
-
- Give AI agents a visual feedback loop when authoring UI Toolkit interfaces
|
|
88
|
-
- Embed a UXML preview in your own tooling (editor extensions, internal tools)
|
|
89
|
-
- Share UI mockups with people who don't have Unity installed
|
|
90
|
-
|
|
91
|
-
### Design principles
|
|
92
|
-
|
|
93
|
-
1. **Never reimplement layout.** Unity UI Toolkit delegates layout to Yoga. So do we.
|
|
94
|
-
Reimplementing it guarantees drift.
|
|
95
|
-
2. **Round-trip fidelity is non-negotiable.** Parse → serialize must preserve comments,
|
|
96
|
-
attribute order, and formatting. If opening and saving a file produces a noisy
|
|
97
|
-
git diff, it's unusable in practice.
|
|
98
|
-
3. **USS is not CSS.** Different box model, different defaults, no `z-index`,
|
|
99
|
-
no `@keyframes`. [**USS is not CSS**](docs/uss-vs-css.md) walks through the
|
|
100
|
-
differences with a live example for each.
|
|
101
|
-
4. **Honest support matrix.** Unsupported properties produce warnings, not silent
|
|
102
|
-
wrong output. See [`docs/supported.en.md`](docs/supported.en.md).
|
|
103
|
-
|
|
104
|
-
### Status & roadmap
|
|
105
|
-
|
|
106
|
-
| Phase | Scope | Status |
|
|
107
|
-
|---|---|---|
|
|
108
|
-
| 0 | Repo scaffold + playground | ✅ |
|
|
109
|
-
| 1 | Data model | ✅ |
|
|
110
|
-
| 2 | Parser + serializer (round-trip) | ✅ |
|
|
111
|
-
| 3 | USS style resolver | ✅ |
|
|
112
|
-
| 4 | Yoga layout + DOM painting | ✅ |
|
|
113
|
-
| 5 | Golden tests against Unity | ✅ |
|
|
114
|
-
| 6 | **v0.1 release** | ✅ |
|
|
115
|
-
| 7 | **v0.2 — ScrollView, Image, states, a measured screen** | ✅ |
|
|
116
|
-
| 8 | **v0.3–0.4 — asset/import resolution semantics, Unity CLI measurement** | ✅ |
|
|
117
|
-
| 9 | **v0.5 — Template / Instance expansion and diagnostics** | ✅ |
|
|
118
|
-
| 10+ | Editing layer, tool integration | ⬜ |
|
|
119
|
-
|
|
120
|
-
Full plan: [`docs/ROADMAP.md`](docs/ROADMAP.md)
|
|
121
|
-
|
|
122
|
-
### What is not verified yet
|
|
123
|
-
|
|
124
|
-
The support matrix is deliberately conservative — see
|
|
125
|
-
[`docs/supported.en.md`](docs/supported.en.md) for the full table.
|
|
126
|
-
|
|
127
|
-
- **Slots are not supported in v0.5.1.** They were measured alive in Unity
|
|
128
|
-
6000.0.40f1; slot children are not placed and `template-slot-unsupported` is
|
|
129
|
-
reported.
|
|
130
|
-
- **A `style` AttributeOverride is not applied.** Unity ignores it during import,
|
|
131
|
-
and the preview reports `override-style-ignored` instead of drawing a plausible
|
|
132
|
-
but wrong result.
|
|
133
|
-
- **`Library/PackageCache` is not searched.** Embedded package UXML physically
|
|
134
|
-
present under `<projectRoot>/Packages/<name>/` resolves through
|
|
135
|
-
`project://database/Packages/...`; a registry-package template available only
|
|
136
|
-
in the cache reports `package-path-not-searched`.
|
|
137
|
-
- **The external 14-document sample contains only 1 template document.** Its
|
|
138
|
-
31 → 0 result counts diagnostic lines, not rendered template subtrees.
|
|
139
|
-
- **Only geometry is compared automatically, and only as far as Yoga.** The
|
|
140
|
-
figure above is measured at the coordinates the layout engine produces.
|
|
141
|
-
Whether the painted DOM reproduces them is checked by an invariant of our own
|
|
142
|
-
rather than against Unity.
|
|
143
|
-
- **Colour, borders and corners rest on a single eye comparison.** One screen was
|
|
144
|
-
put side by side with Unity and checked item by item
|
|
145
|
-
([`docs/visual-check.md`](docs/visual-check.md)); it found two real defects, so
|
|
146
|
-
it was worth doing, but it is one screen and not an automated diff. Everything
|
|
147
|
-
it did not contain is still unmeasured.
|
|
148
|
-
- **Text measurement was not compared.** Unity renders text with its own font
|
|
149
|
-
asset, so any box sized by its text differs — this accounts for ten of the
|
|
150
|
-
sixteen coordinate divergences. The line-height factor is still an estimate.
|
|
151
|
-
- **A wrapped `ScrollView`'s content height diverges.** Unity clamps it to the
|
|
152
|
-
viewport; Yoga grows it to the content. Unity's rule is not yet identified.
|
|
153
|
-
- **Nested disabled elements dim twice.** `enabled="false"` disables a subtree
|
|
154
|
-
and each level takes the half opacity, so a disabled control inside a disabled
|
|
155
|
-
panel comes out at a quarter. Unity almost certainly dims once; this is not
|
|
156
|
-
measured yet.
|
|
157
|
-
- Scrollbars reserve their width but are not drawn, and nothing scrolls.
|
|
158
|
-
- `-unity-slice-*`, `-unity-background-image-tint-color` and `transition` are
|
|
159
|
-
parsed and preserved, but not drawn.
|
|
160
|
-
|
|
161
|
-
### API
|
|
40
|
+
Node 22 or later for tooling; rendering needs a DOM (a browser, or happy-dom /
|
|
41
|
+
jsdom in tests).
|
|
162
42
|
|
|
163
43
|
```ts
|
|
164
44
|
import { loadLayoutEngine, parse, render, serialize } from 'uxml-preview';
|
|
165
45
|
|
|
166
|
-
// Yoga is WebAssembly
|
|
167
|
-
await loadLayoutEngine();
|
|
168
|
-
|
|
169
|
-
// text → model
|
|
170
|
-
const doc = parse(uxmlText, ussText);
|
|
171
|
-
|
|
172
|
-
// model → screen
|
|
173
|
-
const view = render(doc, document.getElementById('preview'), {
|
|
174
|
-
resolveAsset: (path, form) =>
|
|
175
|
-
form === 'url' ? myAssetUrlFor(path) : myResourcesAssetUrlFor(path),
|
|
46
|
+
await loadLayoutEngine(); // Yoga is WebAssembly: load once, up front
|
|
176
47
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
48
|
+
const doc = parse(uxmlText, ussText); // text → model
|
|
49
|
+
const view = render(doc, container, { // model → screen
|
|
50
|
+
size: { width: 1280, height: 720 }, // the panel, not the window
|
|
51
|
+
resolveAsset: (path, form) => myAssetUrl(path, form), // project://… → a URL, or null
|
|
180
52
|
});
|
|
181
|
-
console.log(view.warnings);
|
|
182
53
|
|
|
183
|
-
|
|
184
|
-
view.dispose();
|
|
54
|
+
for (const w of view.warnings) console.log(w.reason ?? w.kind, w.message);
|
|
185
55
|
|
|
186
|
-
//
|
|
187
|
-
const { uxml, uss } = serialize(doc);
|
|
56
|
+
view.dispose(); // Yoga nodes are not garbage collected
|
|
57
|
+
const { uxml, uss } = serialize(doc); // unedited: byte-identical to the input
|
|
188
58
|
```
|
|
189
59
|
|
|
190
|
-
|
|
191
|
-
path; `resource()` is Unity's Resources lookup, where the extension is optional
|
|
192
|
-
and the folder may occur anywhere under `Assets`. Unity can also resolve editor
|
|
193
|
-
built-ins that a disk-only host cannot, so return `null` rather than treating a
|
|
194
|
-
resource name as an ordinary project path.
|
|
60
|
+
## Documentation
|
|
195
61
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
template dependency URLs in source order for host prefetching.
|
|
62
|
+
- [USS is not CSS](https://github.com/ReuHomi/uxml-preview/blob/main/docs/uss-vs-css.md) — the differences that make a ported stylesheet come out wrong, each with an example
|
|
63
|
+
- [Supported](https://github.com/ReuHomi/uxml-preview/blob/main/docs/supported.en.md) — controls, properties, states, versions, and how far each was checked
|
|
64
|
+
- [Accuracy](https://github.com/ReuHomi/uxml-preview/blob/main/docs/accuracy.en.md) — every number, how it was measured, every known difference
|
|
65
|
+
- [API](https://github.com/ReuHomi/uxml-preview/blob/main/docs/api.en.md) — `parse`, `render`, `serialize`, the hooks, warnings, `classifyVisibility`
|
|
66
|
+
- [Changelog](https://github.com/ReuHomi/uxml-preview/blob/main/CHANGELOG.md)
|
|
67
|
+
- [Visual check](https://github.com/ReuHomi/uxml-preview/blob/main/docs/visual-check.md) — the one side-by-side comparison of colour and texture with Unity (2026-08, Korean)
|
|
203
68
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
**[reuhomi.github.io/uxml-preview](https://reuhomi.github.io/uxml-preview/)** —
|
|
207
|
-
or run it locally:
|
|
69
|
+
## Development
|
|
208
70
|
|
|
209
71
|
```bash
|
|
210
72
|
pnpm install
|
|
211
|
-
pnpm dev
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
Edit UXML and USS on the left, see the result on the right. The panel size is
|
|
215
|
-
set explicitly rather than following the window, because USS percentages and
|
|
216
|
-
stretching resolve against the panel — a preview that resizes with the browser
|
|
217
|
-
cannot answer "how does this look at 1920×1080".
|
|
218
|
-
|
|
219
|
-
The corner reads `round-trip: exact` whenever serializing the document back out
|
|
220
|
-
reproduces what you typed, byte for byte. It is the round-trip guarantee checked
|
|
221
|
-
live, on your own file — and it holds for text that does not parse, too, since
|
|
222
|
-
untouched input is copied out of the original rather than regenerated. Half a
|
|
223
|
-
tag, no root element, an empty file: still exact. `DIFFERS` would mean a bug
|
|
224
|
-
here, not in your document.
|
|
225
|
-
|
|
226
|
-

|
|
227
|
-
|
|
228
|
-
The panel size is chosen rather than inherited from the window, so a layout can
|
|
229
|
-
be checked at the resolution it will actually ship at.
|
|
230
|
-
|
|
231
|
-

|
|
232
|
-
|
|
233
|
-
The examples are chosen to show the traps: `flex-direction` defaulting to
|
|
234
|
-
`column`, overlap ordered by markup rather than `z-index`, and unsupported
|
|
235
|
-
controls surviving a round trip while being reported rather than drawn.
|
|
236
|
-
|
|
237
|
-
### Development
|
|
238
|
-
|
|
239
|
-
```bash
|
|
240
|
-
pnpm test # everything
|
|
241
|
-
pnpm test:roundtrip # parse -> serialize is byte-identical
|
|
242
|
-
pnpm test:golden # regression snapshots + comparison against Unity
|
|
243
|
-
pnpm golden:emit # write the golden cases out for loading into Unity
|
|
73
|
+
pnpm dev # the playground
|
|
74
|
+
pnpm test # everything that runs without a browser or Unity
|
|
75
|
+
pnpm test:text # the text cohort, in a real Chromium (see docs/accuracy.en.md)
|
|
244
76
|
pnpm build
|
|
245
77
|
```
|
|
246
78
|
|
|
247
|
-
Reproducing the
|
|
248
|
-
[
|
|
249
|
-
|
|
250
|
-
### Accuracy
|
|
251
|
-
|
|
252
|
-
Checked by comparing element geometry against the Unity Editor, case by case.
|
|
253
|
-
Geometry rather than pixels: Unity draws text with its own font asset and a
|
|
254
|
-
browser does not, so a pixel diff would measure the font more than the layout.
|
|
79
|
+
Reproducing the Unity side needs a Unity install; the procedure is in
|
|
80
|
+
[Accuracy](https://github.com/ReuHomi/uxml-preview/blob/main/docs/accuracy.en.md#producing-the-ground-truth).
|
|
255
81
|
|
|
256
|
-
|
|
257
|
-
elements:
|
|
258
|
-
|
|
259
|
-
| | |
|
|
260
|
-
|---|---|
|
|
261
|
-
| Cases matching exactly | **38 / 40** |
|
|
262
|
-
| Values within 0.5px | **660 / 676 (97.6%)** |
|
|
263
|
-
| Unity baselines recorded | **41 / 41** (40 coordinate cases + 1 resource observation) |
|
|
264
|
-
|
|
265
|
-
The sixteen divergences are four different things, and the distinction matters
|
|
266
|
-
more than the ratio: **ten are text metrics**, three are 1px, two are a
|
|
267
|
-
`yoga-layout` version difference, and **one is unresolved**. The ten are not a
|
|
268
|
-
layout defect — both engines shrink the same box for the same reason and only
|
|
269
|
-
the ruler differs, which is the same fact that makes pixel diffing useless.
|
|
270
|
-
Every one is named in [`docs/accuracy.en.md`](docs/accuracy.en.md), along with
|
|
271
|
-
the failed attempts to configure around the version difference and how to
|
|
272
|
-
reproduce the measurement.
|
|
273
|
-
|
|
274
|
-
### Questions this answers
|
|
275
|
-
|
|
276
|
-
**Can I preview a UXML file without opening the Unity Editor?**
|
|
277
|
-
Yes. Paste `.uxml` and `.uss` into the [playground](https://reuhomi.github.io/uxml-preview/),
|
|
278
|
-
or call `parse()` and `render()` from the library. Nothing is uploaded and Unity
|
|
279
|
-
is never launched.
|
|
280
|
-
|
|
281
|
-
**Why does my CSS layout come out wrong in UI Toolkit?**
|
|
282
|
-
Most often because `flex-direction` defaults to `column` in USS and `row` in CSS,
|
|
283
|
-
so every container without an explicit direction is rotated ninety degrees. The
|
|
284
|
-
other four common causes — no `z-index`, forced `border-box`, no bare text nodes,
|
|
285
|
-
no margin collapsing — are in [USS is not CSS](docs/uss-vs-css.md), each with a
|
|
286
|
-
live example.
|
|
287
|
-
|
|
288
|
-
**Does USS support `z-index`, CSS Grid, or `calc()`?**
|
|
289
|
-
No, none of the three. Overlap follows markup order, grid layouts must be rebuilt
|
|
290
|
-
as nested flex, and computed values have to be resolved to fixed numbers or
|
|
291
|
-
calculated in C#.
|
|
292
|
-
|
|
293
|
-
**How close is the output to Unity?**
|
|
294
|
-
660 of 676 element coordinates identical against Unity 6000.0.40f1, across 40
|
|
295
|
-
layout cases including a complete inventory screen. Geometry is compared rather
|
|
296
|
-
than screenshots, because Unity draws text with its own font asset — which is
|
|
297
|
-
also why ten of the sixteen differences are font metrics rather than layout.
|
|
298
|
-
Every divergence is named in [`docs/accuracy.en.md`](docs/accuracy.en.md).
|
|
299
|
-
|
|
300
|
-
**Will it damage my files if I edit them?**
|
|
301
|
-
Editing goes through a model that keeps the original text. An unedited document
|
|
302
|
-
serializes back byte-for-byte — comments, attribute order, entity encodings and
|
|
303
|
-
CRLF endings included — and an edit rewrites only the region it touched. The
|
|
304
|
-
playground shows this live as `round-trip: exact`.
|
|
305
|
-
|
|
306
|
-
**What happens to controls it does not support?**
|
|
307
|
-
They are drawn as a plain `VisualElement`, reported as a warning, and written
|
|
308
|
-
back out unchanged. Their own styles and their children come out normally; only
|
|
309
|
-
what makes that control look like itself is missing. One unfamiliar tag never
|
|
310
|
-
takes down the rest of the screen, and nothing is silently dropped.
|
|
311
|
-
|
|
312
|
-
**Are templates and instances rendered?**
|
|
313
|
-
Yes. Template declarations resolve through the host import hook, instances become
|
|
314
|
-
opaque `TemplateContainer` elements, and `AttributeOverrides` reach every
|
|
315
|
-
duplicate target for ordinary attributes. A `style` AttributeOverride is reported
|
|
316
|
-
as `override-style-ignored` because Unity ignores it during import. Slot children
|
|
317
|
-
are intentionally not placed; the measured Unity slot behavior is reported as
|
|
318
|
-
`template-slot-unsupported` in this release.
|
|
319
|
-
|
|
320
|
-
### License
|
|
82
|
+
## License
|
|
321
83
|
|
|
322
84
|
Apache-2.0
|
|
323
|
-
|
|
324
|
-
---
|
|
325
|
-
|
|
326
|
-
<a name="한국어"></a>
|
|
327
|
-
## 한국어
|
|
328
|
-
|
|
329
|
-
### 무엇을 하는가
|
|
330
|
-
|
|
331
|
-
`uxml-preview`는 Unity UI Toolkit의 `.uxml`, `.uss` 파일을 파싱해서 웹 브라우저에
|
|
332
|
-
직접 렌더링하는 라이브러리입니다. Unity UI Toolkit이 실제로 사용하는 레이아웃 엔진인
|
|
333
|
-
**Yoga**를 WebAssembly로 그대로 사용하기 때문에, 결과를 "비슷하게 흉내내는" 것이 아니라
|
|
334
|
-
유니티 에디터와 일치시킵니다.
|
|
335
|
-
|
|
336
|
-
Unity 6000.0.40f1과 대조한 결과, 실무형 화면을 포함한 레이아웃 케이스 40개에서
|
|
337
|
-
**요소 좌표 676개 중 660개가 일치**합니다. 어긋난 16개 중 **10개는 레이아웃이 아니라
|
|
338
|
-
폰트 메트릭** 차이입니다 — 브라우저는 유니티 폰트 에셋을 잴 수 없습니다.
|
|
339
|
-
16개 전부 [`docs/accuracy.md`](docs/accuracy.md)에 이름과 사유를 적어뒀습니다.
|
|
340
|
-
|
|
341
|
-
이제 **남이 만든 실제 화면을 열 수 있게 됩니다.** 한 파일에 모든 내용을 넣은
|
|
342
|
-
화면뿐 아니라 재사용 가능한 UXML 조각을 조립한 화면도 `<ui:Template>`과
|
|
343
|
-
`<ui:Instance>`를 전개해 렌더링합니다. 템플릿 코호트는 기본 수치와 분리해
|
|
344
|
-
**55 elements, 11개 렌더 케이스의 좌표 220개 중 200개**로 측정했으며
|
|
345
|
-
660/676에 합산하지 않습니다. 순환은 진단과 함께 fail-closed로 막고, 슬롯은
|
|
346
|
-
Unity 6000.0.40f1에서 살아 있음을 실측했지만 이번 범위 밖이라
|
|
347
|
-
`template-slot-unsupported`로 보고합니다.
|
|
348
|
-
|
|
349
|
-
외부 14개 표본 전체가 템플릿을 검증한 것은 아닙니다. 그중 `<ui:Template>`을
|
|
350
|
-
쓰는 문서는 **1개**뿐이고, 보고된 31 → 0은 열린 서브트리 수가 아니라 진단
|
|
351
|
-
줄 수(선언 1 + Instance 15 + override 15)입니다.
|
|
352
|
-
|
|
353
|
-
```
|
|
354
|
-
.uxml + .uss → 파싱 → 스타일 계산 → Yoga 레이아웃 → DOM 페인팅
|
|
355
|
-
↓
|
|
356
|
-
브라우저에서 편집
|
|
357
|
-
↓
|
|
358
|
-
.uxml/.uss로 다시 저장
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### 왜 만드는가
|
|
362
|
-
|
|
363
|
-
지금 UI Toolkit으로 UI를 만들려면 왕복이 깁니다. 어딘가에 시안을 만들고 → 손으로 UXML로
|
|
364
|
-
옮기고 → 유니티를 켜서 확인하고 → 안 맞으면 되돌아갑니다. 웹 기반 디자인 도구나 AI 코딩
|
|
365
|
-
에이전트가 UXML을 쓸 수는 있지만, 둘 다 그 결과를 **볼 수 없습니다.** 이 끊긴 피드백
|
|
366
|
-
루프를 잇는 것이 이 라이브러리의 목적입니다.
|
|
367
|
-
|
|
368
|
-
**활용**
|
|
369
|
-
- 유니티를 켜지 않고 UXML 레이아웃 확인
|
|
370
|
-
- AI 에이전트가 UI Toolkit UI를 만들 때 시각적 피드백 루프 제공
|
|
371
|
-
- 자체 도구(에디터 확장, 사내 툴)에 UXML 프리뷰 내장
|
|
372
|
-
- 유니티가 없는 사람과 UI 시안 공유
|
|
373
|
-
|
|
374
|
-
### 설계 원칙
|
|
375
|
-
|
|
376
|
-
1. **레이아웃을 직접 구현하지 않는다.** UI Toolkit은 레이아웃을 Yoga에 위임합니다.
|
|
377
|
-
우리도 그렇게 합니다. 직접 구현하면 반드시 어긋납니다.
|
|
378
|
-
2. **왕복 보존은 타협 대상이 아니다.** 파싱 → 직렬화 시 주석, 속성 순서, 서식이
|
|
379
|
-
유지되어야 합니다. 열었다 저장했을 때 git diff가 지저분해지면 실무에서 못 씁니다.
|
|
380
|
-
3. **USS는 CSS가 아니다.** 박스 모델이 다르고, 기본값이 다르고, `z-index`가 없고,
|
|
381
|
-
`@keyframes`가 없습니다. [**USS는 CSS가 아니다**](docs/uss-vs-css.ko.md)에
|
|
382
|
-
차이점마다 직접 해볼 수 있는 예제 링크와 함께 정리해뒀습니다.
|
|
383
|
-
4. **지원 범위를 정직하게 밝힌다.** 미지원 속성은 조용히 틀린 결과를 내는 대신
|
|
384
|
-
경고를 남깁니다. [`docs/supported.md`](docs/supported.md) 참조.
|
|
385
|
-
|
|
386
|
-
### 진행 상황
|
|
387
|
-
|
|
388
|
-
| 단계 | 범위 | 상태 |
|
|
389
|
-
|---|---|---|
|
|
390
|
-
| 0 | 저장소 뼈대 + 놀이터 | ✅ |
|
|
391
|
-
| 1 | 데이터 모델 | ✅ |
|
|
392
|
-
| 2 | 파서 + 직렬화 (왕복 검증) | ✅ |
|
|
393
|
-
| 3 | USS 스타일 리졸버 | ✅ |
|
|
394
|
-
| 4 | Yoga 레이아웃 + DOM 페인팅 | ✅ |
|
|
395
|
-
| 5 | 유니티 대조 골든 테스트 | ✅ |
|
|
396
|
-
| 6 | **v0.1 공개** | ✅ |
|
|
397
|
-
| 7 | **v0.2 — ScrollView·Image·상태, 대표 화면 대조** | ✅ |
|
|
398
|
-
| 8 | **v0.3–0.4 — 에셋·import 해석 의미론, Unity CLI 계측** | ✅ |
|
|
399
|
-
| 9 | **v0.5 — Template / Instance 전개와 진단** | ✅ |
|
|
400
|
-
| 10+ | 편집 레이어, 도구 통합 | ⬜ |
|
|
401
|
-
|
|
402
|
-
전체 계획: [`docs/ROADMAP.md`](docs/ROADMAP.md)
|
|
403
|
-
|
|
404
|
-
### 아직 검증되지 않은 것
|
|
405
|
-
|
|
406
|
-
지원 범위는 일부러 보수적으로 적었습니다. 전체 표는
|
|
407
|
-
[`docs/supported.md`](docs/supported.md)에 있습니다.
|
|
408
|
-
|
|
409
|
-
- **v0.5.1은 슬롯을 지원하지 않습니다.** Unity 6000.0.40f1에서 살아 있음을
|
|
410
|
-
실측했지만 슬롯 자식은 배치하지 않고 `template-slot-unsupported`로 보고합니다
|
|
411
|
-
- **`style` AttributeOverride는 적용하지 않습니다.** Unity가 import 과정에서
|
|
412
|
-
무시하는 동작을 따르며, 그럴듯하지만 틀린 결과 대신
|
|
413
|
-
`override-style-ignored`를 보고합니다
|
|
414
|
-
- **`Library/PackageCache`는 탐색하지 않습니다.**
|
|
415
|
-
`<projectRoot>/Packages/<name>/`에 실물이 있는 embedded package UXML은
|
|
416
|
-
`project://database/Packages/...`로 해석하지만, 캐시에만 있는 레지스트리 패키지
|
|
417
|
-
템플릿은 `package-path-not-searched`로 보고합니다
|
|
418
|
-
- **외부 14개 표본 중 템플릿 문서는 1개뿐입니다.** 31 → 0은 렌더된 템플릿
|
|
419
|
-
서브트리가 아니라 진단 줄 수입니다
|
|
420
|
-
- **자동 대조는 좌표만, 그것도 Yoga 층까지입니다.** 위 수치는 레이아웃 엔진이 낸
|
|
421
|
-
좌표를 잰 것입니다. 그려진 DOM이 그 좌표를 재현하는지는 유니티가 아니라 자체
|
|
422
|
-
불변식 검사로 봅니다
|
|
423
|
-
- **색·테두리·모서리는 육안 대조 1회에 기대고 있습니다.** 화면 하나를 유니티와
|
|
424
|
-
나란히 놓고 항목별로 확인했고([`docs/visual-check.md`](docs/visual-check.md)),
|
|
425
|
-
거기서 실제 결함 두 개가 나왔으니 할 값어치는 있었습니다. 다만 **화면 하나이고
|
|
426
|
-
자동 diff가 아닙니다.** 그 화면에 없던 것은 여전히 미측정입니다
|
|
427
|
-
- **텍스트 측정은 대조하지 않았습니다.** 유니티는 자기 폰트 에셋으로 글자를
|
|
428
|
-
그리므로 텍스트가 크기를 좌우하는 박스는 어긋납니다 — 좌표 불일치 16건 중
|
|
429
|
-
10건이 이것입니다. 행 높이 계수도 아직 추정치입니다
|
|
430
|
-
- **wrap된 `ScrollView`의 콘텐츠 높이가 어긋납니다.** 유니티는 뷰포트에 묶고
|
|
431
|
-
Yoga는 콘텐츠로 키웁니다. 유니티의 규칙을 아직 특정하지 못했습니다
|
|
432
|
-
- **중첩된 비활성 요소가 두 번 흐려집니다.** `enabled="false"`가 하위 트리를
|
|
433
|
-
비활성으로 만들고 각 층이 0.5 불투명도를 받아 1/4이 됩니다. 유니티는 한 번만
|
|
434
|
-
흐리게 할 것이 거의 확실하지만 아직 측정하지 않았습니다
|
|
435
|
-
- 스크롤바는 폭만 예약하고 그리지 않으며, 스크롤되지 않습니다
|
|
436
|
-
- `-unity-slice-*`, `-unity-background-image-tint-color`, `transition`은
|
|
437
|
-
파싱·보존은 되지만 그려지지 않습니다
|
|
438
|
-
|
|
439
|
-
### 놀이터
|
|
440
|
-
|
|
441
|
-
**[reuhomi.github.io/uxml-preview](https://reuhomi.github.io/uxml-preview/)** —
|
|
442
|
-
또는 로컬에서:
|
|
443
|
-
|
|
444
|
-
```bash
|
|
445
|
-
pnpm install
|
|
446
|
-
pnpm dev
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
왼쪽에서 UXML과 USS를 고치면 오른쪽에 바로 반영됩니다. **패널 크기는 창을 따라가지
|
|
450
|
-
않고 직접 지정합니다** — USS의 `%`와 stretch가 전부 패널 크기에 걸려 있어서,
|
|
451
|
-
창 크기를 따라가는 프리뷰로는 "1920×1080에서 어떻게 보이나"에 답할 수 없기 때문입니다.
|
|
452
|
-
|
|
453
|
-
우상단의 `round-trip: exact`는 **지금 입력한 내용을 다시 저장했을 때 바이트 단위로
|
|
454
|
-
같다**는 뜻입니다. 왕복 보존이라는 약속을 사용자 파일로 실시간 검사하는 것이고,
|
|
455
|
-
**파싱되지 않는 텍스트에도 성립합니다** — 건드리지 않은 입력은 재생성하지 않고
|
|
456
|
-
원본에서 그대로 복사하기 때문입니다. 태그를 반쯤 지우든, 루트가 없든, 파일을
|
|
457
|
-
비우든 `exact`입니다. `DIFFERS`가 뜬다면 그건 문서가 아니라 **이 라이브러리의
|
|
458
|
-
버그**라는 뜻입니다.
|
|
459
|
-
|
|
460
|
-
예제는 예쁜 것보다 **함정을 보여주는 것**으로 골랐습니다 — `flex-direction`의 기본값이
|
|
461
|
-
`column`이라는 것, 겹침 순서가 `z-index`가 아니라 마크업 순서로 정해진다는 것,
|
|
462
|
-
전용 렌더러가 없는 컨트롤도 일반 박스로 그려지고 경고와 함께 왕복에서 살아남는다는 것.
|
|
463
|
-
|
|
464
|
-
### 개발
|
|
465
|
-
|
|
466
|
-
```bash
|
|
467
|
-
pnpm test # 전체
|
|
468
|
-
pnpm test:roundtrip # 파싱 -> 직렬화 바이트 일치
|
|
469
|
-
pnpm test:golden # 회귀 스냅샷 + 유니티 대조
|
|
470
|
-
pnpm golden:emit # 골든 케이스를 유니티용 파일로 출력
|
|
471
|
-
pnpm build
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
정확도 수치를 재현하려면 유니티가 필요합니다. 절차는
|
|
475
|
-
[`docs/accuracy.md`](docs/accuracy.md)에 있습니다.
|
|
476
|
-
|
|
477
|
-
### API
|
|
478
|
-
|
|
479
|
-
`render` 옵션의 `resolveAsset(path, form)`에서 `form`은 `'url' | 'resource'`입니다.
|
|
480
|
-
`url()`은 호스트의 에셋 경로이고 `resource()`는 Unity Resources 검색입니다. 후자는
|
|
481
|
-
확장자 없이 쓸 수 있고 Resources 폴더가 `Assets` 아래 어디에나 있을 수 있으며, 에디터
|
|
482
|
-
내장 리소스처럼 프로젝트 디스크만 보는 호스트가 풀 수 없는 값도 있으므로 그때는 `null`을
|
|
483
|
-
반환해야 합니다. 외부 스타일시트와 템플릿 `src`는
|
|
484
|
-
`parse(uxml, uss, { resolveImport: (url, from) => ... })`로 읽습니다. 엔트리 UXML의
|
|
485
|
-
참조는 `from: null`, 중첩 stylesheet import는 부모 stylesheet URL, 중첩 템플릿
|
|
486
|
-
의존성은 부모 UXML URL을 받습니다. 기존 한 인자 콜백은 계속 동작합니다.
|
|
487
|
-
`collectDependencies(source)`는 호스트가
|
|
488
|
-
미리 가져올 템플릿 의존 URL을 소스 순서대로 돌려줍니다.
|
|
489
|
-
|
|
490
|
-
### 이런 질문에 답합니다
|
|
491
|
-
|
|
492
|
-
**유니티를 켜지 않고 UXML을 미리 볼 수 있나요?**
|
|
493
|
-
됩니다. [놀이터](https://reuhomi.github.io/uxml-preview/)에 `.uxml`과 `.uss`를
|
|
494
|
-
붙여넣거나, 라이브러리의 `parse()`·`render()`를 호출하면 됩니다. 아무것도
|
|
495
|
-
업로드되지 않고 유니티도 실행되지 않습니다.
|
|
496
|
-
|
|
497
|
-
**CSS 레이아웃을 옮겼는데 UI Toolkit에서 왜 어긋나나요?**
|
|
498
|
-
대개 `flex-direction` 기본값 때문입니다. USS는 `column`, CSS는 `row`라서
|
|
499
|
-
방향을 명시하지 않은 모든 컨테이너가 90도 틀어집니다. 나머지 네 가지 흔한
|
|
500
|
-
원인(`z-index` 없음, `border-box` 강제, 맨몸 텍스트 노드 없음, margin 상쇄 없음)은
|
|
501
|
-
[USS는 CSS가 아니다](docs/uss-vs-css.ko.md)에 직접 해볼 수 있는 예제와 함께 있습니다.
|
|
502
|
-
|
|
503
|
-
**USS에 `z-index`나 CSS Grid, `calc()`가 있나요?**
|
|
504
|
-
셋 다 없습니다. 겹침은 마크업 순서로 정해지고, 그리드는 중첩 flex로 다시 짜야 하며,
|
|
505
|
-
계산이 필요한 값은 고정값으로 풀거나 C#에서 계산해야 합니다.
|
|
506
|
-
|
|
507
|
-
**유니티와 얼마나 같나요?**
|
|
508
|
-
Unity 6000.0.40f1 기준, 인벤토리 화면 전체를 포함한 레이아웃 케이스 40개에서
|
|
509
|
-
**요소 좌표 676개 중 660개 일치**입니다. 스크린샷이 아니라 좌표를 비교하는데,
|
|
510
|
-
유니티가 자기 폰트 에셋으로 글자를 그리기 때문입니다 — 그리고 그 사실 때문에
|
|
511
|
-
불일치 16개 중 **10개가 레이아웃이 아니라 폰트 메트릭**입니다. 전부
|
|
512
|
-
[`docs/accuracy.md`](docs/accuracy.md)에 이름이 적혀 있습니다.
|
|
513
|
-
|
|
514
|
-
**편집하면 파일이 망가지지 않나요?**
|
|
515
|
-
편집은 원본 텍스트를 그대로 들고 있는 모델을 거칩니다. 고치지 않은 문서는 주석·속성
|
|
516
|
-
순서·엔티티 표기·CRLF까지 **바이트 단위로 같게** 저장되고, 고친 경우에도 건드린
|
|
517
|
-
영역만 바뀝니다. 놀이터의 `round-trip: exact` 표시가 이걸 실시간으로 보여줍니다.
|
|
518
|
-
|
|
519
|
-
**지원하지 않는 컨트롤은 어떻게 되나요?**
|
|
520
|
-
일반 `VisualElement`처럼 그려지고, 경고로 보고되고, 저장하면 그대로 다시 나옵니다.
|
|
521
|
-
자기 스타일과 자식은 정상적으로 나오며 그 컨트롤 고유의 모양만 빠집니다. 모르는 태그
|
|
522
|
-
하나 때문에 화면 전체가 죽지 않고, 조용히 사라지는 것도 없습니다.
|
|
523
|
-
|
|
524
|
-
**템플릿과 인스턴스도 렌더링하나요?**
|
|
525
|
-
네. 템플릿 선언은 호스트 import 훅으로 해석하고, 인스턴스는 불투명한
|
|
526
|
-
`TemplateContainer`로 전개하며, `AttributeOverrides`는 같은 이름의 모든 대상에
|
|
527
|
-
일반 속성을 적용합니다. `style` AttributeOverride는 Unity가 import에서 무시하므로
|
|
528
|
-
`override-style-ignored`로 보고하고 적용하지 않습니다. 슬롯 자식은 이번 릴리스에서
|
|
529
|
-
배치하지 않고 `template-slot-unsupported` 진단으로 보고합니다.
|
|
530
|
-
|
|
531
|
-
### 라이선스
|
|
532
|
-
|
|
533
|
-
Apache-2.0
|
|
534
|
-
|
|
535
|
-
---
|
|
536
|
-
|
|
537
|
-
### Keywords
|
|
538
|
-
|
|
539
|
-
Unity, Unity3D, UI Toolkit, UITK, UXML, USS, renderer, preview, browser,
|
|
540
|
-
Yoga layout, WebAssembly, TypeScript, game UI, editor tooling
|