Skip to content

🧼 optimize install size#35

Merged
natemoo-re merged 11 commits into
mainfrom
ref/opt
May 26, 2026
Merged

🧼 optimize install size#35
natemoo-re merged 11 commits into
mainfrom
ref/opt

Conversation

@natemoo-re

@natemoo-re natemoo-re commented May 23, 2026

Copy link
Copy Markdown
Member

Reduces npm install size by 63% (723kB → 268kB unpacked) via:

  • optimizing clang build flags with explicit exports and dead code elimination
  • stripped source maps and src/ duplication from the npm package

Also bumps minimum node version to v22 (current LTS).

Future optimization opportunities identified (with unknown performance impact) include:

  • switching from -02 to -0z, adding wasm-opt step
  • compress wasm text (testing showed brotli + z85 encoding to be largest byte reduction)
  • strip data that can be extrapolated from wcwidth

@pkg-pr-new

pkg-pr-new Bot commented May 23, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/clayterm@35

commit: 79052b0

@dreyfus92 dreyfus92 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

overall looks really good. since you're optimizing install size, are you planning on the near future to add a "no size regression test", cause rn there's nothing in the CI that asserts the package stays under a certain size. without that the size could quietly creep back up over time.

Comment thread tasks/build-npm.ts Outdated
Comment thread tasks/build-npm.ts
Comment thread tasks/build-npm.ts Outdated
natemoo-re added a commit that referenced this pull request May 24, 2026
Co-Authored-By: ghostdevv <ghostdevbusiness@gmail.com>
natemoo-re added a commit that referenced this pull request May 24, 2026
- replace sourceMap/declarationMap/target compiler options with skipSourceOutput: true
- add type: "module" to package config
- remove redundant files: ["esm"] (npm excludes lock files automatically, .npmignore handles the rest)

Co-Authored-By: ghostdevv <ghostdevbusiness@gmail.com>
natemoo-re added a commit that referenced this pull request May 24, 2026
Co-Authored-By: ghostdevv <47755378+ghostdevv@users.noreply.github.com>
@cowboyd

cowboyd commented May 24, 2026

Copy link
Copy Markdown
Collaborator

There are a couple of optimizations here; some of which I'm 100% cool with, the others I think we need to make sure we do intentionally.

Unalloyed Wins:

  • The linker changes to only export the functions we need and to gc/strip the rest. I don't see a downside to this.
  • same with the npm bundle changes

Needs consideration

  • switching from -02 to -0z is going to result in a smaller bundle size, but there will be a degradation of runtime performance. How much? I've no idea. We should add some benchmarks so that we can understand the tradeoffs
  • the compression of the wasm text is going to add a tiny bit of overhead to the startup time. Do we know how much it will be?
  • as for the wcwidth. That's a piece of the codebase we took from termbox2, so while I'm not opposed to the changes, but I don think we need to make sure we understand it.

Comment thread deno.json Outdated
@cowboyd

cowboyd commented May 24, 2026

Copy link
Copy Markdown
Collaborator

@natemoo-re

switching from -02 to -0z is going to result in a smaller bundle size, but there will be a degradation of runtime performance. How much? I've no idea. We should add some benchmarks so that we can understand the tradeoffs

Just so we don't block this work, can we merge all the other size optimizations and then consider these C options separately in the context of knowing how runtime perf is impacted?

@natemoo-re

natemoo-re commented May 24, 2026

Copy link
Copy Markdown
Member Author

switching from -02 to -0z is going to result in a smaller bundle size, but there will be a degradation of runtime performance. How much? I've no idea. We should add some benchmarks so that we can understand the tradeoffs

Just so we don't block this work, can we merge all the other size optimizations and then consider these C options separately in the context of knowing how runtime perf is impacted?

@cowboyd yep that sounds like the right path forward! happy to split those out with some benchmarks

Reverts three changes that need benchmarks before landing:
- -Oz / wasm-opt
- brotli+Z85 wasm compression
- wcwidth.c rewrite
@natemoo-re natemoo-re requested a review from cowboyd May 24, 2026 17:29

@cowboyd cowboyd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Love it!

@natemoo-re natemoo-re merged commit ef9a3ed into main May 26, 2026
7 checks passed
@natemoo-re natemoo-re deleted the ref/opt branch May 26, 2026 22:48
rauhryan added a commit that referenced this pull request Jun 13, 2026
* ✨ add snapshot() for pre-packing directive subtrees

Introduces a new `snapshot(ops)` constructor that pre-packs a directive
array into its transfer encoding. The returned opaque `Op` can be
spliced into any directive array, and during packing its bytes are
copied directly into the command buffer without re-encoding.

This enables higher-level frameworks to implement dirty tracking:
unchanged component subtrees can reuse a cached snapshot, skipping
the per-frame packing cost entirely.

* docs: add maintainer build guide

* 💄 format build docs

* 🐛 improve pack string overflow errors

* os matrix test in ci (#36)

* 🧼 optimize build

* 🧼 compress bundled wasm

* 🧼 optimize wcwidth.c size

* ⚙️ update npm settings

* 🐛 install wasm-opt in ci

* ⚡ use brotli-11 + z85 wasm encoding

* 📌 pin @types/node to v22

* 🧼 apply @ghostdevv review suggestions from PR #35

Co-Authored-By: ghostdevv <git@willow.sh>

* 🔨 add type to bundle-wasm

* 💌 signed, sealed, delivered

* chore: use hashes for versions

* chore: don't save git credentials

* chore: use array syntax

for some reason the schema for the actions wants it to be an array

* perf: set concurrency limits to reduce cost and improve dx

Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs

* chore: use hashes for versions

* chore: update node version

* perf: set concurrency limits to reduce cost and improve dx

Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs

* chore: don't save git credentials

* chore: mitigate potential template injection

See https://docs.zizmor.sh/audits/#template-injection

* chore: update ::set-output command to new syntax

https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/

* chore: use hashes for versions

* chore: don't save git credentials

* chore: limit id-token permission to the publishing steps

* chore: explicitly disable npm cache to mitigate cache poisoning attacks

* chore: mitigate potential template injection

See https://docs.zizmor.sh/audits/#template-injection

* chore: use oidc

This should be using OIDC for publishing

* chore: update ::set-output command to new syntax

https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/

* 🙅 revert aggressive optimization experiments pending benchmark

Reverts three changes that need benchmarks before landing:
- -Oz / wasm-opt
- brotli+Z85 wasm compression
- wcwidth.c rewrite

* Add CodSpeed performance benchmarks

* 🔨 use deno

* 🧼 deno fmt

* ⚙️ vitest -> tinybench

* 🧼 remove codspeed assets

* 🔨 fix ci

* add type module

* fmt

* chore: update github url (#38)

* downgrade to tinybench@5

* move to examples folder with readme

* 🔧 export animating from wasm build

* 🧪 cover transitions in snapshots and validation

* ✅ enforce nonnegative transition duration

---------

Co-authored-by: Charles Lowell <cowboyd@frontside.com>
Co-authored-by: Jacob Bolda <me@jacobbolda.com>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: ghostdevv <git@willow.sh>
Co-authored-by: Nate Moore <git@natemoo.re>
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
cowboyd added a commit that referenced this pull request Jun 26, 2026
* 📝 add transitions design specification

Design spec for clayterm transitions: frame-snapshot-compatible interpolation
of element position, size, and color properties. Defines the deltaTime
convention, the animating signal on RenderResult, declarative enter/exit
semantics that replace Clay's function-pointer callbacks, and cancellation
as a structural consequence of re-describing state. Implementation is
gated on bumping the Clay submodule past the upstream transition commit.

* ⬆️ bump Clay submodule to latest main (transitions API)

* 🔧 adapt clayterm to new Clay signatures (OpenTextElement, EndLayout)

* ⬆️ pin Clay to 938967a (work around upstream CLAY_WASM_EXPORT typo)

* ✨ add deltaTime parameter to reduce()

* 🔧 add deltaTime to Native.reduce signature

* ✨ track deltaTime on Term, accept deltaTime override

* ✨ add animating_count to Clayterm context

* 🔧 expose animating() via Native binding

* ✨ surface animating: boolean on RenderResult

* 📝 rewrite transitions spec for v1 (Clay-supported subset)

Scope v1 to what Clay currently supports without userData on transition
callbacks: one duration and one easing per element, applied to all listed
properties. Drop per-property longhand, enter/exit deltas, cubicBezier,
and corner radius — each with an explicit "Deferred Until Upstream Clay"
entry in §13 referencing nicbarker/clay#603 and the forthcoming exit-flag
work. Easings are plain string literals ("linear" | "easeIn" | "easeOut"
| "easeInOut") since v1 has no parametric easings.

* ✨ add transition property names, bitmask helpers, and Easing

* ✨ add transition field type to OpenElement

* ✨ encode transition block in pack()

* ✨ register Clay handlers, interpolate on property change

Co-Authored-By:

* ✨ reset deltaTime to 0 after idle (preserve transitions across long gaps)

* ✅ verify color transitions work in line mode

* 🎨 apply deno fmt and clang-format

* ✨ add transitions demo (collapsing sidebar)

* 📝 reference transitions-spec from renderer-spec

* ✨ rewrite transitions demo as interactive full-screen menu

* ✨ add clay-transitions demo port (v1-compatible subset)

Ports the spirit of the raylib-transitions demo to clayterm: a 4×4 grid
of colored boxes that animate position, size, and bg color. Shuffle (s)
animates positions via Clay's transition system; recolor (c) toggles
between two palettes with animated bg interpolation; hover tints each
box by blending its bg toward white (overlay-color field is not yet in
the v1 command buffer, so lighten-on-hover substitutes). Full mouse
tracking is wired via mouseTracking() + pointer state from input events.

* 🎨 let clay-transitions demo rows fill available height

* 🎨 remove modeline from clay-transitions demo

* 📝 note ct_active_context is a workaround for Clay userData PR

* 🎨 use border-only boxes in clay-transitions demo

* 🎨 prevent menu text from wrapping during sidebar transition

* 🔥 drop unused grow import in transitions-run test

* Update transitions branch with upstream changes (#53)

* ✨ add snapshot() for pre-packing directive subtrees

Introduces a new `snapshot(ops)` constructor that pre-packs a directive
array into its transfer encoding. The returned opaque `Op` can be
spliced into any directive array, and during packing its bytes are
copied directly into the command buffer without re-encoding.

This enables higher-level frameworks to implement dirty tracking:
unchanged component subtrees can reuse a cached snapshot, skipping
the per-frame packing cost entirely.

* docs: add maintainer build guide

* 💄 format build docs

* 🐛 improve pack string overflow errors

* os matrix test in ci (#36)

* 🧼 optimize build

* 🧼 compress bundled wasm

* 🧼 optimize wcwidth.c size

* ⚙️ update npm settings

* 🐛 install wasm-opt in ci

* ⚡ use brotli-11 + z85 wasm encoding

* 📌 pin @types/node to v22

* 🧼 apply @ghostdevv review suggestions from PR #35

Co-Authored-By: ghostdevv <git@willow.sh>

* 🔨 add type to bundle-wasm

* 💌 signed, sealed, delivered

* chore: use hashes for versions

* chore: don't save git credentials

* chore: use array syntax

for some reason the schema for the actions wants it to be an array

* perf: set concurrency limits to reduce cost and improve dx

Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs

* chore: use hashes for versions

* chore: update node version

* perf: set concurrency limits to reduce cost and improve dx

Without this it means that, for example, if I push a change to a PR then
shortly push again this workflow will be running twice. This change will
cancel the old run before starting the new one, which reduces the
overall actions cost and DX as you don't have extra runs

* chore: don't save git credentials

* chore: mitigate potential template injection

See https://docs.zizmor.sh/audits/#template-injection

* chore: update ::set-output command to new syntax

https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/

* chore: use hashes for versions

* chore: don't save git credentials

* chore: limit id-token permission to the publishing steps

* chore: explicitly disable npm cache to mitigate cache poisoning attacks

* chore: mitigate potential template injection

See https://docs.zizmor.sh/audits/#template-injection

* chore: use oidc

This should be using OIDC for publishing

* chore: update ::set-output command to new syntax

https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/

* 🙅 revert aggressive optimization experiments pending benchmark

Reverts three changes that need benchmarks before landing:
- -Oz / wasm-opt
- brotli+Z85 wasm compression
- wcwidth.c rewrite

* Add CodSpeed performance benchmarks

* 🔨 use deno

* 🧼 deno fmt

* ⚙️ vitest -> tinybench

* 🧼 remove codspeed assets

* 🔨 fix ci

* add type module

* fmt

* chore: update github url (#38)

* downgrade to tinybench@5

* move to examples folder with readme

* 🔧 export animating from wasm build

* 🧪 cover transitions in snapshots and validation

* ✅ enforce nonnegative transition duration

---------

Co-authored-by: Charles Lowell <cowboyd@frontside.com>
Co-authored-by: Jacob Bolda <me@jacobbolda.com>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: ghostdevv <git@willow.sh>
Co-authored-by: Nate Moore <git@natemoo.re>
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>

* remove uncecessary note

* clean up and consolidate

* re-organize transitions examples

* 🔥remove redundant cast

---------

Co-authored-by: Ryan Rauh <rauhryan@users.noreply.github.com>
Co-authored-by: Jacob Bolda <me@jacobbolda.com>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: ghostdevv <git@willow.sh>
Co-authored-by: Nate Moore <git@natemoo.re>
Co-authored-by: codspeed-hq[bot] <117304815+codspeed-hq[bot]@users.noreply.github.com>
Co-authored-by: Nate Moore <natemoo-re@users.noreply.github.com>
Co-authored-by: Ryan Rauh <rauh.ryan@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants