even-toolkit
Design system & component library for Even Realities G2 smart glasses apps.
55+ web components, 191 pixel-art icons, glasses SDK bridge with per-screen architecture, pixel-accurate G2 text measurement, speech-to-text module, light/dark themes, and design tokens — all following the Even Realities 2025 UIUX Design Guidelines.
Live Demo → even-demo.vercel.app
Install
npm install even-toolkit
Scaffold a new app instantly:
npx @even-toolkit/create-even-app my-app
# or
npx even-toolkit my-app
Choose from 6 templates: minimal, dashboard, notes, chat, tracker, media.
What's Inside
/web — Web Component Library
55+ React components with Tailwind CSS, designed for mobile-first companion apps.
import { Button, Card, NavBar, ListItem, Toggle, AppShell } from 'even-toolkit/web';
Primitives: Button, Card, Badge, Input, Textarea, Select, MultiSelect, Checkbox, RadioGroup, Slider, InputGroup, Skeleton, Progress, StatusDot, Pill, Toggle, SegmentedControl, Table, Kbd, Divider
Layout: AppShell, Page, NavBar, NavHeader, SideDrawer, DrawerShell, DrawerTrigger, ScreenHeader, SectionHeader, SettingsGroup, CategoryFilter, ListItem (swipe-to-delete), SearchBar, Tag, TagCarousel, TagCard, PagedCarousel, CardCarousel, SliderIndicator, PageIndicator, StepIndicator, Timeline, StatGrid, StatusProgress
Feedback: TimerRing, Dialog, ConfirmDialog, Toast, EmptyState, Loading, BottomSheet, CTAGroup, ScrollPicker, DatePicker, TimePicker, SelectionPicker
Charts (recharts): Sparkline, LineChart, BarChart, PieChart, StatCard
Media: ChatContainer, ChatInput, Calendar, FileUpload, VoiceInput, ImageGrid, ImageViewer, AudioPlayer
/web/icons — 191 Pixel-Art Icons
Official Even Realities icon set: 32x32 grid, 2x2px units, 6 categories.
import { IcChevronBack, IcTrash, IcSettings } from 'even-toolkit/web/icons/svg-icons';
<IcChevronBack width={20} height={20} />
Categories: Edit & Settings (32), Feature & Function (50), Guide System (20), Menu Bar (8), Navigate (23), Status (54), Health (12)
Glasses SDK
Everything needed to build G2 glasses apps with a clean, per-screen architecture.
Per-Screen Architecture (v1.4)
Each glasses screen lives in its own file with co-located display + action logic:
src/glass/
shared.ts — Snapshot type + actions interface
selectors.ts — Screen router (3 lines of wiring)
splash.ts — Splash image + loading text
AppGlasses.tsx — useGlasses hook setup
screens/
home.ts — { display, action }
detail.ts — { display, action }
active.ts — { display, action }
Define a screen
import type { GlassScreen } from 'even-toolkit/glass-screen-router';
import { buildScrollableList } from 'even-toolkit/glass-display-builders';
import { moveHighlight } from 'even-toolkit/glass-nav';
export const homeScreen: GlassScreen<MySnapshot, MyActions> = {
display(snapshot, nav) {
return {
lines: buildScrollableList({
items: snapshot.items,
highlightedIndex: nav.highlightedIndex,
maxVisible: 5,
formatter: (item) => item.title,
}),
};
},
action(action, nav, snapshot, ctx) {
if (action.type === 'HIGHLIGHT_MOVE') {
return { ...nav, highlightedIndex: moveHighlight(nav.highlightedIndex, action.direction, snapshot.items.length - 1) };
}
if (action.type === 'SELECT_HIGHLIGHTED') {
ctx.navigate(`/item/${snapshot.items[nav.highlightedIndex].id}`);
return nav;
}
return nav;
},
};
Wire screens together
import { createGlassScreenRouter } from 'even-toolkit/glass-screen-router';
import { homeScreen } from './screens/home';
import { detailScreen } from './screens/detail';
export const { toDisplayData, onGlassAction } = createGlassScreenRouter({
'home': homeScreen,
'detail': detailScreen,
}, 'home');
Navigation Helpers (glass-nav)
import { moveHighlight, clampIndex, calcMaxScroll, wrapIndex } from 'even-toolkit/glass-nav';
// Clamped movement (0 to max)
moveHighlight(current, 'up', max) // Math.max(0, Math.min(max, current - 1))
moveHighlight(current, 'down', max) // Math.max(0, Math.min(max, current + 1))
// Clamp index to button count
clampIndex(index, buttonCount) // Math.min(Math.max(0, index), count - 1)
// Max scroll offset
calcMaxScroll(totalLines, slots) // Math.max(0, totalLines - slots)
// Wrapping movement (loops around)
wrapIndex(current, 'down', count) // (current + 1) % count
Display Builders (glass-display-builders)
import {
buildScrollableList,
buildScrollableContent,
slidingWindowStart,
G2_TEXT_LINES, // 10
DEFAULT_CONTENT_SLOTS, // 7 (below glassHeader)
} from 'even-toolkit/glass-display-builders';
// Scrollable highlighted list with scroll indicators
const lines = buildScrollableList({
items: recipes,
highlightedIndex: nav.highlightedIndex,
maxVisible: 5,
formatter: (r) => r.title,
});
// Header + scrollable content with indicators
const display = buildScrollableContent({
title: 'Recipe Detail',
actionBar: buildStaticActionBar(['Start'], 0),
contentLines: ['Line 1', 'Line 2', ...],
scrollPos: nav.highlightedIndex,
});
Pixel-Accurate Text Measurement (pretext)
Use even-toolkit/pretext when character-count wrapping is not precise enough. It wraps @evenrealities/pretext and uses the same LVGL font metrics as Even Hub for G2 text width, truncation, and wrapped-height prediction.
import {
getTextWidth,
measureGlassText,
truncateGlassText,
G2_TEXT_MAX_WIDTH,
} from 'even-toolkit/pretext';
const title = truncateGlassText('A long glasses title', { width: G2_TEXT_MAX_WIDTH, paddingX: 12 });
const measured = measureGlassText('The quick brown fox jumps over the lazy dog', {
width: 300,
paddingX: 8,
borderWidth: 2,
});
console.log(measured.lineCount, measured.height, measured.maxLineWidth);
console.log(getTextWidth(title));
Speech-to-Text (STT)
Provider-agnostic speech-to-text module for voice input in G2 glasses apps.
Quick Start
import { useSTT } from 'even-toolkit/stt/react';
function VoiceInput() {
const { transcript, isListening, start, stop } = useSTT({
provider: 'soniox',
language: 'en-US',
apiKey: 'your-soniox-key',
});
return (
<div>
<button onClick={isListening ? stop : start}>
{isListening ? 'Stop' : 'Record'}
</button>
<p>{transcript}</p>
</div>
);
}
Configuration
useSTT({
provider: 'soniox',
language: 'en-US', // BCP-47 language tag
apiKey: 'your-key', // Required
vad: { silenceMs: 2500 }, // Auto-stop after silence
chunkIntervalMs: 4000, // Progressive transcription interval
continuous: false, // Don't auto-stop on silence
})
Design Tokens
Light theme following Even Realities 2025 guidelines:
@import "even-toolkit/web/theme-light.css";
@import "even-toolkit/web/typography.css";
@import "even-toolkit/web/utilities.css";
| Token | Value | Usage |
|---|---|---|
--color-text |
#232323 | Primary text (TC-1st) |
--color-text-dim |
#7B7B7B | Secondary text (TC-2nd) |
--color-bg |
#EEEEEE | Page background (BC-3rd) |
--color-surface |
#FFFFFF | Card/component background (BC-1st) |
--color-accent |
#232323 | Accent/highlight (BC-Highlight) |
--color-positive |
#4BB956 | Success/connected (TC-Green) |
--color-negative |
#FF453A | Error/warning (TC-Red) |
--color-accent-warning |
#FEF991 | Active/toast (BC-Accent) |
--radius-default |
6px | Default border radius |
--font-display |
FK Grotesk Neue | Display & body font |
Typography
| Style | Size | Weight | Tracking |
|---|---|---|---|
| Very Large Title | 24px | 400 | -0.72px |
| Large Title | 20px | 400 | -0.6px |
| Medium Title | 17px | 400 | -0.17px |
| Medium Body | 17px | 300 | -0.17px |
| Normal Title | 15px | 400 | -0.15px |
| Normal Body | 15px | 300 | -0.15px |
| Normal Subtitle | 13px | 400 | -0.13px |
| Normal Detail | 11px | 400 | -0.11px |