npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

lecodes-design

v0.10.0

Published

LeCodes Design — a live canvas of app screens for AI-driven prototyping. Dev server + browser board, launched via `lecodes design`.

Readme

lecodes-design

LeCodes Design — a live canvas of app screens for AI-driven prototyping. An intent-capture layer: each screen on the canvas is an executable LeCodes render (real code on mock data), the edges between them are drawn navigation intent, and the whole folder is the spec an AI builds the real app from. See lecodes-design-concept.md at the repo root for the full concept.

Launched through the CLI — this package is the dev server + the browser board. It works inside a cloned lecodes project or standalone in any folder (no login or server project needed):

npm install -g lecodes-design  # alongside lecodes-cli — install it the same way you installed the CLI
lecodes design init            # scaffold design/ (screens/, shared/, meta.json, CLAUDE.md)
lecodes design                 # start the dev server + open the canvas
lecodes design snapshot        # headless JSON/PNG of every screen (Claude's eyes)

How it works

design/
  screens/login.ts    ← one file = one screen; default-exports UIScreen([...]); islands
  shared/tokens.ts    ← design tokens + reusable components (only allowed import)
  meta.json           ← the human-owned graph: positions, descriptions, edges
  CLAUDE.md           ← the conventions, written for the AI
  • The dev server (src/server, zero runtime deps) watches the design folder, compiles each screen on demand through the CLI's pipeline (chisel + the vendored SDK — the CLI injects compileScreen), serves the project files for asset() urls, and pushes SSE change events.
  • The board (src/app, Vue 3) renders every screen live via lecodes-renderer (canvas-ui): each tile is its own creator-ui WASM instance + <canvas>, executing the compiled bundle with _creatorUI bound to it — the browser twin of the renderer's headless entry. Pan/zoom the board (wheel / two-finger scroll = pan, ctrl+wheel / pinch = zoom, middle-button drag = pan from anywhere — even over a screen, double-click = fit). Chrome lives where its effect happens: the mode bar (bottom center, lucide icons) holds the four cursor modes; the view pill (bottom right) holds device shell (popover: None/iOS/Android), hints, −/%/+/fit; the dock-panel buttons (Concept 💡, Comments) render in the host's top bar through the exported BoardToolbar; and Arrange is a quiet icon button hung beside the mode bar (out of flow — the bar never shifts), always reachable, that wears an accent count badge — how many screens the re-layout would move — when pressing it would genuinely tidy: arrangeScreens runs client-side (no endpoint), and the offer appears only when the flow structure changes (screens/edges/ groups/tabs — never in reaction to hand-moving a tile) and the re-layout wins by a clear score margin; while up it re-checks on every change and retires the moment it stops helping. The dot grid lives in world space; edges draw as labeled arrows.
  • Tiles follow a visible-modes model (Figma grammar, Esc always lands on Select): Select (V) — click selects a tile (chrome ring, role editor, mentions), drag anywhere on it moves it (release writes pos into meta.json), arrow keys nudge (Shift = ×10), double-click dives into Interact. Drag on empty canvas sweeps a marquee: every screen it touches joins the selection (Shift adds, Shift+click toggles one tile, Ctrl/Cmd+A selects all), the whole selection moves and nudges as one, and 2+ screens raise a selection bar above the sweep — count · Group (auto-named, the chip opens in rename) · Ungroup · Arrange (tidies ONLY the selection, anchored where it is — the rest of the board never moves). Clicking a group's label chip selects its members, so the same bar arranges a group in place; Hand (H) — everything pans (with the Select tool, panning is the middle button and the wheel/touchpad), tiles are inert; Interact (P) — every tile is a working prototype without selecting: the body forwards pointer input (buttons, scroll, router, drags), and focusing an in-screen input shows the simulated keyboard band + captures real keystrokes; Comment (C, alias M) — every click on a screen pins a comment. Read-only hosts (the share page) open in Interact; hints moved to I, the Concept panel to ⇧C. The header ↻ restarts a tile's prototype state.
  • The flow graph is edited on the canvas too: drag the connect handle (right edge of a tile, on hover) onto another screen to draw an edge; click an edge (or its label) to edit its label/activator or delete it — the activator field offers a dropdown of the source screen's live named elements; click a tile's header note to edit the screen description. Everything writes back into meta.json — the file Claude reads as the app map. Edges between the same pair of screens fan out instead of overlapping.
  • Auto-arrange (the Arrange chip, or lecodes design arrange) re-lays-out the flow graph as columns reading left→right (a small deterministic Sugiyama layout), so edges stop crossing and diving under tiles. It only writes when the result beats the current layout — a hand-arranged board is left alone — tiles glide into place, and Ctrl+Z undoes it like any other board edit: the board keeps a global Undo/Redo history (Ctrl+Z / Ctrl+Shift+Z or Ctrl+Y) over everything it authors — moves, nudges, group/ungroup/rename/dissolve, arranges (full and scoped), edge add/edit/delete, description and role edits. Entries are field-scoped inverse patches, so Claude's concurrent meta.json edits survive an undo untouched. A screen with no pos is already auto-placed next to its flow neighbours on the board (computed live in readDesignState, never written) — so the AI adds screens with edges but no coordinates and they land sensibly. lecodes design arrange --new just commits those positions to meta.json (placing only the position-less screens, never moving the rest). See auto-arrange.md.
  • Tab bars are a surface, not edges (tabbar-surface.md): declare the bar once in shared/tabs.ts (export const mainTabs = defineTabs({ home: {…}, news: {…} }) — keys are the root screen ids) and mount it per screen (mainTabs.screen("news", […])). The board discovers it from source (like states) and draws a rail through the tab roots + a faint lane band per tab — zero edges for tab switching; bar-implied edges in meta.json are flagged for deletion, and arrange stacks each hub's lanes in tab order (rows are tabs, columns are depth). Same-screen edges (home → home@empty) render as amber state chips on their activator element — clicking one switches the tile's state; tapping a tab button in a live prototype focuses that tab's root.
  • Groups carve the board into named sections (Onboarding, Checkout…). Membership lives on the screen ("group" in its meta entry — the AI sets it as it creates screens); each group draws as a tinted region with a label chip you can drag to move the whole group, ✎ to rename, ✕ to dissolve, and click to focus (dimming the rest). A selected tile's header gets a chip to change its group. Arrange treats each group as a sub-flow and lays the groups out left→right by their cross-group edges. See groups.md.
  • Text is edited on the canvas: double-click any rendered text to edit it in place — the edit rewrites the string literal in the screen's source file (Enter commits, Escape cancels, Shift+Enter inserts a newline). This works through the SDK's creation-site capture + the bundle's source map, so it lands exactly where UIText(...) was called — including through shared/ component wrappers. Only literal strings are editable: text computed at runtime (interpolation, node.text = …) is declined with a notice instead of guessed at.
  • Images are replaced on the canvas: double-click an image to pick a file, or drag an image file from your OS onto it (the target highlights). The upload is stored under design/assets/ (names deduped; byte-identical files reused) and the image's source reference is rewritten — an inline asset("…") argument, an asset held in a variable (const man = asset("…")), a hand-written import man from "../assets/man.png", or an asset exported from a shared/ file; a remote-URL literal is converted to a local asset() reference. The tile previews the new image instantly; dynamic or ambiguous sources are declined safely.
  • Device shell (the shell popover in the view pill) frames every tile in that device's chrome — iOS Dynamic Island + home indicator + iPhone-14-Pro corner rounding, Android status bar + 3-button navigation bar — and resolves the safe-*/comfort-* style keywords to that device's real insets (the same values as lecodes render --device), including the edge kind: Android's status/nav bars are declared exact-height bars, so comfort-* adds its knob past them (a pb: "comfort-bottom" tab bar keeps a gap above the button bar), while iOS insets are clearance zones where comfort-* floors — exactly what each real device computes. Switching rebuilds each prototype from scratch under the new insets (compiles are server-cached, so it's one bundle re-run per tile), so everything recalculates — including screens parked in a router stack. A screen that skips safe-top visibly collides with the island/status bar, and Android's translucent nav bar shows content bleeding under the back/home/recents buttons — safe-area misuse is caught at a glance. "None" in the shell popover restores the abstract screen (orientation-default insets). A view preference, remembered locally — never written to meta.json.
  • Comments (design-comments-plan.md) are Figma-style pins. The Comment mode (C/M or the mode bar) makes every click on a screen drop a pin and open the composer — the tool stays armed for a run of comments, Esc or another mode leaves it, and a first-visit nudge above the bar points shared-board reviewers at it. Comments and Concept open from the host's top bar via BoardToolbar (one component, so the three hosts stop hand-rolling their own buttons); the two share one left dock (never both at once); on a narrow viewport it overlays the board instead of docking. The thread window is anchored to its pin in world space, so panning and zooming carry it along, and opening a thread from the list focuses its screen and opens it on the pin. Your own pins drag: pick one up and drop it anywhere, including on another screen, and it re-anchors to whatever named element is under the drop. A pin anchors to the screen + the state the tile was showing + the nearest named element under the cursor, with a normalized point as fallback, so it survives a re-layout and reads as "the submit button on checkout@empty". Pins for another state collapse into a header chip rather than drawing over a layout they weren't written against; a thread whose screen is gone lands in the panel's Detached section instead of vanishing. ?c=7 opens thread #7 directly. On the platform the threads live in the database — not in project files — so a reviewer holding the public share link can write one without an account and without producing a commit; the developer sees it live in the editor's Design tab. Anonymous authors get a display name plus a browser key that grants only "edit/delete my own"; the project owner can switch commenting off without hiding the conversation that already happened. Locally (lecodes design, including standalone folders with no project) the threads live in design/comments/ — one file per thread, attributed via git config user.name — and Claude reads them through the design_comments MCP tool: open threads are its task list, closed with resolve_comment once the change is actually made, answered with comment_reply, opened with comment_add. On a cloned project the running server mirrors the platform's open threads in; everything written locally queues until lecodes push delivers it after the design it describes. lecodes design comments [--all] prints the same list in the terminal, grouped by screen, and comments add / reply <n> / resolve <n> write the same store with no server running (--ai signs the write as Claude — attribution the reviewer is owed).
  • Hint mode (the scan-eye toggle in the view pill, or I) outlines what the canvas can do something with, on every tile: interactive elements in blue, in-place-editable texts in green, replaceable images in purple (a legend appears next to the view pill).
  • Concept panel (the 💡 button in the host's top bar, or ⇧C) docks a read-only reader of spec.md — the narrative half of the design (data model, actors, rules & decisions) — beside the screens, so the developer can review the decisions a backend gets generated from without leaving the board. It renders the markdown (headings, tables, lists, code) with a table of contents; every [[screen-id]] link becomes a chip that focuses that screen on the board ([[id@state]] also switches the tile's state), and a broken [[link]] is flagged (with a count on the 💡 button). The reverse direction: a selected screen shows an "in concept · N" chip that opens a compact popover of the exact spec.md lines mentioning it (the per-screen "why does this exist / what rules touch it" view) — each line jumps the panel to that exact mention, and a footer opens the panel to cycle them. When a design has no spec.md, the panel offers a one-click Create spec.md (same scaffold as lecodes design init). Editing stays in the file — the panel is read-first. A companion toggle (⚑) shows a non-blocking dot on screens with no role tagged. Both are off-by-nothing: everything is toggleable.
  • Edges and their activators cross-highlight: selecting or hovering an edge lights up the element its activator names on the source screen (amber pulsing ring + ⚡ tag — dropdown options preview live while the editor is open); hovering that element on the tile lights the edge(s) up in return, so the flow graph reads from either end.
  • Screens hot-reload: edit screens/x.ts → only that tile recompiles and re-runs; edit shared/ → all tiles reload; edit meta.json → positions/edges update; edit spec.md → only the concept panel refreshes (no screen recompiles).

Because the same render tree drives the board, lecodes design snapshot (JSON/PNG, via lecodes-renderer headless), and the future app — what Claude "sees" is what you see. The same screens are also reachable from the render CLI — lecodes render <id|path> [--state <s>] compiles one screen file the same way and runs it through the full lecodes render flag set (--clip, --device, --script, --desktop), at the screen's board frame.

Development (of this package)

bun run build       # vite build (dist/app) + server bundle (dist/server.js)
bun run typecheck   # vue-tsc
bun run dev         # vite dev server for the board, proxying to a running design server

src/app/wasm/ holds a copy of creator-ui's emscripten glue + wasm (same pattern as the viewer); re-copy from lecodes-renderer/src/layout/creatorUi/ when the layout engine is rebuilt.