microvoxel-5
v0.1.0
Published
Tiny, zero-dependency voxel scoring & analysis toolkit — deterministic VibeVector derivation, structure comparison, and LLM-ready structured output
Maintainers
Readme
microvoxel-5
Tiny, zero-dependency voxel scoring & analysis toolkit.
Derives a VibeVector — a 6-axis aesthetic descriptor — from any 3D voxel arrangement and computes deterministic similarity scores. Designed for LLM structured output pipelines.
Features
- VibeVector derivation — deterministically reduce any voxel arrangement to a 6-dimensional aesthetic fingerprint
- Similarity scoring — compare two structures by spatial overlap (Jaccard) and/or aesthetic feel (VibeVector distance)
- JSON Schemas — ship as
microvoxel-5/schemasfor direct use with LLM structured output APIs - Runtime validation — type guards for all data types, ready for untrusted LLM output
- Zero dependencies — pure TypeScript, works in any runtime
Install
npm install microvoxel-5
# or
bun add microvoxel-5Quick start
import {
deriveVibeVector,
computeVibeScore,
calculateScores,
type Voxel,
} from 'microvoxel-5';
const voxels: Voxel[] = [
{ pos: [0, 0, 0], color: '#FF3B30', type: 'standard' },
{ pos: [1, 1, 0], color: '#0A84FF', type: 'emissive' },
{ pos: [2, 0, 1], color: '#30D158', type: 'standard' },
];
// Derive a VibeVector from a voxel arrangement
const vibe = deriveVibeVector(voxels, [5, 5, 5]);
// → { warmth: 3, density: 1, focus: 3, randomness: 2, saturation: 4, verticality: 2 }
// Compare two VibeVectors (0–100)
const score = computeVibeScore(vibeA, vibeB);VibeVector
Every voxel arrangement maps to a 6-axis integer vector (each 0–4). The axes were chosen empirically to capture the key perceptual qualities of small-grid voxel art — colour mood, spatial distribution, and structural form:
| Axis | Measures | Derivation |
|------|----------|------------|
| warmth | Colour temperature | Hue analysis — red/orange hues → high, blue hues → low |
| density | Grid occupancy | round(sqrt(filledCells / totalCells) × 4) |
| focus | Clustering | Inverse of avg Euclidean distance from centre-of-mass |
| randomness | Structural coherence | Inverse of 6-neighbour connectivity ratio |
| saturation | Colour intensity | Mean HSL saturation |
| verticality | Height vs spread | Y-span / avg horizontal span |
Two VibeVectors are compared by normalised Manhattan distance:
vibeScore = (1 − Σ|playerᵢ − targetᵢ| / 24) × 100This captures how similarly two structures feel — independent of exact block placement.
Scoring
Structure score
Jaccard similarity of voxel position sets:
structureScore = |A ∩ B| / |A ∪ B| × 100Combined score
totalScore = structureScore × 0.6 + vibeScore × 0.4Full scoring
import { calculateScores } from 'microvoxel-5';
const result = calculateScores(playerVoxels, directorPlan);
// → {
// structureScore: 45,
// vibeScore: 75,
// totalScore: 57,
// playerVibeVector: { warmth: 3, ... },
// axisComparisons: [
// { axis: 'warmth', target: 2, actual: 3, delta: 1 },
// ...
// ]
// }JSON Schemas for LLM output
All core types are available as JSON Schema objects, suitable for Gemini's responseSchema, OpenAI's response_format, or any LLM API that accepts JSON Schema:
import {
VoxelSchema,
VibeVectorSchema,
DirectorPlanSchema,
} from 'microvoxel-5/schemas';
// Use with Gemini structured output
const response = await model.generateContent({
contents: [{ role: 'user', parts: [{ text: prompt }] }],
generationConfig: {
responseMimeType: 'application/json',
responseSchema: DirectorPlanSchema,
},
});Validation
Runtime type guards for safely parsing untrusted input (e.g. LLM responses):
import { isValidDirectorPlan, isValidVibeVector } from 'microvoxel-5';
const parsed = JSON.parse(llmOutput);
if (isValidDirectorPlan(parsed)) {
// parsed is now typed as DirectorPlan
}| Guard | Validates |
|-------|-----------|
| isValidVector3 | [number, number, number] tuple |
| isValidVoxelType | 'standard' \| 'emissive' \| 'transparent' |
| isValidHexColour | #RRGGBB format |
| isValidVoxel | Full Voxel with bounds checking |
| isValidVibeVector | All 6 axes present, each 0–4 |
| isValidDirectorPlan | Complete plan with valid voxels and vibe vector |
API reference
Types
type Vector3 = [number, number, number]
type VoxelType = 'standard' | 'emissive' | 'transparent'
interface Voxel {
pos: Vector3
color: string // #RRGGBB
type: VoxelType
}
interface VibeVector {
warmth: number // 0–4
density: number // 0–4
focus: number // 0–4
randomness: number // 0–4
saturation: number // 0–4
verticality: number // 0–4
}
interface DirectorPlan {
grid_size: Vector3
voxels: Voxel[]
vibe_vector: VibeVector
vibe_prompt: string
}
interface ScoreResult {
structureScore: number
vibeScore: number
totalScore: number
playerVibeVector: VibeVector
axisComparisons: AxisComparison[]
}Functions
Scoring
| Function | Signature | Description |
|----------|-----------|-------------|
| deriveVibeVector | (voxels, gridSize) → VibeVector | Derive a VibeVector from a voxel arrangement |
| computeVibeScore | (player, target) → number | Compare two VibeVectors (0–100) |
| calculateStructureScore | (playerVoxels, targetVoxels) → number | Jaccard similarity of position sets (0–100) |
| calculateScores | (playerVoxels, plan) → ScoreResult | Full scoring with axis-by-axis breakdown |
Grid
| Function | Signature | Description |
|----------|-----------|-------------|
| isWithinBounds | (pos, gridSize?) → boolean | Check if position is inside the grid |
| positionKey | (pos) → string | Serialise Vector3 to "x,y,z" |
| positionsEqual | (a, b) → boolean | Compare two Vector3 positions |
| createGridConfig | (size?) → GridConfig | Create a grid config object |
Voxel operations
| Function | Signature | Description |
|----------|-----------|-------------|
| placeVoxel | (voxels, voxel, gridSize?) → Voxel[] | Place or replace (immutable) |
| removeVoxel | (voxels, pos) → Voxel[] | Remove at position (immutable) |
| findVoxel | (voxels, pos) → Voxel \| undefined | Find at position |
| hasVoxelAt | (voxels, pos) → boolean | Check existence at position |
Mock director
import { generateMockDirectorPlan, DEFAULT_PALETTE } from 'microvoxel-5';
const plan = generateMockDirectorPlan({
gridSize: [5, 5, 5], // default
minVoxels: 15, // default
maxVoxels: 45, // default
palette: DEFAULT_PALETTE,
});Background
microvoxel-5 was built as the scoring engine for Vibe Architect — a Gemini 3 Hackathon Tokyo project where an LLM expresses abstract aesthetics as hidden 3D voxel structures and humans try to recreate the same feeling.
Licence
MIT
