GithubHelp home page GithubHelp logo

zeel01 / monsterblocks Goto Github PK

View Code? Open in Web Editor NEW
26.0 5.0 25.0 15.94 MB

A Foundry VTT module to add NPC sheets that faithfully reproduce the appearance of D&D 5e monster statblocks.

JavaScript 64.14% CSS 15.56% Handlebars 20.30%

monsterblocks's Introduction

Forge Installs Latest Release Download Count

Monster Blocks

Monster Blocks is an NPC sheet for FoundryVTT designed to faithfully reproduce the appearance of D&D 5e monster statblocks.

Quick Settings are accessed through the cog menu in the upper left corner. This menu gives access to key functions such as toggling certain features, and themes.

Ancient Red Dragon

Features

  • Generate attack descriptions including hit bonus, damage formula, and average damage
  • Generate spellcasting features for regular and innate casters based on their spellbook data
  • Promote the Multiattack action to be displayed first, even if it isn't the first in the actor's list
  • Present a concise view of all relevant game statistics as shown in official 5e books
  • Optionally display an image of the creature for reference
  • Optionally display "secret" blocks of feature descriptions inline rather than in boxes (useful for SRD monsters as they come with descriptions in secret boxes)
  • Automatically sizes the window to fit the content of the statblock, meaning simple creatures automatically take up less space!
  • Show or hide lair actions. Standard statblocks don't really include those, but since you can add them to the actor I made it possible to display them.
  • Settings cog to toggle key features in the upper left corner.
  • Rolls for ability checks, saving throws, skills, features, actions, and spells
  • Open and edit features, spells, and other items by right-clicking their description
  • Drag and drop items from the sheet to elsewhere
  • Set default options in settings, and per-actor settings from the settings cog
  • Support for Quick Insert
  • Support for Better Rolls for 5e if installed.
  • Per-monster theme selection to help differentiate them.
  • Custom theme support (see Theme Customization)
  • Image pop-ups for creature artwork which can be shown to players
  • Manage various features and items
  • Edit skill and save proficiencies
  • Manage or hide rolls for skills and saves that are not proficient

Theme Customization

Custom CSS class names can be used as a theme. To customize your theme you can either use a module like Custom CSS or a browser extension like Stylish to target .monsterblock.your-class-name and modify the appearance however you like.

The following CSS variables define the most important values:

--heading-color: rgb(89 23 13);
--roll-hover-color: hsl(8 70% 14% / 1);
--divider-color: rgba(140, 42, 42, 1);
--background-filter: hsl(39deg 100% 60% / 80%);
--background-blend: hard-light;
--main-text-color: black;
--inline-link-color: #ff6400;
--background-blend: hard-light;
--main-text-color: black;

FAQ

Q: How do I change the settings for specific monsters?

A: You can adjust the default settings in the Foundry module settings menu. The settings cog located in the upper left corner of the sheet next to the creature's name adjusts settings for each individual monster.

Q. How do I edit avatar/character art?

A: Right click on the image.

Q. How do I edit spells and features?

A: Right click on any feature, item, or spell to edit it.

Q: Why can't I resize the window?

A: The window automatically calculates its own size. Any time the data in the sheet changes, the window size might need to change - even a few extra words in a description might mean it needs more space. To avoid situations where a user custom-sizes the window, and then it either resizes itself, or content becomes invisible, I decided to just disable manual sizing. I may be revisit this in the future.

Q: What are "secret blocks" and how do those settings work?

A: Secret blocks are a feature of Foundry that allows some text to be "secret" for only the GM to see. Typically, this text is displayed differently, in its own special box. The SRD monsters included with Foundry 5e use this feature for all their attack descriptions, such that text like:

Melee Weapon Attack, +17 to hit, reach 15 ft., one target. Hit: 21 (2d10+10) piercing damage.

Is contained in the secret block. Monster Blocks has three ways to handle this type of text: normally, inline, or hidden. You can configure this on a per-actor basis, and set the default under module settings. As an example, this SRD entry for a Silver Dragon looks like this by default:

Block Secrets

The text in the offset blocks is "secret" text. The text above it is generated by Monster Blocks, and the text below is part of the description that is not a secret. Displayed inline we get this:

Inline Secrets

We lose the clear indication of what is or isn't a secret, but it looks more like a statblock. Of course, in this case, that text is repetitive. We can either hide the generated text that we don't need:

Block Secrets

Or we can hide the secrets themselves:

Block Secrets

You can choose how you want the sheet to appear for each actor, depending on need/preference. By default, I leave secrets "normal" though my recommendation is to hide the ones for SRD monsters and use the generated text. You can of course edit your monster to have/not have secret text in the description at all if that works better for you. For monsters you create, you can just let Monster Blocks do all the work, and not bother typing out the attack and damage info yourself.

Q: How can I roll from the sheet?

A: To ensure varisamilitude, the sheet doesn't show rollables in a big obvious way. Inline rolls in feature descriptions are still marked with the d20 icon, but the built-in rolls of Monster Blocks are only indicated when moused over. Monster Blocks supports rolling of abilities, saves, and skills, as well as the ability to send chat cards for features, spells, and actions. Simply click on the name of any feature, action, or spell to send its chat card. Monster Blocks also has "quick rolls" for attacks and damage in the generated descriptions. The text such as "+17 to hit" and "Hit: 21 (2d10 + 10)" are rollables, and will directly roll 1d20+17, or 2d10+10 respectively. Feature recharges, likewise, can be clicked to roll a d6 and the chat card will indicate whether or not the roll was high enough to charge the ability. At this time, there isn't a semantic way to roll a save or skill that the creature is not proficient with, as these are not listed on the sheet. In this case, you can simply roll the corresponding ability check.

If you have Better Rolls installed, most rolls from this sheet will use BRs custom rolls.

Q: When I use [insert creature] something displays wrong!

A: Please let me know! I'm on the lookout for creatures that break the mold, so if you find something that doesn't work right please report it and I'll try to figure out how to handle it.

Q: Does Monster Blocks support Lair Actions?

A: Yes! I have Lair Actions disabled by default, but you can configure this either by changing the default, or per-creature. Technically, Lair Actions aren't part of monster statblocks, but since Foundry 5e treats them as monster features rather than location features, I did make it possible to show them. They appear in their own section after Legendary Actions, in a bulleted list.

Q: Some of the buttons on the title bar are missing! What do I do?

A: When the sheet only needs to be one column wide, the titlebar may not be able to fit the name of the monster and all the buttons. This is much more of a problem if you have lots of other modules installed. A quick fix is to hide the labels on those buttons with Custom CSS:

.window-app.monsterblock .window-header { font-size: 0px; padding-right: 30px; }
.window-app.monsterblock .window-header i { font-size: 14px; }

This will show only icons, which should help as long as you remember what they all do.

Alt

monsterblocks's People

Contributors

akrigline avatar arcanistzed avatar artoriacaster avatar dependabot[bot] avatar eolias78 avatar evan-rash avatar jeremyregnerus avatar mrprimate avatar rencos1 avatar vexofp avatar zeel01 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

monsterblocks's Issues

Loading certain maps lags seemingly due to Monster Blocks.

Basically, there's a long lag when loading certain maps, seemingly without reason. No combat going on, no tokens on the maps, no iniative.. nothing.

DevTools failed to load SourceMap: Could not load content for "DOMAINADDRESS"/modules/monsterblock/input-expressions/math.min.map: HTTP error: status code 404, net::ERR_HTTP_RESPONSE_CODE_FAILURE

Generated Attack Descriptions problem

Great Mod.

I discovered one issue:

When "Generated Attack Descriptions" is enabled (which it is by default), it prevents the NPC window from closing and when I refresh the browser they disappear but I cannot reopen the sheet until I delete the token and create a new one.

I can still switch to the default NPC sheet using your macro but when I toggle back there is no sheet.

This may be related to other add-ons I have running, but all new tokens work perfectly when I disable the "Generated Attack Descriptions" setting.

Roll initiative by clicking monster name? (really minor roll20 inspired feature request)

In roll 20 you could quickly roll initiative for a creature by clicking the name in their sheet.

Now in foundry its usually just as easy to do this from the combat tracker, and i understand if this is a feature you find useless.

But if you want to do it, this would be a neat feature for those of us who moved here from roll20 ;)

Feel free to close this if you find it stupid :P

Problem running with some NPCs

As mentioned, most character sheets are working just fine, but others are giving me an error. This is what had shown up.

foundry.js:3833 TypeError: An error occurred while rendering MonsterBlock5e 70: Cannot read property 'target' of undefined
at Function.isLegendaryResistance (monsterblock.js:392)
at MonsterBlock5e.getLegendaryResistance (monsterblock.js:145)
at MonsterBlock5e.getData (monsterblock.js:42)
at MonsterBlock5e._render (foundry.js:3861)
at MonsterBlock5e._render (foundry.js:4473)
at MonsterBlock5e._render (foundry.js:17411)
at MonsterBlock5e.render (foundry.js:3831)
at ActorDirectory._onClickEntityName (foundry.js:39639)
at HTMLOListElement.dispatch (jquery.min.js:2)
at HTMLOListElement.v.handle (jquery.min.js:2)

Make the saves/skill roll menus optional, or at least not triggered on hover.

Would you be able to make the Saving Throws and Skill check drop-downs an optional setting?

The drop-downs are getting in the way of the listed Proficient Skills since the drop-down appears as soon as I hover over any of the Skills or Saves. I neither want nor need the ability to roll non-proficient skills and saves since they are essentially raw ability checks.

Thank you!

Innate Spellcasting not reflecting available uses

The Innate Spellcasting spells show the max uses but do not reflect the available uses in the same way that regular spellcasting shows the available slots.

Edit: Now that I think about this further, it is likely because you would have to display each spell individually for current/max uses. I am not sure the best approach for this would be. Maybe a single Integer in parenthesis after each spell name for innate spells that have limited uses.

Support continued text content on attacks

Would be nice to recognize text in an attack description that starts with the , character to be a continuation of the default attack string that is created. An example would be as follows, where after the normal damage, there is an , and that follows the default text.
Bite. Melee Weapon Attack: +5 to hit, reach 5 ft., one target. Hit: 7 (1d8 + 3) piercing damage plus 9 (2d8) poison damage, and target must make a DC 11 Constitution saving throw, taking 9 ( 2d8) poison damage on a failed save, or half as much damage on a successful one. If the poison damage reduces the target to 0 hit points, the target is stable but poisoned for 1 hour, even after regaining hit points, and is paralyzed while poisoned in this way.

Nonmagical Attacks

This is fairly minor, but you have such a true to form character sheet, I thought I'd add it.
Non-Magical Physical should always be listed last and preceded by a semi colon for resistances and immunities.

Currently, (Non-Magical Physical) bludgeoning, piercing, and slashing damage appears in alphanumeric order when displayed on the character sheet (after necrotic and before piercing). When in actuality this resistance / immunity is always listed last and preceded by a semicolon. Banshee is a good example of this (acid, fire, lightning, thunder; bludgeoning, piercing, and slashing from nonmagical attacks)

Feet / Miles selection box shows up even when editing is disabled.

At first I was really confused why the text "Feet" showed up when I mouse over speed and senses.

But after a bit of digging I found out that if you enable editing this text lets you choose between miles and feet.

It would probably make sense to not have this show up on a locked (un-editable) sheet. Especially since the the text doesn't really do anything then.

[Enhancement Request] Support strings that include Multiattack

I was looking for a way to include features that include more than the single word multiattack in their name. An example of this would be creatures with forms eg. Multiattack (Humanoid or Hybrid Form Only).

I'm not sure how to submit a push / pull, but I was able to get this to work in the function isMultiAttack at line 1623 with the following. Also not sure if this is the most effiecient way to do this, as I'm much more familiar with c# than js.

static isMultiAttack(item) {	// Checks if the item is the multiattack action.
let name = item.name.toLowerCase().replace(/\s+/g, "");	// Convert the name of the item to all lower case, and remove whitespace.
let locators = game.i18n.localize("MOBLOKS5E.MultiattackLocators");

for (let index = 0; index < locators.length; index++) {
	const val = locators[index];

	if (name.includes(val)) {
		return true;
	}
}
return false;
}

Clicking image now opens tokenizer

One of my favorite features of MonsterBlocks is breaking with 2.0.1. Clicking on the image from the rendered block is opening tokenizer instead of displaying the image so that I can share it with the players.

Without tokenizer activated, it is behaving as it did before by showing the image. Is there a setting that can be added to prevent tokenizer from appearing when clicking the image?

If I want tokenizer to open, I can just click the settings gear and select 'Open VTTA Tokenizer'.

Thank you! Loving the changes in 2.x

Show Artwork to Players functionality

When hovering on a MonsterBlock artwork of a monster, a button in a corner to open the actor avatar of the monster as image journal so that it can be shown to players. This is similar to right click on an actor and show image to players option.

[Feature Request] Expand Biography Section

Allow for the Biography section / page to expand in order to show more content. Similar to how the "front" of the character sheet expands when there is more content added.

Ability to Roll Saving Throws when not proficient

I was wondering if you could add the option to roll a Saving Throw from the ability modifier, in the case a monster is not proficient but still needs to roll to save. I understand that there are additional checks on the back-end where you're actually preventing the Default functionality, however I was thinking something like how you handle Item/Spell cards: Left Click for Ability Checks, Right Click for Saving Throws.

Occasionally I'll have an ability that situationally enhances a monster's Saving Throw, and something like this would make things more transparent.

Make rolling to recharge also set the charged flag on the item.

Hello,
I've encountered a problem with Recharge on monster abilities like Fire Breath. It works as intended on the default 5e NPC Sheet. But when I roll for the charge on Monster Blocks and get success, it says I have no available uses remaining. I am confident I have the right setting since it works as I would expect on the default sheet.

image
image
image

[Bug] Icon to change to Monster Block no longer showing up

I've noticed a strange bug where I am unable to change monsters to their Monster Block counterpart. The gear icon isn't showing up, nor is the module showing in the settings, however, is shown to be installed in the setup. I've attempted disabling all my modules to see if there was a conflict, but that also didn't work.

Love your work! It makes running monsters so much easier.

image
image
image
image

Right click to edit tool tips should not appear if editing is disabled.

When you hover over the NPC image, there's a tooltip that appears to right click to edit the artwork. However, right mousing on the artwork doesn't do anything. If this is not the intended workflow, then this would be a great feature to mitigate the need to go into classic mode to edit the image.

Code for image sharing in biography

As requested the code that can be added at line 1087 of monsterblock.js is:

html.find(".editor-content>>img").click((event) => {
event.preventDefault();
let imgSource = event.target.src;
new ImagePopout(imgSource, {
title: this.actor.name,
shareable: true,
uuid: this.actor.uuid
}).render(true);
});

This will allow any image in the biography to be easily shared.

Error on converting monsters

image

Hitting the above error when trying to convert to a monster block. I used the default air elemental supplied with the compendium. I checked the walk speed and not sure if because it was 'fly' it made a difference. I tried to convert a few other monsters and I'm getting the same issue

Foundry version: 0.7.6
5e version: 0.98
Monster blocks version: 2.2.8
math.js version: 7.5.1

Senses is Null Error

Saw this mentioned on the Discord already. Seems if a monster doesn't have senses entered you get a 'senses is null' error when trying to open the sheet and it refuses to open.

image

Saving throws bug, resistances option missing

Hi, first of all with all the added features this is by far the best NPC Sheet.

While fixing some monsters I found out that Saving throws edit is bugged: it doesn't update its checked status when changing it and you need to go to default sheet to fix them It will do the check uncheck to the template, but since it doesnt update you can toggle them (I noticed them when removing saving throsws from a monster).
I think its a recent addition, but there is a new "Non-magical physical attacks" option in resistances and immunities and it doesnt show on the edit dropdown.

With those fixed the only thing I have to switch to the original sheet for is to update the page! (source field)
Great work!

[Enhancement Request] New tags clutter generated attack descriptions.

Hey! I've been happily using the generated attack descriptions, until a recent update where [prof] and [mod] tags started to show up in the generated attack descriptions.

image

The [prof] and [mod] tags are really distracting and clutter up the user interface. Is it possible to make disabling this behavior an option (or revert it to the way it was before)?

Armor description next to Armor Class

In the MM stat blocks, there is often a description of the type of armor next to the AC entry... for Goblin:

Armor Class 15 (leather armor, shield)

I really like being able to see that the goblin has a shield... I make variant goblins with different weapons, and goblins with spears can drop their shields to use the spear (a versatile weapon) two-handed. Or if I create a goblin with something better than leather armor (or one with no armor) it's clear why the AC differs from the norm.
It would be really cool if this could be incorporated. I like Monster Blocks way better than a character sheet with data spread out over tabs.

One graphical issue and suggestion

Created a drow mage and MonsterBlocks seems to have issues with having both Innate spells and regular spells at the same time when rendering:
Annotation 2020-08-29 232711

Also, it would be very helpful if the spell slots reflected how many were left rather than max.

Thank you for this mod!

Proficient saving throws not working

Found one issue since the last patch:

Monsters with proficient saving throws show the link when hovered over, but do not generate a saving throw roll when clicked.

Missing window tab items

Hey big fan of this npc sheet! I have a problem with tab items along the top being cut off on small monster block sheets though. Prototype Token or Token are often missing from the bar at the top requiring switching to another sheet that can be resized to access them. Is it possible to get those missing tab menus visible in an expandable menu or something?
When I use the Popout window module I am able to resize the Monster Block and see all those missing tab items. Could this resizing also be available in the Foundry window?

Support Minor QOL

Similar but different to Better Rolls, Minor QOL is another common automation suite for combat.

It would be excellent if the way in which rolls for attack items were initiated would mesh with the Minor QOL way as well.

Compatibility with Combat Utility Belt's "Hide Actor Name" feature

CUB adds a little mask icon to character sheets which, when clicked, opens a settings dialogue to hide that actor's name in the Combat Tracker and Chat Cards.

I am hoping that this module be updated to have an option to display the mask icon if CUB is installed (or if that particular setting within CUB is enabled). Unless I am mistaken, currently one would have to switch sheets to the default, change the settings there, and then switch back to Monster Blocks.

Thanks so much for a great and aesthetic mod!!

Skill and abilitychecks does not support shift/ctrl for advantage/disadvantage with better rolls.

Behaves as if I'm trying to select text. Rolls just a straight roll.

How to reproduce:
Have better rolls set to "Single Roll (Shift Advantage, Ctrl Disadvantage)"
Try to roll any skill or ability score with shift or ctrl pressed.

There are many abilities, skills and situations that imbue advantage / disadvantage on for instance perception or stealth rolls, so this is useful if can be done the same way as attack rolls.

Add Biography and make AC editable

Hi, I LOVE the way your mod makes the monster sheets look. I have 2 suggestions:

  1. Add a biography button: the way Some monsters are imported (specially from Roll20) have all the info from the MM in the BIography. Being able to quickly check it is something I miss when using the monster sheets. It could be at the top bar or a small link near the portrait.

  2. If you are just going to make a couple of stuff editable please make AC one of them. I use a lot Foundry's targetting system with autoapply damage, and sometimes an enemy may pickup a shield, or have Magic armor cast... stuff like that where I need a quick AC edit so the calculations are correct.

Make CSS code to show only icons on header buttons an option in module settings or cog-menu

With more modules adding buttons to the top bar of windows (like the new tokenizer preview from VTTA for instance) its getting really crowded up there, and since monster blocks are usually pretty narrow, any overflowing buttons simply disappear. (Because, I assume, foundry has no overflow logic for these buttons)

Currently I'm using stylish to apply the following code:

.window-app.monsterblock .window-header { font-size: 0px; padding-right: 30px; } .window-app.monsterblock .window-header i { font-size: 14px; }

I think it would be nice if this was an option either in the module settings or in the "cogwheel menu" in monsterblocks, for users less knowledgeable about CSS or users not wanting to run yet another extension to modify the CSS.

Support Features with Action type of None

Currently if you assign any feature any action type, those features appear under Actions on the character sheet. This makes it hard to keep the same layout for features that have a limited use, but no action associated with them. There is an action type of none that can be chosen from the pulldown menu. Possibly treat these instances as features on the sheet.

I understand that this is possibly a limitation of how the underlying character sheet is actually moving these features to the actions section, so may be possible that this isn't possible within this module itself.

A good example of this found regularly is Legendary Resistance. It's usually listed early on the character sheets where it exists.

Property read error when rendering NPC sheet

Running with v2.2.2 in FVTT 0.7.5, I've started seeing MonsterBlocks throw the following error upon the opening of particular monster sheets:

foundry.js:4406 TypeError: An error occurred while rendering MonsterBlock5e 62: Cannot read property 'toLowerCase' of null
    at MonsterBlock5e.listsPassPercept (monsterblock.js:483)
    at MonsterBlock5e.getData (monsterblock.js:57)
    at MonsterBlock5e._render (foundry.js:4434)
    at MonsterBlock5e._render (foundry.js:5088)
    at MonsterBlock5e._render (foundry.js:16570)
    at MonsterBlock5e.render (foundry.js:4404)
    at MonsterBlock5e.render (foundry.js:5553)
    at ActorDirectory._onClickEntityName (foundry.js:16051)
    at ActorDirectory._onClickEntityName (foundry.js:25134)
    at HTMLOListElement.dispatch (jquery.min.js:2)
    at HTMLOListElement.v.handle (jquery.min.js:2)

This seems to be an error when calling the value of the NPC's passive perception. The monster blocks that I'm trying to open were grabbed from DNDBeyond using VTTAssets, but this happens with freshly-made NPCs as well. Not every NPC block gives this error, but e.g. the Grung or Lizardfolk Shaman sheets seem to be reproducing the error.

As an example, I can reproduce the error doing the following:

  1. Create NPC actor.
  2. Load the MonsterBlocks module.
  3. Open the NPC sheet.
  4. Close the NPC sheet and attempt to re-open it.

I have no difficulties opening the NPC sheet if MonsterBlocks is then disabled. Also, steps 1 and 2 are interchangable.

Please let me know if there's anything else needed to help with debugging!

Monster Blocks won't open after 2.4.1

Worked fine before the last update.

foundry.js:4481 TypeError: An error occurred while rendering MonsterBlock5e 99: Cannot read property 'missing' of undefined
    at Function.replaceFormulaData (patching.js:202)
    at Function.condenseRollFormula (monsterblock.js:2030)
    at MonsterBlock5e.getAttackBonus (monsterblock.js:989)
    at MonsterBlock5e.prepAttack (monsterblock.js:725)
    at MonsterBlock5e._prepareItems (monsterblock.js:525)
    at MonsterBlock5e.getData (base.js:110)
    at MonsterBlock5e.getData (npc.js:75)
    at MonsterBlock5e.getData (monsterblock.js:53)
    at MonsterBlock5e._render (foundry.js:4509)
    at MonsterBlock5e._render (foundry.js:5157)

MonsterBlocks causes CSS issue with Plut*** mod

Plut*** 1.4.1 + Monsterblocks. Plut*** uses the UI tweak Compact Header Buttons. It can be found in Plut*** settings in Journal, UI tab (bottom on left list). What is caused is that MonsterBlock extends the red X button on the whole length of a window. This affects not only MonsterBlocks but all other sheets. See below:

image

image

Plut*** has many functionalities but its UI tweaks are invaluable and I would love to be able to keep using them.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.