Build parameters for container environment used can be found at Richardn2002/claude-code.
This README is completely written by me, composed mainly of prompts I sent to Claude. There have been, of course, more prompts requesting bug fixes and minor adjustments, which I will omit here.
Name for the project is from "connection complex", with "complex" being a tribute to STAND ALONE COMPLEX.
The project is named "conplex", an experiment on "what if in a messaging app, much more emphasis is put on viewing, managing and discovering connections between messages than the temporal aspects".
In addition to regular actions one can do in an instant messaging app, i.e., sending, editing messages, joining servers, users can additonally create and manage manual connections, just like managing edges between vertices in a graph, between messages, both during and after messages themselves are being created. These connections will affect how user browse through messages and how the interface displays them. Created connections can be either private or shared to others, subject to a traditional permission and visibility system, just like messages. "'Connections' and 'messages' are equally important" is the key.
Assume users are very enthusiastic about creating connections between messages, then there will be many moments they realize some new messages have connections to some past messages, and they would like to promptly record on the app these connections. Thus the connection creating flow must be as easy as possible, and locating past messages with a faint memory should also be easy. A search system that can locate messages given any snippet is a good start.
Still, this is a messaging app where users submit new messages and interact in real time. Users should still be able to learn what's new since the last time they check relatively easily. As initially mentioned, I want to reduce the emphasis on the temporal aspects, so instead of only being able to mark messages as "read" as they walk down a "chain", they should be able to set read/unread status of any message freely, as in email software.
Only a prototype is needed as of now. Do NOT consider any networking, just make a frontend interface that assumes a user is logged in, displaying static test data.
As this concept is highly experimental and unconventional, please frequently PAUSE AND ASK FOR MY INPUT whereever there seems to be multiple interpretations of this spec/multiple possible design choices.
The interface is also unconventional in that the users will browse and navigate their messages in a 3D space (with fixed camera orientation though). This is inspired by how many sci-fi/cyberpunk fictions depict information in the cyberspace. The messages most related to the user will mostly be located in the vertical plane most close to the camera, spreading out, while other messages will be located deeper "into the screen". User can move the camera in all of the 3 directions.
A chain/group of messages may be closely stacked together along the depth direction for organization, expanding on request.
Overlaying the 3D view is a 2D HUD interface with showing additional info and controls, with some elements from a traditional chat interface, for example an input area. User should intuitively figure out how to create new messages/connections.
Naturally, right clicking on messages or connections will open up dropdowns with edit options and info. Messages should be draggable
It is mainly a graph, with nodes and edges. Nodes mainly come in two types, "virtual" and "concrete".
"Virtual" nodes are those which help organizing messages, for example,
- "Send a message in #general channel" would be "create a message that has a connection to the #general virtual node" in this app.
- "Put these messages into a folder" would be "create a virtual node with the folder name and connect all messages to it" in this app.
"Concrete" nodes are those actually associated with data, i.e., message bodies.
It should be clear by now that "replying to a message" in this app is simply, "create a message, and create a connection to the message one wants to reply to".
As this is only a prototype, make up two local files, one in JSON containing all message and connection data, the other one also in JSON that can completely reproduce the view in the app, for example including camera location and locations for all objects.
A environment with vscode, rustup, rust (including rust-analyzer and standard tools), clippy, cargo, sccache, mold, has already been prepared. This prototype will be in Rust.
Do NOT use serde for json serialization and deserialization, it is too bloated. Use nanoserde instead.
Use miniquad for window creation and rendering special objects. Use egui for basic UI elements. egui-miniquad for making the two work together. Hint is scaling UI elements according to a perspective matrix can create the depth effect pretty easily.
glam can be used for 3D rendering related math.
PAUSE AND ASK FOR INPUT before introducing any other library. REMEMBER to consult latest documentations as Rust libraries tend to evolve fast. And apparently make sure the whole project compiles, with neither the compiler nor clippy complaining.
I am very satisfied with the current progress, it is close to what I imagined, yet by playing with it I realize problems I have not anticipated.
The biggest one is that we may need to rethink about layers. I do think the general idea is fine, depth is a good away to still keep some temporal aspects in this app, pushing older messages to the back to reduce clutter, while still accessble if one wants to; and it gives the sci-fi cyberspace vibes. However, it is really unclear to the user "which layer" is they currently operating on. Clicks may fall through and land on unexpected messages, and despite the color differences there are still a lot of messages in the view.
I am thinking about what if we introduce a concept of "current active layer". Basically the z direction will be segmented into uniform intervals, where the "snap-to" values of depths are the middle points of these intervals. At every single time, only messages within a segment will be "active". By moving along the z direction, different segments will become active.
Then, only active messages can be selected by the mouse. Right click and drag shall create a selection box to select multiple messages active, and then one can move them together. The force algorithm should only consider messages in the active layer. Neither inactive messages move, nor inactive messages apply force on active messages.
As virtual nodes are for organization, they should not have a temporal aspect. Make them always keep a same depth away from the camera, and they are always considered active. During the force algorithm, they apply force to active messages, but they themselves never move by force.
Now that we have the concept of an active layer, we need to have strong user experience conveying this concept. Make active messages stand out among inactive ones, dimming all others (while still keep the "further away, dimmer" effect). At the bottom of the left sidebar, place a scrolling list with entries, representing layers. One entry will be highlighted at any time, representing the current layer. Clicking on the entries of the list also navigates. Remember to turn off force mode when navigating between layers to prevent confusion.
Also, never make any message suddenly disappear. Currently when the camera is at a certain position, messages with depth above a threshold will be hidden instantly, which is very confusing. Instead figure out the math to make them keep enlarging and getting more and more transparent as they go towards the camera, and gradually go invisible. This creates a "traveling through messages after messages" effect.
Test data should be more representative of actual conversations: instead of a web of messages, more reasonably there should mostly be "chains" of messages representing a discussion around a topic, with one end connected to a virtual node representing a "channel", and the other end free floating, waiting for further replies. There will be one or two connections between messages from two "chain"s, representing how users find connections between messages. And for virtual nodes like "saved", usually one message along a chain will be connected to them, instead of every one of the messages in a same chain.