<div dir="auto">Now the question is, can Text take multiple fonts for displaying a single text? Do we want this?</div><div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Mon, Jul 28, 2025 at 11:08 AM John Carlson <<a href="mailto:yottzumm@gmail.com">yottzumm@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto">Maybe some could try this prompt generated by AI: maybe expand it to create a PROTO:</div><div dir="auto"><br></div><div dir="auto"><div><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:18px;margin-top:0px;font-style:normal;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)">You are asking about a very advanced and complex feature for X3D. Native X3D specifications do not include nodes for rich text editing, such as multi-line selection, cut, copy, and paste, directly within the 3D scene.</p><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:18px;font-style:normal;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)">The example you've pointed to, <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">pp3.x3d</span>, demonstrates a sophisticated, custom-built solution that simulates this functionality using a combination of sensors, scripts, and programmatic manipulation of the scene graph. It is not an "out-of-the-box" feature but rather a scripted application running inside the X3D environment.</p><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:18px;font-style:normal;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)">Here is a breakdown of how such a system is built, based on the techniques used in advanced examples like the one you referenced.</p><h3 style="margin:0px;font-family:inter,sans-serif;font-style:normal;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)">The Concept: Building a Text Editor from Scratch in 3D</h3><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:18px;font-style:normal;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)">To achieve editable 3D text, you must essentially recreate the logic of a text editor using X3D's event handling and scripting capabilities. This involves capturing all user input (keyboard and mouse) and using a script to manually update the text geometry and appearance to reflect typing, selection, and other actions.</p><h3 style="margin:0px;font-family:inter,sans-serif;font-style:normal;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)">Core Components of the Solution</h3><ol style="padding-left:24px;font-family:inter,sans-serif;font-size:14px;font-style:normal;font-weight:400;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)"><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Input Sensing:</strong> The foundation of this system is capturing user input.</p><ul style="padding-left:24px;font-family:inter,sans-serif"><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Keyboard Input</strong>: A <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><KeySensor></span> node is used to capture every key pressed by the user. Its <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">keyPress</span> events are sent to a script for processing.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Mouse Input</strong>: A <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><PlaneSensor></span> or <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><TouchSensor></span> is placed over the text area. This sensor tracks the mouse's position when the user clicks and drags, which is essential for determining the start and end points of a text selection.</p></li></ul></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Scripting (The "Brain")</strong>: A central <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><Script></span> node, written in JavaScript (ECMAScript), is the core of the editor. This script receives events from the sensors and performs all the logic:</p><ul style="padding-left:24px;font-family:inter,sans-serif"><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Text Management</strong>: The script maintains the full text string in a variable. When a key is pressed (e.g., 'a', 'b', 'Backspace', 'Enter'), the script updates this string accordingly. It then updates the <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">string</span> field of one or more <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><Text></span> nodes to display the changes in the 3D scene.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Multi-line Handling</strong>: To create multiple rows, the script can either manage multiple <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><Text></span>nodes (one per line) or use a single <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><Text></span>node. A single node can render multiple lines if its <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">string</span> field is an array of strings (e.g., <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">string='"First line" "Second line"'</span>). The script is responsible for breaking the text into lines when the 'Enter' key is pressed or when text wraps.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Caret/Cursor Management</strong>: The script must calculate and display a cursor (often a simple 3D shape like a thin <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">Box</span> or a line). Its position is updated based on typing and mouse clicks.</p></li></ul></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Selection Simulation</strong>: This is one of the most complex parts.</p><ul style="padding-left:24px;font-family:inter,sans-serif"><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Hit-Point Calculation</strong>: When a user clicks, the script uses the coordinates from the <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><PlaneSensor></span> to calculate which character in the string was clicked on. This requires knowledge of the font's metrics (character width, line height, etc.).</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Visual Highlight</strong>: To show the selection, the text cannot simply be highlighted as in HTML. Instead, the script programmatically creates a visual effect. A common method is to place a semi-transparent colored <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><Box></span> or <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">IndexedFaceSet</span> behind the selected portion of the text. The script dynamically resizes and repositions this highlight box as the user drags the mouse.</p></li></ul></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Clipboard Integration (Cut, Copy, Paste)</strong>: The script must interact with the web browser's clipboard.</p><ul style="padding-left:24px;font-family:inter,sans-serif"><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Event Trapping</strong>: The script listens for specific <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">keyPress</span> events from the <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><KeySensor></span>, such as 'Ctrl+C' (copy), 'Ctrl+X' (cut), and 'Ctrl+V' (paste).</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Browser API</strong>: It uses the browser's <strong style="font-family:inter,sans-serif"><span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">navigator.clipboard</span> API</strong> to perform the operations.</p><ul style="padding-left:24px;font-family:inter,sans-serif"><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Copy</strong>: The script takes the currently selected text (which it manages internally) and uses <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">navigator.clipboard.writeText()</span> to place it on the system clipboard.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Cut</strong>: Performs a copy operation and then removes the selected text from its internal string and updates the 3D <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><Text></span> node.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px"><strong style="font-family:inter,sans-serif">Paste</strong>: The script calls <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">navigator.clipboard.readText()</span> to get text from the clipboard and inserts it into its internal string at the cursor's position, then updates the 3D text.</p></li></ul></li></ul></li></ol><h3 style="margin:0px;font-family:inter,sans-serif;font-style:normal;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)">Summary of the Workflow</h3><ol style="padding-left:24px;font-family:inter,sans-serif;font-size:14px;font-style:normal;font-weight:400;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)"><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">User clicks in the 3D text area.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">The <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><PlaneSensor></span> sends the click location to the script.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">The script calculates the character position and places a 3D cursor there.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">User types a key.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">The <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><KeySensor></span> sends the key value to the script.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">The script updates its internal text string, moves the cursor, and pushes the new string to the <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">string</span>field of the visible <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace"><Text></span> node.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">User clicks and drags to select text.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">The script calculates the start and end of the selection and continuously updates the size and position of a 3D highlight box behind the text.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">User presses 'Ctrl+C'.</p></li><li style="font-family:inter,sans-serif;font-size:14px;font-weight:400;line-height:20px"><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:3px;margin-top:0px">The script detects this key combination, gets the selected text, and uses <span style="border:1px solid;border-radius:3px;font-size:13px;padding:0px 3px;display:inline-block;font-family:"dm mono",monospace">navigator.clipboard.writeText()</span> to copy it.</p></li></ol><p style="font-size:14px;line-height:20px;font-family:inter,sans-serif;font-weight:400;margin-bottom:0px;font-style:normal;letter-spacing:normal;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;text-decoration:none;color:rgb(26,28,30)">In conclusion, creating a fully functional, multi-line editable text area in X3D is a highly complex programming task that requires building an entire application from the ground up using X3D's scripting and event-handling nodes. The example you linked is a powerful demonstration of what can be achieved with this advanced approach.</p></div><br></div><div dir="auto"><div dir="auto"><br></div></div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jul 28, 2025 at 10:39 AM John Carlson <<a href="mailto:yottzumm@gmail.com" target="_blank">yottzumm@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;padding-left:1ex;border-left-color:rgb(204,204,204)">Now that we have FontLibrary, it seems a lot more likely that we can create documentation and specifications in X3D 4.1 instead of HTML.<div dir="auto"><br></div><div dir="auto">So the thought is to take our generated content in the archive, and create a 3D library world out of it, Maybe call it the X3D 3D library world.</div><div dir="auto"><br></div><div dir="auto">Maybe we can figure out new ways of interacting with specifications and documentation.</div><div dir="auto"><br></div><div dir="auto">The first thing I plan to do is take my textareas in X3DJSONLD 12, and render them in 3D. Maybe the first task is to create a 3D textarea.</div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">See Starcel:<div dir="auto"><a href="https://youtu.be/rJuRTZOE99g?si=VZnjjvI4Sp_-tWGs" target="_blank">https://youtu.be/rJuRTZOE99g</a></div></div><div dir="auto"><br></div><div dir="auto">John </div>
</blockquote></div></div>
</blockquote></div></div>