@qarakash/blockwriteai
v1.0.9
Published
BlockWriteAI JSON-first drop-in block writing editor with free core blocks, preview mounting, and license-gated premium plugins.
Maintainers
Readme
BlockWriteAI
BlockWriteAI is a drop-in block writing editor for the web. It is built to feel familiar to Editor.js users, but ships as plain CSS and JavaScript files that can be used in PHP, Laravel, CodeIgniter, static HTML, dashboards, or any project that can load a script tag.
The editor stores and saves content as JSON first. Projects can render that JSON on any page by adding a BlockWriteAI preview container, while advanced document blocks such as tables, media galleries, attachments, diagrams, charts, signatures, and code editing remain available as plugins.
All public assets, package entry points, and browser globals use the BlockWriteAI name.
Highlights
- Editor.js-style block JSON output.
- Plain script tag integration with no build step required.
- Paragraphs, headings, quotes, callouts, dividers, buttons, toggle blocks, raw HTML, links, embeds, tables, lists, and nested checklists.
- Floating inline toolbar with typography, colors, highlight, alignment, comments, links, and formatting controls.
- Multi-image upload, drag and drop, resize, crop, rotate, and gallery layout.
- Attachment blocks for documents and videos.
- Code block with formatting, syntax help, language detection, and suggestions.
- Charts, LaTeX, audio, layout columns, code assistance, and optional history plugins in the free plugin set.
- Premium plugins for Drawing, Mermaid, Signature, Signature Flow, and AI writing, delivered after server-side license verification.
- Undo, redo, autosave, block actions, drag reordering, and optional JSON save/export buttons.
- JSON-powered preview mounting for public document pages.
- JSON save API examples for future database storage.
Project Structure
BlockWriteAI/
package.json
composer.json
pyproject.toml
dist/
blockwriteai.css
blockwriteai.js
blockwriteai-logo.svg
blockwriteai-favicon.svg
plugins/
blockwriteai-advanced-blocks.js
blockwriteai-drawing.js
blockwriteai-mermaid.js
blockwriteai-ai.js
blockwriteai-code-assist.js
blockwriteai-history.js
blockwriteai-signature.js
blockwriteai-signature-flow.js
examples/
index.html
preview.html
upload.php
api/
document.php
preview.php
uploads/
.gitkeep
blockwriteai_editor/
static/blockwriteai/
src/
BlockWriteAIAssets.php
types/
index.d.tsInstallation
BlockWriteAI can be consumed as a CDN/script-link package, an npm package, a Python static-assets package, or a Composer package.
Script Link
Use the npm CDN for a locked release build:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/blockwriteai.css">
<script src="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/blockwriteai.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/plugins/blockwriteai-code-assist.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/plugins/blockwriteai-advanced-blocks.js"></script>blockwriteai-advanced-blocks.js is the free advanced bundle. It includes Chart,
LaTeX, Audio, and Columns/Layout. Drawing, Mermaid, Signature, Signature Flow,
and AI are premium plugins and should not be loaded directly in production.
Load History only when a project needs the history dropdown:
<script src="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/plugins/blockwriteai-history.js"></script>For development against the current GitHub branch, replace the npm URLs with the GitHub CDN form:
https://cdn.jsdelivr.net/gh/qarAkash/BlockWriteAI@main/dist/...Premium License Gating
Drawing, Mermaid drawing, Signature, Signature Flow, and AI can be licensed through the BlockWriteAI Platform. Normal editor blocks continue to work without a license. Premium plugin scripts are delivered only after the license endpoint returns an active trial or subscription. Without a valid license, those tools are not registered and do not appear in the insert-block menu.
const editor = new BlockWriteAI({
holder: "#editor",
premium: {
licenseKey: "bwai_live_xxxxx",
verifyEndpoint: "http://localhost/blockwriteai-platform/api/license_verify.php",
pluginEndpoint: "http://localhost/blockwriteai-platform/api/premium_plugins.php",
usageEndpoint: "http://localhost/blockwriteai-platform/api/ai_usage.php",
autoLoadPlugins: true,
features: ["drawing", "mermaid", "signature", "signature_flow", "ai"]
},
ai: {
endpoint: "/api/ai.php"
}
});The verify endpoint must return a features object with these keys when enabled:
{
"drawing": true,
"mermaid": true,
"signature": true,
"signature_flow": true,
"ai": true
}The AI plugin calls premium.usageEndpoint before each AI request so the
platform can enforce the 7-day trial and daily prompt limits.
For stronger production security, do not load premium plugin files directly from a public CDN. Load the free core first, request the premium plugins from your BlockWriteAI Platform, and create the editor only after the server has verified the license. The platform serves Drawing, Mermaid, Signature, Signature Flow, and AI as a verified bundle after checking the requested feature flags:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/blockwriteai.css">
<script src="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/blockwriteai.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/plugins/blockwriteai-code-assist.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/plugins/blockwriteai-advanced-blocks.js"></script>
<script>
async function boot() {
await BlockWriteAI.loadPremiumPlugins({
licenseKey: "bwai_live_xxxxx",
endpoint: "http://localhost/blockwriteai-platform/api/premium_plugins.php",
features: ["drawing", "mermaid", "signature", "signature_flow", "ai"]
});
window.editor = new BlockWriteAI({
holder: "#editor",
premium: {
licenseKey: "bwai_live_xxxxx",
verifyEndpoint: "http://localhost/blockwriteai-platform/api/license_verify.php",
usageEndpoint: "http://localhost/blockwriteai-platform/api/ai_usage.php"
}
});
}
boot();
</script>This matters because browser-only locks can be edited in DevTools. Server-side license verification, usage metering, signature event storage, and verified premium bundle delivery are the enforceable parts.
npm
Package name:
@qarakash/blockwriteaiInstall:
npm install @qarakash/blockwriteaiBundler entry points:
import BlockWriteAI from "@qarakash/blockwriteai";
import "@qarakash/blockwriteai/css";
import "@qarakash/blockwriteai/plugins/code-assist";
import "@qarakash/blockwriteai/plugins/advanced";
import "@qarakash/blockwriteai/plugins/history";After npm publishing, the same package is also available through npm CDNs:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/blockwriteai.css">
<script src="https://cdn.jsdelivr.net/npm/@qarakash/[email protected]/dist/blockwriteai.js"></script>Python
Package name:
blockwriteai-editorInstall:
pip install blockwriteai-editorCopy packaged static files into your Flask, Django, or any Python web app static directory:
from blockwriteai_editor import copy_static
copy_static("static/blockwriteai")Python helpers are also available for generating asset tags. script_tags() loads
only core/free plugins by default. Pass history=True only on pages where you want
the optional History dropdown:
from blockwriteai_editor import premium_script_tags, stylesheet_tag, script_tags
print(stylesheet_tag("/static/blockwriteai"))
print(script_tags("/static/blockwriteai"))
print(script_tags("/static/blockwriteai", history=True))
# Only for private/licensed deployments. Public apps should prefer the platform
# premium bundle endpoint shown in the Premium License Gating section.
print(premium_script_tags("/static/blockwriteai", ["signature", "ai"]))PHP / Composer
Package name:
qarakash/blockwriteaiInstall:
composer require qarakash/blockwriteaiPublish assets into your public folder:
cp -R vendor/qarakash/blockwriteai/dist public/blockwriteaiPHP helper. scriptTags() loads only core/free plugins by default. Pass
history: true only on pages where you want the optional History dropdown:
use QarAkash\BlockWriteAI\BlockWriteAIAssets;
echo BlockWriteAIAssets::stylesheetTag('/blockwriteai');
echo BlockWriteAIAssets::scriptTags('/blockwriteai');
echo BlockWriteAIAssets::scriptTags('/blockwriteai', plugins: true, history: true);
// Only for private/licensed deployments. Public apps should prefer the platform
// premium bundle endpoint shown in the Premium License Gating section.
echo BlockWriteAIAssets::premiumScriptTags('/blockwriteai', ['signature', 'ai']);Local XAMPP Demo
Copy the BlockWriteAI folder into your web root, for example:
C:\xampp\htdocs\BlockWriteAIOpen:
http://localhost/BlockWriteAI/examples/Browser Usage
<link rel="stylesheet" href="/BlockWriteAI/dist/blockwriteai.css">
<div id="editor"></div>
<script src="/BlockWriteAI/dist/blockwriteai.js"></script>
<script src="/BlockWriteAI/dist/plugins/blockwriteai-code-assist.js"></script>
<script src="/BlockWriteAI/dist/plugins/blockwriteai-advanced-blocks.js"></script>
<script>
const editor = new BlockWriteAI({
holder: "#editor",
maxWidth: "960px", // optional; omit for full-width editor shell
placeholder: "Write something, or press / for blocks",
data: {
blocks: [
{
type: "paragraph",
data: {
text: "Hello from BlockWriteAI",
alignment: "left"
}
}
]
},
onChange(data) {
console.log("Changed document", data);
},
async onSave(data) {
await fetch("/save-document.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
}
});
</script>By default, BlockWriteAI mounts the full branded editor shell: logo, product subtitle,
Editor heading, centered AI progress, and the right-aligned JSON sync status. If no
data is provided, the editor starts with one empty paragraph block automatically. Use
shell: false when you only want the raw editor surface, or pass maxWidth: "960px" /
shell: { maxWidth: "960px" } to constrain the editor width in your project.
Built-in toolbar buttons are intentionally opt-in for package consumers. saveButton, exportButton, and exportHtmlButton default to false, so applications can use their own UI and call editor.save() when needed.
Saving JSON
BlockWriteAI is designed to save JSON first. In production, store the JSON in your database and render it later in read-only mode or through exported HTML.
document.querySelector("#save").addEventListener("click", async () => {
const data = await editor.save();
await fetch("/save-document.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
});The default toolbar includes a Save button. Use onSave to receive the JSON response when the user clicks it:
const editor = new BlockWriteAI({
holder: "#editor",
async onSave(data) {
await fetch("/documents/123", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
}
});AI Plugin
AI is a premium plugin. Load it through the platform premium bundle after license verification. The browser plugin never receives your OpenAI API key; it calls your own server endpoint.
<script src="/blockwriteai/blockwriteai.js"></script>
<script>
async function boot() {
await BlockWriteAI.loadPremiumPlugins({
licenseKey: "bwai_live_xxxxx",
endpoint: "/blockwriteai-platform/api/premium_plugins.php",
features: ["ai"]
});
window.editor = new BlockWriteAI({
holder: "#editor",
premium: {
licenseKey: "bwai_live_xxxxx",
verifyEndpoint: "/blockwriteai-platform/api/license_verify.php",
usageEndpoint: "/blockwriteai-platform/api/ai_usage.php"
},
ai: {
endpoint: "/api/blockwriteai-ai.php"
}
});
}
boot();
</script>The included demo endpoint is examples/api/ai.php. For local development, copy examples/api/openai.local.example.php to examples/api/openai.local.php and add a development key, or set OPENAI_API_KEY in the server environment. Do not expose the key in browser JavaScript.
The drawer can also be opened without selecting text from the centered AI button in the editor toolbar, or programmatically with editor.openAI().
Available AI drawer actions:
- Improve writing
- Fix grammar
- Summarize
- Expand
- Make professional
- Generate BlockWriteAI blocks from a prompt
Preview Pages
Create any page in your application and add a preview container. BlockWriteAI will load saved JSON and render the document HTML inside that container.
<link rel="stylesheet" href="/blockwriteai/blockwriteai.css">
<div class="blockwriteai-preview" data-source="/documents/123.json"></div>
<script src="/blockwriteai/blockwriteai.js"></script>
<script src="/blockwriteai/plugins/blockwriteai-advanced-blocks.js"></script>
<script>
BlockWriteAI.mountPreviews();
</script>If the preview page must render premium blocks, load the licensed premium bundle
before BlockWriteAI.mountPreviews():
async function mountDocumentPreview() {
await BlockWriteAI.loadPremiumPlugins({
licenseKey: "bwai_live_xxxxx",
endpoint: "/blockwriteai-platform/api/premium_plugins.php",
features: ["drawing", "mermaid", "signature", "signature_flow", "ai"]
});
BlockWriteAI.mountPreviews();
}
mountDocumentPreview();The JSON endpoint can return either a BlockWriteAI document directly or an API wrapper such as:
{
"ok": true,
"data": {
"time": 1779540000000,
"version": "1.0.9",
"blocks": []
}
}Example PHP receiver:
<?php
header('Content-Type: application/json');
$json = file_get_contents('php://input');
$data = json_decode($json, true);
if (!$data || !isset($data['blocks']) || !is_array($data['blocks'])) {
http_response_code(422);
echo json_encode(['error' => 'Invalid BlockWriteAI document']);
exit;
}
file_put_contents(__DIR__ . '/saved-document.json', json_encode($data, JSON_PRETTY_PRINT));
echo json_encode(['ok' => true]);Uploads
The demo includes examples/upload.php and stores files under examples/uploads/. For production, replace this with your own storage layer.
const editor = new BlockWriteAI({
holder: "#editor",
uploadOutput: ["upload", "base64"],
upload: {
image: async (file) => {
const form = new FormData();
form.append("file", file);
form.append("kind", "image");
const response = await fetch("/BlockWriteAI/examples/upload.php", {
method: "POST",
body: form
});
return response.json();
},
file: async (file) => {
const form = new FormData();
form.append("file", file);
form.append("kind", "file");
const response = await fetch("/BlockWriteAI/examples/upload.php", {
method: "POST",
body: form
});
return response.json();
}
}
});uploadOutput controls what gets written into the saved JSON:
"base64"or["base64"]stores uploaded media directly in the block JSON. This is the default."upload"or["upload"]stores the response from your upload handler, such as a server URL.["upload", "base64"]stores both, useful when you want server files plus a portable JSON backup.
Expected upload response:
{
"url": "/BlockWriteAI/examples/uploads/example.pdf",
"name": "example.pdf",
"size": 12345,
"type": "application/pdf"
}When both outputs are enabled, saved image and attachment items include the server response under upload and the inline file data under base64.
API Methods
await editor.save(); // Get JSON document
editor.getData(); // Get current data synchronously
editor.render(data); // Replace editor content
editor.clear(); // Reset editor
editor.exportHTML(); // Export HTML
editor.exportMarkdown(); // Export Markdown API, hidden from the default UI
editor.importHTML(html); // Import HTML into blocks
editor.setReadOnly(true); // Toggle read-only mode
editor.undo(); // Undo last change
editor.redo(); // Redo last undo
editor.destroy(); // Remove editor instance
BlockWriteAI.mountPreviews(); // Render JSON into .blockwriteai-preview containersData Shape
{
"time": 1779540000000,
"version": "1.0.9",
"blocks": [
{
"id": "block-title",
"type": "heading",
"data": {
"level": 2,
"text": "BlockWriteAI document",
"alignment": "left"
}
},
{
"id": "block-body",
"type": "paragraph",
"data": {
"text": "Reusable content saved as JSON."
}
}
]
}Tool Control
Limit available blocks per project:
const editor = new BlockWriteAI({
holder: "#editor",
tools: [
"paragraph",
"heading",
"image",
"list",
"table"
]
});Disable specific tools:
const editor = new BlockWriteAI({
holder: "#editor",
tools: {
raw: false,
attaches: false
}
});Autosave
const editor = new BlockWriteAI({
holder: "#editor",
autosave: {
key: "blockwriteai-draft",
load: true
}
});Security Notes
BlockWriteAI sanitizes normal rich text blocks before saving and exporting. Raw HTML blocks are intentionally treated as trusted HTML, so enable the raw HTML tool only for trusted users.
For production applications:
- Validate JSON on the server.
- Sanitize output again before public rendering.
- Restrict upload types and file sizes.
- Store uploaded files outside executable PHP paths when possible.
- Add authentication before saving documents.
GitHub
Repository target:
https://github.com/qarAkash/BlockWriteAI.gitPublishing Packages
After a release is ready, publish each package from the repository root.
Create a Git release tag for script-link/CDN users:
git tag v1.0.9
git push origin v1.0.9Publish npm:
npm publish --access publicPublish Python:
python -m build
python -m twine upload dist/*Publish Composer:
Submit https://github.com/qarAkash/BlockWriteAI to Packagist as qarakash/blockwriteai.Status
BlockWriteAI is currently an active custom editor library and demo project. It is suitable for continued feature development, integration testing, and database-backed storage work.
