How to Create a Visual Novel Style in Arcweave's Play Mode
Transform your Arcweave project into a professional-looking visual novel with just a few CSS tweaks
Visual novels are one of the most popular storytelling formats in interactive fiction. With their full-screen backgrounds, character sprites, and dialogue boxes, they create an immersive reading experience that draws players into your story. The good news? You can achieve this polished look in Arcweave's Play Mode using custom CSS.
In this tutorial, we'll show you how to customize your Play Mode interface to look like a professional visual novel—no coding experience required!
By the end of this guide, you'll know how to:
- Set full-screen background images for each scene
- Position character sprites at the bottom of the screen
- Create a stylish dialogue box with scrollable text
- Place choice buttons above your dialogue
- Style specific words and paragraphs for emphasis
- Make everything responsive for mobile devices
Before we start
Ingredients
To follow this tutorial, you will need:
- An Arcweave project with some elements, connections, and components
- Image assets uploaded to your project (backgrounds and character sprites)
Preparation
Before diving into CSS, structure your project like this:
- Use element covers for background images
- Attach components (with cover images) to represent characters
- Write your dialogue in the element content
- Use connection labels for player choices
Now, let's get started!
Accessing the Style Editor

First, let's open the CSS editor where all the magic happens:
- Open your project and click the Play button (▶️) in the top menu
- In Play Mode, click the Style Editor icon (palette icon) in the top bar
- You'll see a code editor panel open on the right side
The Style Editor shows you the current CSS and lets you write custom styles that will apply to your entire Play Mode.
The 3 parts of the visual novel
A visual novel interface has three main visual parts that we'll customize:
- Full-screen backgrounds - The scenic backdrop for each scene
- Character sprites - Your characters positioned at the bottom
- Dialogue box - Where your text appears with scrolling for longer content
Let's tackle them one by one:
1. Full-screen backgrounds

By default, element covers appear as small images. Let's make them fill the entire screen:
/* Full-screen background container */
.prototype__media {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
/* Make the image cover the screen */
.prototype__media img.single {
width: 100%;
height: 100%;
object-fit: cover;
}
What this does:
position: absolutelets us place the image anywherewidth: 100%andheight: 100%make it fill the screenobject-fit: coverensures the image fills the space without distortionz-index: 1puts it in the background, behind characters and dialogue
2. Character sprites

Characters should appear at the bottom of the screen, standing above the dialogue box:
/* Character container */
.prototype__components {
position: absolute;
bottom: 350px;
left: 0;
right: 0;
height: 60vh;
display: flex;
align-items: flex-end;
z-index: 2;
padding: 0 5%;
}
/* Character sprite styling */
.prototype__components .comp {
height: 100%;
background: none;
object-fit: contain;
object-position: bottom;
filter: drop-shadow(0 0 20px rgba(0, 0, 0, 0.5));
}
What this does:
bottom: 350pxpositions characters above the dialogue boxheight: 60vhmakes characters take up 60% of screen heightalign-items: flex-endaligns characters to the bottomobject-position: bottomkeeps feet anchored at the bottomfilter: drop-shadow()adds a subtle shadow for depth
💡 Customization tip: Adjust bottom: 350px to change how high characters appear. Try 400px for more space or 300px for less.
3. Dialogue box with scrollable text

The dialogue box is where your text appears. This is important: we need to make sure long text can scroll!
/* Dialogue box container */
.prototype__body {
position: absolute;
bottom: 50px;
left: 50px;
right: 50px;
height: 300px;
background: linear-gradient(135deg,
rgba(30, 41, 59, 0.85) 0%,
rgba(15, 23, 42, 0.98) 100%);
border: 2px solid #475569;
border-radius: 15px;
z-index: 3;
padding: 25px 60px;
backdrop-filter: blur(10px);
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
display: flex;
}
/* Text container with scroll functionality */
.prototype__text {
overflow: auto;
width: 100%;
scrollbar-width: thin;
scrollbar-color: #475569 transparent;
}
/* Custom scrollbar for Chrome/Safari */
.prototype__text::-webkit-scrollbar {
width: 6px;
}
.prototype__text::-webkit-scrollbar-track {
background: transparent;
}
.prototype__text::-webkit-scrollbar-thumb {
background: #475569;
border-radius: 3px;
}
/* Text styling inside the box */
.prototype__text .editor .ProseMirror {
color: #ffffff;
font-size: 30px;
line-height: 1.7;
font-family: 'Segoe UI', 'Noto Sans', sans-serif;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.6);
}
What this does:
bottom: 50pxpositions it near the screen bottombackground: linear-gradient()creates a semi-transparent gradientbackdrop-filter: blur(10px)blurs the background behind the boxborder-radius: 15pxrounds the cornersoverflow: auto- This is crucial! It enables scrolling when text is longscrollbar-width: thinand::-webkit-scrollbarstyle the scrollbar to match your themetext-shadowmakes text more readable
⚠️ Important: Without the overflow: auto property, long dialogue will be cut off! This ensures players can always read everything.
Styling choice buttons

Player choices should appear above the dialogue box:
/* Options container */
.prototype__options {
position: absolute;
bottom: 360px;
left: 50%;
transform: translateX(-50%);
display: block;
z-index: 4;
width: 90%;
max-width: 800px;
}
/* Individual choice button */
.prototype__option {
background: linear-gradient(135deg,
rgba(51, 65, 85, 0.95) 0%,
rgba(30, 41, 59, 0.98) 100%);
border: 2px solid #60a5fa;
border-radius: 50px;
padding: 20px 35px;
margin: 0 0 30px;
color: #ffffff;
font-size: 24px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 20px rgba(59, 130, 246, 0.3);
}
/* Hover effect */
.prototype__option:hover {
transform: translateY(-4px) scale(1.05);
border-color: #a78bfa;
box-shadow: 0 8px 30px rgba(99, 102, 241, 0.4);
}
What this does:
bottom: 360pxplaces buttons just above the dialogue boxtransform: translateX(-50%)centers them horizontallyborder-radius: 50pxcreates pill-shaped buttonstransition: all 0.3ssmoothly animates hover effects:hovermakes buttons lift up when you mouse over them
Using CSS variables for easy customization
Here's a pro technique: define your colors once at the top, then reuse them throughout:
:root {
/* Dialogue box theme */
--vn-dialogue-bg: linear-gradient(135deg,
rgba(30, 41, 59, 0.85) 0%,
rgba(15, 23, 42, 0.98) 100%);
--vn-dialogue-border: #475569;
--vn-dialogue-text: #ffffff;
/* Button theme */
--vn-option-bg: linear-gradient(135deg,
rgba(51, 65, 85, 0.95) 0%,
rgba(30, 41, 59, 0.98) 100%);
--vn-option-border: #60a5fa;
--vn-option-text: #ffffff;
/* Text sizes */
--vn-font-size-dialogue: 30px;
--vn-font-size-option: 24px;
}
Then use them like this:
.prototype__body {
background: var(--vn-dialogue-bg);
border-color: var(--vn-dialogue-border);
}
Why this is useful: Change one value at the top and it updates everywhere! Perfect for trying different color schemes.
Mobile responsiveness
Don't forget about mobile players! Add these media queries:
@media (max-width: 1000px) {
/* Adjust character positioning */
.prototype__components {
bottom: 150px;
height: 50vh;
}
/* Smaller dialogue box */
.prototype__body {
bottom: 20px;
left: 20px;
right: 20px;
height: 150px;
padding: 15px 30px;
}
/* Smaller text */
.prototype__text .editor .ProseMirror {
font-size: 20px;
}
/* Adjust options */
.prototype__options {
bottom: 180px;
}
.prototype__option {
font-size: 18px;
padding: 12px 30px;
}
}
Advanced technique: styling specific words and paragraphs
Here's where things get really interesting! You might want to emphasize certain words—like a character's name in a different color, important clues in bold and red, or sound effects in a stylized font.
The Challenge: Arcweave doesn't let you inject custom HTML classes directly into your text.
The Solution: We can "hijack" the formatting tools that Arcweave already provides!
How it works
When you format text in Arcweave's editor (italic, bold, underline), it generates standard HTML tags:
- Italic creates
<em>tags - Bold creates
<strong>tags - Underline creates
<u>tags
We can target these tags with CSS and override their default appearance. The key is to use the element ID to make sure we only affect specific elements, not every italic word in your entire story.
Finding element IDs
There are two easy ways to find an element's ID:
Method 1: Using the debugger (recommended)
- Enter Play Mode
- Click on Debug in the top menu
- Navigate to the element you want to style
- Look at the Current Element section - you'll see the ID listed there
- Copy the ID (it looks like
el-cb35db92-3c07-41bf-9c45-580ad6b891b4)
Method 2: From the Editor
- In your project, right-click the element you want to style
- Select Properties
- The element ID is shown in the “Details” tab
- Copy the ID
Step-by-step process
1. Format text in the editor
Go to your element and edit it:
- Highlight the word or phrase you want to style
- Apply a format: Italic, Bold, or Underline
- This creates the HTML tag we'll target with CSS
2. Write the CSS
Now in the Style Editor, target that specific formatted text:
/* Target italic text in a specific element and make it red */
#el-your-element-id ditor .editor-content em {
color: red;
font-style: normal; /* Remove the default italic effect */
}
Practical examples
Example 1: Character names in color
Make character names appear in their signature color:
In Arcweave: Format "Alice" with italic CSS:
#el-your-element-id .prototype__text .editor .editor-content em {
color: #60a5fa; /* Blue for Alice */
font-style: normal;
font-weight: bold;
}
Example 2: Important clues
Highlight clues that players should remember:
In Arcweave: Format clue words with bold CSS:
#el-your-element-id .prototype__text .editor .editor-content strong {
color: #fbbf24; /* Gold color */
font-weight: 900;
text-shadow: 0 0 10px rgba(251, 191, 36, 0.5); /* Glow effect */
}
Example 3: Sound effects
Create stylized sound effects:
In Arcweave: Format "crash" with underline CSS:
#el-your-element-id .prototype__text .editor .editor-content u {
text-decoration: none; /* Remove underline */
color: #ef4444;
font-family: 'Impact', sans-serif;
font-size: 1.2em;
font-style: italic;
letter-spacing: 2px;
}
Example 4: Targeting specific paragraphs
You can also style entire paragraphs using nth-child:
/* Style the first paragraph differently (maybe it's narration) */
#el-your-element-id .prototype__text .editor .ProseMirror p:first-child {
color: #a78bfa;
font-style: italic;
font-size: 0.9em;
}
/* Style the second paragraph (maybe it's a character speaking) */
#el-your-element-id .prototype__text .editor .ProseMirror p:nth-child(2) {
color: #60a5fa;
font-weight: bold;
}
Creative uses
Here are some creative ways to use this technique:
1. Dialogue with different character voices:
/* Character 1 - uses italic */
#el-your-element-id em {
color: #60a5fa;
font-style: normal;
font-weight: 600;
}
/* Character 2 - uses bold */
#el-your-element-id strong {
color: #f472b6;
font-weight: 700;
}
/* Narrator - uses underline */
#el-your-element-id u {
text-decoration: none;
color: #a78bfa;
font-style: italic;
}
2. Thoughts vs. spoken dialogue:
/* Inner thoughts in italic */
#el-your-element-id em {
color: #94a3b8;
font-style: italic;
opacity: 0.8;
}
3. Branching indicators:
/* Highlight choices that lead to different paths */
#el-your-element-id strong {
color: #fbbf24;
font-weight: bold;
text-decoration: underline;
}
Important warnings
⚠️ Always include the Element ID! If you forget it, you'll accidentally style EVERY italic/bold/underline word in your entire project:
/* ❌ DON'T DO THIS - affects everything */
em {
color: red;
}
/* ✅ DO THIS - affects only one element */
#el-your-element-id em {
color: red;
}
⚠️ Limitations: You can only use three "channels" (italic, bold, underline) per element. If you need more variety, create different elements or use paragraph targeting.
⚠️ Testing: Always test in Play Mode to make sure your styles look right!
Complete code template
Here's the full CSS ready to copy and paste.
/* ========== FULL-SCREEN BACKGROUND ========== */
.prototype__media {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.prototype__media img.single {
width: 100%;
height: 100%;
object-fit: cover;
}
/* ========== CHARACTER SPRITES ========== */
.prototype__components {
position: absolute;
bottom: 350px;
left: 0;
right: 0;
height: 60vh;
display: flex;
align-items: flex-end;
z-index: 2;
padding: 0 5%;
}
.prototype__components .comp {
height: 100%;
background: none;
object-fit: contain;
object-position: bottom;
filter: drop-shadow(0 0 20px rgba(0, 0, 0, 0.5));
}
/* ========== DIALOGUE BOX ========== */
.prototype__body {
position: absolute;
bottom: 50px;
left: 50px;
right: 50px;
height: 300px;
background: linear-gradient(135deg,
rgba(30, 41, 59, 0.85) 0%,
rgba(15, 23, 42, 0.98) 100%);
border: 2px solid #475569;
border-radius: 15px;
z-index: 3;
padding: 25px 60px;
backdrop-filter: blur(10px);
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
display: flex;
}
/* Text container with scrolling */
.prototype__text {
overflow: auto;
width: 100%;
scrollbar-width: thin;
scrollbar-color: #475569 transparent;
}
/* Custom scrollbar for Chrome/Safari */
.prototype__text::-webkit-scrollbar {
width: 6px;
}
.prototype__text::-webkit-scrollbar-track {
background: transparent;
}
.prototype__text::-webkit-scrollbar-thumb {
background: #475569;
border-radius: 3px;
}
/* Text styling */
.prototype__text .editor .ProseMirror {
color: #ffffff;
font-size: 30px;
line-height: 1.7;
font-family: 'Segoe UI', 'Noto Sans', sans-serif;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.6);
}
/* ========== CHOICE BUTTONS ========== */
.prototype__options {
position: absolute;
bottom: 360px;
left: 50%;
transform: translateX(-50%);
display: block;
z-index: 4;
width: 90%;
max-width: 800px;
}
.prototype__option {
background: linear-gradient(135deg,
rgba(51, 65, 85, 0.95) 0%,
rgba(30, 41, 59, 0.98) 100%);
border: 2px solid #60a5fa;
border-radius: 50px;
padding: 20px 35px;
margin: 0 0 30px;
color: #ffffff;
font-size: 24px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 20px rgba(59, 130, 246, 0.3);
}
.prototype__option:hover {
transform: translateY(-4px) scale(1.05);
border-color: #a78bfa;
box-shadow: 0 8px 30px rgba(99, 102, 241, 0.4);
}
/* ========== STYLING SPECIFIC WORDS (EXAMPLE) ========== */
/* Replace with your actual element ID */
#el-your-element-id .prototype__text .editor .editor-content em {
color: #60a5fa;
font-style: normal;
font-weight: bold;
}
/* ========== MOBILE RESPONSIVE ========== */
@media (max-width: 1000px) {
.prototype__components {
bottom: 150px;
height: 50vh;
}
.prototype__body {
bottom: 20px;
left: 20px;
right: 20px;
height: 150px;
padding: 15px 30px;
}
.prototype__text .editor .ProseMirror {
font-size: 20px;
}
.prototype__options {
bottom: 180px;
}
.prototype__option {
font-size: 18px;
padding: 12px 30px;
}
}
Quick customization guide
Want to tweak the look? Here are the most common adjustments:
| What to Change | Where to Look | Example Values |
|---|---|---|
| Character height | bottom: 350px in .prototype__components |
300px - 500px |
| Character size | height: 60vh in .prototype__components |
40vh - 80vh |
| Dialogue box position | bottom: 50px in .prototype__body |
30px - 100px |
| Dialogue box height | height: 300px in .prototype__body |
200px - 400px |
| Text size | font-size: 30px in .ProseMirror |
24px - 36px |
| Scrollbar color | scrollbar-color in .prototype__text |
Any hex color |
| Button colors | border: 2px solid #60a5fa in .prototype__option |
Any hex color |
| Button shape | border-radius: 50px in .prototype__option |
0px (square) - 50px (pill) |
Pro tips & tricks
Tip 1: Color themes
Create different moods by changing the gradient colors:
Dark & Mysterious:
background: linear-gradient(135deg,
rgba(15, 15, 25, 0.9) 0%,
rgba(5, 5, 15, 0.95) 100%);
Light & Airy:
background: linear-gradient(135deg,
rgba(240, 240, 250, 0.85) 0%,
rgba(220, 220, 240, 0.95) 100%);
Tip 2: Custom fonts
Want a different font? Add this at the top:
@import url('<https://fonts.googleapis.com/css2?family=Your+Font+Name&display=swap>');
.prototype__text .editor .ProseMirror {
font-family: 'Your Font Name', sans-serif;
}
Tip 3: Multiple characters
If you have multiple character components attached to an element, they'll automatically arrange side-by-side thanks to display: flex in .prototype__components.
Tip 4: Scrollbar styling
Match your scrollbar to your theme by changing the color:
.prototype__text {
scrollbar-color: #your-color transparent;
}
.prototype__text::-webkit-scrollbar-thumb {
background: #your-color;
}
Tip 5: Testing text overflow
To test if your scrolling works, write a long element with lots of text. The scrollbar should appear automatically when content exceeds the dialogue box height.
Troubleshooting common issues
Characters are cut off at the top
Solution: Increase height: 60vh to 70vh or 80vh
Dialogue box covers the characters
Solution: Increase bottom: 350px in .prototype__components
Text is hard to read
Solution: Increase the opacity in your background gradient (change 0.85 to 0.95)
Buttons are too close to dialogue box
Solution: Increase bottom: 360px in .prototype__options
Mobile layout looks wrong
Solution: Check your media query values and adjust the breakpoint (max-width: 1000px)
Long text gets cut off instead of scrolling
Solution: Make sure you have overflow: auto on .prototype__text
Can't see the scrollbar
Solution: Check that scrollbar-width: thin and the webkit scrollbar styles are present
My styled words affect other elements
Solution: Make sure you're including the specific element ID: #el-your-id em { } not just em { }
What's next?
Now that you have a beautiful visual novel interface, here are some ideas to take it further:
- Add animations - Try
transitionandtransformproperties for fade-ins - Custom buttons for specific choices - Use element IDs to style individual options
- Day/night themes - Create different CSS themes and switch between them
- Sound effects - Combine your CSS with Arcweave's audio features
- Character portraits - Try different positioning for character components
- Text effects - Experiment with glowing text, shadows, and animations
- Create a name tag system - Use paragraph targeting to style character names
- Animated scrollbar - Add smooth scrolling animations
Conclusion
Congratulations! You've just transformed your Arcweave project into a professional-looking visual novel. The best part? All of this styling happens in Play Mode, so you can iterate quickly without touching your project structure.
You've learned:
- ✅ How to create full-screen backgrounds
- ✅ How to position character sprites
- ✅ How to design a beautiful dialogue box with scrolling text
- ✅ How to style choice buttons
- ✅ How to customize specific words and paragraphs
- ✅ How to make everything mobile-responsive
- ✅ How to find element IDs easily
Remember: CSS is all about experimentation. Don't be afraid to adjust values, try different colors, or completely redesign elements. The Style Editor updates in real-time, so you can see your changes immediately.
Want to share your creation? Use Arcweave's Share feature to make your project public and let others experience your visual novel!
Need more help? Join the Arcweave Discord community where you can share your CSS creations and get feedback from other creators.
Happy storytelling! ✨
Have you created something cool with these CSS techniques? We'd love to see it! Share your projects with us on Discord or tag us on social media.