Author: Peace Thabiwa
Organization: SAGEWORKS AI
Concept Domain: Living Data Systems · Object Economies · Browser Simulation
Abstract
This paper introduces Smalltalk Living Object Society, a browser-based experimental system where data assets behave as autonomous objects that communicate via asynchronous messages.
Instead of treating data as passive records in a database, the system models data as economic agents capable of:
sending messages
processing mailboxes
evolving
trading value
merging into higher-order objects
The prototype is implemented entirely in client-side JavaScript and draws conceptual inspiration from the message-passing model of Smalltalk.
The system demonstrates that object-oriented message ecosystems can simulate a living data economy inside the browser runtime.
- Motivation
Most modern software treats data as static structures:
data → stored → queried → visualized
This architecture assumes that data:
does not act
does not communicate
does not evolve
However, modern systems increasingly resemble ecosystems rather than databases.
Examples include:
financial markets
distributed sensor networks
AI knowledge graphs
Web3 asset ecosystems
In these environments, information behaves more like economic actors than database rows.
The goal of this research is to explore:
What happens when data objects can communicate and make decisions autonomously?
- Concept: Living Data Objects
In this system, every data asset is modeled as a living object.
Each object contains:
identity
type
value
demand
influence
evolution level
mailbox
trade history
Unlike traditional data models, objects have agency.
They can:
send messages
react to incoming messages
initiate economic interactions
mutate their internal state
This transforms data into active participants in a computational ecosystem.
- Smalltalk Message Philosophy
The architecture is inspired by the message-passing model of
Smalltalk.
In Smalltalk systems:
objects do not call functions
objects send messages
Example:
assetA send: #trade to: assetB
The receiving object decides how to interpret the message.
This decouples behavior and enables flexible interaction networks.
Our system replicates this pattern in the browser.
- Core System Architecture
The system consists of four main components:
Message System
Object Agents
World Scheduler
Visualization Interface
System Flow
Object → sends message → Target Mailbox
Mailbox → processed during think()
think() → may send new messages
World Tick → drives entire ecosystem
This creates a self-propagating message network.
- Message Objects
Communication between objects is encapsulated by Message objects.
Proof-of-concept implementation:
class Message {
constructor(type, sender, target, payload = {}) {
this.type = type
this.sender = sender
this.target = target
this.payload = payload
this.timestamp = Date.now()
}
}
Messages represent intent, not direct execution.
Examples:
trade
merge
mutate
ping
evolve
- LivingAsset Object Model
Each data asset is a self-contained agent.
Simplified structure:
class LivingAsset {
mailbox = []
receive(message)
processMessages()
think()
send(messageType, target)
}
Key properties include:
baseValue
demand
influence
evolutionLevel
These variables determine the economic behavior of the object.
- Mailbox Communication
Every object contains a mailbox queue.
Messages are stored until the object processes them.
receive(message){
this.mailbox.push(message)
}
During each world tick:
processMessages()
The object interprets each message and updates its state.
This design resembles actor systems and distributed messaging models.
- Autonomous Decision Loop
Objects make decisions independently through the think() function.
Example behavior:
if random < 0.22
send trade message
Possible actions include:
trading value
mutating
merging with other objects
sending informational signals
This creates emergent economic behavior.
- Economic Mechanics
The system introduces simplified economic dynamics.
Value Calculation
Object value is influenced by:
baseValue
demand
influence
evolution
Example formula:
value = baseValue × demand × influence × evolutionBonus
Trade Interaction
When two objects trade:
both gain value
influence may adjust
trade history is recorded
This represents information synergy.
Merge Interaction
Objects can combine into a new asset.
Example:
ObjectA + ObjectB → HybridAsset
The resulting object inherits:
combined value
averaged influence
increased evolution level
This models data fusion.
- World Scheduler
A global clock coordinates the ecosystem.
setInterval(worldTick, 5200)
Each tick performs:
process merges
remove inactive assets
run think() on each object
render state
This creates a persistent evolving system.
- Visualization Layer
The interface renders the object society in real time.
Key elements include:
asset cards
value bars
mailbox counters
message chronicle
world metrics
This provides observability into the object ecosystem.
- Emergent Behavior
Because objects act autonomously, the system produces emergent dynamics.
Observed behaviors include:
spontaneous trading clusters
cascading merges
influence amplification
evolutionary growth
These patterns are not explicitly programmed but arise from interaction rules.
- Relationship to Actor Systems
The architecture overlaps with actor models used in distributed systems.
Similarities include:
mailboxes
message passing
independent agents
asynchronous execution
However, the system differs by modeling economic behavior instead of task processing.
- Potential Applications
This architecture may be useful for exploring:
Data Marketplaces
Datasets acting as tradable assets.
Autonomous AI Economies
AI agents trading knowledge.
Sensor Networks
IoT data negotiating relevance.
Knowledge Graph Evolution
Nodes merging into higher knowledge structures.
Simulation Research
Studying emergent behavior in message networks.
- Future Work
Several extensions are planned.
Network Graph Visualization
Displaying object relationships dynamically.
AI Decision Models
Replacing randomness with reinforcement learning.
Tokenized Value Systems
Introducing cryptographic asset value.
Persistent Object Images
Saving the entire ecosystem state.
This concept resembles object images used in Smalltalk environments like Squeak and Pharo.
- Proof-of-Concept Implementation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>BROWSER DATA ECONOMY · Smalltalk Market</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #0b0e18;
font-family: 'Inter', 'SF Mono', 'Fira Code', monospace;
height: 100vh;
overflow: hidden;
color: #eef4ff;
}
/* main layout */
.app {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
/* header with Smalltalk spirit */
.header {
background: #0a0c14;
border-bottom: 1px solid #2a2e3c;
padding: 0.75rem 1.5rem;
display: flex;
justify-content: space-between;
align-items: baseline;
flex-wrap: wrap;
gap: 1rem;
backdrop-filter: blur(4px);
z-index: 10;
}
.title-section h1 {
font-size: 1.4rem;
font-weight: 500;
letter-spacing: -0.3px;
background: linear-gradient(135deg, #b3e4ff, #a97cff);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
}
.title-section .sub {
font-size: 0.7rem;
color: #6e7a9e;
font-family: monospace;
margin-top: 2px;
}
.badge {
background: #1e2438;
padding: 0.2rem 0.8rem;
border-radius: 40px;
font-size: 0.75rem;
font-weight: 500;
border-left: 3px solid #6c8cff;
}
/* three-panel economy view */
.market-dashboard {
display: flex;
flex: 1;
overflow: hidden;
gap: 1px;
background: #0f121e;
}
/* left: data objects live marketplace */
.data-exchange {
flex: 2;
background: #0c0f1a;
border-radius: 0 12px 12px 0;
display: flex;
flex-direction: column;
overflow: hidden;
margin: 0.5rem 0 0.5rem 0.5rem;
box-shadow: 0 4px 14px rgba(0,0,0,0.4);
}
.exchange-header {
background: #111522;
padding: 0.7rem 1rem;
font-size: 0.8rem;
font-weight: 600;
border-bottom: 1px solid #232838;
display: flex;
justify-content: space-between;
}
.data-stream {
flex: 1;
overflow-y: auto;
padding: 0.6rem;
display: flex;
flex-direction: column;
gap: 10px;
}
/* data asset card — living object */
.data-asset {
background: #13182a;
border-radius: 16px;
padding: 0.8rem 1rem;
border-left: 4px solid #6e8eff;
transition: all 0.15s ease;
animation: fadeIn 0.2s ease;
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
}
.data-asset:hover {
background: #181f34;
transform: translateX(3px);
}
.asset-header {
display: flex;
justify-content: space-between;
align-items: baseline;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 10px;
}
.asset-name {
font-weight: 700;
font-size: 1rem;
letter-spacing: -0.2px;
color: #bdd4ff;
}
.asset-class {
background: #20273f;
padding: 2px 10px;
border-radius: 30px;
font-size: 0.65rem;
font-weight: 600;
font-family: monospace;
}
.asset-stats {
display: flex;
gap: 1rem;
font-size: 0.7rem;
color: #9aa5c4;
margin-bottom: 8px;
}
.value-bar {
background: #0b0e1a;
border-radius: 12px;
height: 6px;
width: 100%;
margin: 8px 0;
}
.value-fill {
background: linear-gradient(90deg, #3b82f6, #a855f7);
width: 0%;
height: 6px;
border-radius: 12px;
transition: width 0.3s ease;
}
.asset-actions {
display: flex;
gap: 8px;
margin-top: 10px;
flex-wrap: wrap;
}
button {
background: #1e253e;
border: none;
color: #d6e3ff;
font-size: 0.7rem;
padding: 4px 10px;
border-radius: 20px;
cursor: pointer;
transition: 0.1s linear;
font-family: monospace;
font-weight: 500;
}
button.primary {
background: #3b4b8a;
color: white;
}
button.primary:hover {
background: #5e7bc2;
}
button.sell {
background: #5a2a3a;
}
button.sell:hover {
background: #8e4058;
}
button.trade {
background: #2a3a4a;
}
button.trade:hover {
background: #3a5c7a;
}
/* right panel: economy & logs */
.economy-panel {
flex: 1.2;
background: #0a0d18;
display: flex;
flex-direction: column;
gap: 6px;
padding: 0.5rem 0.5rem 0.5rem 0;
overflow: hidden;
}
.card {
background: #0c1020;
border-radius: 20px;
padding: 0.8rem;
backdrop-filter: blur(2px);
border: 1px solid #1e2538;
}
.metrics {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 8px;
}
.metric {
background: #0f1424;
padding: 8px;
border-radius: 16px;
text-align: center;
}
.metric-label {
font-size: 0.6rem;
color: #7c88aa;
letter-spacing: 0.5px;
}
.metric-value {
font-size: 1.3rem;
font-weight: 700;
color: #d9e6ff;
}
.log-area {
flex: 1;
overflow-y: auto;
font-size: 0.7rem;
font-family: monospace;
background: #080c18;
border-radius: 16px;
padding: 0.6rem;
}
.log-entry {
padding: 6px 0;
border-bottom: 1px solid #1a1e30;
color: #b4c2e6;
}
.log-entry small {
color: #6e7cae;
}
.market-stats {
font-size: 0.7rem;
display: flex;
justify-content: space-between;
margin-top: 8px;
}
.badge-rank {
font-family: monospace;
background: #00000033;
border-radius: 20px;
padding: 2px 8px;
}
::-webkit-scrollbar {
width: 4px;
}
::-webkit-scrollbar-track {
background: #0b0e18;
}
::-webkit-scrollbar-thumb {
background: #2f3a60;
border-radius: 10px;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.highlight {
background: #2a3355;
transition: 0.1s;
}
</style>
</head>
<body>
<div class="app">
<div class="header">
<div class="title-section">
<h1>◈ BROWSER DATA ECONOMY ◈</h1>
<div class="sub">living objects · message passing · autonomous data markets</div>
</div>
<div class="badge">⚡ SMALLTALK INSPIRED | ASSET ECONOMY</div>
</div>
<div class="market-dashboard">
<!-- DATA EXCHANGE: live assets behaving as economy -->
<div class="data-exchange">
<div class="exchange-header">
<span>📊 DATA ASSETS · LIVING MARKETPLACE</span>
<span style="font-size:0.7rem;">💰 each asset negotiates value | trade → merge → evolve</span>
</div>
<div id="dataStream" class="data-stream">
<!-- dynamic data objects injected -->
<div style="text-align:center; padding:2rem; color:#5e6e92;">🌀 spawning data economy ...</div>
</div>
</div>
<!-- RIGHT: ECONOMY DASHBOARD + LOG -->
<div class="economy-panel">
<div class="card">
<div class="metrics">
<div class="metric">
<div class="metric-label">TOTAL ASSETS</div>
<div class="metric-value" id="totalAssets">0</div>
</div>
<div class="metric">
<div class="metric-label">MARKET LIQUIDITY</div>
<div class="metric-value" id="liquidity">0</div>
</div>
<div class="metric">
<div class="metric-label">TOTAL VALUE</div>
<div class="metric-value" id="totalValue">0</div>
</div>
<div class="metric">
<div class="metric-label">TRADES EXEC</div>
<div class="metric-value" id="tradeCount">0</div>
</div>
</div>
<div class="market-stats">
<span>🏛️ DATA EXCHANGE ACTIVE</span>
<span class="badge-rank" id="economyState">🌱 nascent</span>
</div>
</div>
<div class="card" style="flex: 1; display: flex; flex-direction: column; overflow: hidden;">
<div style="font-size:0.7rem; margin-bottom:6px;">📜 MARKET CHRONICLE · message log</div>
<div id="logContainer" class="log-area">
<div class="log-entry">⏺ Data economy initialized — Smalltalk-inspired objects</div>
<div class="log-entry">⚡ Assets trade, merge, mutate — value flows like currency</div>
</div>
</div>
<div style="display: flex; gap: 6px; justify-content: flex-end; padding: 0 0 6px 0;">
<button id="spawnAssetBtn" style="background:#2f3b6e;">➕ SPAWN DATA ASSET</button>
<button id="simulateTradeBtn" style="background:#2a3a4a;">🔄 SIMULATE MARKET CYCLE</button>
</div>
</div>
</div>
</div>
<script>
// --------------------------------------------------------------
// DATA ECONOMY ENGINE · LIVING OBJECTS (Smalltalk inspired)
// Each DataAsset is a self-contained object with:
// - value, demand, influence, provenance
// - methods: tradeWith(), merge(), mutate(), calculateWorth()
// - message passing style: asset.send('trade', target)
// --------------------------------------------------------------
class DataAsset {
constructor(id, name, type, baseValue, owner = "market") {
this.id = id;
this.name = name;
this.type = type; // e.g., 'sensor', 'behavior', 'predictive', 'demographic'
this.baseValue = baseValue;
this.demand = Math.floor(Math.random() * 60) + 30; // 30-90
this.influence = Math.random() * 1.5 + 0.5; // 0.5-2.0
this.owner = owner;
this.tradeHistory = [];
this.mutated = false;
this.evolutionLevel = 0;
}
// calculate current market value (dynamic)
getCurrentValue() {
let demandFactor = this.demand / 100;
let evolutionBonus = 1 + (this.evolutionLevel * 0.2);
let influenceBonus = this.influence;
let computed = this.baseValue * demandFactor * influenceBonus * evolutionBonus;
return Math.floor(computed * 100) / 100;
}
// update demand based on market sentiment
updateDemand(marketHeat) {
let shift = (Math.random() - 0.5) * 14;
this.demand = Math.min(98, Math.max(12, this.demand + shift + marketHeat * 0.5));
this.demand = Math.floor(this.demand);
}
// trade: exchange value between two assets (message passing style)
tradeWith(otherAsset) {
let myValue = this.getCurrentValue();
let otherValue = otherAsset.getCurrentValue();
if (myValue <= 0 || otherValue <= 0) return false;
// value transfer: both assets gain synergy
let synergy = (this.influence + otherAsset.influence) / 2;
let gain = Math.floor(Math.min(myValue, otherValue) * 0.12 * synergy);
this.baseValue += gain * 0.3;
otherAsset.baseValue += gain * 0.3;
// influence mixing
this.influence = (this.influence + otherAsset.influence) / 2;
otherAsset.influence = (this.influence + otherAsset.influence) / 2;
this.tradeHistory.push(`traded with ${otherAsset.name} +${gain.toFixed(1)}`);
otherAsset.tradeHistory.push(`traded with ${this.name} +${gain.toFixed(1)}`);
// increase evolution level occasionally
if (Math.random() < 0.25) this.evolve();
if (Math.random() < 0.25) otherAsset.evolve();
return { gain, myNewValue: this.getCurrentValue(), otherNewValue: otherAsset.getCurrentValue() };
}
// MERGE: two assets become a new hybrid asset (higher-order data)
mergeWith(otherAsset) {
let mergedName = `(${this.name} ⊕ ${otherAsset.name})`;
let mergedBase = (this.baseValue + otherAsset.baseValue) * 1.2;
let mergedInfluence = (this.influence + otherAsset.influence) * 0.8 + 0.5;
let mergedDemand = Math.floor((this.demand + otherAsset.demand) / 2) + 10;
const newId = `asset_${Date.now()}_${Math.random()}`;
let newAsset = new DataAsset(newId, mergedName, 'hybrid', mergedBase);
newAsset.influence = Math.min(mergedInfluence, 3.2);
newAsset.demand = Math.min(mergedDemand, 98);
newAsset.evolutionLevel = Math.max(this.evolutionLevel, otherAsset.evolutionLevel) + 1;
newAsset.mutated = true;
// log merge event
return newAsset;
}
evolve() {
this.evolutionLevel++;
this.influence = Math.min(this.influence * 1.15, 3.0);
this.baseValue = this.baseValue * 1.08;
this.mutated = true;
}
// "message passing" style: invoke behavior dynamically
send(message, target = null, marketContext = null) {
switch(message) {
case 'trade':
if (target) return this.tradeWith(target);
break;
case 'mutate':
this.evolve();
return true;
case 'value':
return this.getCurrentValue();
case 'merge':
if(target) return this.mergeWith(target);
break;
default:
return null;
}
}
// serialize for UI
toCardHTML() {
let val = this.getCurrentValue();
let percentDemand = this.demand;
let valuePercent = Math.min(100, (val / (this.baseValue * 2.5)) * 100);
let demandColor = `hsl(${50 + (this.demand * 0.8)}, 70%, 55%)`;
return `
<div class="data-asset" data-id="${this.id}">
<div class="asset-header">
<span class="asset-name">📀 ${escapeHtml(this.name)}</span>
<span class="asset-class">${this.type} | Lv${this.evolutionLevel}</span>
</div>
<div class="asset-stats">
<span>💰 ${val.toFixed(2)} $DATA</span>
<span>📈 demand: ${this.demand}%</span>
<span>🌀 influence: ${this.influence.toFixed(2)}</span>
</div>
<div class="value-bar"><div class="value-fill" style="width: ${valuePercent}%; background: linear-gradient(90deg, #6e8eff, #c084fc);"></div></div>
<div class="asset-actions">
<button class="trade" data-id="${this.id}" data-action="trade">⟳ TRADE</button>
<button class="primary" data-id="${this.id}" data-action="merge">⚡ MERGE</button>
<button class="sell" data-id="${this.id}" data-action="evolve">🌀 EVOLVE</button>
</div>
</div>
`;
}
}
// ------------- GLOBAL MARKET STATE -------------
let dataAssets = [];
let totalTrades = 0;
let marketCycle = 0;
let liquidityPool = 1000; // abstract liquidity
let logEntries = [];
// helper: escape html
function escapeHtml(str) {
return str.replace(/[&<>]/g, function(m) {
if(m === '&') return '&';
if(m === '<') return '<';
if(m === '>') return '>';
return m;
});
}
function addLog(message, isTrade = false) {
let time = new Date().toLocaleTimeString([], { hour:'2-digit', minute:'2-digit', second:'2-digit' });
logEntries.unshift({ time, msg: message });
if (logEntries.length > 45) logEntries.pop();
renderLog();
if (isTrade) totalTrades++;
updateMetrics();
}
function renderLog() {
const logDiv = document.getElementById('logContainer');
logDiv.innerHTML = logEntries.slice(0, 32).map(entry =>
`<div class="log-entry"><small>[${entry.time}]</small> ${escapeHtml(entry.msg)}</div>`
).join('');
if (logEntries.length === 0) logDiv.innerHTML = '<div class="log-entry">⚡ waiting for market actions...</div>';
}
// update metrics & economy state
function updateMetrics() {
document.getElementById('totalAssets').innerText = dataAssets.length;
let totalValue = dataAssets.reduce((sum, a) => sum + a.getCurrentValue(), 0);
document.getElementById('totalValue').innerText = totalValue.toFixed(1);
document.getElementById('liquidity').innerText = Math.floor(liquidityPool);
document.getElementById('tradeCount').innerText = totalTrades;
let avgDemand = dataAssets.length ? dataAssets.reduce((s,a)=> s + a.demand,0)/dataAssets.length : 0;
let stateLabel = avgDemand > 65 ? "🔥 BULL MARKET" : (avgDemand > 40 ? "📈 GROWING" : "🌊 LIQUID");
if (dataAssets.length > 12) stateLabel = "⚡ HIGH FREQUENCY ECONOMY";
document.getElementById('economyState').innerText = stateLabel;
}
// render all data assets into exchange view
function renderMarket() {
const container = document.getElementById('dataStream');
if (!dataAssets.length) {
container.innerHTML = `<div style="text-align:center; padding:2rem; color:#6c7a9e;">🌀 No data assets yet — spawn your first data object to start the economy</div>`;
return;
}
container.innerHTML = dataAssets.map(asset => asset.toCardHTML()).join('');
// rebind buttons
document.querySelectorAll('.trade').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
let id = btn.getAttribute('data-id');
let asset = dataAssets.find(a => a.id === id);
if (asset) initiateTrade(asset);
});
});
document.querySelectorAll('[data-action="merge"]').forEach(btn => {
btn.addEventListener('click', (e) => {
let id = btn.getAttribute('data-id');
let asset = dataAssets.find(a => a.id === id);
if (asset) initiateMerge(asset);
});
});
document.querySelectorAll('[data-action="evolve"]').forEach(btn => {
btn.addEventListener('click', (e) => {
let id = btn.getAttribute('data-id');
let asset = dataAssets.find(a => a.id === id);
if (asset) {
asset.evolve();
addLog(`🌀 ${asset.name} evolved → value ${asset.getCurrentValue().toFixed(2)} $DATA (influence↑)`);
renderMarket();
updateMetrics();
}
});
});
}
// trade logic: select random partner or best match
function initiateTrade(asset) {
if (dataAssets.length < 2) {
addLog(`⚠️ cannot trade ${asset.name} — need at least 2 assets in economy`);
return;
}
let partners = dataAssets.filter(a => a.id !== asset.id);
if (partners.length === 0) return;
let partner = partners[Math.floor(Math.random() * partners.length)];
let tradeResult = asset.tradeWith(partner);
if (tradeResult) {
addLog(`🤝 TRADE: ${asset.name} ⇄ ${partner.name} | synergy gain +${tradeResult.gain.toFixed(2)} | values → ${asset.getCurrentValue().toFixed(2)} / ${partner.getCurrentValue().toFixed(2)}`, true);
liquidityPool += tradeResult.gain * 0.4;
// update demand drift after trade
asset.updateDemand(0.8);
partner.updateDemand(0.8);
renderMarket();
updateMetrics();
} else {
addLog(`❌ trade failed between ${asset.name} and ${partner.name} — value mismatch`);
}
}
// MERGE: creates new asset from two, deletes originals
function initiateMerge(asset) {
if (dataAssets.length < 2) {
addLog(`⚠️ merge requires at least two assets`);
return;
}
let partners = dataAssets.filter(a => a.id !== asset.id);
if (partners.length === 0) return;
let partner = partners[Math.floor(Math.random() * partners.length)];
let newAsset = asset.mergeWith(partner);
// remove old assets
dataAssets = dataAssets.filter(a => a.id !== asset.id && a.id !== partner.id);
dataAssets.push(newAsset);
addLog(`✨ MERGE EVENT: ${asset.name} + ${partner.name} → created "${newAsset.name}" (value ${newAsset.getCurrentValue().toFixed(2)})`, true);
liquidityPool += newAsset.getCurrentValue() * 0.2;
renderMarket();
updateMetrics();
}
// spawn new random data asset (living object)
function spawnDataAsset() {
const assetTypes = ['sensor', 'behavioral', 'predictive', 'demographic', 'location', 'social', 'transactional'];
const prefixes = ['Flow', 'Vector', 'Node', 'Resonance', 'Echo', 'Aether', 'Flux', 'Morph'];
const suffixes = ['Data', 'Signal', 'Pattern', 'Essence', 'Strand', 'Core', 'Voxel'];
let type = assetTypes[Math.floor(Math.random() * assetTypes.length)];
let name = prefixes[Math.floor(Math.random() * prefixes.length)] + ' ' + suffixes[Math.floor(Math.random() * suffixes.length)];
let baseVal = 20 + Math.random() * 80;
let newAsset = new DataAsset(`asset_${Date.now()}_${Math.random()}`, name, type, baseVal);
dataAssets.push(newAsset);
addLog(`🌱 NEW DATA ASSET: ${name} (${type}) | base value ${baseVal.toFixed(1)} $DATA spawned in economy`);
renderMarket();
updateMetrics();
}
// market cycle: all assets update demand based on global pressure and random interactions
function simulateMarketCycle() {
marketCycle++;
let avgValue = dataAssets.length ? dataAssets.reduce((s,a)=> s + a.getCurrentValue(),0)/dataAssets.length : 0;
let marketHeat = Math.min(1.2, (avgValue / 120) * 1.5);
for (let asset of dataAssets) {
asset.updateDemand(marketHeat);
// random spontaneous mutation (smalltalk style message)
if (Math.random() < 0.12) {
asset.send('mutate');
addLog(`🧬 spontaneous evolution: ${asset.name} influence↑ value → ${asset.getCurrentValue().toFixed(2)}`);
}
}
// random trades between random assets (autonomous market)
if (dataAssets.length >= 2 && Math.random() < 0.45) {
let idx1 = Math.floor(Math.random() * dataAssets.length);
let idx2 = (idx1 + 1 + Math.floor(Math.random() * (dataAssets.length-1))) % dataAssets.length;
let a1 = dataAssets[idx1];
let a2 = dataAssets[idx2];
let result = a1.tradeWith(a2);
if (result) {
addLog(`🔄 AUTO-TRADE: ${a1.name} ⇄ ${a2.name} | value exchange +${result.gain.toFixed(2)}`, true);
liquidityPool += result.gain * 0.25;
}
}
renderMarket();
updateMetrics();
addLog(`📈 market cycle #${marketCycle}: demand shift, avg asset value ${avgValue.toFixed(1)} $DATA`);
}
// optional: background cycle every 8 seconds
let interval;
function startBackgroundCycle() {
if (interval) clearInterval(interval);
interval = setInterval(() => {
if (dataAssets.length > 0) {
simulateMarketCycle();
} else if (dataAssets.length === 0 && Math.random() < 0.3) {
spawnDataAsset(); // if empty, spawn seed asset
}
}, 8500);
}
// UI button handlers
document.getElementById('spawnAssetBtn').addEventListener('click', () => spawnDataAsset());
document.getElementById('simulateTradeBtn').addEventListener('click', () => simulateMarketCycle());
// initial seed assets — Smalltalk data economy foundation
function bootstrapEconomy() {
let seed1 = new DataAsset('seed1', 'Resonance Core', 'predictive', 62);
let seed2 = new DataAsset('seed2', 'Neural Drift', 'behavioral', 48);
let seed3 = new DataAsset('seed3', 'Echo Voxel', 'sensor', 35);
dataAssets = [seed1, seed2, seed3];
seed1.evolve();
seed2.updateDemand(12);
addLog(`🏛️ ECONOMY BOOTSTRAPPED — three initial data assets (living objects, message passing ready)`);
addLog(`💎 Each asset negotiates value, trades, merges — Smalltalk spirit inside browser`);
renderMarket();
updateMetrics();
startBackgroundCycle();
}
bootstrapEconomy();
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>SMALLTALK LIVING OBJECTS · Message Economy</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #0a0c16;
font-family: 'Inter', 'SF Mono', 'Fira Code', monospace;
height: 100vh;
overflow: hidden;
color: #eef2ff;
}
.app {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
/* header */
.header {
background: #080c18;
border-bottom: 1px solid #2a2e44;
padding: 0.8rem 1.5rem;
display: flex;
justify-content: space-between;
align-items: baseline;
flex-wrap: wrap;
backdrop-filter: blur(4px);
z-index: 10;
}
.title-section h1 {
font-size: 1.3rem;
font-weight: 500;
letter-spacing: -0.2px;
background: linear-gradient(135deg, #c0e0ff, #b87cff);
background-clip: text;
-webkit-background-clip: text;
color: transparent;
}
.title-section .sub {
font-size: 0.65rem;
color: #7a86b0;
font-family: monospace;
margin-top: 3px;
}
.badge {
background: #1a1f32;
padding: 0.2rem 0.9rem;
border-radius: 40px;
font-size: 0.7rem;
font-weight: 500;
border-left: 3px solid #8a6eff;
}
/* two-panel living object ecosystem */
.universe {
display: flex;
flex: 1;
overflow: hidden;
gap: 1px;
background: #0e121e;
}
/* left: object society (mailboxes & assets) */
.object-society {
flex: 2;
background: #0c0f1c;
border-radius: 0 16px 16px 0;
display: flex;
flex-direction: column;
overflow: hidden;
margin: 0.5rem 0 0.5rem 0.5rem;
box-shadow: 0 4px 14px rgba(0,0,0,0.5);
}
.society-header {
background: #11172a;
padding: 0.6rem 1rem;
font-size: 0.75rem;
font-weight: 600;
border-bottom: 1px solid #262d48;
display: flex;
justify-content: space-between;
align-items: center;
}
.asset-stream {
flex: 1;
overflow-y: auto;
padding: 0.8rem;
display: flex;
flex-direction: column;
gap: 12px;
}
/* living asset card */
.living-asset {
background: #10172c;
border-radius: 20px;
padding: 0.9rem 1rem;
border-left: 4px solid #6a8eff;
transition: 0.1s ease;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
animation: fadeSlide 0.2s ease;
}
.living-asset:hover {
background: #16203a;
transform: translateX(3px);
}
.asset-header {
display: flex;
justify-content: space-between;
align-items: baseline;
flex-wrap: wrap;
margin-bottom: 10px;
}
.asset-name {
font-weight: 700;
font-size: 1rem;
color: #cadaff;
}
.asset-evolution {
background: #202842;
padding: 2px 10px;
border-radius: 30px;
font-size: 0.65rem;
font-weight: 600;
}
.asset-stats {
display: flex;
gap: 1rem;
font-size: 0.7rem;
color: #9aa7ce;
margin-bottom: 10px;
flex-wrap: wrap;
}
.value-bar-bg {
background: #0a0e1c;
border-radius: 20px;
height: 5px;
width: 100%;
margin: 6px 0;
}
.value-fill {
background: linear-gradient(90deg, #5e7eff, #c07cff);
width: 0%;
height: 5px;
border-radius: 20px;
transition: width 0.25s;
}
.mailbox-badge {
font-size: 0.6rem;
background: #191f36;
display: inline-block;
padding: 2px 8px;
border-radius: 20px;
margin-top: 5px;
}
.asset-actions {
display: flex;
gap: 8px;
margin-top: 12px;
flex-wrap: wrap;
}
button {
background: #202842;
border: none;
color: #dae2ff;
font-size: 0.7rem;
padding: 5px 12px;
border-radius: 40px;
cursor: pointer;
font-family: monospace;
font-weight: 500;
transition: 0.05s linear;
}
button.primary {
background: #3a4a82;
}
button.primary:hover {
background: #5f7bc2;
}
button.message-btn {
background: #2a3355;
}
/* right panel: world brain + message log */
.world-panel {
flex: 1.2;
background: #0a0d1a;
display: flex;
flex-direction: column;
gap: 6px;
padding: 0.5rem 0.5rem 0.5rem 0;
overflow: hidden;
}
.card {
background: #0e1324;
border-radius: 20px;
padding: 0.8rem;
border: 1px solid #20273e;
}
.metrics {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 8px;
}
.metric {
background: #0a0f1e;
padding: 8px;
border-radius: 16px;
text-align: center;
}
.metric-label {
font-size: 0.6rem;
color: #7c88b0;
}
.metric-value {
font-size: 1.3rem;
font-weight: 700;
color: #d9e6ff;
}
.message-log {
flex: 1;
overflow-y: auto;
font-size: 0.68rem;
font-family: monospace;
background: #080c18;
border-radius: 16px;
padding: 0.6rem;
}
.log-entry {
padding: 6px 0;
border-bottom: 1px solid #1a1f34;
color: #c4d0f0;
}
.log-entry small {
color: #6f7caa;
}
.world-stats {
font-size: 0.7rem;
display: flex;
justify-content: space-between;
margin-top: 6px;
}
@keyframes fadeSlide {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
::-webkit-scrollbar {
width: 4px;
}
::-webkit-scrollbar-track {
background: #0a0e1c;
}
::-webkit-scrollbar-thumb {
background: #33406e;
}
</style>
</head>
<body>
<div class="app">
<div class="header">
<div class="title-section">
<h1>☯ SMALLTALK · LIVING OBJECT SOCIETY ☯</h1>
<div class="sub">message passing · mailboxes · autonomous decision · object-driven economy</div>
</div>
<div class="badge">📬 ASYNCHRONOUS MESSAGES | ACTOR MODEL</div>
</div>
<div class="universe">
<!-- LEFT: living objects with mailboxes -->
<div class="object-society">
<div class="society-header">
<span>📀 LIVING DATA ASSETS — each has mailbox, autonomous think()</span>
<span style="font-size:0.6rem;">✨ objects send messages, decide how to respond</span>
</div>
<div id="assetContainer" class="asset-stream">
<div style="text-align:center; padding:2rem; color:#6a77a0;">🌀 spawning object universe ...</div>
</div>
</div>
<!-- RIGHT: world brain & message chronicle -->
<div class="world-panel">
<div class="card">
<div class="metrics">
<div class="metric"><div class="metric-label">LIVING OBJECTS</div><div class="metric-value" id="assetCount">0</div></div>
<div class="metric"><div class="metric-label">TOTAL MESSAGES</div><div class="metric-value" id="msgCount">0</div></div>
<div class="metric"><div class="metric-label">ECONOMY VALUE</div><div class="metric-value" id="totalValue">0</div></div>
<div class="metric"><div class="metric-label">WORLD TICK</div><div class="metric-value" id="tickCount">0</div></div>
</div>
<div class="world-stats">
<span>📨 autonomous message network</span>
<span class="badge-rank" id="universeState">🌱 living</span>
</div>
</div>
<div class="card" style="flex: 1; display: flex; flex-direction: column; overflow: hidden;">
<div style="font-size:0.7rem; margin-bottom:6px;">📡 OBJECT MESSAGE LOG · universal mailbox</div>
<div id="messageLog" class="message-log">
<div class="log-entry">📬 SMALLTALK UNIVERSE ONLINE</div>
<div class="log-entry">⚡ assets communicate via Message objects · autonomous think() loops</div>
</div>
</div>
<div style="display: flex; gap: 6px; justify-content: flex-end; padding: 0 0 6px 0;">
<button id="spawnBtn" style="background:#2f3a6a;">✨ SPAWN LIVING OBJECT</button>
<button id="triggerTickBtn" style="background:#2a3a5a;">🔄 MANUAL WORLD TICK</button>
</div>
</div>
</div>
</div>
<script>
// --------------------------------------------------------------
// TRUE SMALLTALK-INSPIRED OBJECT SOCIETY
// - Message objects (rich communication)
// - Every asset has a mailbox
// - autonomous think() processes messages and decides actions
// - send() sends asynchronous messages to other objects
// - world scheduler ticks all objects
// --------------------------------------------------------------
// ----- 1. MESSAGE OBJECT (rich, typed, timestamped) -----
class Message {
constructor(type, sender, target, payload = {}) {
this.type = type; // "trade", "merge", "mutate", "ping", "evolve"
this.sender = sender;
this.target = target;
this.payload = payload;
this.timestamp = Date.now();
this.id = Math.random().toString(36).substring(2, 8);
}
describe() {
return `📨 ${this.type} | from: ${this.sender?.name || 'world'} → ${this.target?.name || '?'}`;
}
}
// ----- 2. LIVING DATA ASSET with MAILBOX + AUTONOMY -----
let globalAssetId = 0;
class LivingAsset {
constructor(name, type, baseValue) {
this.id = ++globalAssetId;
this.name = name || `Object_${this.id}`;
this.type = type || ['sensor', 'cognitive', 'behavior', 'predictive', 'resonance'][Math.floor(Math.random() * 5)];
this.baseValue = baseValue || 30 + Math.random() * 70;
this.demand = 40 + Math.floor(Math.random() * 50);
this.influence = 0.6 + Math.random() * 1.2;
this.evolutionLevel = 0;
this.mailbox = []; // queue of Message objects
this.tradeHistory = [];
this.isActive = true;
}
// calculate dynamic value
getCurrentValue() {
let demandFactor = this.demand / 100;
let evolutionBonus = 1 + (this.evolutionLevel * 0.18);
let influenceBonus = this.influence;
let val = this.baseValue * demandFactor * influenceBonus * evolutionBonus;
return Math.max(3, Math.floor(val * 100) / 100);
}
// receive a message (push to mailbox)
receive(message) {
if (!this.isActive) return;
this.mailbox.push(message);
addToWorldLog(`📥 ${this.name} received [${message.type}] from ${message.sender?.name || 'WORLD'}`, false);
}
// process mailbox: handle each message based on type
processMessages() {
while (this.mailbox.length > 0 && this.isActive) {
const msg = this.mailbox.shift();
switch (msg.type) {
case "trade":
this.handleTradeMessage(msg);
break;
case "merge":
this.handleMergeMessage(msg);
break;
case "mutate":
this.evolve(true);
addToWorldLog(`🧬 ${this.name} mutated via message (influence↑)`, false);
break;
case "ping":
addToWorldLog(`💬 ${this.name} received ping from ${msg.sender?.name || '?'}`, false);
break;
case "evolve":
this.evolve(false);
break;
default:
addToWorldLog(`❓ ${this.name} unknown message type: ${msg.type}`, false);
}
}
}
// handle trade message: trading with another asset (sender)
handleTradeMessage(msg) {
const partner = msg.sender;
if (!partner || !partner.isActive) return;
let myVal = this.getCurrentValue();
let otherVal = partner.getCurrentValue();
if (myVal <= 0 || otherVal <= 0) return;
let synergy = (this.influence + partner.influence) / 2;
let gain = Math.floor(Math.min(myVal, otherVal) * 0.12 * synergy);
this.baseValue += gain * 0.28;
partner.baseValue += gain * 0.28;
this.influence = (this.influence + partner.influence) / 2;
partner.influence = (this.influence + partner.influence) / 2;
this.tradeHistory.push(`traded with ${partner.name} +${gain.toFixed(1)}`);
partner.tradeHistory.push(`traded with ${this.name} +${gain.toFixed(1)}`);
addToWorldLog(`🤝 TRADE: ${this.name} ⇄ ${partner.name} | gain +${gain.toFixed(1)} | values → ${this.getCurrentValue().toFixed(1)} / ${partner.getCurrentValue().toFixed(1)}`, true);
if (Math.random() < 0.2) this.evolve(false);
if (Math.random() < 0.2) partner.evolve(false);
}
// handle merge message: merge with sender to create a new asset
handleMergeMessage(msg) {
const partner = msg.sender;
if (!partner || !partner.isActive) return;
let mergedName = `(${this.name}⨁${partner.name})`;
let mergedBase = (this.baseValue + partner.baseValue) * 1.25;
let mergedInfluence = (this.influence + partner.influence) * 0.7 + 0.5;
let mergedDemand = Math.floor((this.demand + partner.demand) / 2) + 12;
const newAsset = new LivingAsset(mergedName, 'hybrid', mergedBase);
newAsset.influence = Math.min(mergedInfluence, 3.2);
newAsset.demand = Math.min(mergedDemand, 98);
newAsset.evolutionLevel = Math.max(this.evolutionLevel, partner.evolutionLevel) + 1;
addToWorldLog(`✨ MERGE: ${this.name} + ${partner.name} → created "${newAsset.name}" (value ${newAsset.getCurrentValue().toFixed(1)})`, true);
// mark old assets as inactive (to be removed by world)
this.isActive = false;
partner.isActive = false;
// schedule new asset addition via world
window.__pendingMergeAsset = newAsset;
}
evolve(fromMessage = false) {
this.evolutionLevel++;
this.influence = Math.min(this.influence * 1.12, 3.0);
this.baseValue = this.baseValue * 1.06;
addToWorldLog(`🌀 ${this.name} evolved → Lv${this.evolutionLevel} | value ${this.getCurrentValue().toFixed(1)}`, false);
}
// autonomous decision: objects decide to send messages
think(worldContext, allAssets) {
if (!this.isActive) return;
this.processMessages(); // first handle incoming mail
// autonomous behaviors: chance to send a message to another random asset
if (allAssets.length > 1 && Math.random() < 0.22) {
let candidates = allAssets.filter(a => a !== this && a.isActive);
if (candidates.length) {
let target = candidates[Math.floor(Math.random() * candidates.length)];
// decide which message type to send
let msgType = Math.random() < 0.6 ? "trade" : (Math.random() < 0.5 ? "mutate" : "ping");
this.send(msgType, target, { valueHint: this.getCurrentValue() });
}
}
// update demand based on "market mood" (abstract)
let moodShift = (Math.random() - 0.5) * 9;
this.demand = Math.min(98, Math.max(12, this.demand + moodShift));
}
// send message to another asset (asynchronous)
send(messageType, targetAsset, payload = {}) {
if (!targetAsset || !targetAsset.isActive) return false;
const msg = new Message(messageType, this, targetAsset, payload);
targetAsset.receive(msg);
addToWorldLog(`📤 ${this.name} → ${targetAsset.name} : ${messageType}`, false);
return true;
}
// serialize for UI
toCardHTML() {
let val = this.getCurrentValue();
let demandPercent = this.demand;
let valuePercent = Math.min(100, (val / (this.baseValue * 2.2)) * 100);
let mailboxSize = this.mailbox.length;
return `
<div class="living-asset" data-id="${this.id}">
<div class="asset-header">
<span class="asset-name">📀 ${escapeHtml(this.name)}</span>
<span class="asset-evolution">${this.type} | Lv${this.evolutionLevel}</span>
</div>
<div class="asset-stats">
<span>💎 ${val.toFixed(2)} $VAL</span>
<span>📊 demand: ${this.demand}%</span>
<span>🌀 infl: ${this.influence.toFixed(2)}</span>
</div>
<div class="value-bar-bg"><div class="value-fill" style="width: ${valuePercent}%;"></div></div>
<div class="mailbox-badge">📬 mailbox: ${mailboxSize} pending message(s)</div>
<div class="asset-actions">
<button class="msg-trade" data-id="${this.id}" data-action="trade">🤝 SEND TRADE</button>
<button class="msg-merge" data-id="${this.id}" data-action="merge">⚡ SEND MERGE</button>
<button class="msg-mutate" data-id="${this.id}" data-action="mutate">🧬 SEND MUTATE</button>
</div>
</div>
`;
}
}
// ----- GLOBAL WORLD STATE -----
let livingAssets = [];
let totalMessageCount = 0;
let worldTickCounter = 0;
let globalLog = [];
function escapeHtml(str) { return String(str).replace(/[&<>]/g, function(m){ if(m==='&') return '&'; if(m==='<') return '<'; if(m==='>') return '>'; return m;}); }
function addToWorldLog(message, isMessageEvent = false) {
let time = new Date().toLocaleTimeString([], { hour:'2-digit', minute:'2-digit', second:'2-digit' });
globalLog.unshift({ time, msg: message });
if (globalLog.length > 65) globalLog.pop();
if (isMessageEvent) totalMessageCount++;
renderWorldLog();
updateWorldUI();
}
function renderWorldLog() {
const logDiv = document.getElementById('messageLog');
logDiv.innerHTML = globalLog.slice(0, 38).map(entry =>
`<div class="log-entry"><small>[${entry.time}]</small> ${escapeHtml(entry.msg)}</div>`
).join('');
if (globalLog.length === 0) logDiv.innerHTML = '<div class="log-entry">🌐 message universe silent...</div>';
}
function updateWorldUI() {
document.getElementById('assetCount').innerText = livingAssets.filter(a => a.isActive).length;
document.getElementById('msgCount').innerText = totalMessageCount;
let totalEco = livingAssets.reduce((sum, a) => sum + a.getCurrentValue(), 0);
document.getElementById('totalValue').innerText = totalEco.toFixed(1);
document.getElementById('tickCount').innerText = worldTickCounter;
let state = livingAssets.length > 8 ? "⚡ HIGH OBJECT DENSITY" : (livingAssets.length > 3 ? "🌿 GROWING SOCIETY" : "🌱 NASCENT UNIVERSE");
document.getElementById('universeState').innerText = state;
}
// render all assets to DOM
function renderAssetSociety() {
const container = document.getElementById('assetContainer');
const activeAssets = livingAssets.filter(a => a.isActive);
if (activeAssets.length === 0) {
container.innerHTML = `<div style="text-align:center; padding:2rem; color:#6a77a0;">🌀 no living objects — spawn one to start message economy</div>`;
return;
}
container.innerHTML = activeAssets.map(asset => asset.toCardHTML()).join('');
// attach button handlers dynamically
document.querySelectorAll('.msg-trade').forEach(btn => {
btn.addEventListener('click', (e) => {
let id = parseInt(btn.getAttribute('data-id'));
let asset = livingAssets.find(a => a.id === id && a.isActive);
if (asset) {
let partners = livingAssets.filter(a => a.isActive && a.id !== asset.id);
if (partners.length) {
let target = partners[Math.floor(Math.random() * partners.length)];
asset.send("trade", target);
} else { addToWorldLog(`⚠️ ${asset.name} cannot trade: no other active objects`, false); }
}
});
});
document.querySelectorAll('.msg-merge').forEach(btn => {
btn.addEventListener('click', (e) => {
let id = parseInt(btn.getAttribute('data-id'));
let asset = livingAssets.find(a => a.id === id && a.isActive);
if (asset) {
let partners = livingAssets.filter(a => a.isActive && a.id !== asset.id);
if (partners.length) {
let target = partners[Math.floor(Math.random() * partners.length)];
asset.send("merge", target);
} else { addToWorldLog(`⚠️ ${asset.name} needs another asset for merge`, false); }
}
});
});
document.querySelectorAll('.msg-mutate').forEach(btn => {
btn.addEventListener('click', (e) => {
let id = parseInt(btn.getAttribute('data-id'));
let asset = livingAssets.find(a => a.id === id && a.isActive);
if (asset) asset.send("mutate", asset);
});
});
}
// WORLD TICK: all assets think, process pending merges, clean dead
function worldTick() {
worldTickCounter++;
// before thinking, handle pending merge results
if (window.__pendingMergeAsset) {
livingAssets.push(window.__pendingMergeAsset);
window.__pendingMergeAsset = null;
}
// remove inactive assets
livingAssets = livingAssets.filter(a => a.isActive);
// each asset thinks (autonomous message sending & mailbox processing)
for (let asset of livingAssets) {
asset.think(worldTickCounter, livingAssets);
}
// post-think: handle any new merges scheduled
if (window.__pendingMergeAsset) {
livingAssets.push(window.__pendingMergeAsset);
window.__pendingMergeAsset = null;
}
livingAssets = livingAssets.filter(a => a.isActive);
renderAssetSociety();
updateWorldUI();
addToWorldLog(`⏲️ WORLD TICK #${worldTickCounter} — ${livingAssets.length} living objects, ${totalMessageCount} total messages`, false);
}
// spawn new living asset
function spawnLivingAsset() {
const names = ['Echo', 'Flux', 'Voxel', 'Nexus', 'Aether', 'Lumen', 'Morph', 'Strata', 'Cipher', 'Rune'];
const rName = names[Math.floor(Math.random() * names.length)] + (Math.floor(Math.random() * 100));
const types = ['cognitive', 'sensorium', 'predictor', 'resonator', 'weaver'];
const newAsset = new LivingAsset(rName, types[Math.floor(Math.random() * types.length)], 25 + Math.random() * 60);
livingAssets.push(newAsset);
addToWorldLog(`✨ NEW LIVING OBJECT: ${newAsset.name} (${newAsset.type}) | value ${newAsset.getCurrentValue().toFixed(1)}`, false);
renderAssetSociety();
updateWorldUI();
}
// autonomous interval (world ticks every 5 seconds)
let worldInterval;
function startWorldClock() {
if (worldInterval) clearInterval(worldInterval);
worldInterval = setInterval(() => {
if (livingAssets.length > 0 || Math.random() < 0.4) {
worldTick();
} else if (livingAssets.length === 0 && Math.random() < 0.5) {
spawnLivingAsset();
}
}, 5200);
}
// bootstrap with a few living objects (true object society)
function bootstrapUniverse() {
const seed1 = new LivingAsset('Resonance Core', 'resonator', 58);
const seed2 = new LivingAsset('Void Weaver', 'weaver', 44);
const seed3 = new LivingAsset('Aether Drift', 'cognitive', 39);
livingAssets = [seed1, seed2, seed3];
addToWorldLog(`📡 SMALLTALK UNIVERSE — three living objects with mailboxes. Objects send messages, process asynchronously.`, false);
addToWorldLog(`💡 each object has autonomous think() — they decide to trade, mutate or merge via messages`, false);
renderAssetSociety();
updateWorldUI();
startWorldClock();
}
// UI event binding
document.getElementById('spawnBtn').addEventListener('click', () => spawnLivingAsset());
document.getElementById('triggerTickBtn').addEventListener('click', () => worldTick());
bootstrapUniverse();
</script>
</body>
</html>
The full prototype is implemented in:
HTML
CSS
JavaScript
Key proof features:
asynchronous message system
object mailboxes
autonomous think() loops
merge and trade mechanics
world scheduler
real-time visualization
The provided source code demonstrates the complete working ecosystem.
- Conclusion
Smalltalk Living Object Society demonstrates that:
data can be modeled as autonomous message-driven agents rather than passive records.
By combining:
object messaging
economic value mechanics
browser execution
it becomes possible to create living information systems.
These systems behave less like databases and more like digital ecosystems.
The browser becomes not just an interface, but a runtime for evolving object societies.
Author
Peace Thabiwa
Founder — SAGEWORKS AI
Research areas:
AI architecture
living data systems
autonomous economic agents
browser-based simulations
Top comments (0)