Skip to content

feat: add stickers page to the site - #331

Open
khromov wants to merge 2 commits into
mainfrom
stickers-page
Open

feat: add stickers page to the site#331
khromov wants to merge 2 commits into
mainfrom
stickers-page

Conversation

@khromov

@khromov khromov commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Adds the stickers page to the site, split out cleanly from #182.

What's here

  • /stickers — printable sticker sheet with a selectable grid; exports a high-res PNG via html-to-image.
  • /stickers/logo — logo + wordmark export page.
  • New components under packages/site/src/stickers/ (Sticker, StickerExport, StickerLogo, StickerLogoExport), the base64 dango data URI, and the source dango.png/noise.png assets.
  • html-to-image@1.11.13 added to packages/site.
  • Two route registrations in packages/site/src/routes.ts.

Why a new PR

This branch is cut fresh from main. #182 (wip: stickers page) was 172 commits behind and bundled three features that have since landed on main independently — the named-image-sizes rewrite, cache invalidation, and the Hero.svelte header extraction — so merging it would have reverted that work. This PR carries only the sticker content.

Closes #182.

Verification

  • /stickers/ and /stickers/logo/ return 200 and hydrate with no console errors.
  • bun run checks passes.

Printable sticker sheet (/stickers) and logo export (/stickers/logo), with PNG export via html-to-image. Split out from #182 onto current main.
@khromov khromov mentioned this pull request Aug 22, 2026
@github-actions

github-actions Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Mochi review report

Try this PR

Expand instructions
gh run download -R khromov/mochi 32598723900 -n mochi-framework-pr -D /tmp/mochi-pr && bun i /tmp/mochi-pr/mochi-framework-pr.tgz

Download manually

Dependency report

Expand report
Direct: 17
Peer:   5 (@mochi-framework/rsvelte, @mochi-framework/svelte-shaker, @tailwindcss/node, @tailwindcss/oxide, svelte)
Dev:    12
Optional (installed, folded in): 0
Total unique packages reachable from production deps (roots + transitive): 38
Total on-disk size of those packages: 10.40 MB

Toplist — direct deps ranked by total size (self + transitive):
      total       self  count  package
    4.47 MB    2.74 MB     19  svelte
    2.13 MB    1.30 MB      2  css-tree
   868.6 kB   868.6 kB      0  @noble/hashes
   732.6 kB   732.6 kB      0  @css-inline/css-inline-wasm
   709.8 kB   709.8 kB      0  @noble/ciphers
   562.1 kB   562.1 kB      0  nodemailer
   507.5 kB   356.4 kB      1  bun-boss
   151.4 kB    66.4 kB      1  magic-string
   131.3 kB   113.3 kB      1  @joint-ops/hitlimit-bun
   129.2 kB   129.2 kB      0  html-entities
   102.2 kB    80.1 kB      1  chokidar
    99.6 kB    99.6 kB      0  devalue
    62.3 kB    62.3 kB      0  ipaddr.js
    30.4 kB    30.4 kB      0  deepmerge
    28.0 kB    28.0 kB      0  negotiator
    25.8 kB    25.8 kB      0  mitt
    12.3 kB    12.3 kB      0  zimmerframe

Transitive breakdown for the heaviest deps:

  svelte (19, 1.73 MB transitive): @jridgewell/gen-mapping (91.6 kB), @jridgewell/remapping (58.0 kB), @jridgewell/resolve-uri (51.9 kB), @jridgewell/sourcemap-codec (85.0 kB), @jridgewell/trace-mapping (143.3 kB), @sveltejs/acorn-typescript (194.2 kB), @types/estree (25.5 kB), @types/trusted-types (8.4 kB), acorn (545.5 kB), aria-query (172.8 kB), axobject-query (108.3 kB), clsx (8.4 kB), devalue (99.6 kB), esm-env (3.7 kB), esrap (91.4 kB), is-reference (3.9 kB), locate-character (5.2 kB), magic-string (66.4 kB), zimmerframe (12.3 kB)

  css-tree (2, 851.8 kB transitive): mdn-data (715.2 kB), source-map-js (136.6 kB)

  bun-boss (1, 151.1 kB transitive): croner (151.1 kB)

  magic-string (1, 85.0 kB transitive): @jridgewell/sourcemap-codec (85.0 kB)

  @joint-ops/hitlimit-bun (1, 18.0 kB transitive): @joint-ops/hitlimit-types (18.0 kB)

  chokidar (1, 22.1 kB transitive): readdirp (22.1 kB)

Security & licenses

bun audit
bun audit v1.4.0 (34cbb9a40)

brace-expansion@5.0.6
  eslint > @eslint/config-array > minimatch > brace-expansion
  typescript-eslint > @typescript-eslint/utils > @typescript-eslint/typescript-estree > minimatch > brace-expansion
  high: brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash (>=4.0.0 <5.0.8) - https://github.com/advisories/GHSA-mh99-v99m-4gvg
  high: brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-14257 mitigation (>=4.0.0 <5.0.9) - https://github.com/advisories/GHSA-rgw5-rvv9-x895
  high: brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups (>=3.0.0 <5.0.7) - https://github.com/advisories/GHSA-3jxr-9vmj-r5cp

extract-zip@2.0.1
  @memlab/api > puppeteer-core > @puppeteer/browsers > extract-zip
  high: extract-zip unvalidated symlink path traversal (<=2.0.1) - https://github.com/advisories/GHSA-jmr9-qjv8-65gv

ip-address@10.2.0
  @memlab/api > puppeteer-core > @puppeteer/browsers > proxy-agent > pac-proxy-agent > socks-proxy-agent > socks > ip-address
  high: ip-address: Address4 decodes leading-zero octets as decimal while resolvers decode them as octal, allowing SSRF and trust-boundary bypass (<=10.3.0) - https://github.com/advisories/GHSA-mwp4-54f8-5fhr
  moderate: ip-address: a CIDR suffix on the parsed address suppresses special-use classification and can bypass SSRF and trust-boundary checks (>=10.1.1 <=10.2.1) - https://github.com/advisories/GHSA-4xrf-jv44-h6hh
  moderate: ip-address: misclassification of IPv4-mapped/NAT64 IPv6 addresses can bypass SSRF and trust-boundary checks (>=10.1.1 <=10.2.0) - https://github.com/advisories/GHSA-22jq-vg5j-6vgg

js-yaml@4.3.0
  @memlab/api > puppeteer > cosmiconfig > js-yaml
  high: JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026-59870 fix not backported (>=4.0.0 <4.3.1) - https://github.com/advisories/GHSA-5p4m-2wfm-xmqj

nanoid@3.3.12
  eslint-plugin-svelte > postcss > nanoid
  high: nanoid: non-secure generators can loop indefinitely with negative size (<3.3.16) - https://github.com/advisories/GHSA-28wg-ghj8-5hjv
  high: nanoid: custom generators can loop indefinitely when size is zero (<3.3.18) - https://github.com/advisories/GHSA-2v37-7h3g-55p8

postcss@8.5.15
  eslint-plugin-svelte > postcss
  moderate: PostCSS: incomplete fix of GHSA-6g55-p6wh-862q — attacker-controlled sourceMappingURL reads arbitrary .map files when `from` is unset (<=8.5.22) - https://github.com/advisories/GHSA-fxqj-rqcc-2cmp
  high: PostCSS: Path Traversal in Previous Source Map Auto-Loading (sourceMappingURL) leads to Arbitrary .map File Disclosure (<=8.5.17) - https://github.com/advisories/GHSA-r28c-9q8g-f849

valibot@1.4.2, 1.4.1
  workspace:mochi-site > valibot
  workspace:mochi-site > @tmcp/adapter-valibot > valibot
  workspace:mochi-site > tmcp > valibot
  moderate: Valibot: record() issue paths can make flatten() throw for inherited Object property names (<=1.4.1) - https://github.com/advisories/GHSA-5qjj-4xww-7phc

13 vulnerabilities (9 high, 4 moderate)

  bun audit fix           upgrade the vulnerable packages within their ranges
  bun audit fix --latest  also cross major versions
bun pm licenses --prod
Apache-2.0 (6)
├── aria-query@5.3.1
├── axobject-query@4.1.0
├── detect-libc@2.1.2
├── schema-dts@2.0.0
├── schema-dts-lib@1.0.0
└── typescript@6.0.3

BSD-2-Clause (1)
└── entities@8.0.0

BSD-3-Clause (10)
├── d3-array@2.12.1
├── d3-interpolate-path@2.3.0
├── d3-path@1.0.9
├── d3-sankey@0.12.3
├── d3-shape@1.3.7
├── d3-tile@1.0.0
├── fontverter@2.0.0
├── rw@1.3.3
├── source-map-js@1.2.1
└── subset-font@2.5.0

CC0-1.0 (1)
└── mdn-data@2.27.1

ISC (33)
├── @lucide/svelte@1.28.0
├── @ungap/structured-clone@1.3.1
├── css-color-keywords@1.0.0
├── d3-array@3.2.4
├── d3-chord@3.0.1
├── d3-color@3.1.0
├── d3-contour@4.0.2
├── d3-delaunay@6.0.4
├── d3-dispatch@3.0.1
├── d3-dsv@3.0.1
├── d3-force@3.0.0
├── d3-format@3.1.2
├── d3-geo@3.1.1
├── d3-geo-voronoi@2.1.0
├── d3-hierarchy@3.1.2
├── d3-interpolate@3.0.1
├── d3-path@3.1.0
├── d3-quadtree@3.0.1
├── d3-random@3.0.1
├── d3-scale@4.0.2
├── d3-scale-chromatic@3.1.0
├── d3-shape@3.2.0
├── d3-time@3.1.0
├── d3-time-format@4.1.0
├── d3-timer@3.0.1
├── d3-tricontour@1.1.0
├── delaunator@5.1.0
├── github-slugger@2.0.0
├── graceful-fs@4.2.11
├── internmap@1.0.1
├── internmap@2.0.3
├── semver@7.8.5
└── uri-template-matcher@1.1.2

MIT (198)
├── @clack/core@1.4.3
├── @clack/prompts@1.7.0
├── @css-inline/css-inline-wasm@0.21.0
├── @dagrejs/dagre@2.0.4
├── @dagrejs/graphlib@3.0.4
├── @floating-ui/core@1.8.0
├── @floating-ui/dom@1.8.0
├── @floating-ui/utils@0.2.12
├── @joint-ops/hitlimit-bun@1.5.0
├── @joint-ops/hitlimit-types@1.5.0
├── @jridgewell/gen-mapping@0.3.13
├── @jridgewell/remapping@2.3.5
├── @jridgewell/resolve-uri@3.1.2
├── @jridgewell/sourcemap-codec@1.5.5
├── @jridgewell/trace-mapping@0.3.31
├── @layerstack/svelte-actions@1.0.1-next.18
├── @layerstack/svelte-state@0.1.0-next.23
├── @layerstack/tailwind@2.0.0-next.21
├── @layerstack/utils@2.0.0-next.18
├── @napi-rs/canvas@1.0.3
├── @napi-rs/canvas-linux-x64-gnu@1.0.3
├── @napi-rs/canvas-linux-x64-musl@1.0.3
├── @noble/ciphers@2.2.0
├── @noble/hashes@2.2.0
├── @nprapps/sidechain@1.1.5
├── @portabletext/svelte@3.0.1
├── @portabletext/toolkit@2.0.18
├── @portabletext/types@2.0.15
├── @rsvelte/compiler@0.9.4
├── @rsvelte/vite-plugin-svelte-native@0.3.3
├── @rsvelte/vite-plugin-svelte-native-linux-x64-gnu@0.3.3
├── @shikijs/core@4.4.1
├── @shikijs/engine-javascript@4.4.1
├── @shikijs/engine-oniguruma@4.4.1
├── @shikijs/langs@4.4.1
├── @shikijs/primitive@4.4.1
├── @shikijs/themes@4.4.1
├── @shikijs/types@4.4.1
├── @shikijs/vscode-textmate@10.0.2
├── @shuding/opentype.js@1.4.0-beta.0
├── @standard-schema/spec@1.1.0
├── @sveltejs/acorn-typescript@1.0.10
├── @tailwindcss/node@4.3.3
├── @tailwindcss/oxide@4.3.3
├── @tailwindcss/oxide-linux-x64-gnu@4.3.3
├── @tailwindcss/oxide-linux-x64-musl@4.3.3
├── @tanstack/store@0.11.1
├── @tanstack/svelte-store@0.12.1
├── @tanstack/svelte-table@9.0.0
├── @tanstack/table-core@9.0.0
├── @tmcp/adapter-valibot@0.1.6
├── @tmcp/session-manager@0.2.2
├── @tmcp/transport-http@0.8.6
├── @types/bun@1.4.0
├── @types/d3-array@3.2.2
├── @types/d3-contour@3.0.6
├── @types/estree@1.0.9
├── @types/geojson@7946.0.16
├── @types/hast@3.0.4
├── @types/hast@3.0.5
├── @types/mdast@4.0.4
├── @types/node@25.9.1
├── @types/trusted-types@2.0.7
├── @types/unist@2.0.11
├── @types/unist@3.0.3
├── @typescript-eslint/types@8.65.0
├── @valibot/to-json-schema@1.7.1
├── acorn@8.16.0
├── base64-js@0.0.8
├── bun-boss@0.5.1
├── bun-types@1.4.0
├── camelize@1.0.1
├── ccount@2.0.1
├── character-entities-html4@2.1.0
├── character-entities-legacy@3.0.0
├── chokidar@5.0.0
├── clsx@2.1.1
├── color-name@1.1.4
├── comma-separated-tokens@2.0.3
├── commander@7.2.0
├── commander@15.0.0
├── croner@10.0.1
├── css-background-parser@0.1.0
├── css-box-shadow@1.0.0-3
├── css-gradient-parser@0.0.17
├── css-to-react-native@3.2.0
├── css-tree@3.2.1
├── deepmerge@4.3.1
├── dequal@2.0.3
├── devalue@5.8.2
├── devalue@5.9.0
├── devlop@1.1.0
├── emoji-regex-xs@2.0.1
├── enhanced-resolve@5.24.3
├── escape-html@1.0.3
├── esm-env@1.2.2
├── esrap@2.2.13
├── fast-string-truncated-width@3.0.3
├── fast-string-width@3.0.2
├── fast-wrap-ansi@0.2.2
├── fflate@0.7.4
├── harfbuzzjs@0.10.3
├── hast-util-heading-rank@3.0.0
├── hast-util-to-html@9.0.5
├── hast-util-to-string@3.0.1
├── hast-util-whitespace@3.0.0
├── hex-rgb@4.3.0
├── html-entities@2.6.0
├── html-to-image@1.11.13
├── html-void-elements@3.0.0
├── iconv-lite@0.6.3
├── inline-style-parser@0.2.7
├── ipaddr.js@2.4.0
├── is-reference@3.0.3
├── jiti@2.7.0
├── json-rpc-2.0@1.7.1
├── layerchart@2.0.4
├── linebreak@1.1.0
├── locate-character@3.0.0
├── lodash@4.18.1
├── lz-string@1.5.0
├── magic-string@0.30.21
├── magic-string@1.0.0
├── magic-string@1.1.0
├── mdast-util-to-hast@13.2.1
├── mdsvex@0.12.8
├── memoize@10.2.0
├── micromark-util-character@2.1.1
├── micromark-util-encode@2.0.1
├── micromark-util-sanitize-uri@2.0.1
├── micromark-util-symbol@2.0.1
├── micromark-util-types@2.0.2
├── mimic-function@5.0.1
├── mitt@3.0.1
├── mode-watcher@1.1.0
├── negotiator@1.0.0
├── oniguruma-parser@0.12.2
├── oniguruma-to-es@4.3.6
├── p-limit@3.1.0
├── pako@0.2.9
├── parse-css-color@0.2.1
├── picomatch@4.0.5
├── postcss-value-parser@4.2.0
├── prism-svelte@0.4.7
├── prismjs@1.30.0
├── property-information@7.1.0
├── readdirp@5.0.0
├── regex@6.1.0
├── regex-recursion@6.0.2
├── regex-utilities@2.3.0
├── rehype-slug@6.0.0
├── runed@0.37.1
├── safer-buffer@2.1.2
├── shiki@4.4.1
├── sisteransi@1.0.5
├── slugify@1.6.9
├── space-separated-tokens@2.0.2
├── sqids@0.3.0
├── string.prototype.codepointat@0.2.1
├── stringify-entities@4.0.4
├── style-to-object@1.0.14
├── svelte@5.56.8
├── svelte-french-toast@2.0.0-alpha.0
├── svelte-meta-tags@5.0.2
├── svelte-shaker@0.18.1
├── svelte-shaker-engine-scan-native@0.3.0
├── svelte-writable-derived@3.1.1
├── tailwind-merge@3.6.0
├── tailwindcss@4.3.3
├── tapable@2.3.3
├── tiny-inflate@1.0.3
├── tmcp@1.19.4
├── trim-lines@3.0.1
├── undici-types@7.24.6
├── unicode-trie@2.0.0
├── unist-util-is@4.1.0
├── unist-util-is@6.0.1
├── unist-util-position@5.0.0
├── unist-util-stringify-position@2.0.3
├── unist-util-stringify-position@4.0.0
├── unist-util-visit@2.0.3
├── unist-util-visit@5.1.0
├── unist-util-visit-parents@3.1.1
├── unist-util-visit-parents@6.0.2
├── uqr@0.1.3
├── valibot@1.4.1
├── valibot@1.4.2
├── varlock@1.16.0
├── vfile@6.0.3
├── vfile-message@2.0.4
├── vfile-message@4.0.3
├── wawoff2@2.0.1
├── woff2sfnt-sfnt2woff@1.0.0
├── yocto-queue@0.1.0
├── yoga-layout@3.2.1
├── zimmerframe@1.1.4
├── zod@3.25.76
└── zwitch@2.0.4

(MIT AND Zlib) (1)
└── pako@1.0.11

MIT-0 (1)
└── nodemailer@9.0.3

MPL-2.0 (7)
├── @resvg/resvg-js@2.6.2
├── @resvg/resvg-js-linux-x64-gnu@2.6.2
├── @resvg/resvg-js-linux-x64-musl@2.6.2
├── lightningcss@1.32.0
├── lightningcss-linux-x64-gnu@1.32.0
├── lightningcss-linux-x64-musl@1.32.0
└── satori@0.26.0

OFL-1.1 (5)
├── @fontsource-variable/fraunces@5.3.0
├── @fontsource-variable/public-sans@5.3.0
├── @fontsource/jetbrains-mono@5.3.0
├── @fontsource/lobster-two@5.3.0
└── @fontsource/public-sans@5.3.0

Python-2.0 (1)
└── argparse@2.0.1

Unlicense (1)
└── robust-predicates@3.0.3

Unknown (4)
├── runed@0.23.4
├── runed@0.25.0
├── svelte-toolbelt@0.7.1
└── svelte-youtube-lite@1.3.0

Lines of code

packages/mochi
Category main PR Δ
Total 51739 51739 0

Unchanged: src/**/*.test.ts (23437), src/Mochi.ts (2107), src/{events,log,logger}.ts (469), src/extensions.ts (318), src/image/** (1734), src/middleware/** (80), src/{types.ts,*.d.ts} (949), src/web-components/** (719), src/debug-bar/** (3436), src/templates/** (1720), Other (16770).

packages/docs
Category main PR Δ
Total 6462 6462 0

Unchanged: Docs (6462).

packages/site
Category main PR Δ
Other 4488 4921 +433
Total 24083 24516 +433

Unchanged: src/demos/** (13793), src/components/** (3033), src/lib/** (2743), src/stores/** (26).

packages/demos
Category main PR Δ
Total 3058 3058 0

Unchanged: src/hn/** (1066), Other (1992).

packages/minimal
Category main PR Δ
Total 550 550 0

Unchanged: Other (550).

packages/minimal-rsvelte
Category main PR Δ
Total 548 548 0

Unchanged: Other (548).

packages/support
Category main PR Δ
Total 3294 3294 0

Unchanged: src/**/*.test.ts (634), src/admin/** (671), src/components/** (84), src/*.server.ts (379), src/{index,routes}.ts (236), Other (1290).

packages/shared
Category main PR Δ
Total 44 44 0

Unchanged: Other (44).

packages/mochi-rsvelte
Category main PR Δ
Total 177 177 0

Unchanged: Other (177).

packages/mochi-svelte-shaker
Category main PR Δ
Total 184 184 0

Unchanged: Other (184).

packages/cli
Category main PR Δ
Total 1066 1066 0

Unchanged: src/**/*.test.ts (440), src/cli* (165), src/{create,templates,utils}.ts (277), Other (184).

packages/video-animations
Category main PR Δ
Total 646 646 0

Unchanged: src/{frame,anim,theme}.ts (389), src/{render,render-worker,generate}.ts (182), Other (75).

packages/msgpackr-extract-stub
Category main PR Δ
Total 29 29 0

Unchanged: *.test.ts (22), Other (7).

Wrap /stickers and /stickers/logo in the DEVELOPMENT conditional so they 404 in production.
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.

1 participant