@runek/core 0.5.0 → 0.10.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/dist/index.d.ts +245 -28
- package/dist/index.js +706 -83
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ComponentType, ReactNode } from 'react';
|
|
3
3
|
import { KeyboardControlsEntry } from '@react-three/drei';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* The single default font bundled with Runek, for the in-world text carve-out
|
|
7
|
+
* (CONTRACT §4). It travels as a base64 `data:` URI so it ships inside the JS
|
|
8
|
+
* bundle: no separate font file to resolve, no CDN fetch, nothing for the host
|
|
9
|
+
* app to serve. A world can override it per role via `WorldData.fonts`; a text
|
|
10
|
+
* component falls back to this whenever a role is undeclared, so it always
|
|
11
|
+
* renders.
|
|
12
|
+
*
|
|
13
|
+
* Face: Pixelspace, the Runek brand pixel display font (woff2, ~8KB).
|
|
14
|
+
*/
|
|
15
|
+
declare const DEFAULT_FONT = "data:font/woff2;base64,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";
|
|
16
|
+
/**
|
|
17
|
+
* Named font roles a world declares and text components draw from. Values are
|
|
18
|
+
* font URLs (or `data:` URIs). Mirrors {@link WorldPalette}: a world overrides
|
|
19
|
+
* the roles it cares about; the rest fall back to {@link DEFAULT_FONT}.
|
|
20
|
+
*/
|
|
21
|
+
interface WorldFonts {
|
|
22
|
+
/** Titles, signage, headings. */
|
|
23
|
+
display: string;
|
|
24
|
+
/** Labels, paragraphs, body copy. */
|
|
25
|
+
body: string;
|
|
26
|
+
}
|
|
27
|
+
/** Every role resolved to the bundled default. A world's `fonts` layers on top. */
|
|
28
|
+
declare const DEFAULT_FONTS: WorldFonts;
|
|
29
|
+
|
|
5
30
|
/**
|
|
6
31
|
* Named color slots shared by the whole world. Components default their colors
|
|
7
32
|
* to these slots, so swapping the palette re-themes every component at once —
|
|
@@ -38,7 +63,63 @@ interface WorldPalette {
|
|
|
38
63
|
}
|
|
39
64
|
declare const DEFAULT_PALETTE: WorldPalette;
|
|
40
65
|
|
|
66
|
+
/**
|
|
67
|
+
* A world's resolved time-of-day, the value day/night-aware components (`Sky`,
|
|
68
|
+
* `LightRig`, `Clock`) read from `useWorld()`. A world pins a fixed `time`
|
|
69
|
+
* ("HH:MM", reproducible) or tracks a live `timezone`; either way it lands here.
|
|
70
|
+
*/
|
|
71
|
+
interface WorldTime {
|
|
72
|
+
/** Fractional hours in [0, 24). For a live world this is a snapshot at resolve
|
|
73
|
+
* time; call `currentHours()` for the up-to-date value each frame. */
|
|
74
|
+
hours: number;
|
|
75
|
+
/** True when the time tracks a live clock (`timezone` or system), false when pinned. */
|
|
76
|
+
live: boolean;
|
|
77
|
+
/** IANA zone in effect, if any. Drives live reads and `Clock`'s default timezone. */
|
|
78
|
+
timezone?: string;
|
|
79
|
+
}
|
|
80
|
+
/** A neutral, pinned midday — the default when a world declares no time. Renders
|
|
81
|
+
* as bright day, so a world that opts out of day/night looks unchanged. */
|
|
82
|
+
declare const DEFAULT_WORLD_TIME: WorldTime;
|
|
83
|
+
/** Parse "HH:MM" (24-hour) into fractional hours in [0, 24), or null if malformed. */
|
|
84
|
+
declare function parseClockTime(value: string): number | null;
|
|
85
|
+
/** Read the current fractional hours-of-day in `timezone` (or the local system
|
|
86
|
+
* clock when omitted), falling back to UTC if the zone is unusable. */
|
|
87
|
+
declare function clockHours(timezone?: string): number;
|
|
88
|
+
/**
|
|
89
|
+
* Resolve a world's `time`/`timezone` fields into a `WorldTime`. Precedence: a
|
|
90
|
+
* valid pinned `time` wins (deterministic); else a live clock in `timezone`; else
|
|
91
|
+
* the local system clock; else UTC. A malformed `time` is ignored, not fatal.
|
|
92
|
+
*/
|
|
93
|
+
declare function resolveWorldTime(opts: {
|
|
94
|
+
time?: string;
|
|
95
|
+
timezone?: string;
|
|
96
|
+
}): WorldTime;
|
|
97
|
+
/** The fractional hours for a `WorldTime` right now: constant when pinned, the
|
|
98
|
+
* live clock when not. Components call this each frame for a live world. */
|
|
99
|
+
declare function currentHours(time: WorldTime): number;
|
|
100
|
+
/** Where the sun sits for a given time-of-day, shared by `Sky` and `LightRig` so
|
|
101
|
+
* the sky's bright spot and the cast shadows always agree. */
|
|
102
|
+
interface SunState {
|
|
103
|
+
/** Direction to the sun, usable directly as a `sunPosition`. Dips below the
|
|
104
|
+
* ground plane (`position[1] < 0`) at night. */
|
|
105
|
+
position: Vec3;
|
|
106
|
+
/** 0 at or below the horizon, rising to 1 at the zenith. */
|
|
107
|
+
elevation: number;
|
|
108
|
+
/** Whether the sun is above the horizon. */
|
|
109
|
+
day: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* A simple time-of-day → sun position curve. The sun rises at 06:00, peaks at
|
|
113
|
+
* noon, sets at 18:00, and sits below the horizon overnight. This is a
|
|
114
|
+
* latitude/date-free model (azimuth is a plain east→west sweep); accurate solar
|
|
115
|
+
* position is deliberately out of scope (see the v0.8.0 spec).
|
|
116
|
+
*/
|
|
117
|
+
declare function sunState(hours: number, radius?: number): SunState;
|
|
118
|
+
|
|
41
119
|
type Vec3 = [number, number, number];
|
|
120
|
+
/** How the player camera frames the avatar. A world default `Player` reads when
|
|
121
|
+
* its own `view` is unset; an explicit component `view` still wins. */
|
|
122
|
+
type AvatarView = 'first' | 'third';
|
|
42
123
|
/** The contract every Runek component implements. */
|
|
43
124
|
interface WorldComponentProps {
|
|
44
125
|
position?: Vec3;
|
|
@@ -57,12 +138,130 @@ interface WorldContextValue {
|
|
|
57
138
|
/** Meters per unit. Components scale their geometry by this. */
|
|
58
139
|
unit: number;
|
|
59
140
|
gravity: Vec3;
|
|
141
|
+
/** Baseline ground level (Y, in world units). Floor-sitting and water components
|
|
142
|
+
* default their placement to it; an explicit `position` wins. Default 0. */
|
|
143
|
+
ground: number;
|
|
60
144
|
/** Resolved color slots components default their materials to. */
|
|
61
145
|
palette: WorldPalette;
|
|
146
|
+
/** Resolved font roles (display, body) text components draw from. Every role
|
|
147
|
+
* is filled (the world's overrides over the bundled default), so a text
|
|
148
|
+
* component can read `fonts[role]` unconditionally. */
|
|
149
|
+
fonts: WorldFonts;
|
|
150
|
+
/** Resolved time-of-day. Day/night-aware components (`Sky`, `LightRig`,
|
|
151
|
+
* `Clock`) read this; defaults to a pinned midday. */
|
|
152
|
+
time: WorldTime;
|
|
153
|
+
/** World default camera view for the player, if the world declares one. */
|
|
154
|
+
avatar?: AvatarView;
|
|
62
155
|
}
|
|
63
156
|
|
|
64
157
|
declare const WorldContext: react.Context<WorldContextValue>;
|
|
65
158
|
|
|
159
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
160
|
+
[key: string]: JsonValue;
|
|
161
|
+
};
|
|
162
|
+
/** One contributor to a world. */
|
|
163
|
+
interface WorldAuthor {
|
|
164
|
+
name: string;
|
|
165
|
+
url?: string;
|
|
166
|
+
}
|
|
167
|
+
/** Where a world lives, so it can be linked, forked, and contributed back to. */
|
|
168
|
+
interface WorldSource {
|
|
169
|
+
/** Full web URL of the canonical repo, e.g. `https://github.com/owner/repo`.
|
|
170
|
+
* Stored whole (not `owner/repo`) so the host is detectable for the fork flow. */
|
|
171
|
+
url: string;
|
|
172
|
+
/** Path to the world file within the repo, e.g. `public/helicon.world.json`. */
|
|
173
|
+
path?: string;
|
|
174
|
+
branch?: string;
|
|
175
|
+
}
|
|
176
|
+
/** A world's descriptive identity: attribution, license, and where it lives.
|
|
177
|
+
* Everything is optional; a world with no `meta` still renders. Travels in the
|
|
178
|
+
* world file (not tooling config) so it survives a fork. */
|
|
179
|
+
interface WorldMeta {
|
|
180
|
+
title?: string;
|
|
181
|
+
description?: string;
|
|
182
|
+
/** Worlds accrue contributors, hence an array. */
|
|
183
|
+
authors?: WorldAuthor[];
|
|
184
|
+
/** Free SPDX-ish string. Components are MIT code; a world is content, so authors
|
|
185
|
+
* often prefer a Creative Commons license for the world itself. */
|
|
186
|
+
license?: string;
|
|
187
|
+
source?: WorldSource;
|
|
188
|
+
}
|
|
189
|
+
/** One placed component: a registry key, its props, and optional nested children. */
|
|
190
|
+
interface WorldNode {
|
|
191
|
+
/** Registry key — the component's name, e.g. "Bookshelf". */
|
|
192
|
+
type: string;
|
|
193
|
+
/** Stable identity, durable across edits and reorders. Optional in hand-authored
|
|
194
|
+
* worlds; the editor fills it in (see `assignNodeIds`). Drives React keys,
|
|
195
|
+
* selection, and minimal PR diffs. */
|
|
196
|
+
id?: string;
|
|
197
|
+
props?: Record<string, JsonValue>;
|
|
198
|
+
children?: WorldNode[];
|
|
199
|
+
}
|
|
200
|
+
/** A whole world as plain data — diffable, forkable, version-controlled like any file. */
|
|
201
|
+
interface WorldData {
|
|
202
|
+
version: 1;
|
|
203
|
+
/** The world's identity (title, authors, license, source). Optional. */
|
|
204
|
+
meta?: WorldMeta;
|
|
205
|
+
unit?: number;
|
|
206
|
+
gravity?: Vec3;
|
|
207
|
+
/** Baseline ground level (Y, in units). Floor-sitting and water components default
|
|
208
|
+
* their placement to it; an explicit `position` wins. Default 0. */
|
|
209
|
+
ground?: number;
|
|
210
|
+
/** Pinned time-of-day ("HH:MM", 24h) for a reproducible world. Drives day/night. */
|
|
211
|
+
time?: string;
|
|
212
|
+
/** IANA timezone for a live, clock-driven day/night (used when `time` is unset). */
|
|
213
|
+
timezone?: string;
|
|
214
|
+
/** World default camera view; `Player` reads it when its own `view` is unset. */
|
|
215
|
+
avatar?: AvatarView;
|
|
216
|
+
/** Color-slot overrides applied to every component in the world. */
|
|
217
|
+
palette?: Partial<WorldPalette>;
|
|
218
|
+
/** Fonts the world ships, by role (`display`, `body`). Text components draw from
|
|
219
|
+
* these; unset roles fall back to the bundled default. Values are font URLs. */
|
|
220
|
+
fonts?: Partial<WorldFonts>;
|
|
221
|
+
fog?: WorldFog;
|
|
222
|
+
nodes: WorldNode[];
|
|
223
|
+
}
|
|
224
|
+
type ComponentRegistry = Record<string, ComponentType<any>>;
|
|
225
|
+
/**
|
|
226
|
+
* Serialize a world to pretty JSON text with a canonical, stable key order
|
|
227
|
+
* (`version, meta, unit, gravity, ground, time, timezone, avatar, palette, fonts,
|
|
228
|
+
* fog, nodes`; each node `type, id, props, children`). Stable output means an
|
|
229
|
+
* unchanged node never churns the diff, so PR reviews show only the real change.
|
|
230
|
+
*/
|
|
231
|
+
declare function serializeWorld(data: WorldData): string;
|
|
232
|
+
/** Parse and lightly validate world JSON text. Throws on an unsupported shape. */
|
|
233
|
+
declare function parseWorld(json: string): WorldData;
|
|
234
|
+
/**
|
|
235
|
+
* Return a copy of the world where every node has a stable `id`. Existing ids are
|
|
236
|
+
* preserved; missing ones are generated (unique within the world). The editor calls
|
|
237
|
+
* this on load, so edits and serialized output carry durable node identity even when
|
|
238
|
+
* the source world was hand-authored without ids.
|
|
239
|
+
*/
|
|
240
|
+
declare function assignNodeIds(data: WorldData): WorldData;
|
|
241
|
+
|
|
242
|
+
/** A GitHub-hosted world source, parsed into the pieces the contribute URLs need. */
|
|
243
|
+
interface GitHubSource {
|
|
244
|
+
owner: string;
|
|
245
|
+
repo: string;
|
|
246
|
+
branch: string;
|
|
247
|
+
path?: string;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Parse a `WorldSource` into its GitHub owner/repo (plus branch + path), or `null`
|
|
251
|
+
* if the source is not a github.com URL. `meta.source` stores the full web URL
|
|
252
|
+
* precisely so the host is detectable here; non-GitHub hosts fall back to "open the
|
|
253
|
+
* repo" in the UI.
|
|
254
|
+
*/
|
|
255
|
+
declare function parseGitHubSource(source: WorldSource | undefined): GitHubSource | null;
|
|
256
|
+
/** URL that forks the world's repo on GitHub. */
|
|
257
|
+
declare function forkUrl(gh: GitHubSource): string;
|
|
258
|
+
/**
|
|
259
|
+
* GitHub web edit-file URL. Opening it as a non-collaborator makes GitHub auto-fork
|
|
260
|
+
* the repo and open its web editor on the fork — the zero-auth contribution path.
|
|
261
|
+
* Returns `null` when the world's file path is unknown (nothing to deep-link).
|
|
262
|
+
*/
|
|
263
|
+
declare function editFileUrl(gh: GitHubSource): string | null;
|
|
264
|
+
|
|
66
265
|
/** Default movement bindings, matching the action names ecctrl reads. */
|
|
67
266
|
declare const keyboardMap: KeyboardControlsEntry[];
|
|
68
267
|
|
|
@@ -80,47 +279,65 @@ declare const useWorld: () => WorldContextValue;
|
|
|
80
279
|
interface WorldProps {
|
|
81
280
|
unit?: number;
|
|
82
281
|
gravity?: Vec3;
|
|
282
|
+
/** Baseline ground level (Y). Floor-sitting and water components default to it;
|
|
283
|
+
* an explicit `position` still wins. Default 0. */
|
|
284
|
+
ground?: number;
|
|
83
285
|
keyboardMap?: KeyboardControlsEntry[];
|
|
84
286
|
/** Render the default light rig. Set false to supply your own (e.g. <LightRig>). */
|
|
85
287
|
lights?: boolean;
|
|
86
288
|
/** Override color slots; unset slots keep their defaults. Components read these via `useWorld()`. */
|
|
87
289
|
palette?: Partial<WorldPalette>;
|
|
290
|
+
/** Fonts the world ships, by role (`display`, `body`). Text components draw from
|
|
291
|
+
* these; unset roles fall back to the bundled default. Values are font URLs. */
|
|
292
|
+
fonts?: Partial<WorldFonts>;
|
|
88
293
|
/** Linear distance fog. Pair the color with your sky's horizon. */
|
|
89
294
|
fog?: WorldFog;
|
|
295
|
+
/** Pin a fixed time-of-day ("HH:MM", 24h) so the world is reproducible. Drives
|
|
296
|
+
* day/night-aware components. A `timezone` instead makes it track a live clock. */
|
|
297
|
+
time?: string;
|
|
298
|
+
/** IANA timezone (e.g. "Asia/Kolkata") for a live, clock-driven day/night. Ignored
|
|
299
|
+
* when `time` is set (a pin wins); used as the live source otherwise. */
|
|
300
|
+
timezone?: string;
|
|
301
|
+
/** World default camera view. `Player` reads it when its own `view` is unset. */
|
|
302
|
+
avatar?: AvatarView;
|
|
90
303
|
/** Fired when a pointer click misses every object (used to deselect in the editor). */
|
|
91
304
|
onPointerMissed?: () => void;
|
|
305
|
+
/** Keep the WebGL backbuffer so the canvas can be snapshotted via `toDataURL`
|
|
306
|
+
* (the editor enables this for the "suggest changes" PNG). Off by default — it can
|
|
307
|
+
* cost a little performance. */
|
|
308
|
+
preserveDrawingBuffer?: boolean;
|
|
92
309
|
debug?: boolean;
|
|
93
310
|
children?: ReactNode;
|
|
94
311
|
}
|
|
95
|
-
declare function World({ unit, gravity, keyboardMap, lights, palette, fog, onPointerMissed, debug, children, }: WorldProps): react.JSX.Element;
|
|
312
|
+
declare function World({ unit, gravity, ground, keyboardMap, lights, palette, fonts, fog, time, timezone, avatar, onPointerMissed, preserveDrawingBuffer, debug, children, }: WorldProps): react.JSX.Element;
|
|
96
313
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
/** One placed component: a registry key, its props, and optional nested children. */
|
|
101
|
-
interface WorldNode {
|
|
102
|
-
/** Registry key — the component's name, e.g. "Bookshelf". */
|
|
103
|
-
type: string;
|
|
104
|
-
props?: Record<string, JsonValue>;
|
|
105
|
-
children?: WorldNode[];
|
|
314
|
+
interface WorldAboutProps {
|
|
315
|
+
/** The world's identity. When absent, the panel shows a minimal "untitled world". */
|
|
316
|
+
meta?: WorldMeta;
|
|
106
317
|
}
|
|
107
|
-
/**
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
318
|
+
/**
|
|
319
|
+
* A small `ⓘ` affordance that opens a read-only "About this world" panel over the
|
|
320
|
+
* canvas. A pure view of `meta` (title, description, authors, license, source repo)
|
|
321
|
+
* plus a "built with Runek" tag. Surfaced in both walk (`WorldRenderer`) and edit
|
|
322
|
+
* (`WorldEditor`) modes — a visitor wants to know whose world it is and how it is
|
|
323
|
+
* licensed, not just an editor.
|
|
324
|
+
*/
|
|
325
|
+
declare function WorldAbout({ meta }: WorldAboutProps): react.JSX.Element;
|
|
326
|
+
|
|
327
|
+
interface WorldContributeProps {
|
|
328
|
+
/** The edited world. Its `meta.source` drives the GitHub URLs; its content is the download. */
|
|
329
|
+
data: WorldData;
|
|
330
|
+
onClose: () => void;
|
|
116
331
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
332
|
+
/**
|
|
333
|
+
* "Suggest changes upstream": a modal that couriers the edited world to GitHub's own
|
|
334
|
+
* UI with no account, token, or backend. Runek downloads the edited JSON + a snapshot,
|
|
335
|
+
* then opens GitHub's edit-file URL (which auto-forks for non-collaborators); the modal
|
|
336
|
+
* copy walks paste → commit → PR. Non-GitHub hosts fall back to opening the repo.
|
|
337
|
+
*/
|
|
338
|
+
declare function WorldContribute({ data, onClose }: WorldContributeProps): react.JSX.Element;
|
|
122
339
|
|
|
123
|
-
interface WorldEditorProps extends Omit<WorldProps, 'children' | 'unit' | 'gravity' | 'palette' | 'fog'> {
|
|
340
|
+
interface WorldEditorProps extends Omit<WorldProps, 'children' | 'unit' | 'gravity' | 'palette' | 'fog' | 'time' | 'timezone' | 'avatar'> {
|
|
124
341
|
data: WorldData;
|
|
125
342
|
registry: ComponentRegistry;
|
|
126
343
|
onChange: (next: WorldData) => void;
|
|
@@ -138,11 +355,11 @@ interface WorldNodesProps {
|
|
|
138
355
|
/** Render a list of world nodes by looking each `type` up in the registry. Recurses into children. */
|
|
139
356
|
declare function WorldNodes({ nodes, registry }: WorldNodesProps): react.JSX.Element;
|
|
140
357
|
|
|
141
|
-
interface WorldRendererProps extends Omit<WorldProps, 'children' | 'unit' | 'gravity' | 'palette' | 'fog'> {
|
|
358
|
+
interface WorldRendererProps extends Omit<WorldProps, 'children' | 'unit' | 'gravity' | 'palette' | 'fog' | 'time' | 'timezone' | 'avatar'> {
|
|
142
359
|
data: WorldData;
|
|
143
360
|
registry: ComponentRegistry;
|
|
144
361
|
}
|
|
145
362
|
/** Render a `WorldData` object inside a `<World>`, resolving each node via the registry. */
|
|
146
363
|
declare function WorldRenderer({ data, registry, ...worldProps }: WorldRendererProps): react.JSX.Element;
|
|
147
364
|
|
|
148
|
-
export { type ComponentRegistry, DEFAULT_PALETTE, type JsonValue, type Rng, type Vec3, World, type WorldComponentProps, WorldContext, type WorldContextValue, type WorldData, WorldEditor, type WorldEditorProps, type WorldFog, type WorldNode, WorldNodes, type WorldNodesProps, type WorldPalette, type WorldProps, WorldRenderer, type WorldRendererProps, int, keyboardMap, parseWorld, pick, range, rng, serializeWorld, sub, useWorld };
|
|
365
|
+
export { type AvatarView, type ComponentRegistry, DEFAULT_FONT, DEFAULT_FONTS, DEFAULT_PALETTE, DEFAULT_WORLD_TIME, type GitHubSource, type JsonValue, type Rng, type SunState, type Vec3, World, WorldAbout, type WorldAboutProps, type WorldAuthor, type WorldComponentProps, WorldContext, type WorldContextValue, WorldContribute, type WorldContributeProps, type WorldData, WorldEditor, type WorldEditorProps, type WorldFog, type WorldFonts, type WorldMeta, type WorldNode, WorldNodes, type WorldNodesProps, type WorldPalette, type WorldProps, WorldRenderer, type WorldRendererProps, type WorldSource, type WorldTime, assignNodeIds, clockHours, currentHours, editFileUrl, forkUrl, int, keyboardMap, parseClockTime, parseGitHubSource, parseWorld, pick, range, resolveWorldTime, rng, serializeWorld, sub, sunState, useWorld };
|