@stage5/lumine 0.2.1 → 0.2.3

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/bin/lumine.js CHANGED
@@ -96,8 +96,9 @@ lumine save --summary "Describe the change"
96
96
  - Use local project files with relative or root-local imports only. Do not add package imports, CDN scripts, external network calls, or app-local /api/* routes.
97
97
  - Build apps run in sandboxed iframes without allow-forms. Do not use <form> elements, native form submission, requestSubmit(), or browser form navigation. Build input flows with JavaScript-handled inputs and buttons instead.
98
98
  - For canvas, WebGL, Three.js, fullscreen, or game builds, use Twinkle.preview for layout. Do not size roots from 100vh, 100vw, 100dvh, 100dvw, window.innerWidth, window.innerHeight, visualViewport, or document viewport dimensions.
99
- - For Three.js, use import * as THREE from '/build/vendor/three/0.160.0/three.module.min.js';.
99
+ - For Three.js, use import * as THREE from '/build/vendor/three/0.184.0/three.module.min.js';. Addons (OrbitControls, GLTFLoader, ...) live under /build/vendor/three/0.184.0/addons/, e.g. import { OrbitControls } from '/build/vendor/three/0.184.0/addons/controls/OrbitControls.js';. Builds saved with the older /build/vendor/three/0.160.0/ path keep working.
100
100
  - Do not invent or guess Twinkle.* SDK method names. Use ${SDK_REFERENCE_FILE} as the local SDK reference and prefer Twinkle.capabilities checks for gated features.
101
+ - Match storage to update frequency. Twinkle.privateDb and Twinkle.sharedDb are for LOW-frequency durable state only — things that change on a user action (settings, inventory checkpoints, completed quests, saved progress; comments, votes, room settings, submitted records). NEVER write high-frequency or per-frame/per-tick state to them (camera or cursor position, animation state, live movement, presence, autosave every frame/tick). Keep live state in client memory, broadcast realtime/presence via Twinkle.world, and for durable per-user state flush an occasional snapshot on an interval or on exit (never per frame) — e.g. the viewer/user DB or a single latest-snapshot key. The server rate-limits these writes per key and returns 429 on excess; never retry-loop a 429.
101
102
 
102
103
  ## Completion Report
103
104
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stage5/lumine",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Command line tools for launching Lumine builds on Twinkle.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,16 +2,17 @@
2
2
 
3
3
  Version: 1.26.2
4
4
  Updated: 2026-06-09
5
- Generated: 2026-06-11T01:12:56.894Z
5
+ Generated: 2026-06-18T12:26:29.648Z
6
6
 
7
7
  ## Notes
8
8
  - This SDK is injected into Build iframes via the Build preview/runtime.
9
9
  - Widgets call SDK methods; the parent proxies to the API.
10
10
  - Data API methods require scoped tokens handled by the parent; some namespaces include write methods.
11
- - Use Twinkle.privateDb as the default private per-user persistence layer for preferences, drafts, settings, and small JSON state.
11
+ - Use Twinkle.privateDb for LOW-frequency durable private per-user state such as preferences, drafts, settings, inventory checkpoints, and saved progress. It is NOT for high-frequency or per-frame/per-tick writes; the server rate-limits writes and returns 429.
12
+ - Match storage to update frequency: privateDb and sharedDb are for LOW-frequency durable state that changes on a user action. NEVER write per-frame/per-tick state to them (camera or cursor position, animation, live movement, presence, autosave every frame/tick). Keep live state in client memory, broadcast realtime/presence via Twinkle.world, and flush only occasional durable snapshots (on an interval or on exit, never per frame). The server enforces per-key write rate limits and returns 429 on excess; never retry-loop a 429.
12
13
  - Use Twinkle.userDb only for advanced private SQLite needs such as tables, indexes, many rows, filtered queries, or aggregates.
13
14
  - Use Twinkle.leaderboards for public Build scoreboards. Signed-in viewers are ranked by Twinkle username; guests can submit with a display name.
14
- - Use Twinkle.sharedDb for custom shared multi-user structured data, guestbooks, votes, and append-only run history.
15
+ - Use Twinkle.sharedDb for LOW-frequency durable shared multi-user state such as guestbooks, votes, room settings, submitted records, and append-only run history. It is NOT for high-frequency or per-frame/per-tick writes; keep live/realtime state in Twinkle.world or client memory. The server rate-limits writes and returns 429.
15
16
  - Use Twinkle.subjects.search for in-app subject pickers. Twinkle.mount remains an optional host-provided preselection/context shortcut, not a data API.
16
17
  - Use Twinkle.aiCards for read-only existing public AI Card words and example texts, including word levels for typing games.
17
18
  - Use Twinkle.aiStories for read-only existing AI Story galleries, readers, quizzes, topic chapter indexes, and remix tools.
@@ -383,7 +384,7 @@ const result = await Twinkle.characters.chat({ character: 'zero', thinkingMode:
383
384
  - Filter with hasImage or hasQuestions when building visual galleries or quiz apps.
384
385
  - Example: const { stories } = await Twinkle.aiStories.list({ difficulty: 1, type: 'science', topicKey: 'Astronomy', order: 'oldest', limit: 20 });
385
386
  - async chapters({ limit, cursor, groupBy, difficulty, type, topicKey, storyBy, isListening, userId, hasImage, hasQuestions } = {}) | scopes: content:read
386
- - Returns: Default (groupBy:'topicKey'): { chapters: [{ difficulty, type, topicKey, title, sampleTopic, storyCount, readingCount, listeningCount, imageCount, questionCount, latestStoryId, latestTimeStamp }], cursor?, pagination, filters }. groupBy:'type': { books: [{ difficulty, type, title, sampleTopic, chapterCount, storyCount, readingCount, listeningCount, imageCount, questionCount, latestStoryId, latestTimeStamp }], ... } — one row per (level, topic) book. groupBy:'author': { authors: [{ storyBy, title, bookCount, chapterCount, storyCount, readingCount, listeningCount, imageCount, questionCount, minDifficulty, maxDifficulty, latestStoryId, latestTimeStamp }], ... } — one row per generating model (the story's author).
387
+ - Returns: Default (groupBy:'topicKey'): { chapters: [{ difficulty, type, topicKey, title, sampleTopic, storyCount, readingCount, listeningCount, imageCount, questionCount, latestStoryId, latestTimeStamp }], cursor?, pagination, filters }. groupBy:'type': { books: [{ difficulty, type, title, sampleTopic, chapterCount, storyCount, readingCount, listeningCount, imageCount, questionCount, latestStoryId, latestTimeStamp }], ... } — one row per (level, topic) book. groupBy:'author': { authors: [{ storyBy, title, bookCount, chapterCount, storyCount, minDifficulty, maxDifficulty, latestStoryId }], ... } — one row per generating model (the story's author); an index-only landing, so it omits media counts (use a scoped books/chapters call for those).
387
388
  - List the AI Story library index. Default groups by (level, type, topicKey) for per-subtopic chapter rows. groupBy:'type' returns one row per (level, topic) book; groupBy:'author' returns one row per generating model (storyBy = the author) — a tiny top-level set. Filter by storyBy to scope books/chapters/stories to one author, and by difficulty/type to scope further. Counts and navigation metadata only, no story bodies.
388
389
  - groupBy:'author' returns one row per generating model under an authors key (the library's authors); groupBy:'type' returns (level, topic) books under a books key; default groupBy:'topicKey' returns per-subtopic chapter rows under a chapters key.
389
390
  - storyBy is the generating model id (e.g. 'gpt-5.1', 'gpt-4o') and acts as the story's author. Pass a single id, or an array of ids to scope to a model family (e.g. fold gpt-4o snapshots into one author). Scopes books, chapters, and stories.
@@ -567,7 +568,7 @@ const result = await Twinkle.characters.chat({ character: 'zero', thinkingMode:
567
568
  - Returns: { sessionId, session, room, players, snapshot, subscribe(listener), updatePresence(patch), send(actionOrType, data), leave() }
568
569
  - Join a realtime Build world room and receive a snapshot plus a session handle for presence updates, actions, and room events.
569
570
  - Always available in the build iframe.
570
- - World state is ephemeral and heartbeat/TTL based. Use sharedDb/privateDb for durable inventory, XP, quests, ownership, and saved progress.
571
+ - World state is ephemeral and heartbeat/TTL based. Use sharedDb/privateDb for durable inventory, XP, quests, ownership, and saved progress — but write those LOW-frequency only (on a user action or an occasional snapshot, never per frame/tick); per-frame/live state stays in world presence or client memory. The server rate-limits sharedDb/privateDb writes and returns 429.
571
572
  - Events are room-scoped and include serverTime, seq, eventId, schemaVersion, sessionId, player, and room metadata.
572
573
  - Subscribe to session.ended and catch updatePresence/send errors. Stop using stale handles and reconnect only when Twinkle.world.isSessionEndedError(error) is true; for other Twinkle.world.isRecoverableSessionError(error) cases, drop the transient presence/action and keep the handle.
573
574
  - Use updatePresence for live avatar snapshots and send for lightweight actions such as emotes, interactions, and chat bubbles.
@@ -581,7 +582,7 @@ world.updatePresence({ x, y, z, facing });
581
582
  - Return true when a world request error is expected to be handled by app code instead of crashing.
582
583
  - Recoverable session errors include ended, missing, socket-disconnected, socket-not-ready, room-missing, preview-updating, and timed-out world session requests.
583
584
  - Only session-ended errors prove that the current handle should be discarded. Timed-out or preview-updating presence requests can be dropped without reconnecting.
584
- - For durable game state, write through sharedDb/privateDb instead of relying on world presence.
585
+ - For durable game state, write through sharedDb/privateDb instead of relying on world presence — but LOW-frequency only (on a user action or an occasional snapshot, never per frame/tick).
585
586
  - Example: try {
586
587
  await world.updatePresence({ x, y, z, facing });
587
588
  } catch (error) {
@@ -852,7 +853,7 @@ await Twinkle.chat.sendMessage('lobby', 'hello');
852
853
  ```
853
854
 
854
855
  ### Realtime MMO town room
855
- Use Twinkle.world for live avatar presence and lightweight room actions, recover stale session handles, and keep durable state like inventory and quests in sharedDb/privateDb.
856
+ Use Twinkle.world for live avatar presence and lightweight room actions, recover stale session handles, and keep durable state like inventory and quests in sharedDb/privateDb — written low-frequency (never per frame/tick).
856
857
  Keywords: multiplayer, mmo, town, presence, avatars, movement, three.js, realtime
857
858
 
858
859
  ```js