開発者向け

.velq を、あなたのツールにも。

.velq は ZIP ベースのオープンなコンテナです。約束はひとつ、どのマシンでも、何年後でも、ネットワークなしで描画され続けること。このページはその仕様書であり、読む・書く・拡張するための道具一式です。リファレンス実装の Rust クレート、準拠チェックリスト、プラグイン API、そして名前にまつわるルール。

ZIP コンテナ仕様バージョン 1Apache-2.0application/velq+zip

全体像

エントリは、4 種類だけ。

独自エンコードも隠しヘッダもありません。ZIP と JSON が書ければ、.velq は書けます。

manifest.json

パッケージのメタデータ。タイトル、日時、タグ、それと拡張ポイントがひとつ。必須。

index.html

ドキュメント本体であり、正となる表示。中の参照はすべてアーカイブ内を指します。必須。

index.md

Markdown から作られたパッケージだけが持つ、編集用の原稿。ビューアはこれを読む必要がありません。

assets/

ドキュメントが使うすべて。CSS・スクリプト・画像・フォントを重複なく収め、相対パスで参照します。

確かめるのは簡単です。.velq.zip にリネームするか、unzip -l report.velq を実行してください。何も隠れていないことが、この形式の要点です。

仕様

.velq コンテナ 仕様バージョン 1

Stable · Velq 0.1 から出荷 · リファレンス実装: velq-core

以下の「しなければならない(MUST)」「すべき(SHOULD)」は RFC 2119 の意味で使います。MUST は準拠の条件、SHOULD は良い実装の作法です。

1 · コンテナ

  • .velq は ZIP アーカイブそのものです。マジックナンバーは PK\x03\x04、エントリ名は UTF-8。圧縮方式は Stored か Deflate だけを使わなければなりません(MUST)。世の中のあらゆる ZIP ツールで開けることを守るためです。
  • 拡張子は .velq。メディアタイプは application/velq+zip を推奨します(未登録)。実務上の識別子は拡張子です。
  • 「.zip にリネームすればどこでも開ける」は正式にサポートされた操作で、この先も変わりません。これを壊す改訂は .velq を名乗りません。

2 · エントリ

  • ルートに manifest.jsonindex.html の両方を含む ZIP だけが、有効な .velq です。条件はそれ以外にありません。
  • index.md は任意です。存在する場合は Markdown パッケージで、index.md が編集用の原稿、index.html はその描画結果でなければなりません(MUST)。
  • それ以外のエントリはすべてアセットです。Velq のバンドラは assets/css|js|img|fonts/ 配下に SHA-256 のハッシュ名で置きますが、これは慣習であって規則ではありません。リーダーが当てにしてよいのは「相対パスで、アーカイブの中」までです。
  • 既存パッケージを編集するツールは、自分が知らないエントリを 1 バイトも変えずに持ち越さなければなりません(MUST)。知らないファイルは他のツールの機能であって、ゴミではありません。
  • ディスクへ展開するときはエントリのパスを検査してください(絶対パスと .. を拒否する、いつもの ZIP の作法です)。

3 · manifest.json

  • camelCase キーの JSON オブジェクト 1 つです。フィールドはすべて省略可能で、欠けていれば下表のデフォルトが立ちます。リーダーは知らないトップレベルフィールドを無視しなければなりません(MUST)。
  • エディタは書き戻し時に知らないトップレベルフィールドを落としても構いません(MAY)。つまりツール固有のデータをトップレベルに置いてはいけません。置き場所は custom の下、あなたが所有する名前("com.example.mytool" など)をキーにして。エディタは custom をそのまま保持しなければなりません(MUST)。
フィールドデフォルト意味
titlestring"Untitled"ドキュメントのタイトル。ビューアやファイルマネージャが表示します。
creatednumber0作成日時。Unix エポック秒。
updatednumber0最終更新日時。Unix エポック秒。
sourceUrlstring · nullnullURL から梱包した場合の取得元。
generatorstring"velq-core x.y.z"パッケージを書いたツール名。あなたのツール名を入れてください。
tagsstring[][]自由なラベル。
custom任意の JSONnull唯一の拡張ポイント。所有する名前で名前空間を切ること。エディタはここを変更せず保持します。

velq-core が実際に読み書きしているスキーマそのままです。願望は書いていません。

完全かつ有効な manifest の例

{
  "title": "Q3 report",
  "created": 1783814400,
  "updated": 1783814400,
  "sourceUrl": null,
  "generator": "velq-core 0.1.1",
  "tags": ["report", "finance"],
  "custom": { "com.example.mytool": { "reviewed": true } }
}

4 · オフラインの契約

  • index.html は同梱アセットだけで完全に描画されなければなりません(MUST)。ネットワークを抜いた状態が基準です。準拠ライターはスタイルシート・スクリプト・画像・フォントへの参照をすべて同梱の相対パスに書き換えます。
  • スクリプトは同梱してよく、実行されて構いません。ビューアは通信とファイルアクセスを遮断したサンドボックスで開くべきです(SHOULD)。Velq 自身のビューアは権限ゼロの隔離 WebView で、CSP は connect-src 'none' です。

5 · バージョニングと安定性

  • このページが定めるのはバージョン 1 です。バージョン 1 のパッケージは、バージョンを宣言しません。
  • バージョン 1 の中での変更は追加のみで、後方互換です。バージョン 1 のリーダーは、今日の .velq も 10 年後の .velq も開けます。
  • この約束を破る必要が生じたときは、manifest.jsonformatVersion フィールドとして宣言され、先にこのページで告知されます。黙って変わることはありません。

準拠

「.velq 対応」の定義

短いチェックリストが 2 つ。あなたのツールに当てはまる側を満たせば、対応を名乗れます。

準拠リーダー

  • ルートに manifest.json と index.html を含む ZIP なら開ける。前提条件はそれだけ。
  • index.html を、参照をすべてアーカイブ内から解決して、ネットワークなしで表示できる。
  • 知らない manifest フィールドを無視し、中身が {} だけの manifest でも動く。
  • ディスクへ展開するなら、エントリのパスを検査している。

準拠ライター / エディタ

  • manifest.json と index.html を含むプレーンな ZIP(Stored / Deflate)を書き出す。
  • サブリソースへの参照をすべて同梱の相対パスへ書き換え、オフラインで描画されるファイルにする。
  • index.md と index.html が両方あるときは、必ず揃えて更新する。
  • 既存パッケージの編集では、custom と、自分が知らないすべてのエントリを保持する。
  • 自分のメタデータは custom の下に置く。トップレベルには増やさない。

既知の正しいサンプルがリポジトリに入っています — demo.velq。Velq 自身のテストが「スクリプトは動き、サンドボックスは破れない」ことの確認に開いているのと同じフィクスチャです。velq-core のテストスイートは、このチェックリストの実行可能版です(pack → validate → read → edit → 再 validate)。

当てはまるリストを満たしたら、どうぞ堂々と「.velq 対応」を名乗ってください。歓迎します。

リファレンス実装

velq-core: この仕様の実装、Rust で約 350 行

Velq 本体が土台にしているクレートです。Apache-2.0、#![forbid(unsafe_code)]、Tauri 非依存なので、どんな Rust プログラムにもリンクできます。小ささは意図的なものです。.velq は ZIP と JSON オブジェクトであり、ライブラリはそれ以上に賢くなろうとしません。

使う

# Cargo.toml — not on crates.io yet, so pull it straight from the repo
[dependencies]
velq-core = { git = "https://github.com/iKora128/velq" }

書く・検証する・読む

use std::path::Path;
use velq_core::{pack, read_manifest, validate, Asset, Manifest};

let manifest = Manifest { title: "Q3 report".into(), ..Manifest::default() };
let assets = [Asset {
    path: "assets/css/main.css".into(),
    bytes: b"body{margin:2rem}".to_vec(),
}];

pack(Path::new("report.velq"), &manifest, b"<h1>Q3</h1>", &assets)?;
validate(Path::new("report.velq"))?;          // manifest.json + index.html: ok
let title = read_manifest(Path::new("report.velq"))?.title;

API はこれで全部

pack / pack_md

パッケージを書き出す。HTML のみ、または Markdown 原稿と描画済み HTML のペア。

validate

必須 2 エントリの検査。「この ZIP は .velq か?」

read_manifest / read_index_md / read_file_bytes / read_assets

メタデータ、Markdown 原稿、任意のエントリを読む。

update_index / update_md

ドキュメントだけ差し替えて manifest とアセットは保持。アトミックに書くので、途中で落ちてもパッケージは壊れません。

unpack

フォルダへ全展開(「.zip リネーム」の関数版)。

スタックに Rust がなくても大丈夫です。このフォーマットは Rust を要求しません。ZIP と JSON は JavaScript でも Python でも Go でも Swift でも標準ライブラリの距離にあります。移植したらぜひ教えてください。ここからリンクします。

エディタの拡張

プラグイン = CodeMirror 6 拡張

Velq の描画プラグインは、内蔵のライブプレビューと同じ仕組みで動きます。コアは個々のプラグインを一切知りません。KaTeX と Mermaid は公開 API だけで書かれた参考実装として同梱されていて、オフにすればただの Markdown に戻ります。CM6 拡張が書けるなら、Velq プラグインは書けます。

import { usePlugins } from "@/plugins/runtime";
import type { VelqPlugin } from "@/plugins/api";

const myPlugin: VelqPlugin = {
  id: "highlight-todo",
  name: "TODO highlighter",
  description: "Tint TODO and FIXME markers.",
  extension: todoHighlightExtension, // any CodeMirror 6 extension
};

usePlugins.register(myPlugin);

参考実装 2 つの解剖つきの完全版ガイド: docs/plugin-api.md

名称と方針

コードはフォークしていい。「.velq」の意味は守る。

どこで開いても同じに開ける限りにおいて、この形式には価値があります。自由な範囲と、予約されている範囲を正確に。

コードは Apache-2.0

利用・組み込み・改変・販売、すべて許可不要です。商用も、特許グラント込みで。velq-core にもバンドラにもアプリ本体にも適用されます。

名前はこのプロジェクトのもの

Apache-2.0 §6 は商標を許諾しません。「Velq」の語とロゴはプロジェクトに帰属します。「.velq 対応」「velq-core 製」は事実である限り自由に名乗ってください。製品やフォークに「Velq」や紛らわしい名前を付けるのは不可です。

フォーマットの管理はここで

仕様の変更はコードより先にこのページに載り、バージョン 1 の中では追加だけが行われます。拡張は custom へ。チェックリストを破る方言は .velq ではありません。別の名前でどうぞ。

.velq を話すものを、作ってください。