Yes — it’s possible, and it’s a pretty natural extension if you’re willing to treat “documents” as a universal substrate and add a few missing pieces (identity, types, security, and interoperability). A document-CRDT gives you the hardest part for the web already: offline-first, concurrent edits, and deterministic convergence without central coordination.

    Here’s what it takes to turn a document CRDT system into a distributed object framework.

      1) Map “objects” onto CRDT-backed documents

        A distributed object framework needs:

          Object identity (stable IDs)

          Object state (fields / collections)

          Methods / behavior (logic)

          References (object graph edges)

          Consistency model (what clients can assume)

        A document CRDT can represent object state in at least two workable ways:

          A. “One object = one CRDT document”

            Each object is a CRDT map (or JSON-like tree). References are IDs.

              Pros: clean modularity, caching, per-object access control

              Cons: lots of small docs, cross-object transactions are tricky

          B. “Object graph = one CRDT document”

            All objects live inside a single CRDT tree (e.g., objects[id] = {...}).

              Pros: easy traversal, atomic multi-object edits (within one doc)

              Cons: access control and partial replication are harder

            In both cases, you end up with replicated stateful objects whose fields are CRDTs (registers, maps, sets, lists, counters).

      2) Add a type system on top of “generic JSON”

        Document CRDTs often operate on generic structures (text, maps, lists). A framework needs stronger semantics:

          Typed fields: counter, lww_register, mv_register, orset, rga_list, etc.

          Schema evolution: forward/backward compatible changes

          Validation: reject/ignore invalid operations deterministically

        Key point: validation must be pure and deterministic, or else replicas can diverge. A common approach:

          Accept ops structurally, but mark invalid ones as “tombstoned” or no-ops consistently.

          Or restrict the op language so invalid states are unrepresentable.

      3) Decide how “methods” work (commands vs events vs reducers)

        Objects aren’t just state; they have behavior. You can do this a few ways:

        Option 1: Local-first reducers (“pure functions on CRDT state”)

          Clients call methods that compile into CRDT ops.

            Best for: collaborative apps, offline-first UX

            Challenge: side effects (payments, emails) can’t be “pure CRDT”

        Option 2: Event-sourced commands + CRDT materialization

          Methods emit events; state is derived (possibly into CRDT structures).

            Best for: auditable systems, complex workflows

            Challenge: making event processing deterministic across replicas

        Option 3: Capability-secured remote procedures + replicated state

          “Methods” are RPCs to a service, but state sync remains CRDT-based.

            Best for: side effects, compliance, authority

            Challenge: you lose some “fully decentralized” feel

          A practical web framework often blends these:

            CRDT for shared UI state

            Server authority for side effects / invariants

      4) Handle references, loading, and partial replication

        A distributed object framework needs “webby” mechanics:

          Links: object A references object B by ID (like URLs)

          Resolvers: fetch/sync on demand

          Partial replication: don’t sync everything, only what you need

          Indexing/querying: CRDT state is not automatically query-friendly

        Common solutions:

          Maintain materialized indexes (also CRDTs or derived views)

          Use subscriptions by object ID and by query

          Allow “views” that are re-computable from state

      5) Security: auth is not optional

        CRDT convergence doesn’t solve “who is allowed to do what.”

        You typically need:

          Per-operation authentication (signed ops)

          Authorization rules (ACLs or capabilities)

          Encryption (at rest and ideally end-to-end)

          Key rotation / revocation story

        Two patterns:

          ACL / policy server

            Server filters ops; clients can’t apply unauthorized ops.

              Easier revocation

              More centralized

          Capability-based (object capabilities)

            Possession of an unforgeable token/key grants rights.

              More decentralized

              Revocation is harder; often time-bounded capabilities help

      6) Cross-object invariants and “transactions”

        CRDTs are great when operations commute. But object frameworks often need invariants:

          “Balance can’t go below 0”

          “Username must be unique”

          “Move item from A to B exactly once”

        You can’t get all invariants in a fully concurrent CRDT world without tradeoffs.

        Your options:

          Design invariants as monotonic / commutative (best case)

          Use escrow / bounded counters for “can’t exceed X” constraints

          Introduce coordination (locks/leases/consensus) for the hard cases

          Accept eventual violation + repair (compensating actions)

        A good framework makes this explicit: most objects are coordination-free; some operations require coordination.

      7) Interop: make “object ops” a portable protocol

        To be a web framework rather than an app-specific system, you want:

          A canonical op format (binary or JSON)

          Stable IDs (UUID/ULID + actor IDs + Lamport/time)

          Versioned schemas

          Deterministic merge rules

        If the protocol is stable, any web client can participate.

      What you get if you do this well

        Offline-first distributed objects with “real-time” collaboration

        Conflict-free shared state by default

        Multi-device sync “for free”

        A nice programming model: “objects that just converge”

      The big pitfalls

        Performance (metadata growth, tombstones, causal history)

        Query/index complexity (CRDT state ≠ database query engine)

        Security/revocation (especially end-to-end)

        Invariants (some business rules need coordination)

        UX surprises (eventual consistency is user-visible unless designed around)

      A concrete “minimal architecture” that works

        Each object is a CRDT document (map/tree) with typed fields

        Operations are signed and versioned

        Clients run pure reducers that produce CRDT ops

        A relay/server provides:

          discovery + transport (WebSocket/WebRTC)

          authorization filtering

          persistence

          optional coordination endpoints for “hard” operations

        Derived indexes/views for queries

      If you tell me what kind of “distributed objects” you mean (UI components? shared domain models like tasks/files? or general-purpose remote objects with methods and side effects?), I can sketch a more specific design (data model + op format + method semantics) that fits that use case.