@telemetryos/cli 1.9.0 → 1.11.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 +25 -0
- package/dist/commands/auth.js +8 -15
- package/dist/commands/init.js +131 -68
- package/dist/commands/publish.d.ts +22 -0
- package/dist/commands/publish.js +238 -0
- package/dist/index.js +2 -0
- package/dist/plugins/math-tools.d.ts +2 -0
- package/dist/plugins/math-tools.js +18 -0
- package/dist/services/api-client.d.ts +18 -0
- package/dist/services/api-client.js +70 -0
- package/dist/services/archiver.d.ts +4 -0
- package/dist/services/archiver.js +65 -0
- package/dist/services/build-poller.d.ts +10 -0
- package/dist/services/build-poller.js +63 -0
- package/dist/services/cli-config.d.ts +10 -0
- package/dist/services/cli-config.js +45 -0
- package/dist/services/generate-application.d.ts +2 -1
- package/dist/services/generate-application.js +31 -32
- package/dist/services/project-config.d.ts +24 -0
- package/dist/services/project-config.js +51 -0
- package/dist/services/run-server.js +29 -73
- package/dist/types/api.d.ts +44 -0
- package/dist/types/api.js +1 -0
- package/dist/types/applications.d.ts +44 -0
- package/dist/types/applications.js +1 -0
- package/dist/utils/ansi.d.ts +10 -0
- package/dist/utils/ansi.js +10 -0
- package/dist/utils/path-utils.d.ts +55 -0
- package/dist/utils/path-utils.js +99 -0
- package/package.json +4 -2
- package/templates/vite-react-typescript/CLAUDE.md +14 -6
- package/templates/vite-react-typescript/_claude/skills/tos-architecture/SKILL.md +4 -28
- package/templates/vite-react-typescript/_claude/skills/tos-multi-mode/SKILL.md +359 -0
- package/templates/vite-react-typescript/_claude/skills/tos-render-design/SKILL.md +304 -12
- package/templates/vite-react-typescript/_claude/skills/tos-render-kiosk-design/SKILL.md +384 -0
- package/templates/vite-react-typescript/_claude/skills/tos-render-signage-design/SKILL.md +515 -0
- package/templates/vite-react-typescript/_claude/skills/tos-render-ui-design/SKILL.md +325 -0
- package/templates/vite-react-typescript/_claude/skills/tos-requirements/SKILL.md +405 -125
- package/templates/vite-react-typescript/_claude/skills/tos-store-sync/SKILL.md +96 -5
- package/templates/vite-react-typescript/_claude/skills/tos-weather-api/SKILL.md +443 -269
- package/templates/vite-react-typescript/index.html +1 -1
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tos-render-ui-design
|
|
3
|
+
description: Foundation for TelemetryOS Render views. MUST use FIRST before tos-render-signage-design or tos-render-kiosk-design. Covers UI scaling, rem usage, responsive layouts, and best practices for all display types.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Render View UI Design (Foundation)
|
|
7
|
+
|
|
8
|
+
This skill covers the foundational UI design patterns for ALL TelemetryOS Render views, whether building digital signage (display-only) or interactive kiosks (touch-enabled).
|
|
9
|
+
|
|
10
|
+
> **Note:** Always read this skill FIRST, then read either `tos-render-signage-design` (display-only) or `tos-render-kiosk-design` (interactive) depending on your use case.
|
|
11
|
+
|
|
12
|
+
> **Base styles:** The init project already provides base infrastructural styles in `index.css` (viewport scaling, box-sizing) and `Render.css` (`.render` class with padding, overflow, flexbox). Build on these—don't override them. But feel free to build a new visual theme.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## Design Thinking
|
|
16
|
+
|
|
17
|
+
Before coding, understand the context and commit to a BOLD aesthetic direction:
|
|
18
|
+
- **Purpose**: What problem does this interface solve? Who uses it?
|
|
19
|
+
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
|
|
20
|
+
- **Constraints**: Technical requirements (framework, performance, accessibility).
|
|
21
|
+
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
|
|
22
|
+
|
|
23
|
+
**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
|
|
24
|
+
|
|
25
|
+
Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
|
|
26
|
+
- Production-grade and functional
|
|
27
|
+
- Visually striking and memorable
|
|
28
|
+
- Cohesive with a clear aesthetic point-of-view
|
|
29
|
+
- Meticulously refined in every detail
|
|
30
|
+
|
|
31
|
+
## Frontend Aesthetics Guidelines
|
|
32
|
+
|
|
33
|
+
Focus on:
|
|
34
|
+
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
|
|
35
|
+
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
|
|
36
|
+
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
|
|
37
|
+
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
|
|
38
|
+
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.
|
|
39
|
+
|
|
40
|
+
NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.
|
|
41
|
+
|
|
42
|
+
Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.
|
|
43
|
+
|
|
44
|
+
**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
|
|
45
|
+
|
|
46
|
+
Remember: Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Quick Reference
|
|
51
|
+
|
|
52
|
+
| Concept | Key Points | Where Used |
|
|
53
|
+
|---------|-----------|------------|
|
|
54
|
+
| UI Scaling | Call `useUiScaleToSetRem(uiScale)` once in Render | All render views |
|
|
55
|
+
| rem Units | All sizing in rem (not px) | All styles |
|
|
56
|
+
| Title Safe Zone | Keep ~3rem padding from edges | All layouts |
|
|
57
|
+
| Text Size | Minimum 2rem for body, 4rem for headlines | All text |
|
|
58
|
+
| Flex Layouts | Use `min-height: 0` on flex children | All containers |
|
|
59
|
+
| Text Overflow | Truncate with ellipsis or line-clamp | All text that might overflow |
|
|
60
|
+
| Responsive | Use `useUiAspectRatio()` for portrait/landscape | Adaptive layouts |
|
|
61
|
+
| Outside-In Layout | Divide viewport space first, components fill allocations (see signage skill) | Signage layouts |
|
|
62
|
+
|
|
63
|
+
**Next steps after reading:**
|
|
64
|
+
- Display-only content? → Read `tos-render-signage-design`
|
|
65
|
+
- Interactive kiosk? → Read `tos-render-kiosk-design`
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## UI Scale System
|
|
70
|
+
|
|
71
|
+
Displays range from tablets to 8K video walls. Standard CSS pixels create inconsistent sizing. The SDK provides hooks that redefine `rem` as viewport-relative:
|
|
72
|
+
|
|
73
|
+
### useUiScaleToSetRem(uiScale)
|
|
74
|
+
|
|
75
|
+
Sets the document's root font-size based on viewport. **Call once in your Render view:**
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { useUiScaleToSetRem } from '@telemetryos/sdk/react'
|
|
79
|
+
import { useUiScaleStoreState } from '../hooks/store'
|
|
80
|
+
|
|
81
|
+
export function Render() {
|
|
82
|
+
const [_isLoading, uiScale] = useUiScaleStoreState()
|
|
83
|
+
useUiScaleToSetRem(uiScale)
|
|
84
|
+
|
|
85
|
+
return <div className="content">...</div>
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**How it works:**
|
|
90
|
+
- At scale 1: `1rem` = 1% of viewport's longest dimension
|
|
91
|
+
- At scale 2: `1rem` = 2% of viewport's longest dimension
|
|
92
|
+
- A 2rem font occupies identical screen percentage on Full HD and 4K
|
|
93
|
+
|
|
94
|
+
### useUiAspectRatio()
|
|
95
|
+
|
|
96
|
+
Returns current aspect ratio, updating on resize:
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { useUiAspectRatio } from '@telemetryos/sdk/react'
|
|
100
|
+
|
|
101
|
+
export function Render() {
|
|
102
|
+
const aspectRatio = useUiAspectRatio()
|
|
103
|
+
|
|
104
|
+
// > 1 = landscape, < 1 = portrait, = 1 = square
|
|
105
|
+
const isPortrait = aspectRatio < 1
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<div className={isPortrait ? 'portrait-layout' : 'landscape-layout'}>
|
|
109
|
+
...
|
|
110
|
+
</div>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Layout Fundamentals
|
|
118
|
+
|
|
119
|
+
### Use rem for Everything
|
|
120
|
+
|
|
121
|
+
All sizing should use `rem` to scale with the UI scale setting:
|
|
122
|
+
|
|
123
|
+
```css
|
|
124
|
+
/* CORRECT - Scales with viewport */
|
|
125
|
+
.title {
|
|
126
|
+
font-size: 4rem;
|
|
127
|
+
margin-bottom: 1rem;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.card {
|
|
131
|
+
padding: 2rem;
|
|
132
|
+
border-radius: 0.5rem;
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
```css
|
|
137
|
+
/* WRONG - Fixed pixels don't scale */
|
|
138
|
+
.title {
|
|
139
|
+
font-size: 48px;
|
|
140
|
+
margin-bottom: 12px;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Title Safe Zone
|
|
145
|
+
|
|
146
|
+
The init project's `.render` class already applies ~3rem padding from screen edges (SMPTE ST 2046-1 standard for avoiding bezel cutoff). Keep this padding when building your layout.
|
|
147
|
+
|
|
148
|
+
### Constrain Layouts
|
|
149
|
+
|
|
150
|
+
The init project's `index.css` and `.render` class already set up the base layout with `overflow: hidden` and flexbox. When adding child elements, use `min-height: 0` or `min-width: 0` on flex children to allow them to shrink:
|
|
151
|
+
|
|
152
|
+
```css
|
|
153
|
+
.my-content {
|
|
154
|
+
flex: 1;
|
|
155
|
+
min-height: 0; /* Allows flex children to shrink below content size */
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Text Truncation
|
|
160
|
+
|
|
161
|
+
When text might overflow, truncate gracefully:
|
|
162
|
+
|
|
163
|
+
```css
|
|
164
|
+
/* Single line truncation */
|
|
165
|
+
.title {
|
|
166
|
+
white-space: nowrap;
|
|
167
|
+
overflow: hidden;
|
|
168
|
+
text-overflow: ellipsis;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* Multi-line truncation */
|
|
172
|
+
.description {
|
|
173
|
+
display: -webkit-box;
|
|
174
|
+
-webkit-line-clamp: 3;
|
|
175
|
+
-webkit-box-orient: vertical;
|
|
176
|
+
overflow: hidden;
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Typography
|
|
183
|
+
|
|
184
|
+
### Minimum Text Size
|
|
185
|
+
|
|
186
|
+
Text should be no smaller than ~2rem for comfortable viewing at typical distances (approximately 4% of screen height):
|
|
187
|
+
|
|
188
|
+
```css
|
|
189
|
+
.body-text {
|
|
190
|
+
font-size: 2rem; /* Minimum readable size */
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.headline {
|
|
194
|
+
font-size: 4rem;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.small-label {
|
|
198
|
+
font-size: 1.5rem; /* Use sparingly */
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Why 2rem minimum?**
|
|
203
|
+
- Content is viewed from a distance (not handheld)
|
|
204
|
+
- Smaller text becomes unreadable
|
|
205
|
+
- 2rem ≈ 4% of screen height at scale 1
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Responsive Design
|
|
210
|
+
|
|
211
|
+
### Adaptive Content for Orientation
|
|
212
|
+
|
|
213
|
+
Use `useUiAspectRatio()` to adapt layouts for portrait vs landscape:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
function Dashboard() {
|
|
217
|
+
const aspectRatio = useUiAspectRatio()
|
|
218
|
+
const isPortrait = aspectRatio < 1
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<div className={`dashboard ${isPortrait ? 'dashboard--portrait' : ''}`}>
|
|
222
|
+
<PrimaryContent />
|
|
223
|
+
{/* Hide sidebar in portrait mode */}
|
|
224
|
+
{!isPortrait && <Sidebar />}
|
|
225
|
+
</div>
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
```css
|
|
231
|
+
.dashboard {
|
|
232
|
+
display: flex;
|
|
233
|
+
gap: 2rem;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.dashboard--portrait {
|
|
237
|
+
flex-direction: column;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Store Hook for UI Scale
|
|
244
|
+
|
|
245
|
+
Create a store hook to let admins adjust the UI scale in Settings:
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// hooks/store.ts
|
|
249
|
+
import { createUseInstanceStoreState } from '@telemetryos/sdk/react'
|
|
250
|
+
|
|
251
|
+
export const useUiScaleStoreState = createUseInstanceStoreState<number>('ui-scale', 1)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
// Settings.tsx - Add slider control
|
|
256
|
+
import { SettingsSliderFrame, SettingsField, SettingsLabel } from '@telemetryos/sdk/react'
|
|
257
|
+
import { useUiScaleStoreState } from '../hooks/store'
|
|
258
|
+
|
|
259
|
+
export function Settings() {
|
|
260
|
+
// Pass 0 debounce for instant slider updates
|
|
261
|
+
const [isLoading, uiScale, setUiScale] = useUiScaleStoreState(0)
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<SettingsField>
|
|
265
|
+
<SettingsLabel>UI Scale</SettingsLabel>
|
|
266
|
+
<SettingsSliderFrame>
|
|
267
|
+
<input
|
|
268
|
+
type="range"
|
|
269
|
+
min={1}
|
|
270
|
+
max={3}
|
|
271
|
+
step={0.01}
|
|
272
|
+
disabled={isLoading}
|
|
273
|
+
value={uiScale}
|
|
274
|
+
onChange={(e) => setUiScale(parseFloat(e.target.value))}
|
|
275
|
+
/>
|
|
276
|
+
<span>{uiScale}x</span>
|
|
277
|
+
</SettingsSliderFrame>
|
|
278
|
+
</SettingsField>
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Best Practices Summary
|
|
286
|
+
|
|
287
|
+
✅ **Use rem everywhere** - All sizing should use rem units, not px
|
|
288
|
+
✅ **Call useUiScaleToSetRem() once** - In Render view with uiScale from store
|
|
289
|
+
✅ **Respect title safe zone** - Keep the ~3rem padding from init project
|
|
290
|
+
✅ **Keep text readable** - Minimum 2rem for body, 4rem for headlines
|
|
291
|
+
✅ **Constrain flex layouts** - Use `min-height: 0` on flex children
|
|
292
|
+
✅ **Truncate overflow** - Use ellipsis or line-clamp for text that might overflow
|
|
293
|
+
✅ **Adapt to orientation** - Use `useUiAspectRatio()` for portrait/landscape layouts
|
|
294
|
+
✅ **Don't override base styles** - Build on index.css, don't replace it
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Common Mistakes
|
|
299
|
+
|
|
300
|
+
| Mistake | Problem | Fix |
|
|
301
|
+
|---------|---------|-----|
|
|
302
|
+
| Using `px` units | Won't scale across resolutions | Use `rem` everywhere |
|
|
303
|
+
| Fixed heights in `px` | Breaks on different aspect ratios | Use `vh`, `%`, or flex |
|
|
304
|
+
| Forgetting `useUiScaleToSetRem()` | `rem` units won't scale properly | Call it once in Render view with uiScale |
|
|
305
|
+
| Text below 2rem | Unreadable from viewing distance | Minimum 2rem for body text |
|
|
306
|
+
| Removing `.render` padding | Content cut off by bezels | Keep the ~3rem padding from init project |
|
|
307
|
+
| Overriding `index.css` base styles | Breaks viewport scaling | Add new styles, don't modify base setup |
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Next Steps
|
|
312
|
+
|
|
313
|
+
After mastering these foundational concepts, read the appropriate specialized skill:
|
|
314
|
+
|
|
315
|
+
### Building Display-Only Content (Digital Signage)?
|
|
316
|
+
→ Read `tos-render-signage-design`
|
|
317
|
+
- No user interaction patterns
|
|
318
|
+
- No scrolling constraints
|
|
319
|
+
- Auto-rotation considerations
|
|
320
|
+
|
|
321
|
+
### Building Interactive Content (Kiosk)?
|
|
322
|
+
→ Read `tos-render-kiosk-design`
|
|
323
|
+
- Touch interaction patterns
|
|
324
|
+
- Idle timeout behavior
|
|
325
|
+
- Navigation state management
|