Skip to content

FE-1129: Token encoding playground (Storybook)#8943

Open
kube wants to merge 6 commits into
cf/h-6519-add-uuid-boolean-and-int-discrete-typesfrom
cf/token-encoding-playground
Open

FE-1129: Token encoding playground (Storybook)#8943
kube wants to merge 6 commits into
cf/h-6519-add-uuid-boolean-and-int-discrete-typesfrom
cf/token-encoding-playground

Conversation

@kube

@kube kube commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

🌟 What is the purpose of this PR?

Adds a dev-only Storybook playground for inspecting how token values are encoded into the simulation frame buffers: define a colour's dimensions, author a token value in a typed Monaco editor, and see the exact bits stored — with coercion round-trips made visible (input 2.7 → stored 3 → reads back 3).

It doubles as the visual testbed for the packed-struct token layout (format v2, follow-up PR), and lands a small enabler: the token value codec is now exported from @hashintel/petrinaut-core instead of being duplicated in UI components.

🔗 Related links

🚫 Blocked by

🔍 What does this change?

  • Exports the token value codec (coerceTokenAttributeValue, coerceTokenRecord, encodeTokenAttributeValue, decodeTokenAttributeValue, decodeTokenRecord, defaultTokenAttributeValue) and compileUserCode from @hashintel/petrinaut-core; the spreadsheet and initial-state editors reuse defaultTokenAttributeValue instead of local switches.
  • Adds src/ui/dev/token-encoding-playground/ with a Storybook story (Dev / Token Encoding Playground):
    • store-free dimensions editor (name + Real/Integer/Boolean select);
    • Monaco value editor (export default Token(() => ({ … }))) typed against declarations generated live from the dimensions;
    • a compact memory view: one byte (8 bits) per row grouped by slot, one colour per field with IEEE-754 anatomy shading (sign/exponent/mantissa), hatched padding, hover highlights the whole slot and reveals offset/size/hex and the coercion round-trip in a side panel; toggle between logical (MSB→LSB) and little-endian memory byte order.
  • Evaluation runs the real product pipeline (compileUserCode + the real codec), debounced, with errors displayed inline.
  • Monaco's built-in TypeScript language service is imported for the playground only and strictly scoped to its mount: silenced at module load, enabled while mounted, disabled with markers cleared on unmount — so it never shadows the SDCPN LSP in the product's editors (verified: opening the playground then an LSP-backed editor story shows zero foreign diagnostics).

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies an npm-publishable library and I have added a changeset file(s)

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change
    • (dev-only Storybook tooling — explicitly out of scope for the user guide)

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • The playground evaluates authored code in-page (same compileUserCode pipeline and same-realm sandboxing posture as the product's code surfaces) — acceptable for a dev tool, not a hardened boundary.

🐾 Next steps

  • Format v2 (packed struct token layout) stacks on this PR and switches the playground to render the real engine layout module.
  • 128-bit field rendering (UUID, FE-1121) once that type lands.

🛡 What tests cover this?

  • libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/physical-layout.test.ts (layout ordering/padding/stride, encode/decode round-trips, IEEE-754 bit extraction)
  • Full test:unit, lint:tsc (tsgo), lint:eslint (oxlint) for both petrinaut packages

❓ How to test this?

  1. yarn dev in libs/@hashintel/petrinaut, open Dev / Token Encoding Playground.
  2. Edit dimensions (add a Boolean, rename one) — the editor's Token type updates live; wrong-typed values get squiggles.
  3. Enter count: 2.7 — the memory view shows the stored value 3 and the round-trip line.
  4. Hover slots/legend chips — whole-slot highlight + details panel.
  5. Open Components / CodeEditor / With LSP afterwards — no stray TypeScript diagnostics on the product editor.

📹 Demo

The story itself is the demo — screenshots in the Storybook story render exactly what reviewers will see locally.

kube and others added 5 commits July 3, 2026 00:47
Exposes coerce/encode/decode/default token attribute helpers and
compileUserCode so the UI package can reuse the exact product
encoding pipeline; replaces the duplicated default-value switches
in the spreadsheet and initial-state editor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dev-only playground for the simulation token buffer encoding: a
store-free dimension editor, a Monaco value editor typed against
generated Token declarations (opts into Monaco's TS language service
locally — the shared provider only ships the SDCPN LSP), and a
bit-level memory view with IEEE-754 anatomy shading, round-trip
display, and little-endian byte order toggle.

The memory view is built against the planned format-v2 layout
abstraction (per-field physical types, alignment ordering, stride
padding), so the shipped v1 all-f64 encoding and the planned v2
packed layout (u8 booleans) can be compared side by side.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One byte (8 bits) per row grouped by slot; static legend on the left;
per-slot details (offset, hex, round-trip) in a side panel shown on
hover; hovering a row or legend chip highlights the whole slot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 3, 2026 10:33
@vercel

vercel Bot commented Jul 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Jul 3, 2026 2:27pm
petrinaut Ready Ready Preview, Comment Jul 3, 2026 2:27pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jul 3, 2026 2:27pm

@cursor

cursor Bot commented Jul 3, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Changes are mostly dev-only Storybook tooling plus a minor public API export; spreadsheet/initial-state behavior should match prior defaults via shared defaultTokenAttributeValue.

Overview
Exports the simulation token value codec and compileUserCode from @hashintel/petrinaut-core (with a changeset: core minor, petrinaut patch). The spreadsheet and place initial-state editor now call defaultTokenAttributeValue instead of duplicating per-type defaults.

Adds a Dev / Token Encoding Playground Storybook story under token-encoding-playground/: edit colour dimensions, author Token(() => ({ … })) in Monaco with live generated typings, and inspect encoded bytes via computeTokenLayout (shipped v1 f64 slots vs planned v2 packed struct), encodeToken using the real codec, and an interactive memory view (padding, IEEE-754 shading, coercion round-trips). Playground-only Monaco TypeScript worker wiring and extra libs are scoped so product SDCPN LSP editors stay unaffected. physical-layout.test.ts covers layout, round-trips, and bit/hex helpers.

Reviewed by Cursor Bugbot for commit 59a88b8. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions github-actions Bot added area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team area/apps > hash.design Affects the `hash.design` design site (app) labels Jul 3, 2026
allowNonTsExtensions: true,
});
typescriptDefaults.setEagerModelSync(true);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Monaco TS never torn down

Medium Severity

The playground enables Monaco’s TypeScript worker and setExtraLibs via module-level state, but nothing restores MonacoEnvironment or clears extra libs when the story unmounts. After visiting the playground once in Storybook, other typescript editors in the same session can keep the patched worker and playground typings.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit da4b714. Configure here.

dimensions: readonly PlaygroundDimension[],
): string {
const properties = dimensions
.filter((dimension) => IDENTIFIER_RE.test(dimension.name))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid dimension names desync layout

Medium Severity

generateTokenDefs drops dimensions whose names are not valid identifiers, but evaluate still passes the full dimension list into computeTokenLayout. Renaming a field to a non-identifier leaves the memory view encoding that slot while the Monaco Token type and sample code no longer mention it, so displayed bits and coercion no longer match what the editor shows.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit da4b714. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a dev-only Storybook playground in @hashintel/petrinaut for inspecting how typed token values are coerced/encoded into simulation buffers, and moves the “token value codec” + compileUserCode to public exports in @hashintel/petrinaut-core so UI surfaces can reuse the canonical defaults/encoding logic.

Changes:

  • Exported token value codec helpers and compileUserCode from @hashintel/petrinaut-core (with a changeset) and reused defaultTokenAttributeValue in UI editors.
  • Added a new Storybook “Dev / Token Encoding Playground” with a dimensions editor, Monaco-based typed token editor, and a byte/bit memory visualization for v1 vs planned v2 layouts.
  • Added unit coverage for layout/padding, encode/decode round-trips, and IEEE-754 bit extraction.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/PropertiesPanel/place-properties/subviews/place-initial-state/initial-state-editor.tsx Reuses defaultTokenAttributeValue from core instead of local defaults logic.
libs/@hashintel/petrinaut/src/ui/components/spreadsheet.tsx Reuses defaultTokenAttributeValue for spreadsheet default cell values.
libs/@hashintel/petrinaut-core/src/index.ts Re-exports token codec helpers + compileUserCode from the core package entrypoint.
.changeset/token-codec-exports.md Versions the public API change (core minor, petrinaut patch).
libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/token-encoding-playground.tsx Implements the playground UI and debounced evaluation pipeline.
libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/token-memory-view.tsx Renders encoded token bytes/bits with hover-driven field detail.
libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/physical-layout.ts Computes v1/v2 layouts and encodes/decodes tokens via the real core codec.
libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/dimension-editor.tsx Store-free dimension/type editor for the playground.
libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/playground-monaco.ts Adds Story-scoped Monaco TypeScript contribution wiring + token type defs generation.
libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/monaco-typescript.d.ts Declares minimal types for Monaco TS contribution APIs used by the playground.
libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/token-encoding-playground.stories.tsx Registers the Storybook story under “Dev / Token Encoding Playground”.
libs/@hashintel/petrinaut/src/ui/dev/token-encoding-playground/physical-layout.test.ts Adds unit tests for layout, round-trips, and bit/hex inspection.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +26 to +34
export function enableTypescriptLanguageService(): void {
if (environmentPatched) {
return;
}
environmentPatched = true;

const previousEnvironment = window.MonacoEnvironment;
window.MonacoEnvironment = {
getWorker(workerId: string, label: string) {
Comment on lines +141 to +145
use(use(MonacoContext));
// Both calls are idempotent and MUST run before the editor's `typescript`
// model is created below (worker routing + extra libs).
enableTypescriptLanguageService();
setPlaygroundTokenDefs(defs);
Comment on lines +81 to +85
groups.push({
key: `field-${field.name}`,
field,
fieldIndex,
startByte: field.byteOffset,
Comment on lines +316 to +320
<span
key={field.name}
className={legendChipStyle}
onMouseEnter={() => setHoveredKey(`field-${field.name}`)}
onMouseLeave={() => setHoveredKey(null)}

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 59a88b8. Configure here.

onChange={(next) => onChange(next ?? "")}
options={{ minimap: { enabled: false }, scrollBeyondLastLine: false }}
/>
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Monaco TS never torn down

Medium Severity

PlaygroundEditor enables Monaco’s TypeScript worker, compiler options, eager model sync, and playground extra libs during render but never reverses that on unmount. Module-level environmentPatched keeps the patched MonacoEnvironment and TS defaults for the whole Storybook session, so leaving the playground can leave TS checking active on other typescript editors (including LSP stories).

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 59a88b8. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash.design Affects the `hash.design` design site (app) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

2 participants