neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Composable image optimization for Node.js. Zero-dependency core, pluggable storage adapters and codecs.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Image optimization you can actually audit.
Resize, compress and convert images, then hand them to whatever storage you already use.
A processing core with no dependencies, and everything heavy behind an interface you control.
Pre-1.0 and moving. The API will change before 1.0. Pin an exact version and read the
changelog before upgrading. AVIF output depends on how your sharp binary
was built, so treat it as best-effort rather than guaranteed.
Eight lines, six optimized files in S3, and a ready-to-paste srcset.README 전문 보기 ↗[!WARNING] Pre-1.0 and moving. The API will change before 1.0. Pin an exact version and read the changelog before upgrading. AVIF output depends on how your
sharpbinary was built, so treat it as best-effort rather than guaranteed.
npm install @lens-image/core sharp @lens-image/adapter-s3 @aws-sdk/client-s3
import { ImageOptimizer } from '@lens-image/core';
import { S3Adapter } from '@lens-image/adapter-s3';
const optimizer = new ImageOptimizer({
adapter: new S3Adapter({ bucket: 'my-images', region: 'us-east-1' }),
});
const result = await optimizer.optimize({
source: './photo.jpg',
quality: 80,
formats: ['webp', 'jpg'],
sizes: [{ width: 1200 }, { width: 600 }, { width: 300 }],
});
result.formats.webp.srcset;
// 'https://...-300w.webp 300w, https://...-600w.webp 600w, https://...-1200w.webp 1200w'
Eight lines, six optimized files in S3, and a ready-to-paste srcset.
npm install
npm run dev
Drop an image in and watch the file size move as you drag the quality slider. The encoding is real, done by your browser's own WebP encoder, and the storage keys come from the same functions the server calls.
Most image libraries make you choose between "does everything, owns your stack" and "does one thing, you wire up the rest". Lens is the second kind, with the wiring included.
| Zero dependencies in the core | npm install @lens-image/core adds exactly one package to your lockfile. Not one plus forty. A CI check enforces it. |
| Storage is an interface | S3, filesystem, Cloudinary, or forty lines of your own for R2, GCS, Backblaze. |
| The codec is an interface too | sharp is an optional peer. Swap it, stub it in tests, or skip it entirely if you only validate and store. |
| Degrades instead of failing | AVIF unsupported on your platform? You get WebP and a warning, not a 500. |
| Errors you can branch on | Every failure is a LensError with a stable code and a suggested HTTP status. |
| Package | What it does | Dependencies |
|---|---|---|
@lens-image/core | Processing engine, adapter contract, upload handler | 0 |
@lens-image/adapter-local | Filesystem storage | 0 |
@lens-image/adapter-s3 | S3, R2, MinIO, Spaces, B2 | 0 (AWS SDK is a peer) |
@lens-image/adapter-cloudinary | Cloudinary | 0 |
@lens-image/react | Headless upload hooks | 0 (React is a peer) |
@lens-image/core also exposes @lens-image/core/browser,
a Node-free subset (sniffing, validation, key templating) that bundles for browsers and edge
runtimes. You can reject a bad file from its first 4 KB, before the upload starts.
Being precise, because this is the sort of claim that deserves it.
@lens-image/core has zero entries in dependencies. Installing it adds one package to
your lockfile and downloads no native binaries. That is enforced in CI by
scripts/release-check.mjs, not just promised here.
Actual pixel work needs sharp, which is a native module. Lens treats the codec as a
pluggable ImageEngine and declares sharp as an optional peer dependency, imported
dynamically only when you first encode something.
So:
ImageEngine is three methods. Point it at squoosh, a WASM codec,
or an ImageMagick shell-out.The claim is "core is dependency-free and the heavy thing is your explicit choice", not "image processing happens by magic".
The full adapter contract:
interface StorageAdapter {
readonly name: string;
upload(file: StorageFile, ctx: StorageContext): Promise<StorageObject>;
exists?(key: string): Promise<boolean>; // unlocks cache: 'storage'
remove?(key: string): Promise<void>; // unlocks optimizer.delete()
getUrl?(key: string): string;
dispose?(): Promise<void> | void;
}
One required method. A complete Google Cloud Storage adapter:
import { Storage } from '@google-cloud/storage';
import type { StorageAdapter } from '@lens-image/core';
export class GCSAdapter implements StorageAdapter {
readonly name = 'gcs';
#bucket = new Storage().bucket(this.bucketName);
constructor(private bucketName: string) {}
async upload(file) {
const object = this.#bucket.file(file.key);
await object.save(file.data, {
contentType: file.contentType,
metadata: { cacheControl: file.cacheControl },
});
return {
key: file.key,
url: `https://storage.googleapis.com/${this.bucketName}/${file.key}`,
size: file.data.byteLength,
};
}
async exists(key) {
const [exists] = await this.#bucket.file(key).exists();
return exists;
}
async remove(key) {
await this.#bucket.file(key).delete({ ignoreNotFound: true });
}
}
Lens handles retries, concurrency limiting and error wrapping around it.
@lens-image/core ships a Request to Response handler. It works in Next.js, Remix, Hono,
Bun and Deno without a framework adapter, because it only uses web standards.
Server, app/api/upload/route.ts:
import { ImageOptimizer, createUploadHandler } from '@lens-image/core';
import { S3Adapter } from '@lens-image/adapter-s3';
const optimizer = new ImageOptimizer({
adapter: new S3Adapter({ bucket: 'uploads', region: 'us-east-1' }),
});
export const POST = createUploadHandler({
optimizer,
maxFiles: 5,
async authorize(request) {
const session = await auth(request);
return session ? undefined : Response.json({ error: 'Unauthorized' }, { status: 401 });
},
options: { formats: ['webp', 'jpg'], sizes: [{ width: 1200 }, { width: 600 }], thumbnail: true },
});
Client:
import { useImageUpload } from '@lens-image/react';
function Uploader() {
const { upload, items, progress, isUploading, error } = useImageUpload({
endpoint: '/api/upload',
maxBytes: 10 * 1024 * 1024,
accept: ['image/*'],
});
return (
<>
<input type="file" multiple onChange={(e) => upload(e.target.files)} disabled={isUploading} />
{isUploading && <progress value={progress} max={100} />}
{error && <p role="alert">{error.message}</p>}
</>
);
}
Progress is real, from XMLHttpRequest.upload.onprogress, and weighted by file size. fetch
cannot report request-body progress in any shipping browser, so a fetch-based hook would have
to fake the bar.
Every failure is a LensError with a stable code and a suggested HTTP status:
import { LensError } from '@lens-image/core';
try {
await optimizer.optimize({ source, validate: { maxBytes: 5_000_000 } });
} catch (error) {
if (LensError.is(error, 'VALIDATION_FAILED')) {
return Response.json({ error: error.message }, { status: error.status }); // 422
}
throw error;
}
| Code | Status | Means |
|---|---|---|
INVALID_SOURCE | 400 | source was not a shape Lens understands |
SOURCE_UNREADABLE | 400 | The file could not be read |
UNSUPPORTED_INPUT | 415 | Bytes are not a recognisable image |
VALIDATION_FAILED | 422 | Failed a size, dimension or format rule |
INVALID_OPTIONS | 400 | Contradictory or out-of-range options |
ENGINE_UNAVAILABLE | 500 | No codec, usually sharp is not installed |
ENCODE_FAILED | 500 | The codec threw |
ALL_FORMATS_FAILED | 500 | Nothing could be produced, fallback included |
UPLOAD_FAILED | 502 | Storage failed after retries |
ADAPTER_REQUIRED | 500 | The operation needs an adapter |
ADAPTER_UNSUPPORTED | 501 | The adapter lacks an optional method |
ADAPTER_MISCONFIGURED | 500 | Bad adapter construction options |
ABORTED | 499 | Your AbortSignal fired |
A per-format failure is a warning, not an exception:
const result = await optimizer.optimize({ source, formats: ['avif', 'webp', 'jpg'] });
// AVIF unavailable on this platform? You still get WebP and JPEG.
result.warnings;
// [{ code: 'format_unsupported', format: 'avif', message: '...' }]
Only a total failure throws. This is not hypothetical: prebuilt sharp binaries do not all ship AV1.
Things that are on unless you turn them off, because getting them wrong is expensive:
.jpg that is actually an SVG is detected as SVG.LocalAdapter rejects any key that resolves outside its root.packages/
core/ the engine, adapter contract, upload handler 0 deps
adapter-local/ filesystem 0 deps
adapter-s3/ S3 and anything that speaks it SDK is a peer
adapter-cloudinary/ Cloudinary over plain fetch 0 deps
react/ headless upload hooks React is a peer
docs/ the documentation site private
The build is tsc twice per package, once for ESM and once for CJS, and nothing else. No
bundler, by design: a library whose selling point is a readable dependency graph should not
need a hundred dev packages to produce a dist.
Strict mode with noUncheckedIndexedAccess on. Tests run on Node's built-in runner with no
framework.
npm install
npm run dev # the docs site on :3000
npm run build # all five packages, dual ESM and CJS
npm test # 213 tests
npm run typecheck
npm run release:check # enforces the promises made above
| Command | |
|---|---|
npm run dev | Docs site on :3000 |
npm test core | One package |
npm run test:watch | |
npm run docs:build | Static export to packages/docs/out |
npm run hero:build | Regenerate the docs imagery through Lens itself |
npm run set-scope @you | Rename the npm scope across the repo |
npm run example | Run examples/basic.mjs |
Requires Node 18.19 or newer.
Every app that accepts an image eventually grows the same three hundred lines: a resize loop, a format matrix, a naming scheme, an S3 client, a retry, and a nagging suspicion that none of it validates the input properly. I had written that file more than once and did not want to write it again.
So the opinions here are the ones you arrive at after getting it wrong. Keys are content-addressed because cache invalidation was the recurring bug. Formats fail independently because one missing codec taking down an upload is infuriating. The pixel-count guard exists because a byte-size limit does not stop a decompression bomb. sharp is a peer dependency because a native binary appearing in a lockfile without being asked for is how you lose an afternoon.
The docs hero is not stock art either. It is built by running photographs through Lens, and the figure printed under it is what that run measured.
Issues and PRs welcome. CONTRIBUTING.md covers the rules that are not
negotiable, which are the ones the whole project exists for: zero dependencies in the core,
SDKs as peers, a Node-free browser entry point, and errors with stable codes.
MIT