fundus
v0.15.0
Published
> **Fundus** /ˈfʊndʊs/ _German noun_ — a stock, collection, or reservoir to draw > from.
Readme
Fundus
Fundus /ˈfʊndʊs/ German noun — a stock, collection, or reservoir to draw from.
Fundus is a local, typed asset pipeline for SvelteKit. It turns source images, slices, video, chroma-key video, and audio into optimized files and generated TypeScript manifests. One package contains the visual editor, headless CLI, Sharp and FFmpeg processing, and Svelte 5 runtime components.
Originals stay intact. Structured presets produce deterministic, git-friendly
outputs; custom FFmpeg templates control their own reproducibility. No mystery
CDN, no dashboard account, no final-final-2x-really-final.png archaeology.
Why Fundus?
- One source of truth. The editor and CLI mutate the same local library and run the same processing pipeline.
- Typed delivery. Assets become properties such as
main.logo; a rename or deletion becomes a compiler error instead of a broken URL in production. - Explicit budgets. Manifests define what ships and preloads for a screen, route, or feature. Unassigned assets do not quietly hitch a ride.
- Boring builds. Raw inputs, optimized proxies, and generated modules can
all live in git.
fundus checkproves they agree without writing anything.
The workflow
file or Figma node
↓
raw original + library record
↓
type, parameters, manifest membership
↓
optimized proxy + typed manifest
↓
Svelte component- Import in the editor or CLI, or place a supported file in the raw directory.
- Choose its stable id, asset type, processing settings, folder, and manifest.
- Fundus saves the library, processes affected assets, and regenerates manifest modules as one operation.
- Import the generated manifest in Svelte and render the typed entry.
- Run
fundus checkin CI to catch stale proxies, invalid references, out-of-sync modules, unresolved raw-file drift, and potential duplicate images.
Only manifest members and the assets they reference are processed and shipped. Manifests also preload and release their complete delivery set.
Quick start
Fundus requires Node.js 20.19 or newer, Svelte 5, and an existing SvelteKit project.
npm install fundus
npx fundus init
npx fundus startinit creates fundus.config.ts, a local library, a raw asset directory, and a
default manifest named main. start opens the editor at
http://127.0.0.1:7583; add --no-open or --port 8080 when appropriate.
Add assets, assign them to main, then use the generated module:
<script lang="ts">
import { Image, Slice } from 'fundus';
import { main } from '$lib/fundus/main.generated';
</script>
<Image src={main.logo} alt="Acme" />
<Slice src={main.dialogFrame} />For changes made outside the editor:
npx fundus build # write current proxies and manifest modules
npx fundus check # verify without writing; ideal for CICommit the config, library, raw originals, processed proxies, and generated
modules. With the default config, those live in fundus.config.ts, assets/,
static/fundus/, and src/lib/fundus/.
Supported assets
| Type | Processing | Runtime |
| ---------------- | ------------------------------------------------ | --------------------------------------- |
| Image | WebP, PNG, AVIF, or JPEG; optional width | <Image> |
| Slice | 1-, 3-, or 9-slice; optional stretch compression | <Slice> |
| Video | H.264 MP4; optional width cap | <Video> |
| Chroma-key video | H.264 MP4 with WebGL2 keying, mask, and fallback | <ChromaKeyVideo> |
| Audio | Opus/WebM or AAC/M4A | Your audio engine via audioSourceOf() |
Named presets in fundus.config.ts keep encoding choices consistent. Each asset
currently produces one processed proxy, which is often exactly what an app wants
and refreshingly unlike configuring a small television network.
Video presets are shared by video and chroma-key video assets. For complete control, a preset can provide the full tokenized FFmpeg command instead of the structured encoder settings:
plugins: {
video: {
presets: {
cropped: {
container: 'mp4',
ffmpegArgs: ({ input, output }) => [
'-i',
input,
'-vf',
'crop=1280:720:0:180',
'-c:v',
'libx264',
'-preset',
'slow',
'-crf',
'28',
'-pix_fmt',
'yuv420p',
'-movflags',
'+faststart',
output
]
}
}
}
}Each array element is one argument. input and output are opaque path tokens
that can only be inserted as complete arguments; Fundus replaces them with the
job paths and adds no encoding or determinism arguments. The editor therefore
hides Max width for these presets.
Editor and CLI
Use the editor for visual work: organize assets, author slices and chroma keys, tune processing, manage manifests, inspect delivered bytes, and review potential image duplicates from the Duplicates view or an asset's detail panel.
Use the CLI for scripts, CI, and coding agents:
npx fundus state --json
npx fundus asset ingest ./exports/panel.png --type slice --manifests main \
--compression-x 75 --compression-y 25
npx fundus asset replace panel ./exports/panel-v2.png
npx fundus asset replace panel \
'https://www.figma.com/design/abc/UI?node-id=12-34' --from figma --scale 3
npx fundus checkSlice stretch compression is specified per axis as a percentage from 0 to 100.
Use asset set panel --compression-x 50 to change one axis while preserving the
other; setting both axes to 0 removes compression.
Every command except start supports --json and emits one JSON document on
stdout. Run npx fundus --help or npx fundus asset ingest --help for the full
surface.
Fundus serializes writes inside one editor server, but does not lock across processes. Do not run mutating CLI commands while the editor is changing the same project. Two writers remain one writer too many.
Asset usage analysis
Fundus can delegate source-reference discovery and editor navigation to the
language tooling already configured by the host project. Add both callbacks to
fundus.config.ts:
import { defineConfig } from 'fundus/config';
export default defineConfig({
// paths and plugins…
usage: {
async referenceProvider({ assetId, manifest, declaration }) {
// Ask your TypeScript/LSP/framework adapter for references to declaration.
return { status: 'resolved', references: [] };
},
async openLocation({ file, line, column }) {
// Open the location with your editor integration.
}
}
});Locations use absolute paths and one-based line and column numbers. Fundus
passes the column unit through unchanged, so an LSP adapter must convert from
zero-based positions and honor the server's negotiated UTF-8/UTF-16/UTF-32
position encoding. Return { status: 'unknown', reason } whenever dynamic
access or an incomplete language-service result prevents a conclusive answer;
only a fully resolved empty reference list is classified as unused.
The callbacks execute in the local Fundus Node server and may run up to four
reference requests concurrently. Fundus bundles no TypeScript, Svelte, Vue, or
editor SDK for this feature. When configured, the editor adds an Unused filter,
a Usage section, and source-location navigation. Without it, start and check
print a non-fatal advisory and the related editor controls stay hidden.
When the editor regains focus, any visible usage result is refreshed while the
previous result remains on screen.
The same analysis is available without starting the editor:
npx fundus usage # status for every asset
npx fundus usage --unused # conclusively unused assets only
npx fundus usage hero --json # references and attribution for one assetThe JSON response is { "ok": true, "assets": [...] }. Source locations are
included, but persistent-server editor tokens are omitted because they would
expire with the one-shot CLI process.
Figma import
Fundus can import one selected Figma node as a PNG at 1x–4x and process it as an
Image or Slice. Create a personal access token with file_content:read and keep
it in an environment variable:
import { defineConfig } from 'fundus/config';
export default defineConfig({
// paths created by `fundus init`...
import: {
figma: {
token: process.env.FIGMA_ACCESS_TOKEN,
defaults: { scale: 2 }
}
}
});npx fundus asset ingest 'https://www.figma.com/design/abc/UI?node-id=12-34' \
--from figma --type slice --id navigationPanel --scale 3
npx fundus asset reimport navigationPanelFor Slice assets, the pixel ratio defaults to the chosen Figma export scale. Changing the saved link or scale and reimporting synchronizes that ratio, while refreshing the unchanged source preserves a manually authored value. The editor offers Figma import from both its main controls and folder context menus.
Fundus persists the stable Figma file and node identifiers, never the token or temporary URL. The downloaded original stays local, so builds remain offline. Replacing or accepting an external edit to it intentionally disconnects the Figma source.
Is Fundus for me?
Fundus fits SvelteKit apps that keep product assets in git and want repeatable processing, typed references, visual authoring, and agent-friendly automation.
It is not a cloud DAM, CDN, hosted collaboration service, or runtime media CMS.
It does not currently handle SVG, fonts, responsive srcset generation,
platform variants, or concurrent writers. Figma support is deliberate one-node
import and reimport, not two-way sync.
Contributing
Run npm install and npx playwright install chromium once, then use
npm test, npm run check, and npm run lint. Public package changes also
need npm run changeset. See CHANGELOG.md for release history
and RELEASING.md for publishing notes.
For editor development, run npm run dev. It creates an ignored .fundus-dev
host on first use and starts the editor from source with Vite HMR. The host is
kept between runs, so its library and assets survive restarts; remove
.fundus-dev when you want a clean host. Set FUNDUS_PROJECT_ROOT to an
existing Fundus host directory to develop against that project instead.
The default .fundus-dev host also enables a basic TypeScript usage provider.
Its tsconfig.json owns the analyzed .ts, .tsx, .js, and .jsx files;
src/usage-example.ts is a convenient place for typed manifest reads while
testing the Unused filter and Usage inspector. Source-location buttons use
code --goto by default. Set FUNDUS_DEV_EDITOR=cursor (or another compatible
CLI command) to open references in a different editor. Framework template files
remain the responsibility of a richer host-project provider.
License
Fundus does not currently include a license file.
