Skip to content

Apply the B3Pay design system to B3Note and add on-device AI - #12

Merged
b3hr4d merged 3 commits into
mainfrom
design/b3note-cute
Oct 27, 2026
Merged

b3hr4d merged 3 commits into
mainfrom
design/b3note-cute

Conversation

@b3hr4d

@b3hr4d b3hr4d commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

What changed

A new look, from the B3Pay design system. B3Note now uses B3Pay's tokens (warm graphite neutrals, B3Pay amber, its radii, buttons, fields and notices) plus a B3Note layer of paper:

  • Tailwind's zinc palette is remapped to B3Pay's graphite and brand to amber (bronze where it is text on a light ground), so the existing utility classes pick up the new look with few edits (frontend/src/styles.css).
  • Notes are paper. Each note gets one of five pastel papers from its id, with a folded top-right corner: in the list (a stack of small sheets that rest at a slight tilt and lift under the pointer, the open one ringed in amber) and in the editor (a ruled sheet; the body is now 16/28 sans so text sits on the rules).
  • Schibsted Grotesk and Martian Mono replace Inter and JetBrains Mono, bundled with Fontsource so no font request leaves the app.
  • Empty states show a stack of blank paper, and waits use the animated mark instead of a spinner.
  • New draft B3Note mark: B3Pay's mark with the amber node folded into a note, as B3Wallet and B3Forge change only the node. It's used in the header, favicons, app icons, the maskable icon and the README (light and dark). frontend/scripts/brand-icons.py now generates it.

On-device AI (frontend/src/lib/localAi.ts). Every assistant action and "Ask your notes" now runs in the browser by default:

  • It uses Chrome's built-in Gemini Nano when the browser has it, otherwise Qwen2.5-1.5B-Instruct on the GPU with WebLLM.
  • The model downloads once (about 1 GB for Qwen), and only after the user clicks "Download the model". The WebLLM code is a lazy chunk, so nothing loads until then.
  • Note text never leaves the browser, so the assistant works with the end-to-end encryption on, unlike the LLM canister.
  • The LLM canister stays as a second choice ("Internet Computer") when ai_enabled is on, with its consent dialog unchanged.
  • Results show as blocks: dashed while drafting (with Stop for on-device), solid when ready, and always saying where they ran and which model.
  • Settings gets an "On-device AI" section that can remove the downloaded model.

Why

The ask was to use our B3Pay design system, give the note app a cuter look and add AI. The canister's AI is off on mainnet because it needs plaintext. An on-device model gives users AI without leaving the encryption.

For reviewers

  • CSP change (public/.ic-assets.json5): script-src adds 'wasm-unsafe-eval' (WebLLM compiles its WebAssembly) and connect-src adds huggingface.co, *.huggingface.co, *.hf.co and raw.githubusercontent.com for the one-time model download. Chrome's built-in model needs none of this. If we'd rather not widen the CSP, the WebLLM fallback can be dropped and on-device AI kept for Chrome only.
  • The mark is a draft. B3Pay's logo is locked, so the B3Note mark needs sign-off from Donya and the CEO and should then come from tools/logo/build.js.
  • Design system: the B3Note design system artifact documents the tokens, rules and 21 components this PR implements. It is private, so share it before asking others to review it: https://claude.ai/artifact/3iUrs9c9fb6QMjSEGmDXkB
  • New dependencies: @fontsource-variable/schibsted-grotesk, @fontsource/martian-mono, @mlc-ai/web-llm@0.2.85.

Testing

  • pnpm typecheck, pnpm test (52 passing, including 4 new tests for the on-device prompts), vite build and Prettier all pass.
  • Clicked through the app against a local PocketIC with the mock LLM (scripts/pocketic-dev.ts): landing, guest sign-in, creating and editing notes, tags, the AI panel on both engines, applying a result, Ask, Settings, light and dark themes, and phone width.
  • Not yet tested with a real on-device model. The on-device path was exercised with a stand-in for Chrome's LanguageModel; Gemini Nano and Qwen weren't downloaded, so answer quality and speed on real hardware still need a try. Internet Identity and share links weren't exercised locally (the PocketIC setup has no II).

🤖 Generated with Claude Code

b3hr4d and others added 2 commits October 27, 2026 00:48
Restyle the app with the B3Note design system (B3Pay's tokens plus paper):
- Tailwind's zinc palette now maps to B3Pay's warm graphite and brand to B3Pay
  amber (bronze where it is text on a light ground); B3Pay radii, buttons,
  fields, chips and notices; Schibsted Grotesk and Martian Mono bundled with
  Fontsource instead of Inter, so no font request leaves the app.
- Notes are paper: each note gets one of five papers from its id, with a
  folded top-right corner, in the list (a stack of small sheets that lift
  under the pointer) and in the editor (a ruled sheet for writing).
- Empty states show a stack of blank paper; waits use the animated mark.
- New draft B3Note mark (B3Pay's mark with the node folded into a note) for
  the header, favicons, app icons and README; scripts/brand-icons.py now
  generates it. The mark still needs sign-off.

Add an on-device AI assistant (lib/localAi.ts): Chrome's built-in Gemini
Nano when the browser has it, otherwise Qwen2.5-1.5B-Instruct on the GPU with
WebLLM, downloaded once only after the user asks. Every assistant action and
"Ask your notes" run in the browser by default, so note text stays inside the
end-to-end encryption; the LLM canister remains a second, opt-in choice. AI
results show as blocks that are dashed while drafting and solid when ready,
and always say where they ran. Settings can remove the downloaded model.

The CSP gains 'wasm-unsafe-eval' and the model download hosts (Hugging Face,
raw.githubusercontent.com) for WebLLM; nothing else changes on the network.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two holes in the on-device AI's promise that no note text leaves the
browser.

Remote images. AI answers render as Markdown, and the CSP's img-src
allowed any https host. A prompt hidden in a note (pasted from a web
page, say) could steer the model into writing a Markdown image whose URL
carries other notes' text, and the browser would fetch it. An image in a
shared note also told its sender when it was opened. Markdown now shows
images as links, and img-src allows only 'self' and data:.

The WebLLM model. web-llm's own record downloads the model's files and
its WebAssembly library from the main branches of Hugging Face and
GitHub, unchecked. WEBLLM_CONFIG pins both at a commit (Hugging Face
9bd564b, binary-mlc-llm-libs 025bcaf, the commit that added the v0_2_84
library) and gives web-llm SRI hashes for the config, tokenizer.json and
the library, with onFailure "error". Loading and removing the model both
use it. A test compares it with web-llm 0.2.85's own record.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cSwEz3Q2o3DpuJ8qSQzY5
fix(ai): load no remote images, and pin the on-device model
@b3hr4d
b3hr4d merged commit 1593af2 into main Oct 27, 2026
2 checks passed
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.

2 participants